//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 outside
        for(iVertex = 0; iVertex < 4; iVertex++)
        {
                if(pafTetrahedronValue[iVertex] <= fTargetValue) 
                        iFlagIndex |= 1<<iVertex;
        }

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

        //If the tetrahedron is entirely inside or outside of the surface, then there will be no intersections
        if(iEdgeFlags == 0)
        {
                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 < 6; iEdge++)
        {
                //if there is an intersection on this edge
                if(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 tetrahedron
        for(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);
                }
        }
}
Ejemplo n.º 2
0
void vMarchCube(
    const BoundedVolume<T,roo::TargetHost> vol,
    const BoundedVolume<TColor,roo::TargetHost> volColor,
    int x, int y, int z,
    std::vector<aiVector3D>& verts,
    std::vector<aiVector3D>& norms,
    std::vector<aiFace>& faces,
    std::vector<aiColor4D>& colors,
    float fTargetValue = 0.0f
) {
    const float3 p = vol.VoxelPositionInUnits(x,y,z);
    const float3 fScale = vol.VoxelSizeUnits();

    //Make a local copy of the values at the cube's corners
    float afCubeValue[8];
    for(int iVertex = 0; iVertex < 8; iVertex++) {
        afCubeValue[iVertex] = vol.Get(x+a2fVertexOffset[iVertex][0],y+a2fVertexOffset[iVertex][1],z+a2fVertexOffset[iVertex][2]);
        if(!std::isfinite(afCubeValue[iVertex])) return;
    }

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

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

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

    //Find the point of intersection of the surface with each edge
    //Then find the normal to the surface at those points
    float3 asEdgeVertex[12];
    float3 asEdgeNorm[12];

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

            asEdgeVertex[iEdge] = make_float3(
                p.x + (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][0]  +  fOffset * a2fEdgeDirection[iEdge][0]) * fScale.x,
                p.y + (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][1]  +  fOffset * a2fEdgeDirection[iEdge][1]) * fScale.y,
                p.z + (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][2]  +  fOffset * a2fEdgeDirection[iEdge][2]) * fScale.z
            );

            const float3 deriv = vol.GetUnitsBackwardDiffDxDyDz( asEdgeVertex[iEdge] );
            asEdgeNorm[iEdge] = deriv / length(deriv);

            if( !std::isfinite(asEdgeNorm[iEdge].x) || !std::isfinite(asEdgeNorm[iEdge].y) || !std::isfinite(asEdgeNorm[iEdge].z) ) {
                asEdgeNorm[iEdge] = make_float3(0,0,0);
            }
        }
    }


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

        aiFace face;
        face.mNumIndices = 3;
        face.mIndices = new unsigned int[face.mNumIndices];

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

            face.mIndices[iCorner] = verts.size();
            verts.push_back(aiVector3D(asEdgeVertex[iVertex].x, asEdgeVertex[iVertex].y, asEdgeVertex[iVertex].z) );
            norms.push_back(aiVector3D(asEdgeNorm[iVertex].x,   asEdgeNorm[iVertex].y,   asEdgeNorm[iVertex].z) );

            if(volColor.IsValid()) {
                const TColor c = volColor.GetUnitsTrilinearClamped(asEdgeVertex[iVertex]);
                float3 sColor = roo::ConvertPixel<float3,TColor>(c);
                colors.push_back(aiColor4D(sColor.x, sColor.y, sColor.z, 1.0f));
            }

        }

        faces.push_back(face);
    }
}
//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 corners
        for(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 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) 
        {
                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);

                        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 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];

                        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);
                }
        }
}
Ejemplo n.º 4
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]);
						}
					}
				}
        }
}