2
\$\begingroup\$

I have my game generate random voxel terrain, and then generate a mesh on only the visible parts of that terrain. I want it to be able to select some part of the terrain with the mouse, but I'm not sure how highlighting should be done properly. The only thing that comes to my mind is to recalculate whole chunks, updating selected voxels to brighter textures but it would by damn slow. I want to be able to change textures in that certain selected part of the mesh, without recalculating the whole chunk mesh. How to achieve that?

Edit: For better understanding, this is how the terrain looks: terrain Voxels are kept in a 3d array and chunks are recalculated every time its voxels are affected, adding mesh to chunk by checking if the voxel is exposed to air.

Chunk

Word object:
private void GenWorld()
{
    voxels = new Voxel[size * chunkSize, chunkHeight, size * chunkSize];

    for (int x = 0; x < size * chunkSize; x++)
    {
        for (int z = 0; z < size * chunkSize; z++)
        {
            int grass = PerlinNoise(x, 0, z, 100, 32, 0);
            grass += PerlinNoise(x, 0, z, 50, 16, 0);

            for (int y = 0; y < chunkHeight; y++)
            {
                if (y <= grass)
                    voxels[x, y, z] = new Voxel(new Vector3(x, y, z), VoxelType.Grass);
                else
                    voxels[x, y, z] = new Voxel(new Vector3(x, y, z), VoxelType.Air);
            }
        }
    }
}

private void GenChunks()
{
    chunks = new Chunk[size, size];

    for (int x = 0; x < size; x++)
    {
        for (int z = 0; z < size; z++)
        {
            GameObject tempChunk = Instantiate(chunkGO,
                new Vector3(x * chunkSize, 0, z * chunkSize),
                new Quaternion(0, 0, 0, 0)) as GameObject;
            tempChunk.transform.parent = transform;

            chunks[x, z] = tempChunk.GetComponent<Chunk>();
            chunks[x, z].worldGO = gameObject;
            chunks[x, z].posX = x * chunkSize;
            chunks[x, z].posY = 0;
            chunks[x, z].posZ = z * chunkSize;
        }
    }
}

Chunk object:
public void GenerateMesh()
{
    for (int x = 0; x < world.chunkSize; x++)
    for (int z = 0; z < world.chunkSize; z++)
    for (int y = 0; y < world.chunkHeight; y++)
    {
        Voxel voxel = GetVoxel(x, y, z);
        if (voxel.Type == VoxelType.Grass)
        {
            // Check if any face is exposed to air
            if (GetVoxel(x, y + 1, z).Type == VoxelType.Air)
                CubeTop(x, y, z, voxel);
            if (GetVoxel(x, y - 1, z).Type == VoxelType.Air)
                CubeBottom(x, y, z, voxel);
            if (GetVoxel(x + 1, y, z).Type == VoxelType.Air)
                CubeEast(x, y, z, voxel);
            if (GetVoxel(x - 1, y, z).Type == VoxelType.Air)
                CubeWest(x, y, z, voxel);
            if (GetVoxel(x, y, z + 1).Type == VoxelType.Air)
                CubeNorth(x, y, z, voxel);
            if (GetVoxel(x, y, z - 1).Type == VoxelType.Air)
                CubeSouth(x, y, z, voxel);
        }
    }

    UpdateMesh(); // Just passing data to unity mesh obj
}

void CubeTop(int x, int y, int z, Voxel voxel)
{
    vertices.Add(new Vector3(x, y, z + 1));
    vertices.Add(new Vector3(x + 1, y, z + 1));
    vertices.Add(new Vector3(x + 1, y, z));
    vertices.Add(new Vector3(x, y, z));

    BuildFace(voxel.TextureTop);
}


void BuildFace(TextureType type)
{
    triangles.Add(faceCount * 4);
    triangles.Add(faceCount * 4 + 1);
    triangles.Add(faceCount * 4 + 2);
    triangles.Add(faceCount * 4);
    triangles.Add(faceCount * 4 + 2);
    triangles.Add(faceCount * 4 + 3);

    Texture.SetTexture(uv, type);

    faceCount++;
}


public static void SetTexture(List<Vector2> uv, TextureType type)
{         
    Vector2 texturePos = (Vector2)textures[type];        

    uv.Add(new Vector2(textureOffset * texturePos.x + textureOffset, textureOffset * texturePos.y));
    uv.Add(new Vector2(textureOffset * texturePos.x + textureOffset, textureOffset * texturePos.y + textureOffset));
    uv.Add(new Vector2(textureOffset * texturePos.x, textureOffset * texturePos.y + textureOffset));
    uv.Add(new Vector2(textureOffset * texturePos.x, textureOffset * texturePos.y));
}
\$\endgroup\$
  • \$\begingroup\$ It depends how you create your blocks... How do you do that? \$\endgroup\$ – Savlon Jun 15 '14 at 11:18
  • \$\begingroup\$ Blocks are just array of objects stacked in column 16x64x16. Mesh is generated by checking if block is exposed to air (if it is visible). \$\endgroup\$ – ddl Jun 15 '14 at 11:24
  • \$\begingroup\$ So you are just looking for a way to display which block the cursor is over? \$\endgroup\$ – Savlon Jun 15 '14 at 11:42
  • \$\begingroup\$ Yes I'm having mouse-selecting module already done but I dont know how to update certain voxel texture in whole chunk mesh to make it have 'highlight' texture. \$\endgroup\$ – ddl Jun 15 '14 at 11:47
  • \$\begingroup\$ Ok well I need to know how you create your mesh and texture it so we can figure out which way to approach the highlighting... There are a lot of ways to implement voxel terrain and if you can't show how YOU implement it then I can't help you... \$\endgroup\$ – Savlon Jun 15 '14 at 11:58
1
\$\begingroup\$

A projector would work here. They're a little expensive because they cause the meshes they touch to be redrawn (essentially adds one more draw call in the manner certain shaders would), but that's something Unity internally during rendering, you won't have to do anything with the chunk's data.

\$\endgroup\$
1
\$\begingroup\$

Better than a projector you should be able to write a custom shader that highlights some quads given the mouse click world coordinates. Should be pretty cheap in resources if done right, and you can both use another texture or simply multiply by a color and avoid wasting unneeded memory.

I'm not a shader expert but I'm working on something similar and you can do this in the fragment shader with a single rectangle check for the mouse click and the fragment world position (I can provide more help with that if you're interested).

\$\endgroup\$
  • \$\begingroup\$ Note that I might have made this sound easy, if you're not familiar with shader writing this might get tricky. If you know how to write shaders in unity this shouldn't be really difficult though. As I said I can provide more help if you need it. \$\endgroup\$ – Setzer22 Aug 11 '14 at 12:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.