public static void ClusterIndexes(OctreeNode[] nodes, int direction, ref int max_surface_index, List<Vertex> collected_vertices) { if (nodes[0] == null && nodes[1] == null && nodes[2] == null && nodes[3] == null) return; Vertex[] vertices = new Vertex[4]; int v_count = 0; int node_count = 0; for (int i = 0; i < 4; i++) { if (nodes[i] == null) continue; if (nodes[i].size > 1) { } node_count++; if (nodes[i].vertices.Length > 1) { } int edge = Utilities.TProcessEdgeMask[direction, i]; int c1 = Utilities.TEdgePairs[edge, 0]; int c2 = Utilities.TEdgePairs[edge, 1]; int m1 = (nodes[i].corners >> c1) & 1; int m2 = (nodes[i].corners >> c2) & 1; //if (!((m1 == 0 && m2 != 0) || (m1 != 0 && m2 == 0))) // continue; //find the vertex index int index = 0; bool skip = false; for (int k = 0; k < 16; k++) { int e = Utilities.TransformedEdgesTable[nodes[i].corners, k]; if (e == -1) { index++; continue; } if (e == -2) { if (!((m1 == 0 && m2 != 0) || (m1 != 0 && m2 == 0))) skip = true; break; } if (e == edge) break; } if (!skip && index < nodes[i].vertices.Length) { if (nodes[i].index == 30733) { } if (nodes[i].index == 12) { } vertices[i] = nodes[i].vertices[index]; while (vertices[i].parent != null) vertices[i] = vertices[i].parent; if (i > v_count) { } v_count++; } } if (v_count == 0) return; if (node_count != v_count) { } if (!(vertices[0] != vertices[1] && vertices[1] != vertices[2] && vertices[2] != vertices[3])) { //return; } int surface_index = -1; for (int i = 0; i < 4; i++) { Vertex v = vertices[i]; if (v == null) continue; //while (v != null) //{ if (v.surface_index != -1) { if (surface_index != -1 && surface_index != v.surface_index) { AssignSurface(collected_vertices, v.surface_index, surface_index); } else if (surface_index == -1) surface_index = v.surface_index; //break; } //break; //v = v.parent; //} } if (surface_index == -1) surface_index = max_surface_index++; for (int i = 0; i < 4; i++) { Vertex v = vertices[i]; if (v == null) continue; //while (v.parent != null) // v = v.parent; //while (v != null) //{ if (v.surface_index == -1) { collected_vertices.Add(v); } v.surface_index = surface_index; //v = v.parent; //} } }
/* * Cell stage */ public void ClusterCell(float error) { if (type != NodeType.Internal) return; /* * First cluster all the children nodes */ int[] signs = { -1, -1, -1, -1, -1, -1, -1, -1 }; int mid_sign = -1; bool is_collapsible = true; for (int i = 0; i < 8; i++) { if (children[i] == null) continue; children[i].ClusterCell(error); if (children[i].type == NodeType.Internal) //Can't cluster if the child has children is_collapsible = false; else { mid_sign = (children[i].corners >> (7 - i)) & 1; signs[i] = (children[i].corners >> i) & 1; } } corners = 0; for (int i = 0; i < 8; i++) { if (signs[i] == -1) corners |= (byte)(mid_sign << i); else corners |= (byte)(signs[i] << i); } //if (!is_collapsible) // return; int surface_index = 0; List<Vertex> collected_vertices = new List<Vertex>(); List<Vertex> new_vertices = new List<Vertex>(); if (index == 31681) { } if (index == 61440) { } if (index == 7715) { } if ((int)position.X == 12 && (int)position.Y == 18 && (int)position.Z == 26) { } /* * Find all the surfaces inside the children that cross the 6 Euclidean edges and the vertices that connect to them */ for (int i = 0; i < 12; i++) { OctreeNode[] face_nodes = new OctreeNode[2]; int c1 = Utilities.TEdgePairs[i, 0]; int c2 = Utilities.TEdgePairs[i, 1]; face_nodes[0] = children[c1]; face_nodes[1] = children[c2]; ClusterFace(face_nodes, Utilities.TEdgePairs[i, 2], ref surface_index, collected_vertices); } for (int i = 0; i < 6; i++) { OctreeNode[] edge_nodes = { children[Utilities.TCellProcEdgeMask[i, 0]], children[Utilities.TCellProcEdgeMask[i, 1]], children[Utilities.TCellProcEdgeMask[i, 2]], children[Utilities.TCellProcEdgeMask[i, 3]] }; if (size == 4 && i == 1) { } ClusterEdge(edge_nodes, Utilities.TCellProcEdgeMask[i, 4], ref surface_index, collected_vertices); } if (size == 16 && position.X == 0 && position.Y == 16 && position.Z == 16) { } if (index == 61440) { } int highest_index = surface_index; if (highest_index == -1) highest_index = 0; /* * Gather the stray vertices */ foreach (OctreeNode n in children) { if (n == null) continue; foreach (Vertex v in n.vertices) { if (v == null) continue; if (v.surface_index == -1) { v.surface_index = highest_index++; collected_vertices.Add(v); } } } //GatherVertices(this, collected_vertices, ref highest_index); //if (surface_index == 0 && highest_index > 1) // return; if (highest_index == 7) { } int clustered_count = 0; if (collected_vertices.Count > 0) { for (int i = 0; i <= highest_index; i++) { QEFProper.QEFSolver qef = new QEFProper.QEFSolver(); Vector3 normal = Vector3.Zero; int count = 0; int[] edges = new int[12]; int euler = 0; int e = 0; foreach (Vertex v in collected_vertices) { if (v.surface_index == i) { /*if (!v.qef.hasSolution) v.qef.Solve(1e-6f, 4, 1e-6f); if (v.qef.GetError() > error) { count = 0; break; }*/ /* Calculate ei(Sv) */ for (int k = 0; k < 3; k++) { int edge = Utilities.TExternalEdges[v.in_cell, k]; edges[edge] += v.eis[edge]; } /* Calculate e(Svk) */ for (int k = 0; k < 9; k++) { int edge = Utilities.TInternalEdges[v.in_cell, k]; e += v.eis[edge]; } euler += v.euler; qef.Add(ref v.qef.data); normal += v.normal; count++; } } /* * One vertex might have an error greater than the threshold, preventing simplification. * When it's just one, we can ignore the error and proceed. */ if (count == 0) { continue; } bool face_prop2 = true; for (int f = 0; f < 6 && face_prop2; f++) { int intersections = 0; for (int ei = 0; ei < 4; ei++) { intersections += edges[Utilities.TFaces[f, ei]]; } if (!(intersections == 0 || intersections == 2)) face_prop2 = false; } Vertex new_vertex = new Vertex(); normal /= (float)count; normal.Normalize(); new_vertex.normal = normal; new_vertex.qef = qef; new_vertex.eis = edges; new_vertex.euler = euler - e / 4; if (new_vertex.euler != 1) { } new_vertex.in_cell = this.child_index; new_vertex.face_prop2 = face_prop2; if (face_prop2) { } if (new_vertex.euler != 1) { } new_vertices.Add(new_vertex); //new_vertex.index = rnd.Next(); qef.Solve(1e-6f, 4, 1e-6f); float err = qef.GetError(); new_vertex.collapsible = err <= error/* && new_vertex.euler == 1 && face_prop2*/; new_vertex.error = err; clustered_count++; if (count > 4) { } foreach (Vertex v in collected_vertices) { if (v.surface_index == i) { Vertex p = v; //p.surface_index = -1; /*while (p.parent != null) { p = p.parent; //p.surface_index = -1; if (p == p.parent) { p.parent = null; break; } }*/ if (p != new_vertex) p.parent = new_vertex; else p.parent = null; } } } } else { return; } if (new_vertices.Count >= collected_vertices.Count) { } //if (clustered_count <= 0) { foreach (Vertex v2 in collected_vertices) { v2.surface_index = -1; } } //this.type = NodeType.Collapsed; //for (int i = 0; i < 8; i++) // children[i] = null; this.vertices = new_vertices.ToArray(); if (this.vertices.Length > 4) { } }
public Vertex() { parent = null; index = -1; collapsible = true; qef = null; normal = Vector3.Zero; surface_index = -1; eis = null; }