本文描述了一个创建三维标量场等值面多边形曲面表示的算法。这类问题的一个常见名称是所谓的“移动立方体”算法。它结合了简单和高速,因为它几乎完全用于查找表。
这种技术有很多应用,两个非常常见的是:
    从医学体积数据集重建表面。例如,MRI扫描在常规3d网格的顶点处产生一个3d体积的样本。
    创建数学标量场的三维轮廓。在这种情况下,函数是已知的,但在一个常规的3D网格的顶点采样。

1.解决方案
    其基本问题是通过在矩形三维网格上采样的标量场形成一个面逼近等值面。给定一个由顶点和每个顶点的标量值定义的网格单元,有必要创建通过该网格单元最能代表等值面的平面facet。等值面可能不会穿过网格单元格,它可能切断任何一个顶点,或者它可能通过许多更复杂的方式中的任何一种。每一种可能性都将以等值面以上或以下值的顶点数来表征。如果一个顶点在等值面上,而另一个相邻顶点在等值面上,那么我们就知道等值面上切割这两个顶点之间的边。它切割边缘的位置将被线性插值,两个顶点之间的长度之比将与等值面值与网格单元格顶点处值之比相同。
    算法中使用的顶点和边的索引约定如下所示

例如,如果顶点3的值低于等值面值,而所有其他顶点的值都高于等值面值,那么我们将创建一个三角形面,它穿过边2、3和11。三角形面的顶点的确切位置分别取决于等值面值与顶点3-2、3-0、3-7上的值的关系。

使算法“困难”的是大量的可能组合(256个),以及需要为每个解决方案导出一致的facet组合,以便相邻网格单元的facet正确地连接在一起。
    算法的第一部分使用一个表(edgeTable),它将等值面下的顶点映射到相交的边缘。一个8位的索引是由每个位对应一个顶点形成的。
   cubeindex = 0;
   if (grid.val[0] < isolevel) cubeindex |= 1;
   if (grid.val[1] < isolevel) cubeindex |= 2;
   if (grid.val[2] < isolevel) cubeindex |= 4;
   if (grid.val[3] < isolevel) cubeindex |= 8;
   if (grid.val[4] < isolevel) cubeindex |= 16;
   if (grid.val[5] < isolevel) cubeindex |= 32;
   if (grid.val[6] < isolevel) cubeindex |= 64;
   if (grid.val[7] < isolevel) cubeindex |= 128;
    查找边缘表返回一个12位的数字,每一位对应一条边,0表示该边没有被等值面切割,1表示该边被等值面切割。如果没有任何边被切割,则表返回0,当cubeindex为0(等值面以下的所有顶点)或0xff(等值面以上的所有顶点)时就会发生这种情况。
    使用前面的例子,只有顶点3低于等值面,cubeindex将等于0000 1000或8。edgeTable[8] = 1000 0000 1100。这意味着边2,3和11与等值面相交。
    交点现在由线性插值计算。如果P1和P2是切边的两个顶点,V1和V2是每个顶点的标量值,那么交点P是
    P = P1 +(等值- V1) (P2 - P1) / (V2 - V1)
    算法的最后一部分涉及到从等值面与网格单元的边缘相交的位置形成正确的facet。同样使用了一个表(triTable),这次使用相同的立方体索引,但允许查找顶点序列,因为在网格单元中表示等值面需要多少三角形面就需要多少三角形面。最多需要5个三角形面。
    回到我们的例子,在前面的步骤中,我们计算了沿边2、3和11的交点。triTable中的第8个元素是
    {3、11、2、1,1,1,1,1,1,1,1,1,1,1,1,1},
    这是一个特别简单的示例,请确保facet组合对于表中的许多情况不是那么明显。
2.举例子
    假设顶点0和3在等值面以下。Cubeindex将是0000 1001 == 9。进入egdeTable的第9项是905hex == 1001 0000 0101,这意味着边11、8、2和0被切割,所以我们计算出等面与这些边相交的顶点。
    接下来,triitable中的9是0,11,2,8,11,0。这对应于两个三角形面片,一个在边0,11和2的交点之间。另一个在沿边8 11和0的交点之间。
3.网格分辨率
    当对一个值已知或可以在空间中任意位置插值的字段进行多边形化时,一个非常理想的控制是采样网格的分辨率。这允许根据所需的平滑度和/或显示表面的处理能力生成等面的过程或精细近似。

4.源代码
    基于OpenGL绘制(VS可直接运行)

#include "stdio.h"
#include "math.h"
//This program requires the OpenGL and GLUT libraries
// You can obtain them for free from http://www.opengl.org
#include "GL/glut.h"struct GLvector
{GLfloat fX;GLfloat fY;GLfloat fZ;
};//These tables are used so that everything can be done in little loops that you can look at all at once
// rather than in pages and pages of unrolled code.//a2fVertexOffset lists the positions, relative to vertex0, of each of the 8 vertices of a cube
static const GLfloat a2fVertexOffset[8][3] =
{{0.0, 0.0, 0.0},{1.0, 0.0, 0.0},{1.0, 1.0, 0.0},{0.0, 1.0, 0.0},{0.0, 0.0, 1.0},{1.0, 0.0, 1.0},{1.0, 1.0, 1.0},{0.0, 1.0, 1.0}
};//a2iEdgeConnection lists the index of the endpoint vertices for each of the 12 edges of the cube
static const GLint a2iEdgeConnection[12][2] =
{{0,1}, {1,2}, {2,3}, {3,0},{4,5}, {5,6}, {6,7}, {7,4},{0,4}, {1,5}, {2,6}, {3,7}
};//a2fEdgeDirection lists the direction vector (vertex1-vertex0) for each edge in the cube
static const GLfloat a2fEdgeDirection[12][3] =
{{1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{-1.0, 0.0, 0.0},{0.0, -1.0, 0.0},{1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{-1.0, 0.0, 0.0},{0.0, -1.0, 0.0},{0.0, 0.0, 1.0},{0.0, 0.0, 1.0},{ 0.0, 0.0, 1.0},{0.0,  0.0, 1.0}
};//a2iTetrahedronEdgeConnection lists the index of the endpoint vertices for each of the 6 edges of the tetrahedron
static const GLint a2iTetrahedronEdgeConnection[6][2] =
{{0,1},  {1,2},  {2,0},  {0,3},  {1,3},  {2,3}
};//a2iTetrahedronEdgeConnection lists the index of verticies from a cube
// that made up each of the six tetrahedrons within the cube
static const GLint a2iTetrahedronsInACube[6][4] =
{{0,5,1,6},{0,1,2,6},{0,2,3,6},{0,3,7,6},{0,7,4,6},{0,4,5,6},
};static const GLfloat afAmbientWhite [] = {0.25, 0.25, 0.25, 1.00};
static const GLfloat afAmbientRed   [] = {0.25, 0.00, 0.00, 1.00};
static const GLfloat afAmbientGreen [] = {0.00, 0.25, 0.00, 1.00};
static const GLfloat afAmbientBlue  [] = {0.00, 0.00, 0.25, 1.00};
static const GLfloat afDiffuseWhite [] = {0.75, 0.75, 0.75, 1.00};
static const GLfloat afDiffuseRed   [] = {0.75, 0.00, 0.00, 1.00};
static const GLfloat afDiffuseGreen [] = {0.00, 0.75, 0.00, 1.00};
static const GLfloat afDiffuseBlue  [] = {0.00, 0.00, 0.75, 1.00};
static const GLfloat afSpecularWhite[] = {1.00, 1.00, 1.00, 1.00};
static const GLfloat afSpecularRed  [] = {1.00, 0.25, 0.25, 1.00};
static const GLfloat afSpecularGreen[] = {0.25, 1.00, 0.25, 1.00};
static const GLfloat afSpecularBlue [] = {0.25, 0.25, 1.00, 1.00}; GLenum    ePolygonMode = GL_LINE;
GLint     iDataSetSize = 26;
GLfloat   fStepSize = 1.0/iDataSetSize;
GLfloat   fTargetValue = 48.0;
GLfloat   fTime = 0.0;
GLvector  sSourcePoint[3];
GLboolean bSpin = true;
GLboolean bMove = true;
GLboolean bLight = true;void vIdle();
void vDrawScene();
void vResize(GLsizei, GLsizei);
void vKeyboard(unsigned char cKey, int iX, int iY);
void vSpecial(int iKey, int iX, int iY);GLvoid vPrintHelp();
GLvoid vSetTime(GLfloat fTime);
GLfloat fSample1(GLfloat fX, GLfloat fY, GLfloat fZ);
GLfloat fSample2(GLfloat fX, GLfloat fY, GLfloat fZ);
GLfloat fSample3(GLfloat fX, GLfloat fY, GLfloat fZ);
GLfloat (*fSample)(GLfloat fX, GLfloat fY, GLfloat fZ) = fSample1;GLvoid vMarchingCubes();
GLvoid vMarchCube1(GLfloat fX, GLfloat fY, GLfloat fZ, GLfloat fScale);
GLvoid vMarchCube2(GLfloat fX, GLfloat fY, GLfloat fZ, GLfloat fScale);
GLvoid (*vMarchCube)(GLfloat fX, GLfloat fY, GLfloat fZ, GLfloat fScale) = vMarchCube1;void main(int argc, char **argv)
{ GLfloat afPropertiesAmbient [] = {0.50, 0.50, 0.50, 1.00}; GLfloat afPropertiesDiffuse [] = {0.75, 0.75, 0.75, 1.00}; GLfloat afPropertiesSpecular[] = {1.00, 1.00, 1.00, 1.00}; GLsizei iWidth = 640.0; GLsizei iHeight = 480.0; glutInit(&argc, argv);glutInitWindowPosition( 0, 0);glutInitWindowSize(iWidth, iHeight);glutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE );glutCreateWindow( "Marching Cubes" );glutDisplayFunc( vDrawScene );glutIdleFunc( vIdle );glutReshapeFunc( vResize );glutKeyboardFunc( vKeyboard );glutSpecialFunc( vSpecial );glClearColor( 0.0, 0.0, 0.0, 1.0 ); glClearDepth( 1.0 ); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING);glPolygonMode(GL_FRONT_AND_BACK, ePolygonMode);glLightfv( GL_LIGHT0, GL_AMBIENT,  afPropertiesAmbient); glLightfv( GL_LIGHT0, GL_DIFFUSE,  afPropertiesDiffuse); glLightfv( GL_LIGHT0, GL_SPECULAR, afPropertiesSpecular); glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 1.0); glEnable( GL_LIGHT0 ); glMaterialfv(GL_BACK,  GL_AMBIENT,   afAmbientGreen); glMaterialfv(GL_BACK,  GL_DIFFUSE,   afDiffuseGreen); glMaterialfv(GL_FRONT, GL_AMBIENT,   afAmbientBlue); glMaterialfv(GL_FRONT, GL_DIFFUSE,   afDiffuseBlue); glMaterialfv(GL_FRONT, GL_SPECULAR,  afSpecularWhite); glMaterialf( GL_FRONT, GL_SHININESS, 25.0); vResize(iWidth, iHeight); vPrintHelp();glutMainLoop(); }GLvoid vPrintHelp()
{printf("Marching Cubes Example by Cory Bloyd (dejaspaminacan@my-deja.com)\n\n");printf("+/-  increase/decrease sample density\n");printf("PageUp/PageDown  increase/decrease surface value\n");printf("s  change sample function\n");printf("c  toggle marching cubes / marching tetrahedrons\n");printf("w  wireframe on/off\n");printf("l  toggle lighting / color-by-normal\n");printf("Home  spin scene on/off\n");printf("End  source point animation on/off\n");
}void vResize( GLsizei iWidth, GLsizei iHeight )
{ GLfloat fAspect, fHalfWorldSize = (1.4142135623730950488016887242097/2); glViewport( 0, 0, iWidth, iHeight ); glMatrixMode (GL_PROJECTION);glLoadIdentity ();if(iWidth <= iHeight){fAspect = (GLfloat)iHeight / (GLfloat)iWidth;glOrtho(-fHalfWorldSize, fHalfWorldSize, -fHalfWorldSize*fAspect,fHalfWorldSize*fAspect, -10*fHalfWorldSize, 10*fHalfWorldSize);}else{fAspect = (GLfloat)iWidth / (GLfloat)iHeight; glOrtho(-fHalfWorldSize*fAspect, fHalfWorldSize*fAspect, -fHalfWorldSize,fHalfWorldSize, -10*fHalfWorldSize, 10*fHalfWorldSize);}glMatrixMode( GL_MODELVIEW );
}void vKeyboard(unsigned char cKey, int iX, int iY)
{switch(cKey){case 'w' :{if(ePolygonMode == GL_LINE){ePolygonMode = GL_FILL;}else{ePolygonMode = GL_LINE;}glPolygonMode(GL_FRONT_AND_BACK, ePolygonMode);} break;case '+' :case '=' :{++iDataSetSize;fStepSize = 1.0/iDataSetSize;} break;case '-' :{if(iDataSetSize > 1){--iDataSetSize;fStepSize = 1.0/iDataSetSize;}} break;case 'c' :{if(vMarchCube == vMarchCube1){vMarchCube = vMarchCube1;//Use Marching Tetrahedrons}else{vMarchCube = vMarchCube1;//Use Marching Cubes}} break;case 's' :{if(fSample == fSample1){fSample = fSample1;}else if(fSample == fSample2){fSample = fSample1;}else{fSample = fSample1;}} break;case 'l' :{if(bLight){glDisable(GL_LIGHTING);//use vertex colors}else{glEnable(GL_LIGHTING);//use lit material color}bLight = !bLight;};}
}void vSpecial(int iKey, int iX, int iY)
{switch(iKey){case GLUT_KEY_PAGE_UP :{if(fTargetValue < 1000.0){fTargetValue *= 1.1;}} break;case GLUT_KEY_PAGE_DOWN :{if(fTargetValue > 1.0){fTargetValue /= 1.1;}} break;case GLUT_KEY_HOME :{bSpin = !bSpin;} break;case GLUT_KEY_END :{bMove = !bMove;} break;}
}void vIdle()
{glutPostRedisplay();
}void vDrawScene()
{ static GLfloat fPitch = 0.0;static GLfloat fYaw   = 0.0;static GLfloat fTime = 0.0;glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glPushMatrix(); if(bSpin){fPitch += 4.0;fYaw   += 2.5;}if(bMove){fTime  += 0.025;}vSetTime(fTime);glTranslatef(0.0, 0.0, -1.0);  glRotatef( -fPitch, 1.0, 0.0, 0.0);glRotatef(     0.0, 0.0, 1.0, 0.0);glRotatef(    fYaw, 0.0, 0.0, 1.0);glPushAttrib(GL_LIGHTING_BIT);glDisable(GL_LIGHTING);glColor3f(1.0, 1.0, 1.0);glutWireCube(1.0); glPopAttrib(); glPushMatrix(); glTranslatef(-0.5, -0.5, -0.5);glBegin(GL_TRIANGLES);vMarchingCubes();glEnd();glPopMatrix(); glPopMatrix(); glutSwapBuffers();
}//fGetOffset finds the approximate point of intersection of the surface
// between two points with the values fValue1 and fValue2
GLfloat fGetOffset(GLfloat fValue1, GLfloat fValue2, GLfloat fValueDesired)
{GLdouble fDelta = fValue2 - fValue1;if(fDelta == 0.0){return 0.5;}return (fValueDesired - fValue1)/fDelta;
}//vGetColor generates a color from a given position and normal of a point
GLvoid vGetColor(GLvector &rfColor, GLvector &rfPosition, GLvector &rfNormal)
{GLfloat fX = rfNormal.fX;GLfloat fY = rfNormal.fY;GLfloat fZ = rfNormal.fZ;rfColor.fX = (fX > 0.0 ? fX : 0.0) + (fY < 0.0 ? -0.5*fY : 0.0) + (fZ < 0.0 ? -0.5*fZ : 0.0);rfColor.fY = (fY > 0.0 ? fY : 0.0) + (fZ < 0.0 ? -0.5*fZ : 0.0) + (fX < 0.0 ? -0.5*fX : 0.0);rfColor.fZ = (fZ > 0.0 ? fZ : 0.0) + (fX < 0.0 ? -0.5*fX : 0.0) + (fY < 0.0 ? -0.5*fY : 0.0);
}GLvoid vNormalizeVector(GLvector &rfVectorResult, GLvector &rfVectorSource)
{GLfloat fOldLength;GLfloat fScale;fOldLength = sqrtf( (rfVectorSource.fX * rfVectorSource.fX) +(rfVectorSource.fY * rfVectorSource.fY) +(rfVectorSource.fZ * rfVectorSource.fZ) );if(fOldLength == 0.0){rfVectorResult.fX = rfVectorSource.fX;rfVectorResult.fY = rfVectorSource.fY;rfVectorResult.fZ = rfVectorSource.fZ;}else{fScale = 1.0/fOldLength;rfVectorResult.fX = rfVectorSource.fX*fScale;rfVectorResult.fY = rfVectorSource.fY*fScale;rfVectorResult.fZ = rfVectorSource.fZ*fScale;}
}//Generate a sample data set.  fSample1(), fSample2() and fSample3() define three scalar fields whose
// values vary by the X,Y and Z coordinates and by the fTime value set by vSetTime()
GLvoid vSetTime(GLfloat fNewTime)
{GLfloat fOffset;GLint iSourceNum;for(iSourceNum = 0; iSourceNum < 3; iSourceNum++){sSourcePoint[iSourceNum].fX = 0.5;sSourcePoint[iSourceNum].fY = 0.5;sSourcePoint[iSourceNum].fZ = 0.5;}fTime = fNewTime;fOffset = 1.0 + sinf(fTime);sSourcePoint[0].fX *= fOffset;sSourcePoint[1].fY *= fOffset;sSourcePoint[2].fZ *= fOffset;
}//fSample1 finds the distance of (fX, fY, fZ) from three moving points
GLfloat fSample3(GLfloat fX, GLfloat fY, GLfloat fZ)
{GLdouble fResult = 0.0;GLdouble fDx, fDy, fDz;fDx = fX - sSourcePoint[0].fX;fDy = fY - sSourcePoint[0].fY;fDz = fZ - sSourcePoint[0].fZ;fResult += 0.5/(fDx*fDx + fDy*fDy + fDz*fDz);fDx = fX - sSourcePoint[1].fX;fDy = fY - sSourcePoint[1].fY;fDz = fZ - sSourcePoint[1].fZ;fResult += 1.0/(fDx*fDx + fDy*fDy + fDz*fDz);fDx = fX - sSourcePoint[2].fX;fDy = fY - sSourcePoint[2].fY;fDz = fZ - sSourcePoint[2].fZ;fResult += 1.5/(fDx*fDx + fDy*fDy + fDz*fDz);return fResult;
}//fSample2 finds the distance of (fX, fY, fZ) from three moving lines
GLfloat fSample2(GLfloat fX, GLfloat fY, GLfloat fZ)
{GLdouble fResult = 0.0;GLdouble fDx, fDy, fDz;fDx = fX - sSourcePoint[0].fX;fDy = fY - sSourcePoint[0].fY;fResult += 0.5/(fDx*fDx + fDy*fDy);fDx = fX - sSourcePoint[1].fX;fDz = fZ - sSourcePoint[1].fZ;fResult += 0.75/(fDx*fDx + fDz*fDz);fDy = fY - sSourcePoint[2].fY;fDz = fZ - sSourcePoint[2].fZ;fResult += 1.0/(fDy*fDy + fDz*fDz);return fResult;
}//fSample2 defines a height field by plugging the distance from the center into the sin and cos functions
GLfloat fSample1(GLfloat fX, GLfloat fY, GLfloat fZ)
{GLfloat fHeight = ((sqrt((0.5-fX)*(0.5-fX) + (0.5-fY)*(0.5-fY))) +48);GLdouble fResult = (fHeight-fZ);return fResult;
}//vGetNormal() finds the gradient of the scalar field at a point
//This gradient can be used as a very accurate vertx normal for lighting calculations
GLvoid vGetNormal(GLvector &rfNormal, GLfloat fX, GLfloat fY, GLfloat fZ)
{rfNormal.fX = fSample(fX-0.01, fY, fZ) - fSample(fX+0.01, fY, fZ);rfNormal.fY = fSample(fX, fY-0.01, fZ) - fSample(fX, fY+0.01, fZ);rfNormal.fZ = fSample(fX, fY, fZ-0.01) - fSample(fX, fY, fZ+0.01);vNormalizeVector(rfNormal, rfNormal);
}//vMarchCube1 performs the Marching Cubes algorithm on a single cube
GLvoid vMarchCube1(GLfloat fX, GLfloat fY, GLfloat fZ, GLfloat fScale)
{extern GLint aiCubeEdgeFlags[256];extern GLint a2iTriangleConnectionTable[256][16];GLint iCorner, iVertex, iVertexTest, iEdge, iTriangle, iFlagIndex, iEdgeFlags;GLfloat fOffset;GLvector sColor;GLfloat afCubeValue[8];GLvector asEdgeVertex[12];GLvector asEdgeNorm[12];//Make a local copy of the values at the cube's cornersfor(iVertex = 0; iVertex < 8; iVertex++){afCubeValue[iVertex] = fSample(fX + a2fVertexOffset[iVertex][0]*fScale,fY + a2fVertexOffset[iVertex][1]*fScale,fZ + a2fVertexOffset[iVertex][2]*fScale);}//Find which vertices are inside of the surface and which are outsideiFlagIndex = 0;for(iVertexTest = 0; iVertexTest < 8; iVertexTest++){if(afCubeValue[iVertexTest] <= fTargetValue) iFlagIndex |= 1<<iVertexTest;}//Find which edges are intersected by the surfaceiEdgeFlags = aiCubeEdgeFlags[iFlagIndex];//If the cube is entirely inside or outside of the surface, then there will be no intersectionsif(iEdgeFlags == 0) {return;}//Find the point of intersection of the surface with each edge//Then find the normal to the surface at those pointsfor(iEdge = 0; iEdge < 12; iEdge++){//if there is an intersection on this edgeif(iEdgeFlags & (1<<iEdge)){fOffset = fGetOffset(afCubeValue[ a2iEdgeConnection[iEdge][0] ], afCubeValue[ a2iEdgeConnection[iEdge][1] ], fTargetValue);asEdgeVertex[iEdge].fX = fX + (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][0]  +  fOffset * a2fEdgeDirection[iEdge][0]) * fScale;asEdgeVertex[iEdge].fY = fY + (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][1]  +  fOffset * a2fEdgeDirection[iEdge][1]) * fScale;asEdgeVertex[iEdge].fZ = fZ + (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][2]  +  fOffset * a2fEdgeDirection[iEdge][2]) * fScale;vGetNormal(asEdgeNorm[iEdge], asEdgeVertex[iEdge].fX, asEdgeVertex[iEdge].fY, asEdgeVertex[iEdge].fZ);}}//Draw the triangles that were found.  There can be up to five per cubefor(iTriangle = 0; iTriangle < 5; iTriangle++){if(a2iTriangleConnectionTable[iFlagIndex][3*iTriangle] < 0)break;for(iCorner = 0; iCorner < 3; iCorner++){iVertex = a2iTriangleConnectionTable[iFlagIndex][3*iTriangle+iCorner];vGetColor(sColor, asEdgeVertex[iVertex], asEdgeNorm[iVertex]);glColor3f(sColor.fX, sColor.fY, sColor.fZ);glNormal3f(asEdgeNorm[iVertex].fX,   asEdgeNorm[iVertex].fY,   asEdgeNorm[iVertex].fZ);glVertex3f(asEdgeVertex[iVertex].fX, asEdgeVertex[iVertex].fY, asEdgeVertex[iVertex].fZ);}}
}//vMarchTetrahedron performs the Marching Tetrahedrons algorithm on a single tetrahedron
GLvoid vMarchTetrahedron(GLvector *pasTetrahedronPosition, GLfloat *pafTetrahedronValue)
{extern GLint aiTetrahedronEdgeFlags[16];extern GLint a2iTetrahedronTriangles[16][7];GLint iEdge, iVert0, iVert1, iEdgeFlags, iTriangle, iCorner, iVertex, iFlagIndex = 0;GLfloat fOffset, fInvOffset, fValue = 0.0;GLvector asEdgeVertex[6];GLvector asEdgeNorm[6];GLvector sColor;//Find which vertices are inside of the surface and which are outsidefor(iVertex = 0; iVertex < 4; iVertex++){if(pafTetrahedronValue[iVertex] <= fTargetValue) iFlagIndex |= 1<<iVertex;}//Find which edges are intersected by the surfaceiEdgeFlags = aiTetrahedronEdgeFlags[iFlagIndex];//If the tetrahedron is entirely inside or outside of the surface, then there will be no intersectionsif(iEdgeFlags == 0){return;}//Find the point of intersection of the surface with each edge// Then find the normal to the surface at those pointsfor(iEdge = 0; iEdge < 6; iEdge++){//if there is an intersection on this edgeif(iEdgeFlags & (1<<iEdge)){iVert0 = a2iTetrahedronEdgeConnection[iEdge][0];iVert1 = a2iTetrahedronEdgeConnection[iEdge][1];fOffset = fGetOffset(pafTetrahedronValue[iVert0], pafTetrahedronValue[iVert1], fTargetValue);fInvOffset = 1.0 - fOffset;asEdgeVertex[iEdge].fX = fInvOffset*pasTetrahedronPosition[iVert0].fX  +  fOffset*pasTetrahedronPosition[iVert1].fX;asEdgeVertex[iEdge].fY = fInvOffset*pasTetrahedronPosition[iVert0].fY  +  fOffset*pasTetrahedronPosition[iVert1].fY;asEdgeVertex[iEdge].fZ = fInvOffset*pasTetrahedronPosition[iVert0].fZ  +  fOffset*pasTetrahedronPosition[iVert1].fZ;vGetNormal(asEdgeNorm[iEdge], asEdgeVertex[iEdge].fX, asEdgeVertex[iEdge].fY, asEdgeVertex[iEdge].fZ);}}//Draw the triangles that were found.  There can be up to 2 per tetrahedronfor(iTriangle = 0; iTriangle < 2; iTriangle++){if(a2iTetrahedronTriangles[iFlagIndex][3*iTriangle] < 0)break;for(iCorner = 0; iCorner < 3; iCorner++){iVertex = a2iTetrahedronTriangles[iFlagIndex][3*iTriangle+iCorner];vGetColor(sColor, asEdgeVertex[iVertex], asEdgeNorm[iVertex]);glColor3f(sColor.fX, sColor.fY, sColor.fZ);glNormal3f(asEdgeNorm[iVertex].fX,   asEdgeNorm[iVertex].fY,   asEdgeNorm[iVertex].fZ);glVertex3f(asEdgeVertex[iVertex].fX, asEdgeVertex[iVertex].fY, asEdgeVertex[iVertex].fZ);}}
}//vMarchCube2 performs the Marching Tetrahedrons algorithm on a single cube by making six calls to vMarchTetrahedron
GLvoid vMarchCube2(GLfloat fX, GLfloat fY, GLfloat fZ, GLfloat fScale)
{GLint iVertex, iTetrahedron, iVertexInACube;GLvector asCubePosition[8];GLfloat  afCubeValue[8];GLvector asTetrahedronPosition[4];GLfloat  afTetrahedronValue[4];//Make a local copy of the cube's corner positionsfor(iVertex = 0; iVertex < 8; iVertex++){asCubePosition[iVertex].fX = fX + a2fVertexOffset[iVertex][0]*fScale;asCubePosition[iVertex].fY = fY + a2fVertexOffset[iVertex][1]*fScale;asCubePosition[iVertex].fZ = fZ + a2fVertexOffset[iVertex][2]*fScale;}//Make a local copy of the cube's corner valuesfor(iVertex = 0; iVertex < 8; iVertex++){afCubeValue[iVertex] = fSample(asCubePosition[iVertex].fX,asCubePosition[iVertex].fY,asCubePosition[iVertex].fZ);}for(iTetrahedron = 0; iTetrahedron < 6; iTetrahedron++){for(iVertex = 0; iVertex < 4; iVertex++){iVertexInACube = a2iTetrahedronsInACube[iTetrahedron][iVertex];asTetrahedronPosition[iVertex].fX = asCubePosition[iVertexInACube].fX;asTetrahedronPosition[iVertex].fY = asCubePosition[iVertexInACube].fY;asTetrahedronPosition[iVertex].fZ = asCubePosition[iVertexInACube].fZ;afTetrahedronValue[iVertex] = afCubeValue[iVertexInACube];}vMarchTetrahedron(asTetrahedronPosition, afTetrahedronValue);}
}//vMarchingCubes iterates over the entire dataset, calling vMarchCube on each cube
GLvoid vMarchingCubes()
{GLint iX, iY, iZ;for(iX = 0; iX < iDataSetSize; iX++)for(iY = 0; iY < iDataSetSize; iY++)for(iZ = 0; iZ < iDataSetSize; iZ++){vMarchCube(iX*fStepSize, iY*fStepSize, iZ*fStepSize, fStepSize);}
}// For any edge, if one vertex is inside of the surface and the other is outside of the surface
//  then the edge intersects the surface
// For each of the 4 vertices of the tetrahedron can be two possible states : either inside or outside of the surface
// For any tetrahedron the are 2^4=16 possible sets of vertex states
// This table lists the edges intersected by the surface for all 16 possible vertex states
// There are 6 edges.  For each entry in the table, if edge #n is intersected, then bit #n is set to 1GLint aiTetrahedronEdgeFlags[16]=
{0x00, 0x0d, 0x13, 0x1e, 0x26, 0x2b, 0x35, 0x38, 0x38, 0x35, 0x2b, 0x26, 0x1e, 0x13, 0x0d, 0x00,
};// For each of the possible vertex states listed in aiTetrahedronEdgeFlags there is a specific triangulation
// of the edge intersection points.  a2iTetrahedronTriangles lists all of them in the form of
// 0-2 edge triples with the list terminated by the invalid value -1.
//
// I generated this table by handGLint a2iTetrahedronTriangles[16][7] =
{{-1, -1, -1, -1, -1, -1, -1},{ 0,  3,  2, -1, -1, -1, -1},{ 0,  1,  4, -1, -1, -1, -1},{ 1,  4,  2,  2,  4,  3, -1},{ 1,  2,  5, -1, -1, -1, -1},{ 0,  3,  5,  0,  5,  1, -1},{ 0,  2,  5,  0,  5,  4, -1},{ 5,  4,  3, -1, -1, -1, -1},{ 3,  4,  5, -1, -1, -1, -1},{ 4,  5,  0,  5,  2,  0, -1},{ 1,  5,  0,  5,  3,  0, -1},{ 5,  2,  1, -1, -1, -1, -1},{ 3,  4,  2,  2,  4,  1, -1},{ 4,  1,  0, -1, -1, -1, -1},{ 2,  3,  0, -1, -1, -1, -1},{-1, -1, -1, -1, -1, -1, -1},
};// For any edge, if one vertex is inside of the surface and the other is outside of the surface
//  then the edge intersects the surface
// For each of the 8 vertices of the cube can be two possible states : either inside or outside of the surface
// For any cube the are 2^8=256 possible sets of vertex states
// This table lists the edges intersected by the surface for all 256 possible vertex states
// There are 12 edges.  For each entry in the table, if edge #n is intersected, then bit #n is set to 1GLint aiCubeEdgeFlags[256]=
{0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, 0x190, 0x099, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, 0x230, 0x339, 0x033, 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, 0x3a0, 0x2a9, 0x1a3, 0x0aa, 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, 0x460, 0x569, 0x663, 0x76a, 0x066, 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0x0ff, 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x055, 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0x0cc, 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0x0cc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x055, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0x0ff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x066, 0x76a, 0x663, 0x569, 0x460, 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0x0aa, 0x1a3, 0x2a9, 0x3a0, 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x033, 0x339, 0x230, 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x099, 0x190, 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000
};//  For each of the possible vertex states listed in aiCubeEdgeFlags there is a specific triangulation
//  of the edge intersection points.  a2iTriangleConnectionTable lists all of them in the form of
//  0-5 edge triples with the list terminated by the invalid value -1.
//  For example: a2iTriangleConnectionTable[3] list the 2 triangles formed when corner[0]
//  and corner[1] are inside of the surface, but the rest of the cube is not.
//
//  I found this table in an example program someone wrote long ago.  It was probably generated by handGLint a2iTriangleConnectionTable[256][16] =
{{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},{3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},{3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},{3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},{9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},{1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},{9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},{2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},{8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},{9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},{4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},{3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},{1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},{4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},{4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},{9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},{1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},{5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},{2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},{9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},{0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},{2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},{10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},{4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},{5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},{5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},{9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},{0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},{1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},{10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},{8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},{2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},{7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},{9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},{2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},{11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},{9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},{5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},{11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},{11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},{1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},{9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},{5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},{2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},{0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},{5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},{6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},{0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},{3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},{6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},{5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},{1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},{10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},{6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},{1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},{8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},{7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},{3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},{5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},{0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},{9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},{8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},{5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},{0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},{6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},{10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},{10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},{8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},{1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},{3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},{0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},{10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},{0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},{3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},{6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},{9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},{8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},{3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},{6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},{0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},{10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},{10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},{1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},{2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},{7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},{7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},{2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},{1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},{11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},{8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},{0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},{7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},{10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},{2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},{6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},{7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},{2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},{1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},{10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},{10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},{0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},{7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},{6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},{8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},{9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},{6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},{1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},{4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},{10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},{8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},{0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},{1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},{8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},{10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},{4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},{10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},{5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},{11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},{9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},{6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},{7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},{3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},{7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},{9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},{3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},{6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},{9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},{1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},{4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},{7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},{6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},{3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},{0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},{6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},{1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},{0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},{11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},{6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},{5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},{9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},{1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},{1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},{10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},{0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},{5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},{10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},{11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},{0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},{9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},{7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},{2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},{8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},{9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},{9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},{1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},{9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},{9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},{5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},{0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},{10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},{2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},{0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},{0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},{9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},{5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},{3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},{5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},{8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},{0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},{9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},{0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},{1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},{3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},{4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},{9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},{11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},{11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},{2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},{9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},{3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},{1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},{4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},{4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},{0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},{3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},{3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},{0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},{9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},{1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
};

亲测运行效果如下:

5.算法细节
    这个算法有两个主要组成部分。第一个是决定如何定义切割单个立方体的截面或表面截面。如果我们将每个角分类为低于或高于等值,就有256种可能的角分类构型。其中两个是无关紧要的;所有点都在立方体内部或外部的位置对等值面没有影响。对于所有其他构型,我们需要确定在每个立方体边缘上等值面相交的位置,并使用这些边缘交点为等值面创建一个或多个三角形块。
    如果考虑对称性,在剩下的254种可能中,实际上只有14种构型是唯一的。当只有一个角小于等值时,这就形成了一个三角形,它与在这个角上相交的边缘相交,而补丁法线朝向这个角。显然,这种类型有8个相关配置(例如,配置2 -你可能需要调整colormap来查看球体/像素之间的平面)。通过反转法线,我们得到8种构型它们有7个角比等值小。然而,我们并不认为这些是独一无二的。对于两个角小于等值的构型,有3种独特的构型(例如,构型12),这取决于这些角是否属于同一条边,属于立方体的同一面,或相对于彼此的对角位置。对于3个角小于等值的构型,也有3个独特的构型(例如构型14),这取决于是否有0、1或2个共享边(2个共享边会给你一个L形)。有7独特配置有4个角小于等值时,根据是否有0,2、3(3变体在这一点),或4共享边缘(例如配置30 -你可能需要调整颜色看到孤立(远)范围内的三角形/像素)。
    每一种非平凡构型都会导致1到4个三角形被添加到等值面上。实际的顶点本身可以通过沿边的插值来计算,或者默认它们的位置在边的中间。插值位置显然会给你更好的阴影计算和更平滑的表面。
    现在我们可以为单个体素创建表面补丁,我们可以将这个过程应用到整个体素。我们可以在板中处理体积,其中每个板由2个像素片组成。我们可以独立对待每个立方体,或者我们可以传播共享边的立方体之间的边相交。这种共享也可以在相邻的板之间完成,这增加了一些存储和复杂性,但节省了计算时间。边缘/顶点信息的共享也导致了一个更紧凑的模型,一个更易于插值着色。

6.总结
    Marching Cubes是一种用于绘制立体数据中等值面的算法。基本概念是,我们可以通过立方体8个角的像素值来定义体素(立方体)。如果一个立方体中的一个或多个像素的值小于用户指定的等值,并且一个或多个像素的值大于这个值,我们知道体素必须贡献等值面的某个分量。通过确定立方体的哪些边与等值面相交,我们可以创建三角形块,将立方体划分为等值面内部区域和外部区域。通过连接等值面边界上所有立方体的小块,我们得到了一个表面表示法。

移动立方体的算法原理及C++实现相关推荐

  1. PCL库中Marching Cubes(移动立方体)算法的解析

    PCL库中Marching Cubes(移动立方体)算法解析 1. Marching Cubes算法的原理这里不再赘述,不懂的话,提供一下文献资源: 链接:MARCHING CUBES A HIGH ...

  2. 激光SLAM之NDT算法(1)算法原理

    /在激光SLAM之NDT算法(2)-建图中我会给出实测可用的建图代码,并予以解释代码结构,这里就先讲讲原理吧!!!/ 无人车激光SLAM系统简单可以分为建图和定位两部分,无人车的定位问题,实际上就是要 ...

  3. CRF(条件随机场)与Viterbi(维特比)算法原理详解

    摘自:https://mp.weixin.qq.com/s/GXbFxlExDtjtQe-OPwfokA https://www.cnblogs.com/zhibei/p/9391014.html C ...

  4. 三维目标检测算法原理

    三维目标检测算法原理 输入输出接口 Input: (1)图像视频分辨率(整型int) (2)图像视频格式(RGB,YUV,MP4等) (3)左右两边的车道线位置信息摄像头标定参数(中心位置(x,y) ...

  5. 3D-2D:PnP算法原理

    3D-2D:PnP算法原理 1.问题背景-- 什么是PnP问题 ? 2.PnP问题的求解方法 2.1 P3P 2.1.1 算法的实际理解 2.1.2 算法的数学推导 2.1.3 算法的缺陷 2.2 直 ...

  6. MySQL索引背后的数据结构及算法原理【转】

    http://blog.codinglabs.org/articles/theory-of-mysql-index.html MySQL索引背后的数据结构及算法原理[转] 摘要 本文以MySQL数据库 ...

  7. 文本分类的基本思想和朴素贝叶斯算法原理

    文本分类的基本思想和朴素贝叶斯算法原理

  8. Bagging与随机森林算法原理小结

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 在集成学习原理小结中,我们讲到了集成学习有两个流派,一个是boos ...

  9. 干货 | 非常全面的谱聚类算法原理总结

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 谱聚类算法是目前最流行的聚类算法之一,其性能及适用场景优于传统的聚 ...

最新文章

  1. Android 蓝牙4.0(BLE)开发实现对蓝牙的写入数据和读取数据
  2. crontab定时任务中文乱码问题
  3. chrome 插件 页面请求转发_巧用Chrome插件二三事
  4. Python 爬虫利器二之 Beautiful Soup 的用法
  5. hilbert谱 matlab,怎么在matlab中做信号hilbert边际谱分析
  6. 【MySQL】MySQL 8 新特性
  7. mysql 修改字段编码_mysql修改数据库编码字段编码
  8. 花书+吴恩达深度学习(十五)序列模型之循环神经网络 RNN
  9. P1394 山上的国度
  10. 阿里巴巴java开发手册pdf
  11. mysql 5.6.15.0 源码_源码编译mysql-5.6.15
  12. matlab图像的邻域操作,matlab图像的邻域操作与块操作 | 学步园
  13. 单片机编程软件很简单(六),V5.29 keil mdk单片机编程软件新特性+烧写程序
  14. python清洗数据去除停用词_python去除停用词(结巴分词下)
  15. AE表达式中英对照及解释
  16. 一对一高清直播系统解决方案
  17. 【经典】对static关键字深入理解
  18. Bypass-分流抢票
  19. 加州大学圣地亚哥分校计算机科学排名,加州大学圣地亚哥分校UCSD计算机科学Computer Science专业排名第37位(2021年THE世界大学商科排名)...
  20. 全志VR9虚拟现实专用芯片处理器介绍

热门文章

  1. Code Ocean 上传代码 手把手教程
  2. openlayers6 第一篇绘制点线面
  3. openstack中的flavor
  4. 利用枚举类型变量求从5种颜色球中取3个不同颜色球的取法
  5. labview霍夫曼编码_香农编码与霍夫曼编码
  6. 穷小子云计算创业暴富成功报复前老板
  7. php 组合算法,PHP简单排列组合算法示例分享
  8. 微软的秘密(china-pub首发)
  9. linux 多进程广播通知,linux进程状态D
  10. BIOS固件是什么?