public static CellInfo[,,] GenVertices(int resolution, UtilFuncs.Sampler samp) { CellInfo[,,] cellInfos = new CellInfo[resolution, resolution, resolution]; for (int x = 0; x < resolution; x++) { for (int y = 0; y < resolution; y++) { for (int z = 0; z < resolution; z++) { //Vector3 p = new Vector3(x, y, z); byte caseCode = 0; sbyte[] densities = new sbyte[8]; for (int i = 0; i < 8; i++) { Vector3 pos = new Vector3(x, y, z) + DCC.vfoffsets[i]; densities[i] = (sbyte)Mathf.Clamp((samp(pos.x, pos.y, pos.z) * 127f), -127f, 127f); //data[index + inArray[i]]; if (densities[i] < 0) { caseCode |= (byte)(1 << i); } } Vector3[] cpositions = new Vector3[4]; Vector3[] cnormals = new Vector3[4]; int edgeCount = 0; for (int i = 0; i < 12 && edgeCount < 4; i++) { byte c1 = (byte)DCC.edgevmap[i][0]; byte c2 = (byte)DCC.edgevmap[i][1]; Vector3 p1 = new Vector3(x, y, z) + DCC.vfoffsets[c1]; Vector3 p2 = new Vector3(x, y, z) + DCC.vfoffsets[c2]; bool m1 = ((caseCode >> c1) & 1) == 1; bool m2 = ((caseCode >> c2) & 1) == 1; if (m1 != m2) { cpositions[edgeCount] = ApproximateZeroCrossingPosition(p1, p2, samp); cnormals[edgeCount] = CalculateSurfaceNormal(cpositions[edgeCount], samp); edgeCount++; } } if (edgeCount == 0) { continue; } CellInfo cellInfo = new CellInfo(); QEF.QEFSolver qef = new QEF.QEFSolver(); for (int i = 0; i < edgeCount; i++) { qef.Add(cpositions[i], cnormals[i]); } cellInfo.Position = qef.Solve(0.0001f, 4, 0.0001f); //drawInfo.index = vertices.Count; Vector3 max = new Vector3(x, y, z) + Vector3.one; if (cellInfo.Position.x < x || cellInfo.Position.x > max.x || cellInfo.Position.y < y || cellInfo.Position.y > max.y || cellInfo.Position.z < z || cellInfo.Position.z > max.z) { cellInfo.Position = qef.MassPoint; } //vertices.Add(drawInfo.position); for (int i = 0; i < edgeCount; i++) { cellInfo.Normal += cnormals[i]; } cellInfo.Normal = Vector3.Normalize(cellInfo.Normal); //CalculateSurfaceNormal(drawInfo.position, samp); //normals.Add(drawInfo.averageNormal); cellInfo.Corners = caseCode; cellInfos[x, y, z] = cellInfo; } } } return(cellInfos); }
public static OctreeNode SimplifyOctree(OctreeNode node, float threshold) { if (node == null) { return(null); } if (node.type != DCC.OctreeNodeType.Node_Internal) { return(node); } QEF.QEFSolver qef = new QEF.QEFSolver(); int[] signs = { -1, -1, -1, -1, -1, -1, -1, -1 }; int midsign = -1; int edgeCount = 0; bool isCollapsible = true; for (int i = 0; i < 8; i++) { node.children[i] = SimplifyOctree(node.children[i], threshold); if (node.children[i] != null) { OctreeNode child = node.children[i]; if (child.type == DCC.OctreeNodeType.Node_Internal) { isCollapsible = false; } else { qef.Add(ref child.drawInfo.qef.data); if (qef.data.numPoints == 0) { Debug.Log("warning: zero points in qef"); Debug.Log("child number of points: " + child.drawInfo.qef.data.numPoints); } //Debug.LogError("Qef points: " + qef.data.numPoints); midsign = (child.drawInfo.corners >> (7 - i)) & 1; signs[i] = (child.drawInfo.corners >> i) & 1; edgeCount++; } } else { //Debug.LogError("Null child! type: " + node.type); } } if (!isCollapsible) { // at least one child is an internal node, can't collapse return(node); } float QEF_ERROR = 0.1f; int QEF_SWEEPS = 4; float PINV_TOL = 0.1f; if (qef.data.numPoints == 0) { for (int i = 0; i < 8; i++) { //DestroyOctree(node->children[i]); node.children[i] = null; } node.type = DCC.OctreeNodeType.Node_Psuedo; OctreeDrawInfo drawInfo2 = new OctreeDrawInfo(); for (int i = 0; i < 8; i++) { if (signs[i] == -1) { // Undetermined, use centre sign instead drawInfo2.corners |= (midsign << i); } else { drawInfo2.corners |= (signs[i] << i); } } drawInfo2.averageNormal = Vector3.zero; node.drawInfo = drawInfo2; return(node); } Vector3 position = qef.Solve(QEF_ERROR, QEF_SWEEPS, PINV_TOL); //if(qef.data.num) float error = qef.GetError(); // at this point the masspoint will actually be a sum, so divide to make it the average if (error > threshold) { // this collapse breaches the threshold return(node); } if (position.x < node.min.x || position.x > (node.min.x + node.size) || position.y < node.min.y || position.y > (node.min.y + node.size) || position.z < node.min.z || position.z > (node.min.z + node.size)) { Vector3 mp = qef.MassPoint; position = new Vector3(mp.x, mp.y, mp.z); } // change the node from an internal node to a 'psuedo leaf' node OctreeDrawInfo drawInfo = new OctreeDrawInfo(); for (int i = 0; i < 8; i++) { if (signs[i] == -1) { // Undetermined, use centre sign instead drawInfo.corners |= (midsign << i); } else { drawInfo.corners |= (signs[i] << i); } } drawInfo.averageNormal = Vector3.zero; for (int i = 0; i < 8; i++) { if (node.children[i] != null) { OctreeNode child = node.children[i]; if (child.type == DCC.OctreeNodeType.Node_Psuedo || child.type == DCC.OctreeNodeType.Node_Leaf) { drawInfo.averageNormal += child.drawInfo.averageNormal; } } } drawInfo.averageNormal = Vector3.Normalize(drawInfo.averageNormal); drawInfo.position = position; QEF.QEFSolver qef2 = new QEF.QEFSolver(); qef2.data = qef.data; drawInfo.qef = qef2; for (int i = 0; i < 8; i++) { //DestroyOctree(node->children[i]); node.children[i] = null; } node.type = DCC.OctreeNodeType.Node_Psuedo; node.drawInfo = drawInfo; return(node); }