add Marching Tetrahedrons code
authormegacz <adam@megacz.com>
Wed, 4 Mar 2009 16:08:12 +0000 (08:08 -0800)
committermegacz <adam@megacz.com>
Wed, 4 Mar 2009 16:08:12 +0000 (08:08 -0800)
src/edu/berkeley/qfat/voxel/MarchingCubes.java

index 3112d8d..46b83b6 100644 (file)
@@ -49,11 +49,11 @@ public class MarchingCubes {
                              (mesh.numTriangles()-initialTriangles) + " triangles");
             for(int iY = 0; iY < voxels.getNumSamplesY(); iY++)
                 for(int iZ = 0; iZ < voxels.getNumSamplesZ(); iZ++)
-                    march(voxels, mesh, threshold,
-                          iX*scaleX + voxels.getMinX(),
-                          iY*scaleY + voxels.getMinY(),
-                          iZ*scaleZ + voxels.getMinZ(),
-                          scaleX, scaleY, scaleZ);
+                    /*marchCubes*/marchTetrahedrons(voxels, mesh, threshold,
+                                                    iX*scaleX + voxels.getMinX(),
+                                                    iY*scaleY + voxels.getMinY(),
+                                                    iZ*scaleZ + voxels.getMinZ(),
+                                                    scaleX, scaleY, scaleZ);
         }
         System.out.print("\r");
         for(int i=0; i<78; i++) System.out.print(' ');
@@ -62,9 +62,9 @@ public class MarchingCubes {
     }
 
     /** performs the Marching Cubes algorithm on a single cube */
-    static void march(VoxelData voxels, Mesh mesh, double threshold,
-                      double fX, double fY, double fZ,
-                      double scaleX, double scaleY, double scaleZ) {
+    static void marchCubes(VoxelData voxels, Mesh mesh, double threshold,
+                           double fX, double fY, double fZ,
+                           double scaleX, double scaleY, double scaleZ) {
         int iCorner, iVertex, iVertexTest, iEdge, iTriangle, iFlagIndex, iEdgeFlags;
         double fOffset;
         GLvector sColor;
@@ -110,6 +110,8 @@ public class MarchingCubes {
             vGetNormal(voxels, asEdgeNorm[iEdge], asEdgeVertex[iEdge].fX, asEdgeVertex[iEdge].fY, asEdgeVertex[iEdge].fZ);
         }
 
+        System.out.println();
+
         // 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)
@@ -132,7 +134,124 @@ public class MarchingCubes {
                 points[1].equals(points[2]))
                 continue;
 
-            mesh.newT(points[0], points[1], points[2], norm.norm().times(-1));
+            System.out.println("creating triangle: " + points[0] + " " + points[1] + " " + points[2]);
+            try {
+                Mesh.T t = mesh.newT(points[0], points[1], points[2], norm.norm().times(-1));
+                System.out.println("  created " + t);
+            } catch (Throwable t) { }
+        }
+    }
+
+    /**
+     *  marchTetrahedron performs the Marching Tetrahedrons algorithm
+     *  on a single tetrahedron
+     */
+    static void marchTetrahedron(VoxelData voxels, Mesh mesh, double threshold,
+                                 GLvector[] pasTetrahedronPosition,
+                                 float[] pafTetrahedronValue,
+                                 double scaleX, double scaleY, double scaleZ) {
+
+        int iEdge, iVert0, iVert1, iEdgeFlags, iTriangle, iCorner, iVertex, iFlagIndex = 0;
+        double fOffset, fInvOffset, fValue = 0.0;
+        GLvector[] asEdgeVertex = new GLvector[6];
+        GLvector[] asEdgeNorm = new GLvector[6];
+        GLvector sColor = new GLvector();
+        for(int i=0; i<asEdgeVertex.length; i++) asEdgeVertex[i] = new GLvector();
+        for(int i=0; i<asEdgeNorm.length; i++) asEdgeNorm[i] = new GLvector();
+
+        // Find which vertices are inside of the surface and which are outside
+        for(iVertex = 0; iVertex < 4; iVertex++)
+            if(pafTetrahedronValue[iVertex] <= threshold) 
+                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))==0 ) continue;
+
+            iVert0 = a2iTetrahedronEdgeConnection[iEdge][0];
+            iVert1 = a2iTetrahedronEdgeConnection[iEdge][1];
+            fOffset = fGetOffset(pafTetrahedronValue[iVert0], pafTetrahedronValue[iVert1], threshold,
+                                 Math.min(Math.min(scaleX, scaleY), scaleZ) * 0.1);
+            fInvOffset = 1.0f - 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(voxels, 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;
+
+            Point[] points = new Point[3];
+            Vec norm = new Vec(0,0,0);
+            for(iCorner = 0; iCorner < 3; iCorner++) {
+                iVertex = a2iTetrahedronTriangles[iFlagIndex][3*iTriangle+iCorner];
+                points[iCorner] = new Point(asEdgeVertex[iVertex].fX, asEdgeVertex[iVertex].fY, asEdgeVertex[iVertex].fZ);
+                // questionable, but we do it anyways
+                norm = norm.plus(new Vec(asEdgeNorm[iVertex].fX,   asEdgeNorm[iVertex].fY,   asEdgeNorm[iVertex].fZ));
+            }
+            // Eliminate triangles with "length-zero" sides.
+            // Unfortunately this puts holes in the mesh.
+            if (points[0].equals(points[1]) ||
+                points[0].equals(points[2]) ||
+                points[1].equals(points[2]))
+                continue;
+            System.out.println("creating triangle: " + points[0] + " " + points[1] + " " + points[2]);
+            Mesh.T t = mesh.newT(points[0], points[1], points[2], norm.norm().times(-1));
+            System.out.println("  created " + t);
+        }
+    }
+
+    /**
+     *  marchTetrahedrons performs the Marching Tetrahedrons algorithm on a
+     *  single cube by making six calls to marchTetrahedron
+     */
+    static void marchTetrahedrons(VoxelData voxels, Mesh mesh, double threshold,
+                                  double fX, double fY, double fZ,
+                                  double scaleX, double scaleY, double scaleZ) {
+        int iVertex, iTetrahedron, iVertexInACube;
+        GLvector[] asCubePosition = new GLvector[8];
+        float[]  afCubeValue = new float[8];
+        GLvector[] asTetrahedronPosition = new GLvector[8];
+        float[]  afTetrahedronValue = new float[4];
+
+        for(int i=0; i<asCubePosition.length; i++) asCubePosition[i] = new GLvector();
+        for(int i=0; i<asTetrahedronPosition.length; i++) asTetrahedronPosition[i] = new GLvector();
+
+        // Make a local copy of the cube's corner positions
+        for(iVertex = 0; iVertex < 8; iVertex++) {
+            asCubePosition[iVertex].fX = fX + a2fVertexOffset[iVertex][0]*scaleX;
+            asCubePosition[iVertex].fY = fY + a2fVertexOffset[iVertex][1]*scaleY;
+            asCubePosition[iVertex].fZ = fZ + a2fVertexOffset[iVertex][2]*scaleZ;
+        }
+
+        // Make a local copy of the cube's corner values
+        for(iVertex = 0; iVertex < 8; iVertex++)
+            afCubeValue[iVertex] =
+                voxels.getSample(new Point(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];
+            }
+            marchTetrahedron(voxels, mesh, threshold, asTetrahedronPosition, afTetrahedronValue, scaleX, scaleY, scaleZ);
         }
     }