# Rendering different materials in a voxel terrain

Each voxel datapoint in my terrain model is made up of two properties: density and material type. Each is stored as an unsigned integer value (but the density is interpreted as a decimal value between 0 and 1). The density values are used to generate a mesh with the marching cubes algorithm.

My current idea for rendering these different materials on the terrain mesh is to store eleven extra attributes in each vertex: six material values corresponding to the materials of the voxels that the vertices lie between, three decimal values that correspond to the interpolation each vertex has between each voxel, and two decimal values that are used to determine where the fragment lies on the triangle.

The material and interpolation attributes are the exact same for each vertex in the triangle. The fragment shader samples each texture that corresponds to each material and then uses the aforementioned couple of decimal values to interpolate between these samples and obtain the final textured color of the fragment.

It should work fine, but it seems like a big memory hog. I won't be able to reuse vertices in the mesh with indexing, and each vertex will have a lot of data associated with it. It also seems pretty slow. What are some ways to improve or replace this technique for drawing materials on a voxel terrain mesh?

Due to the sheer volume of data in your average voxel world, it will be challenging to draw much geometry with your approach, before hardware limits are reached, without some kind of spatial subdivision approach. You also need to be highly efficient in packing data at the bit/byte level.

Method: RLE

Enter Run-Length Encoding (RLE) compression as a popular option. Voxels are stored columns, as in the following example:

6E1G9A

Which means, from top to bottom, "6 earth, 1 grass, then 9 air".

So instead of storing a byte or more for every voxel, let alone every vertex, you instead create compressed columns of data that allow you to upload far more to the GPU, as uniform variables (GLSL lingo, not sure what they're called in HLSL). Instead of voxels scattered in 3D space, you have a single mesh representing each columnar run of homogeneous voxels (y-axis).

From a mesh building perspective, the idea is that you would then evaluate these RLE columns, fragment them into there individual runs, and create 8 vertices per run. You would simultaneously set up a uniform variable (GLSL) for any additional data you might need for that run, and upload the lot.

You would want to keep the full run-length encoded columns "from fundament to heaven", so to speak, on the CPU side, but you would send individual runs up to the GPU. This is because there will be breaks in a column where meshes end and new ones begin; think of a cross-section of an (x, z) area where there is a cave or air-pocket; you would have to end one columnar mesh where the floor is, and start another where the roof begins. You might have to do this several times in a single (x, z) location.

You largely want to avoid conditional logic / loops in shaders wherever possible, so try to do that sort of thing on the CPU side -- especially as regards basic geometry (see the next method for more on why I say "basic" geometry).

Where RLE gets more difficult is where you have to store eg. lighting, cellular automata or other information as well as data on materials. This causes a higher ratio of fragmentation if the same RLE container is used for that data, since the data is no longer as homogeneous as it was; hence, it may be better to simply upload separate runs for other elements that may affect rendering, such as lighting.