/*Go through all the Blobs, and travel from the center outwards in a negative Z direction * until we reach the surface, then begin to recurse around the surface. This isn't flawless * if the blob isn't completely within the lattice boundaries in the minimal Z axis and no * other blob that does check out is in contact with it. The blob will dissapear, but otherwise * works well*/ private void march() { int i, jx, jy, jz; for (i = 0; i < this.GetComponent <FluidBehaviour>().Particles.Count; i++) { FluidParticle pb = this.GetComponent <FluidBehaviour>().Particles[i]; jx = (int)((pb.Position.x + .5f) * dimX); jy = (int)((pb.Position.y + .5f) * dimY); jz = (int)((pb.Position.z + .5f) * dimZ); while (jz >= 0) { mcCube cube = getCube(jx, jy, jz); if (cube != null && cube.cntr < pctr) { cube.cntr = pctr; if (doCube(cube)) { recurseCube(cube); jz = -1; } } else { jz = -1; } jz -= 1; } } }
/*Go through all the Blobs, and travel from the center outwards in a negative Z direction * until we reach the surface, then begin to recurse around the surface. This isn't flawless * if the blob isn't completely within the lattice boundaries in the minimal Z axis and no * other blob that does check out is in contact with it. The blob will dissapear, but otherwise * works well*/ private void march() { int i, jx, jy, jz; for (i = 0; i < blobs.Length; i++) { float[] pb = blobs[i]; jx = (int)((pb[0] + .5f) * dimX); jy = (int)((pb[1] + .5f) * dimY); jz = (int)((pb[2] + .5f) * dimZ); while (jz >= 0) { mcCube cube = getCube(jx, jy, jz); if (cube != null && cube.cntr < pctr) { if (doCube(cube)) { recurseCube(cube); jz = -1; } cube.cntr = pctr; } else { jz = -1; } jz -= 1; } } }
private void recurseCube(mcCube cube) { mcCube nCube; int jx, jy, jz; jx = cube.px; jy = cube.py; jz = cube.pz; cubec++; /* Test 6 axis cases. This seems to work well, no need to test all 26 cases */ nCube = getCube(jx + 1, jy, jz); if (nCube != null && nCube.cntr < pctr) { nCube.cntr = pctr; if (doCube(nCube)) { recurseCube(nCube); } } nCube = getCube(jx - 1, jy, jz); if (nCube != null && nCube.cntr < pctr) { nCube.cntr = pctr; if (doCube(nCube)) { recurseCube(nCube); } } nCube = getCube(jx, jy + 1, jz); if (nCube != null && nCube.cntr < pctr) { nCube.cntr = pctr; if (doCube(nCube)) { recurseCube(nCube); } } nCube = getCube(jx, jy - 1, jz); if (nCube != null && nCube.cntr < pctr) { nCube.cntr = pctr; if (doCube(nCube)) { recurseCube(nCube); } } nCube = getCube(jx, jy, jz + 1); if (nCube != null && nCube.cntr < pctr) { nCube.cntr = pctr; if (doCube(nCube)) { recurseCube(nCube); } } nCube = getCube(jx, jy, jz - 1); if (nCube != null && nCube.cntr < pctr) { nCube.cntr = pctr; if (doCube(nCube)) { recurseCube(nCube); } } nCube = getCube(jx, jy + 1, jz - 1); }
/*If an edge of a cube has not been processed, find the interpolated point for * that edge (assumes the boundary crosses the edge) and compute the normal * for that point, as well as assigning it an index into the vertex list*/ private void genEdge(mcCube cube, int edgei, int p1i, int p2i) { Vector3 v; mcEdge e = cube.edges[edgei]; if (e.cntr < pctr) { v = mPos(cube.points[p1i], cube.points[p2i], e.axisI); e.v3 = v; e.vi = vertP; newNormal[vertP] = calcNormal(v); newVertex[vertP++] = v; e.cntr = pctr; } }
/*Generate the Cube Lattice * All shared vertices and edges are connected across cubes, * it's not perfect in that the edges along the lower index borders * are not connected, but all the rest are, this shouldn't make any * noticeable visual impact, and have no performance impact unless * a blob lies along those borders*/ private void startObjs( ) { int i; float jx, jy, jz; int ijx, ijy, ijz; int pointCount = ((dimX + 1) * (dimY + 1) * (dimZ + 1)); int cubeCount = (dimX * dimY * dimZ); int edgeCount = (cubeCount * 3) + ((2 * dimX * dimY) + (2 * dimX * dimZ) + (2 * dimY * dimZ)) + dimX + dimY + dimZ; //Ideal Edge Count int edgeNow = edgeCount + ((dimX * dimY) + (dimY * dimZ) + (dimZ * dimX)) * 2; //Haven't combined the edges of the 0 index borders //Should be a pretty safe amount int tmpv = (int)(dimX * dimY * dimZ / 7); tadam = tmpv * 4; fv = new Vector3[tmpv]; fn = new Vector3[tmpv]; fuv = new Vector2[tmpv]; //Pretty save amount of Tris as well ft = new int[(int)(cubeCount * .75)]; newVertex = new Vector3[300000]; newTri = new int[300000]; newNormal = new Vector3[300000]; tada = new Vector3[tadam * 2]; tada2 = new Vector2[tadam * 2]; //newUV=new Vector2[300000]; _cubes = new mcCube[cubeCount]; _points = new mcPoint[pointCount]; _edges = new mcEdge[edgeNow]; for (i = 0; i < tadam * 2; i++) { tada[i] = new Vector3(0, 0, 0); tada2[i] = new Vector2(0, 0); } for (i = 0; i < edgeNow; i++) { _edges[i] = new mcEdge(-1); } i = 0; for (jx = 0.0f; jx <= dimX; jx++) { for (jy = 0.0f; jy <= dimY; jy++) { for (jz = 0.0f; jz <= dimZ; jz++) { _points[i] = new mcPoint((jx / dimX) - .5f, (jy / dimY) - .5f, (jz / dimZ) - .5f, (int)jx, (int)jy, (int)jz, this); i++; } } } for (i = 0; i < cubeCount; i++) { _cubes[i] = new mcCube(); } int ep = 0; mcCube c; mcCube tc; i = 0; int topo = 0; for (ijx = 0; ijx < dimX; ijx++) { for (ijy = 0; ijy < dimY; ijy++) { for (ijz = 0; ijz < dimZ; ijz++) { c = _cubes[i]; i++; c.px = ijx; c.py = ijy; c.pz = ijz; mcPoint[] cpt = c.points; cpt[0] = getPoint(ijx, ijy, ijz); cpt[1] = getPoint(ijx + 1, ijy, ijz); cpt[2] = getPoint(ijx + 1, ijy + 1, ijz); cpt[3] = getPoint(ijx, ijy + 1, ijz); cpt[4] = getPoint(ijx, ijy, ijz + 1); cpt[5] = getPoint(ijx + 1, ijy, ijz + 1); cpt[6] = getPoint(ijx + 1, ijy + 1, ijz + 1); cpt[7] = getPoint(ijx, ijy + 1, ijz + 1); mcEdge[] e = c.edges; e[5] = _edges[ep++]; e[5].axisI = 1; e[6] = _edges[ep++]; e[6].axisI = 0; e[10] = _edges[ep++]; e[10].axisI = 2; tc = getCube(ijx + 1, ijy, ijz); if (tc != null) { tc.edges[11] = e[10]; tc.edges[7] = e[5]; } tc = getCube(ijx, ijy + 1, ijz); if (tc != null) { tc.edges[4] = c.edges[6]; tc.edges[9] = c.edges[10]; } tc = getCube(ijx, ijy + 1, ijz + 1); if (tc != null) { tc.edges[0] = c.edges[6]; } tc = getCube(ijx + 1, ijy, ijz + 1); if (tc != null) { tc.edges[3] = c.edges[5]; } tc = getCube(ijx + 1, ijy + 1, ijz); if (tc != null) { tc.edges[8] = c.edges[10]; } tc = getCube(ijx, ijy, ijz + 1); if (tc != null) { tc.edges[1] = c.edges[5]; tc.edges[2] = c.edges[6]; } if (e[0] == null) { e[0] = _edges[ep++]; e[0].axisI = 0; } if (e[1] == null) { e[1] = _edges[ep++]; e[1].axisI = 1; } if (e[2] == null) { e[2] = _edges[ep++]; e[2].axisI = 0; } else { topo++; } if (e[3] == null) { e[3] = _edges[ep++]; e[3].axisI = 1; } if (e[4] == null) { e[4] = _edges[ep++]; e[4].axisI = 0; } if (e[7] == null) { e[7] = _edges[ep++]; e[7].axisI = 1; } if (e[8] == null) { e[8] = _edges[ep++]; e[8].axisI = 2; } if (e[9] == null) { e[9] = _edges[ep++]; e[9].axisI = 2; } if (e[11] == null) { e[11] = _edges[ep++]; e[11].axisI = 2; } } } } }
/*Calculate a cube: * First set a boolean pointer made up of all the vertices within the cube * then (if not all in or out of the surface) go through all the edges that * are crossed by the surface and make sure that a vertex&normal is assigned * at the point of crossing. Then add all the triangles that cover the surface * within the cube. * Returns true if the surface crosses the cube, false otherwise.*/ private bool doCube(mcCube cube) { int edgec, vertc; edgec = 0; vertc = 0; int cubeIndex = 0; if (cube.points[0].i() > isoLevel) { cubeIndex |= 1; } if (cube.points[1].i() > isoLevel) { cubeIndex |= 2; } if (cube.points[2].i() > isoLevel) { cubeIndex |= 4; } if (cube.points[3].i() > isoLevel) { cubeIndex |= 8; } if (cube.points[4].i() > isoLevel) { cubeIndex |= 16; } if (cube.points[5].i() > isoLevel) { cubeIndex |= 32; } if (cube.points[6].i() > isoLevel) { cubeIndex |= 64; } if (cube.points[7].i() > isoLevel) { cubeIndex |= 128; } int edgeIndex = edgeTable[cubeIndex]; edgec += edgeIndex; if (edgeIndex != 0) { if ((edgeIndex & 1) > 0) { genEdge(cube, 0, 0, 1); } if ((edgeIndex & 2) > 0) { genEdge(cube, 1, 1, 2); } if ((edgeIndex & 4) > 0) { genEdge(cube, 2, 2, 3); } if ((edgeIndex & 0x8) > 0) { genEdge(cube, 3, 3, 0); } if ((edgeIndex & 0x10) > 0) { genEdge(cube, 4, 4, 5); } if ((edgeIndex & 0x20) > 0) { genEdge(cube, 5, 5, 6); } if ((edgeIndex & 0x40) > 0) { genEdge(cube, 6, 6, 7); } if ((edgeIndex & 0x80) > 0) { genEdge(cube, 7, 7, 4); } if ((edgeIndex & 0x100) > 0) { genEdge(cube, 8, 0, 4); } if ((edgeIndex & 0x200) > 0) { genEdge(cube, 9, 1, 5); } if ((edgeIndex & 0x400) > 0) { genEdge(cube, 10, 2, 6); } if ((edgeIndex & 0x800) > 0) { genEdge(cube, 11, 3, 7); } int tpi = 0; int tmp; while (triTable[cubeIndex, tpi] != -1) { tmp = cube.edges[triTable[cubeIndex, tpi + 2]].vi; newTri[triP++] = tmp; vertc += tmp; tmp = cube.edges[triTable[cubeIndex, tpi + 1]].vi; newTri[triP++] = tmp; vertc += tmp; tmp = cube.edges[triTable[cubeIndex, tpi]].vi; newTri[triP++] = tmp; vertc += tmp; tpi += 3; } return(true); } else { return(false); } }
/*Generate the Cube Lattice All shared vertices and edges are connected across cubes, it's not perfect in that the edges along the lower index borders are not connected, but all the rest are, this shouldn't make any noticeable visual impact, and have no performance impact unless a blob lies along those borders*/ private void startObjs( ) { int i; float jx,jy,jz; int ijx,ijy,ijz; int pointCount=((dimX+1)*(dimY+1)*(dimZ+1)); int cubeCount=(dimX*dimY*dimZ); int edgeCount=(cubeCount*3)+((2*dimX*dimY)+(2*dimX*dimZ)+(2*dimY*dimZ))+dimX+dimY+dimZ; //Ideal Edge Count int edgeNow=edgeCount+((dimX*dimY)+(dimY*dimZ)+(dimZ*dimX))*2; //Haven't combined the edges of the 0 index borders //Should be a pretty safe amount int tmpv=(int)(dimX*dimY*dimZ/7); tadam=tmpv*4; fv=new Vector3[tmpv]; fn=new Vector3[tmpv]; fuv=new Vector2[tmpv]; //Pretty save amount of Tris as well ft=new int[(int)(cubeCount*.75)]; newVertex=new Vector3[300000]; newTri=new int[300000]; newNormal=new Vector3[300000]; tada=new Vector3[tadam*2]; tada2=new Vector2[tadam*2]; //newUV=new Vector2[300000]; _cubes=new mcCube[cubeCount]; _points=new mcPoint[pointCount]; _edges=new mcEdge[edgeNow]; for (i=0;i<tadam*2;i++) { tada[i]=new Vector3(0,0,0); tada2[i]=new Vector2(0,0); } for (i=0;i<edgeNow;i++) { _edges[i]=new mcEdge(-1); } i=0; for(jx=0.0f;jx<=dimX;jx++) { for(jy=0.0f;jy<=dimY;jy++) { for(jz=0.0f;jz<=dimZ;jz++){ _points[i]=new mcPoint((jx/dimX)-.5f,(jy/dimY)-.5f,(jz/dimZ)-.5f,(int)jx,(int)jy,(int)jz,this); i++; } } } for(i=0;i<cubeCount;i++) _cubes[i]=new mcCube(); int ep=0; mcCube c; mcCube tc; i=0; int topo=0; for(ijx=0;ijx<dimX;ijx++){ for(ijy=0;ijy<dimY;ijy++) { for(ijz=0;ijz<dimZ;ijz++) { c=_cubes[i]; i++; c.px=ijx; c.py=ijy; c.pz=ijz; mcPoint[] cpt=c.points; cpt[0]=getPoint(ijx,ijy,ijz); cpt[1]=getPoint(ijx+1,ijy,ijz); cpt[2]=getPoint(ijx+1,ijy+1,ijz); cpt[3]=getPoint(ijx,ijy+1,ijz); cpt[4]=getPoint(ijx,ijy,ijz+1); cpt[5]=getPoint(ijx+1,ijy,ijz+1); cpt[6]=getPoint(ijx+1,ijy+1,ijz+1); cpt[7]=getPoint(ijx,ijy+1,ijz+1); mcEdge[] e=c.edges; e[5]=_edges[ep++];e[5].axisI=1; e[6]=_edges[ep++];e[6].axisI=0; e[10]=_edges[ep++];e[10].axisI=2; tc=getCube(ijx+1,ijy,ijz); if(tc!=null) {tc.edges[11]=e[10];tc.edges[7]=e[5];} tc=getCube(ijx,ijy+1,ijz); if(tc!=null) {tc.edges[4]=c.edges[6];tc.edges[9]=c.edges[10];} tc=getCube(ijx,ijy+1,ijz+1); if(tc!=null) {tc.edges[0]=c.edges[6];} tc=getCube(ijx+1,ijy,ijz+1); if(tc!=null) {tc.edges[3]=c.edges[5];} tc=getCube(ijx+1,ijy+1,ijz); if(tc!=null) {tc.edges[8]=c.edges[10];} tc=getCube(ijx,ijy,ijz+1); if(tc!=null) {tc.edges[1]=c.edges[5];tc.edges[2]=c.edges[6];} if(e[0]==null) { e[0]=_edges[ep++];e[0].axisI=0; } if(e[1]==null) { e[1]=_edges[ep++];e[1].axisI=1; } if(e[2]==null) { e[2]=_edges[ep++];e[2].axisI=0; } else { topo++; } if(e[3]==null) { e[3]=_edges[ep++];e[3].axisI=1; } if(e[4]==null) { e[4]=_edges[ep++];e[4].axisI=0; } if(e[7]==null) { e[7]=_edges[ep++];e[7].axisI=1; } if(e[8]==null) { e[8]=_edges[ep++];e[8].axisI=2; } if(e[9]==null) { e[9]=_edges[ep++];e[9].axisI=2; } if(e[11]==null) { e[11]=_edges[ep++];e[11].axisI=2; } } } } }
private void recurseCube( mcCube cube ) { mcCube nCube; int jx,jy,jz; jx=cube.px; jy=cube.py; jz=cube.pz; cubec++; /* Test 6 axis cases. This seems to work well, no need to test all 26 cases */ nCube=getCube(jx+1,jy,jz); if(nCube!=null && nCube.cntr<pctr) {nCube.cntr=pctr; if(doCube(nCube)) { recurseCube(nCube); }} nCube=getCube(jx-1,jy,jz); if(nCube!=null && nCube.cntr<pctr) {nCube.cntr=pctr; if(doCube(nCube)) { recurseCube(nCube); }} nCube=getCube(jx,jy+1,jz); if(nCube!=null && nCube.cntr<pctr) {nCube.cntr=pctr; if(doCube(nCube)) { recurseCube(nCube); }} nCube=getCube(jx,jy-1,jz); if(nCube!=null && nCube.cntr<pctr) {nCube.cntr=pctr; if(doCube(nCube)) { recurseCube(nCube); }} nCube=getCube(jx,jy,jz+1); if(nCube!=null && nCube.cntr<pctr) {nCube.cntr=pctr; if(doCube(nCube)) { recurseCube(nCube); }} nCube=getCube(jx,jy,jz-1); if(nCube!=null && nCube.cntr<pctr) {nCube.cntr=pctr; if(doCube(nCube)) { recurseCube(nCube); }} }
/*If an edge of a cube has not been processed, find the interpolated point for that edge (assumes the boundary crosses the edge) and compute the normal for that point, as well as assigning it an index into the vertex list*/ private void genEdge(mcCube cube,int edgei,int p1i,int p2i) { Vector3 v; mcEdge e=cube.edges[edgei]; if (e.cntr<pctr) { v=mPos(cube.points[p1i],cube.points[p2i],e.axisI); e.v3=v; e.vi=vertP; newNormal[vertP]=calcNormal(v); newVertex[vertP++]=v; e.cntr=pctr; } }
/*Calculate a cube: First set a boolean pointer made up of all the vertices within the cube then (if not all in or out of the surface) go through all the edges that are crossed by the surface and make sure that a vertex&normal is assigned at the point of crossing. Then add all the triangles that cover the surface within the cube. Returns true if the surface crosses the cube, false otherwise.*/ private bool doCube( mcCube cube ) { int edgec,vertc; edgec=0;vertc=0; int cubeIndex=0; if(cube.points[0].i()>isoLevel) {cubeIndex|=1;} if(cube.points[1].i()>isoLevel) {cubeIndex|=2;} if(cube.points[2].i()>isoLevel) {cubeIndex|=4;} if(cube.points[3].i()>isoLevel) {cubeIndex|=8;} if(cube.points[4].i()>isoLevel) {cubeIndex|=16;} if(cube.points[5].i()>isoLevel) {cubeIndex|=32;} if(cube.points[6].i()>isoLevel) {cubeIndex|=64;} if(cube.points[7].i()>isoLevel) {cubeIndex|=128;} int edgeIndex=edgeTable[cubeIndex]; edgec+=edgeIndex; if(edgeIndex!=0) { if( (edgeIndex & 1) > 0) { genEdge(cube,0,0,1); } if( (edgeIndex & 2) > 0) { genEdge(cube,1,1,2);} if( (edgeIndex & 4) > 0) { genEdge(cube,2,2,3); } if( (edgeIndex & 0x8) > 0) { genEdge(cube,3,3,0); } if( (edgeIndex & 0x10) > 0) { genEdge(cube,4,4,5); } if( (edgeIndex & 0x20) > 0) { genEdge(cube,5,5,6); } if( (edgeIndex & 0x40) > 0) { genEdge(cube,6,6,7); } if( (edgeIndex & 0x80) > 0) { genEdge(cube,7,7,4); } if( (edgeIndex & 0x100) > 0) { genEdge(cube,8,0,4); } if( (edgeIndex & 0x200) > 0) { genEdge(cube,9,1,5); } if( (edgeIndex & 0x400) > 0) { genEdge(cube,10,2,6); } if( (edgeIndex & 0x800) > 0) { genEdge(cube,11,3,7); } int tpi=0; int tmp; while (triTable[cubeIndex,tpi]!=-1) { tmp=cube.edges[triTable[cubeIndex,tpi+2]].vi; newTri[triP++]=tmp;vertc+=tmp; tmp=cube.edges[triTable[cubeIndex,tpi+1]].vi; newTri[triP++]=tmp;vertc+=tmp; tmp=cube.edges[triTable[cubeIndex,tpi]].vi; newTri[triP++]=tmp;vertc+=tmp; tpi+=3; } return true; } else return false; }