//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);
}
Exemple #2
0
//vMarchCube performs the Marching Cubes algorithm on a single cube
void vMarchCube(int iX, int iY, int iZ)
{
        extern GLint aiCubeEdgeFlags[256];
        extern GLint a2iTriangleConnectionTable[256][16];

		int iValueIndex;
		GLfloat    fX, fY, fZ;
		GLfloat    fXScale, fYScale, fZScale;
		GLfloat	   fCentralPoint = 0.0;
		GLfloat	   fDeltaValue, fDeltaX, fDeltaY, fDeltaZ;

		GLint iCorner, iVertex, iVertexTest, iEdge, iTriangle, iFlagIndex, iEdgeFlags;
        GLfloat fOffset;
        GLvector sColor;
        GLfloat afCubeValue[8];
        GLvector asEdgeVertex[12];
		GLvector asEdgeNorm[12];

		int iX0, iY0, iZ0;
		int iX1, iY1, iZ1;
		GLfloat fValue0, fValue1;

        //Make a local copy of the values at the cube's corners

		for(iVertex = 0; iVertex < 8; iVertex++)
        {
			afCubeValue[iVertex] = fSample(iX + a2fVertexOffset[iVertex][0]*iXStep,
                                           iY + a2fVertexOffset[iVertex][1]*iYStep,
                                           iZ + a2fVertexOffset[iVertex][2]*iZStep);

			fCentralPoint += afCubeValue[iVertex];
        }

		if (iUseGridPointers)
		{
			fX = fSourceXPointer[iX];
			fY = fSourceYPointer[iY];
			fZ = fSourceZPointer[iZ];
			/* this can be calculated beforehand ... */
			if ((iX+iXStep) < iXDataSetSize)
			{
				fXScale = fSourceXPointer[iX+iXStep] - fX;
			}else{
				fXScale = 0.0;
			}
			if ((iY+iYStep) < iYDataSetSize)
			{
				fYScale = fSourceYPointer[iY+iYStep] - fY;
			}else{
				fYScale = 0.0;
			}
			if ((iZ+iZStep) < iZDataSetSize)
			{
				fZScale = fSourceZPointer[iZ+iZStep] - fZ;
			}else{
				fZScale = 0.0;
			}
		}
		else
		{
			iValueIndex = iX * (iYDataSetSize * iZDataSetSize) + \
							iY * (iZDataSetSize) + iZ;
			fX = fSourceDataVerticesPointer[iValueIndex].fX;
			fY = fSourceDataVerticesPointer[iValueIndex].fY;
			fZ = fSourceDataVerticesPointer[iValueIndex].fZ;
			iValueIndex = (iX+iXStep) * (iYDataSetSize * iZDataSetSize) + \
					  (iY +iYStep) * (iZDataSetSize) + (iZ+iZStep);
			fXScale = fSourceDataVerticesPointer[iValueIndex].fX - fX;
			fYScale = fSourceDataVerticesPointer[iValueIndex].fY - fY;
			fZScale = fSourceDataVerticesPointer[iValueIndex].fZ - fZ;
		}

		/* Normal calucation */
		/* Store the value of the scalar field at the center of the cube */
		fCentralPoint *= 0.125;

		/* The central point has coordinates
		fCentralPointX = fX + 0.5 * fXScale
		fCentralPointY = fY + 0.5 * fYScale
		fCentralPointZ = fZ + 0.5 * fZScale
		*/


        //Find which vertices are inside of the surface and which are outside
        iFlagIndex = 0;
        for(iVertexTest = 0; iVertexTest < 8; iVertexTest++)
        {
                if(afCubeValue[iVertexTest] <= fTargetValue)
                        iFlagIndex |= 1<<iVertexTest;
        }

        //Find which edges are intersected by the surface
        iEdgeFlags = aiCubeEdgeFlags[iFlagIndex];

        //If the cube is entirely inside or outside of the surface, then there will be no intersections
        if((iEdgeFlags == 0) || (iEdgeFlags == 255))
        {
                return;
        }

        //Find the point of intersection of the surface with each edge
        //Then find the normal to the surface at those points

		for(iEdge = 0; iEdge < 12; iEdge++)
        {
                //if there is an intersection on this edge
                if(iEdgeFlags & (1<<iEdge))
                {
                        fOffset = fGetOffset(afCubeValue[ a2iEdgeConnection[iEdge][0] ],
                                             afCubeValue[ a2iEdgeConnection[iEdge][1] ], fTargetValue);

						//The vertex value in actual coordenates
                        asEdgeVertex[iEdge].fX = fX + fXScale * (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][0]  +  fOffset * a2fEdgeDirection[iEdge][0]);
                        asEdgeVertex[iEdge].fY = fY + fYScale * (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][1]  +  fOffset * a2fEdgeDirection[iEdge][1]);
                        asEdgeVertex[iEdge].fZ = fZ + fZScale * (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][2]  +  fOffset * a2fEdgeDirection[iEdge][2]);

						if (0)
						{
							//This would be for the interpolating case:
							vGetNormal(&asEdgeNorm[iEdge], asEdgeVertex[iEdge].fX, asEdgeVertex[iEdge].fY, asEdgeVertex[iEdge].fZ);
						}
						else
						{
							/* This is for the "regular" grid */
							if (1){
								/* the correct way ... (hopefully) */
								/* calculate the indices of the two vertices */
								iX0 = a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][0];
								iY0 = a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][1];
								iZ0 = a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][2];

								iX1 = a2fVertexOffset[ a2iEdgeConnection[iEdge][1] ][0];
								iY1 = a2fVertexOffset[ a2iEdgeConnection[iEdge][1] ][1];
								iZ1 = a2fVertexOffset[ a2iEdgeConnection[iEdge][1] ][2];

								/* I have the indices */
								/* The derivative in the first vertex respect to X*/
								if (fXScale != 0){
									fValue0 = fSample(iX + (iX0 + 1) * iXStep, iY + iY0 * iYStep, iZ + iZ0 * iZStep) -\
									          fSample(iX + (iX0 - 1) * iXStep, iY + iY0 * iYStep, iZ + iZ0 * iZStep);
									fValue1 = fSample(iX + (iX1 + 1) * iXStep, iY + iY1 * iYStep, iZ + iZ1 * iZStep) -\
									          fSample(iX + (iX1 - 1) * iXStep, iY + iY1 * iYStep, iZ + iZ1 * iZStep);
									asEdgeNorm[iEdge].fX = 0.5 * (fValue1 - fValue0) / fXScale;
								}else{
									asEdgeNorm[iEdge].fX = 0.0;
								}
								/* The derivative in the first vertex respect to X */
								if (fXScale != 0){
									fValue0 = fSample(iX + (iX0 + 1) * iXStep, iY + iY0 * iYStep, iZ + iZ0 * iZStep) -\
									          fSample(iX + (iX0 - 1) * iXStep, iY + iY0 * iYStep, iZ + iZ0 * iZStep);
									fValue1 = fSample(iX + (iX1 + 1) * iXStep, iY + iY1 * iYStep, iZ + iZ1 * iZStep) -\
									          fSample(iX + (iX1 - 1) * iXStep, iY + iY1 * iYStep, iZ + iZ1 * iZStep);
									asEdgeNorm[iEdge].fX = 0.5 * (fValue0 + fOffset * fValue1) / fXScale;
								}else{
									asEdgeNorm[iEdge].fX = 0.0;
								}
								/* The derivative in the first vertex respect to Y */
								if (fYScale != 0){
									fValue0 = fSample(iX * iXStep, iY + (iY0 + 1) * iYStep, iZ + iZ0 * iZStep) -\
									          fSample(iX * iXStep, iY + (iY0 - 1) * iYStep, iZ + iZ0 * iZStep);
									fValue1 = fSample(iX + iX1 * iXStep, iY + (iY1 + 1) * iYStep, iZ + iZ1 * iZStep) -\
									          fSample(iX + iX1 * iXStep, iY + (iY1 - 1) * iYStep, iZ + iZ1 * iZStep);
									asEdgeNorm[iEdge].fY = 0.5 * (fValue0 + fOffset * fValue1) / fYScale;
								}else{
									asEdgeNorm[iEdge].fY = 0.0;
								}
								/* The derivative in the first vertex respect to Z */
								if (fYScale != 0){
									fValue0 = fSample(iX * iXStep, iY + iY0 * iYStep, iZ + (iZ0 + 1) * iZStep) -\
									          fSample(iX * iXStep, iY + iY0 * iYStep, iZ + (iZ0 - 1) * iZStep);
									fValue1 = fSample(iX + iX1 * iXStep, iY + iY1 * iYStep, iZ + (iZ1 + 1) * iZStep) -\
									          fSample(iX + iX1 * iXStep, iY + iY1 * iYStep, iZ + (iZ1 - 1) * iZStep);
									asEdgeNorm[iEdge].fZ = 0.5 * (fValue0 + fOffset * fValue1) / fZScale;
								}else{
									asEdgeNorm[iEdge].fZ = 0.0;
								}
							}else {
								/* calculate all respect to the center */
								fDeltaValue = fTargetValue - fCentralPoint;
								fDeltaX = asEdgeVertex[iEdge].fX - fX - 0.5 * fXScale;
								fDeltaY = asEdgeVertex[iEdge].fY - fY - 0.5 * fYScale;
								fDeltaZ = asEdgeVertex[iEdge].fZ - fZ - 0.5 * fZScale;
								if (fDeltaX > 0)
								{
									asEdgeNorm[iEdge].fX = fDeltaValue/fDeltaX;
								}else{
									asEdgeNorm[iEdge].fX = 0.0;
								}
								if (fDeltaY > 0)
								{
									asEdgeNorm[iEdge].fY = fDeltaValue/fDeltaY;
								}else{
									asEdgeNorm[iEdge].fY = 0.0;
								}
								if (fDeltaZ > 0)
								{
									asEdgeNorm[iEdge].fZ = fDeltaValue/fDeltaZ;
								}else{
									asEdgeNorm[iEdge].fZ = 0.0;
								}
							}
							vNormalizeVector(&asEdgeNorm[iEdge], asEdgeNorm[iEdge]);
						}
                }
        }

        //Draw the triangles that were found.  There can be up to five per cube
        for(iTriangle = 0; iTriangle < 5; iTriangle++)
        {
                if(a2iTriangleConnectionTable[iFlagIndex][3*iTriangle] < 0)
                        break;

                for(iCorner = 0; iCorner < 3; iCorner++)
                {
                        iVertex = a2iTriangleConnectionTable[iFlagIndex][3*iTriangle+iCorner];

						if ((fIsoColor[0] < 0) || (fIsoColor[2] < 0) || (fIsoColor[3] < 0))
						{
							vGetColor(&sColor, asEdgeVertex[iVertex], asEdgeNorm[iVertex]);
							glColor3f(sColor.fX, sColor.fY, sColor.fZ);
						}
						else
						{
							//glColor4f(fIsoColor[0], fIsoColor[1], fIsoColor[2], fIsoColor[3]);
						}
                        glNormal3f(asEdgeNorm[iVertex].fX,   asEdgeNorm[iVertex].fY,   asEdgeNorm[iVertex].fZ);
                        glVertex3f(asEdgeVertex[iVertex].fX, asEdgeVertex[iVertex].fY, asEdgeVertex[iVertex].fZ);
						/*
						if ((asEdgeVertex[iVertex].fZ > 1.93) || (asEdgeVertex[iVertex].fZ < 1.8))
						{
							printf("iVertex = %d Z = %f\n", iVertex, asEdgeVertex[iVertex].fZ);
							printf("iX = %d iY = %d iZ = %d\n", iX, iY, iZ);
							printf("fx = %f, fy = %f, fz = %f\n", fX, fY, fZ);
							printf("scalex = %f, scaley = %f, scalez = %f\n", fXScale , fYScale , fZScale );
							exit(1);
						}
						*/
                }
				iNTotalTriangles++;
				/* This was for some tests */
				if (0)
				{
					if (iNTotalTriangles < 2)
					{
						printf("Triangle %d\n", iNTotalTriangles);
						printf("Target value =%f\n", fTargetValue);
						printf("Indices = %d, %d, %d\n", iX, iY, iZ);
						iValueIndex = iX * (iYDataSetSize * iZDataSetSize) + \
									  iY * (iZDataSetSize) + iZ;
						printf("Value index = %d,  value =%f, vertex = %f, %f, %f\n", iValueIndex, *fSourceDataValuesPointer, fX, fY, fZ);
						printf("iFlagIndex=%d\n", iFlagIndex);
						printf("Edge flags =%d\n", iEdgeFlags);
						printf("Cube limits\n");
						for(iVertex = 0; iVertex < 8; iVertex++)
						{
							printf("vertex = %d, value = %f\n", iVertex, afCubeValue[iVertex]);
						}
					}
				}
        }
}