void BuildTestingGrid() { gameObject.GetComponent<MeshFilter>().mesh = mesh = new Mesh(); mesh.name = "Variable Mesh"; vertices = new List<Vector3>(); triangles = new List<int>(); uvs = new List<Vector2>(); gridPoints = new List<GridPoint04>(); for (int y = 0; y < depthHeight; y += gridStep) { for (int x = 0; x < depthWidth; x += gridStep) { int depthIndex = x + (y * depthWidth); GridPoint04 gp = new GridPoint04(x, y, depthIndex); gp.Reset(); gridPoints.Add(gp); } } gridWidth = (int)Mathf.Floor(depthWidth / gridStep); gridHeight = (int)Mathf.Floor(depthHeight / gridStep); }
void GenerateMeshPerFrame() { mesh.Clear(); vertices.Clear(); triangles.Clear(); uvs.Clear(); int halfDepthWidth = depthWidth / 2; int halfDepthHeight = depthHeight / 2; // FIRST RESET ANY EXISTING GRID VERTEX DATA foreach ( GridPoint04 gp in gridPoints) { gp.Reset(); } GridPoint04[] testingSquare = new GridPoint04[4]; int armTest1, headTest1, armTest2, headTest2; // NOW REEVALUATE THE GRID, CALCULATING EACH SQUARE TO FIND ACCEPTABLE TRIANGLES for (int gridIndex = 0, y = 0; y < gridHeight; y++, gridIndex++) { for (int x = 0; x < gridWidth; x++, gridIndex++) { GridPoint04 a = testingSquare[0] = gridPoints[gridIndex]; GridPoint04 b = testingSquare[1] = gridPoints[gridIndex + 1]; GridPoint04 c = testingSquare[2] = gridPoints[gridIndex + gridWidth + 1]; GridPoint04 d = testingSquare[3] = gridPoints[gridIndex + gridWidth + 2]; // EVALUATE THE TESTING SQUARE FOR GridPoints THAT SHOULD BE CONVERTED TO VERTICES foreach (GridPoint04 gp in testingSquare) { // IF THE GRIDPOINT IS IN THE BODY SILHOUETTE... if (bodyIndexData[gp.DepthIndex] != 255) { if ( !gp.IsVertex()) { // CALUCATE THE WORLD POSITION CameraSpacePoint csp = cameraSpacePoints[gp.DepthIndex]; gp.CameraPosition = new Vector3(csp.X, csp.Y, csp.Z); // IF THE CAMERA POSITION IS VALID if (!float.IsInfinity(gp.CameraPosition.x) && !float.IsInfinity(gp.CameraPosition.y) && !float.IsInfinity(gp.CameraPosition.z)) { // AND IT LIES WITHIN THE USER DEFINED DEPTH RANGE if (gp.CameraPosition.z > DepthMinimum && gp.CameraPosition.z < DepthMaximum) { // ADD IT TO OUR VERTEX COLLECTION AND RECORD IT'S VERTEX INDEX gp.VertexID = vertices.Count; vertices.Add(gp.CameraPosition); uvs.Add(new Vector2(gp.DepthX / (float)depthWidth, gp.DepthY / (float)depthHeight)); } } } } } // CALCULATE THE BIT KEY FOR ALL ACCEPTABLE VERTICES IN OUR TESTING SQUARE int SquareKey = 0; if (a.IsVertex()) SquareKey |= 1; if (b.IsVertex()) SquareKey |= 2; if (c.IsVertex()) SquareKey |= 4; if (d.IsVertex()) SquareKey |= 8; switch (SquareKey) { case 0: // NO VERTICES WERE FOUND. DO NOTHING. break; case 1: // CUT TRIANGLE - ONLY A IS GOOD, FIND A ARM AND A HEAD armTest1 = getArmVertex(a); headTest1 = getHeadVertex(a); if ((armTest1 < 0) || (headTest1 < 0)) continue; addTriangle(a.VertexID, armTest1, headTest1); break; case 2: // CUT TRIANGLE - ONLY B IS GOOD, FIND A ARM AND B HEAD armTest1 = getArmVertex(a); headTest1 = getHeadVertex(b); if ((armTest1 < 0) || (headTest1 < 0)) continue; addTriangle(armTest1, b.VertexID, headTest1); break; case 3: // CUT QUAD - ONLY A AND B ARE GOOD, FIND A HEAD AND B HEAD headTest1 = getHeadVertex(a); headTest2 = getHeadVertex(b); if ((headTest1 < 0) || (headTest2 < 0)) continue; // BOTTOM TRIANGLE addTriangle(a.VertexID, b.VertexID, headTest1); // TOP TRIANGLE addTriangle(b.VertexID, headTest2, headTest1); break; case 4: // CUT TRIANGLE - ONLY C IS GOOD, FIND A HEAD AND C ARM armTest1 = getArmVertex(c); headTest1 = getHeadVertex(a); if ((armTest1 < 0) || (headTest1 < 0)) continue; addTriangle(headTest1, armTest1, c.VertexID); break; case 5: // CUT QUAD - ONLY A AND C ARE GOOD, FIND A ARM AND C ARM armTest1 = getArmVertex(a); armTest2 = getArmVertex(c); if ((armTest1 < 0) || (armTest2 < 0)) continue; // LEFT TRIANGLE addTriangle(a.VertexID, armTest1, c.VertexID); // RIGHT TRIANGLE addTriangle(armTest1, armTest2, c.VertexID); break; case 6: // 6 AND 9 ARE AMBIGUOUS AS OPPOSITE CORNERS C AND B ARE HOT. // THEY MAY REPRESENT A DIAGNONAL STRIP ACROSS THE GRID OR TWO INDEPENDENT // CUT TRIANGLES AT THE CORNERS. WE NEED TO CHECK THE GRID // CENTER TO DETERMINE WHICH SOLUTION TO ASSUME armTest1 = getArmVertex(a); headTest1 = getHeadVertex(a); armTest2 = getArmVertex(c); headTest2 = getHeadVertex(b); if ((armTest1 < 0) || (headTest1 < 0) || (armTest2 < 0) || (headTest2 < 0 ) ) continue; if ( isGridCenterInBody(a) ) { // ADD CORNER CUT TRIANGLES AND DIAGONAL PARTIAL QUAD FOR CENTER addTriangle(headTest1, armTest2, c.VertexID); addTriangle(armTest1, armTest2, headTest1); addTriangle(armTest1, headTest2, armTest2); addTriangle(armTest1, b.VertexID, headTest2); } else { // ONLY ADD CORNER CUT TRIANGLES addTriangle(headTest1, armTest2, c.VertexID); addTriangle(armTest1, b.VertexID, headTest2); } break; case 7: // DIAMOND - A, B, C ARE GOOD SO MARCH TOWARD D armTest1 = getArmVertex(c); headTest1 = getHeadVertex(b); if ((armTest1 < 0) || (headTest1 < 0)) continue; addTriangle(a.VertexID, armTest1, c.VertexID); addTriangle(a.VertexID, headTest1, armTest1); addTriangle(a.VertexID, b.VertexID, headTest1); break; case 8: // CUT TRIANGLE - ONLY D IS GOOD, FIND C ARM AND B HEAD armTest1 = getArmVertex(c); headTest1 = getHeadVertex(b); if ((armTest1 < 0) || (headTest1 < 0)) continue; addTriangle(headTest1, d.VertexID, armTest1); break; case 9: // 6 AND 9 ARE AMBIGUOUS AS OPPOSITE CORNERS A AND D ARE HOT. // THEY MAY REPRESENT A DIAGNONAL STRIP ACROSS THE GRID OR TWO INDEPENDENT // CUT TRIANGLES AT THE CORNERS. WE NEED TO CHECK THE GRID // CENTER TO DETERMINE WHICH SOLUTION TO ASSUME armTest1 = getArmVertex(a); headTest1 = getHeadVertex(a); armTest2 = getArmVertex(c); headTest2 = getHeadVertex(b); if ((armTest1 < 0) || (headTest1 < 0) || (armTest2 < 0) || (headTest2 < 0)) continue; if (isGridCenterInBody(a)) { // ADD CORNER CUT TRIANGLES AND DIAGONAL PARTIAL QUAD FOR CENTER addTriangle(a.VertexID, armTest1, headTest1); addTriangle(headTest1, armTest1, armTest2); addTriangle(headTest2, armTest2, armTest1); addTriangle(armTest2, headTest2, d.VertexID); } else { // ONLY ADD CORNER CUT TRIANGLES addTriangle(a.VertexID, armTest1, headTest1); addTriangle(armTest2, headTest2, d.VertexID); } break; case 10: // CUT QUAD - ONLY B AND D ARE GOOD, FIND A ARM AND C ARM armTest1 = getArmVertex(a); armTest2 = getArmVertex(c); if ((armTest1 < 0) || (armTest2 < 0)) continue; // LEFT TRIANGLE addTriangle(armTest1, d.VertexID, armTest2); // RIGHT TRIANGLE addTriangle(armTest1, b.VertexID, d.VertexID); break; case 11: // DIAMOND - A, B, D ARE GOOD SO MARCH TOWARD C armTest1 = getArmVertex(c); headTest1 = getHeadVertex(a); if ((armTest1 < 0) || (headTest1 < 0)) continue; addTriangle(b.VertexID, headTest1, a.VertexID); addTriangle(b.VertexID, armTest1, headTest1); addTriangle(b.VertexID, d.VertexID, armTest1); break; case 12: // CUT QUAD - ONLY C AND D ARE GOOD, FIND A HEAD AND B HEAD headTest1 = getHeadVertex(a); headTest2 = getHeadVertex(b); if ((headTest1 < 0) || (headTest2 < 0)) continue; // BOTTOM TRIANGLE addTriangle(headTest1, headTest2, c.VertexID); // TOP TRIANGLE addTriangle(headTest2, d.VertexID, c.VertexID); break; case 13: // DIAMOND - A, C, D ARE GOOD SO MARCH TOWARD B armTest1 = getArmVertex(a); headTest1 = getHeadVertex(b); if ((armTest1 < 0) || (headTest1 < 0)) continue; addTriangle(c.VertexID, a.VertexID, armTest1); addTriangle(c.VertexID, armTest1, headTest1); addTriangle(c.VertexID, headTest1, d.VertexID); break; case 14: // DIAMOND - B, C, D ARE GOOD SO MARCH TOWARD A armTest1 = getArmVertex(a); headTest1 = getHeadVertex(a); if ((armTest1 < 0) || (headTest1 < 0)) continue; addTriangle(d.VertexID, c.VertexID, headTest1); addTriangle(d.VertexID, headTest1, armTest1); addTriangle(d.VertexID, armTest1, b.VertexID); break; case 15: // FULL QUAD - ALL GRID POINTS ARE VALID addTriangle(a.VertexID, b.VertexID, c.VertexID); addTriangle(b.VertexID, d.VertexID, c.VertexID); break; } } } mesh.vertices = vertices.ToArray(); mesh.triangles = triangles.ToArray(); mesh.uv = uvs.ToArray(); mesh.RecalculateNormals(); }
int getHeadVertex(GridPoint04 gp) { if (gp.isHeadVertex()) { return gp.headVertexID; } bool seekingSilhouette = true; if (gp.IsVertex()) seekingSilhouette = false; int startingIndex = gp.DepthIndex; for (int i = 0; i <= gridStep; i++) { // WE ARE MOVING UP THE DEPTH IMAGE, SO OUR INDEX JUMPS A ROW EACH TIME bool isInBody = (bodyIndexData[startingIndex] != 255); if (isInBody && seekingSilhouette) { CameraSpacePoint csp = cameraSpacePoints[startingIndex]; if (!float.IsInfinity(csp.X) && !float.IsInfinity(csp.Y) && !float.IsInfinity(csp.Z)) { gp.headVertexID = vertices.Count; vertices.Add(new Vector3(csp.X, csp.Y, csp.Z)); uvs.Add(new Vector2(gp.DepthX / (float)depthWidth, (gp.DepthY + i) / (float)depthHeight)); return gp.headVertexID; } } if ( !isInBody && !seekingSilhouette) { // IF WE WERE IN THE BODY AND MOVING OUTWARD, AT THIS POINT WE HAVE PASSED // THE EDGE SO WE WANT TO MOVE BACK ONE TO THE LAST VALID VALUE. CameraSpacePoint csp = cameraSpacePoints[startingIndex - depthWidth]; if (float.IsInfinity(csp.X) || float.IsInfinity(csp.Y) || float.IsInfinity(csp.Z)) { continue; } gp.headVertexID = vertices.Count; vertices.Add(new Vector3(csp.X, csp.Y, csp.Z)); uvs.Add(new Vector2(gp.DepthX / (float)depthWidth, ( gp.DepthY + (i-1)) / (float)depthHeight)); return gp.headVertexID; } startingIndex += depthWidth; } if (gp.IsVertex()) { return gp.VertexID; } else { return -1; } }
bool isGridCenterInBody(GridPoint04 gp) { int centerDepthIndex = gp.VertexID + (gridStep / 2) + ((gridStep / 2) * depthWidth); return bodyIndexData[centerDepthIndex] != 255; }
int getArmVertex(GridPoint04 gp) { // IF THE ARM HAS BEEN MARCHED BY A PREVIOUS TESTING SQUARE, // IT WILL ALREADY HAVE A VERTEX ID SO JUST RETURN IT. // OTHERWISE, WE WILL NEED TO MARCH THE ARM AND CREATE A NEW VERTEX if (gp.isArmVertex()) { return gp.armVertexID; } // WE ASSUME THE GRID POINT IS OUTSIDE THE SILHOUETTE AND LOOKING FOR IT bool seekingSilhouette = true; // BUT WE MAY BE STARTING INSIDE THE SILHOUETTE AND LOOKING FOR THE EDGE // SO TEST FOR THAT BY CHECKING IF THE CORE IS A VERTEX, WHICH WOULD MEAN IT WAS VALID if (gp.IsVertex()) { seekingSilhouette = false; } int startingIndex = gp.DepthIndex; for (int i = 0; i <= gridStep; i++) { bool isInBody = (bodyIndexData[startingIndex + i] != 255); if (isInBody && seekingSilhouette) { // IF WE WERE IN THE BODY AND MOVING OUTWARD, AT THIS POINT WE HAVE PASSED // THE EDGE SO WE WANT TO MOVE BACK ONE TO THE LAST VALID VALUE. CameraSpacePoint csp = cameraSpacePoints[startingIndex + i]; if (float.IsInfinity(csp.X) || float.IsInfinity(csp.Y) || float.IsInfinity(csp.Z)) { continue; } gp.armVertexID = vertices.Count; vertices.Add(new Vector3(csp.X, csp.Y, csp.Z)); uvs.Add(new Vector2((gp.DepthX + i) / (float)depthWidth, gp.DepthY / (float)depthHeight)); return gp.armVertexID; } if (!isInBody && !seekingSilhouette) { // IF WE WERE IN THE BODY AND MOVING OUTWARD, AT THIS POINT WE HAVE PASSED // THE EDGE SO WE WANT TO MOVE BACK ONE TO THE LAST VALID VALUE. CameraSpacePoint csp = cameraSpacePoints[startingIndex + (i-1)]; if (float.IsInfinity(csp.X) || float.IsInfinity(csp.Y) || float.IsInfinity(csp.Z)) { continue; } gp.armVertexID = vertices.Count; vertices.Add(new Vector3(csp.X, csp.Y, csp.Z)); uvs.Add(new Vector2( (gp.DepthX + (i-1)) / (float)depthWidth, gp.DepthY / (float)depthHeight)); return gp.armVertexID; } } if ( gp.IsVertex() ) { return gp.VertexID; } else { return -1; } }