If you haven’t already, it’s worth taking a look through the Marching Squares posts for visualising scalar fields before jumping into these 3D versions. The basic principles are the same (I’ll assume knowledge of those principles in these posts), but they’re probably a bit easier to get to grips with. The 2D version of this contour example can be found here.
There’s a really great post on Marching Cubes by Paul Bourke, with all the case configurations – I’ve simply applied his work to the examples I used in the Marching Squares posts in Unity, so all credit for these posts to him.
Marching Cubes is the algorithm that Marching Squares (used in the 2D scalar field posts) was derived from. A lot of the work is therefore the same, but with a couple of changes. Firstly, we’re adding another dimension, which gives us a little more work to do in terms of assigning corner values and drawing the mesh.
Secondly, the number of configurations for each cube has increased. As before there are two possible states for each corner of the cube: inside the isolevel (equivalent of the term ‘threshold value’ used in the 2D posts), or outside the isolevel. This time, however, there are eight corners to consider instead of 4, so we have 256 different configurations instead of 16 (28 instead of 24). That’s unfortunately too many to display here, but I’ve created a CaseDemonstration scene to view them individually (there’s a tickbox in the App inspector that displays the grid cell outline, and you might have to move the view around in the Scene window to see the mesh correctly).
With the extra dimension, we’re now working with a cube that has the following corner indexing for determining the case index, going from the bottom to top and moving clockwise:
With those corner values assigned, we can work out the case configuration :
if (gridCell.VertexValue  < isolevel) caseIndex |= 1; if (gridCell.VertexValue  < isolevel) caseIndex |= 2; if (gridCell.VertexValue  < isolevel) caseIndex |= 4; if (gridCell.VertexValue  < isolevel) caseIndex |= 8; if (gridCell.VertexValue  < isolevel) caseIndex |= 16; if (gridCell.VertexValue  < isolevel) caseIndex |= 32; if (gridCell.VertexValue  < isolevel) caseIndex |= 64; if (gridCell.VertexValue  < isolevel) caseIndex |= 128;
This then gives us the case index for the triangle table lookup and tells us which and the edge points of our cube that need to be added to our mesh vertices array.
There are 12 of these edge points (indexing is shown below).
As with marching squares, a lot of the values and edge points are shared between cubes, so I’ve done a little extra work to pass information between neighbours where possible.
Applying this to a 3D grid, we now get the following result for the cone example:
NB : The colours are applied based Mesh.colors, by adding a colour value for each vertex being sampled based on its y value.