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: 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.
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));
}