From: megacz Date: Sat, 28 Feb 2009 21:36:00 +0000 (-0800) Subject: add first draft of Marching Cubes codefg X-Git-Url: http://git.megacz.com/?p=anneal.git;a=commitdiff_plain;h=1cff1b9494433864546e120b5fe4952e15b3ea94 add first draft of Marching Cubes codefg --- diff --git a/src/edu/berkeley/qfat/voxel/MarchingCubes.java b/src/edu/berkeley/qfat/voxel/MarchingCubes.java new file mode 100644 index 0000000..f8fb4e4 --- /dev/null +++ b/src/edu/berkeley/qfat/voxel/MarchingCubes.java @@ -0,0 +1,1024 @@ +package edu.berkeley.qfat.voxel; +import edu.berkeley.qfat.*; +import edu.berkeley.qfat.geom.*; + +///////////////////////////////////////////////////////////////////////////////////// +// Derived from: // +// http://local.wasp.uwa.edu.au/~pbourke/geometry/polygonise/marchingsource.cpp // +// (which is public domain) // +///////////////////////////////////////////////////////////////////////////////////// +// +// Marching Cubes Example Program +// by Cory Bloyd (corysama@yahoo.com) +// +// A simple, portable and complete implementation of the Marching Cubes +// and Marching Tetrahedrons algorithms in a single source file. +// There are many ways that this code could be made faster, but the +// intent is for the code to be easy to understand. +// +// For a description of the algorithm go to +// http://astronomy.swin.edu.au/pbourke/modelling/polygonise/ +// +// This code is public domain. +// +////////////////////////////////////////////////////////////////////////////////////// + +public abstract class MarchingCubes { + + private int iEdgeFlags; + + private static class GLvector { + public double fX; + public double fY; + public double 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 final double a2fVertexOffset[][] = { + {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 final int a2iEdgeConnection[][] = { + {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 final double a2fEdgeDirection[][] = { + {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 final int a2iTetrahedronEdgeConnection[][] = { + {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 final int a2iTetrahedronsInACube[][] = { + {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 final double afAmbientWhite [] = {0.25, 0.25, 0.25, 1.00}; + static final double afAmbientRed [] = {0.25, 0.00, 0.00, 1.00}; + static final double afAmbientGreen [] = {0.00, 0.25, 0.00, 1.00}; + static final double afAmbientBlue [] = {0.00, 0.00, 0.25, 1.00}; + static final double afDiffuseWhite [] = {0.75, 0.75, 0.75, 1.00}; + static final double afDiffuseRed [] = {0.75, 0.00, 0.00, 1.00}; + static final double afDiffuseGreen [] = {0.00, 0.75, 0.00, 1.00}; + static final double afDiffuseBlue [] = {0.00, 0.00, 0.75, 1.00}; + static final double afSpecularWhite[] = {1.00, 1.00, 1.00, 1.00}; + static final double afSpecularRed [] = {1.00, 0.25, 0.25, 1.00}; + static final double afSpecularGreen[] = {0.25, 1.00, 0.25, 1.00}; + static final double afSpecularBlue [] = {0.25, 0.25, 1.00, 1.00}; + + GLvector sSourcePoint[] = new GLvector[3]; + + /* + GLenum ePolygonMode = GL_FILL; + int iDataSetSize = 16; + double fStepSize = 1.0/iDataSetSize; + double fTargetValue = 48.0; + double fTime = 0.0; + boolean bSpin = true; + boolean bMove = true; + boolean 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(double fTime); + double fSample1(double fX, double fY, double fZ); + double fSample2(double fX, double fY, double fZ); + double fSample3(double fX, double fY, double fZ); + double (*fSample)(double fX, double fY, double fZ) = fSample1; + + GLvoid vMarchingCubes(); + GLvoid vMarchCube1(double fX, double fY, double fZ, double fScale); + GLvoid vMarchCube2(double fX, double fY, double fZ, double fScale); + GLvoid (*vMarchCube)(double fX, double fY, double fZ, double fScale) = vMarchCube1; + + void main(int argc, char **argv) + { + double afPropertiesAmbient [] = {0.50, 0.50, 0.50, 1.00}; + double afPropertiesDiffuse [] = {0.75, 0.75, 0.75, 1.00}; + double 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 ) + { + double fAspect, fHalfWorldSize = (1.4142135623730950488016887242097/2); + + glViewport( 0, 0, iWidth, iHeight ); + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + + if(iWidth <= iHeight) + { + fAspect = (double)iHeight / (double)iWidth; + glOrtho(-fHalfWorldSize, fHalfWorldSize, -fHalfWorldSize*fAspect, + fHalfWorldSize*fAspect, -10*fHalfWorldSize, 10*fHalfWorldSize); + } + else + { + fAspect = (double)iWidth / (double)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 = vMarchCube2;//Use Marching Tetrahedrons + } + else + { + vMarchCube = vMarchCube1;//Use Marching Cubes + } + } break; + case 's' : + { + if(fSample == fSample1) + { + fSample = fSample2; + } + else if(fSample == fSample2) + { + fSample = fSample3; + } + 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 double fPitch = 0.0; + static double fYaw = 0.0; + static double 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(); + } + + + + //vGetColor generates a color from a given position and normal of a point + GLvoid vGetColor(GLvector &rfColor, GLvector &rfPosition, GLvector &rfNormal) + { + double fX = rfNormal.fX; + double fY = rfNormal.fY; + double 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); + } + + + + //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(double fNewTime) + { + double fOffset; + int 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 + double fSample1(double fX, double fY, double 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 + double fSample2(double fX, double fY, double 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 + double fSample3(double fX, double fY, double fZ) + { + double fHeight = 20.0*(fTime + sqrt((0.5-fX)*(0.5-fX) + (0.5-fY)*(0.5-fY))); + fHeight = 1.5 + 0.1*(sinf(fHeight) + cosf(fHeight)); + GLdouble fResult = (fHeight - fZ)*50.0; + + return fResult; + } + + + + + + + //vMarchTetrahedron performs the Marching Tetrahedrons algorithm on a single tetrahedron + GLvoid vMarchTetrahedron(GLvector *pasTetrahedronPosition, double *pafTetrahedronValue) + { + extern int aiTetrahedronEdgeFlags[16]; + extern int a2iTetrahedronTriangles[16][7]; + + int iEdge, iVert0, iVert1, iEdgeFlags, iTriangle, iCorner, iVertex, iFlagIndex = 0; + double 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<