public static void ClusterEdge(OctreeNode[] nodes, int direction, ref int surface_index, List<Vertex> collected_vertices) { if ((nodes[0] == null || nodes[0].type != NodeType.Internal) && (nodes[1] == null || nodes[1].type != NodeType.Internal) && (nodes[2] == null || nodes[2].type != NodeType.Internal) && (nodes[3] == null || nodes[3].type != NodeType.Internal)) { ClusterIndexes(nodes, direction, ref surface_index, collected_vertices); } else { for (int i = 0; i < 2; i++) { OctreeNode[] edge_nodes = new OctreeNode[4]; for (int j = 0; j < 4; j++) { if (nodes[j] == null) continue; if (nodes[j].type == NodeType.Leaf) edge_nodes[j] = nodes[j]; else edge_nodes[j] = nodes[j].children[Utilities.TEdgeProcEdgeMask[direction, i, j]]; } ClusterEdge(edge_nodes, Utilities.TEdgeProcEdgeMask[direction, i, 4], ref surface_index, collected_vertices); } } }
public override long Contour(float threshold) { Stopwatch watch = new Stopwatch(); watch.Start(); if (tree == null) { VerticesDN.Clear(); tree = new OctreeNode(); List<VertexPositionColorNormalNormal> vs = new List<VertexPositionColorNormalNormal>(); tree.ConstructBase(Resolution, 0, ref vs); tree.ClusterCellBase(0); //VerticesDN = vs.ToList(); tree.GenerateVertexBuffer(VerticesDN); if (VerticesDN.Count > 0) VertexBuffer.SetData<VertexPositionColorNormalNormal>(VerticesDN.ToArray()); VertexCount = VerticesDN.Count; } OutlineLocation = 0; //ConstructTreeGrid(tree); CalculateIndexes(threshold); watch.Stop(); return watch.ElapsedMilliseconds; }
public void ConstructTreeGrid(OctreeNode node) { if (node == null) return; VertexPositionColor[] vs = new VertexPositionColor[24]; int x = (int)node.position.X; int y = (int)node.position.Y; int z = (int)node.position.Z; Color c = Color.LightSteelBlue; Color v = Color.Red; float size = node.size; vs[0] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 0 * size), c); vs[1] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 0 * size), c); vs[2] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 0 * size), c); vs[3] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 0 * size), c); vs[4] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 0 * size), c); vs[5] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 0 * size), c); vs[6] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 0 * size), c); vs[7] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 0 * size), c); vs[8] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 1 * size), c); vs[9] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 1 * size), c); vs[10] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 1 * size), c); vs[11] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 1 * size), c); vs[12] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 1 * size), c); vs[13] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 1 * size), c); vs[14] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 1 * size), c); vs[15] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 1 * size), c); vs[16] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 0 * size), c); vs[17] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 1 * size), c); vs[18] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 0 * size), c); vs[19] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 1 * size), c); vs[20] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 0 * size), c); vs[21] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 1 * size), c); vs[22] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 0 * size), c); vs[23] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 1 * size), c); OutlineBuffer.SetData<VertexPositionColor>(OutlineLocation * VertexPositionColor.VertexDeclaration.VertexStride, vs, 0, 24, VertexPositionColor.VertexDeclaration.VertexStride); OutlineLocation += 24; /*if (node.type != OctreeNodeType.Leaf || node.draw_info.index == -1 || true) { OutlineBuffer.SetData<VertexPositionColor>(outline_location * VertexPositionColor.VertexDeclaration.VertexStride, vs, 0, 8, VertexPositionColor.VertexDeclaration.VertexStride); outline_location += 8; } else { x += (int)(node.draw_info.position.X * (float)this.size); y += (int)(node.draw_info.position.Y * (float)this.size); float r = 2; vs[8] = new VertexPositionColor(new Vector3(x - r, y - r, 0), v); vs[9] = new VertexPositionColor(new Vector3(x + r, y - r, 0), v); vs[10] = new VertexPositionColor(new Vector3(x + r, y - r, 0), v); vs[11] = new VertexPositionColor(new Vector3(x + r, y + r, 0), v); vs[12] = new VertexPositionColor(new Vector3(x + r, y + r, 0), v); vs[13] = new VertexPositionColor(new Vector3(x - r, y + r, 0), v); vs[14] = new VertexPositionColor(new Vector3(x - r, y + r, 0), v); vs[15] = new VertexPositionColor(new Vector3(x - r, y - r, 0), v); OutlineBuffer.SetData<VertexPositionColor>(outline_location * VertexPositionColor.VertexDeclaration.VertexStride, vs, 0, 16, VertexPositionColor.VertexDeclaration.VertexStride); outline_location += 16; }*/ if (node.type == NodeType.Internal && node.vertices.Length == 0) { for (int i = 0; i < 8; i++) { ConstructTreeGrid(node.children[i]); } } }
public void ConstructTreeGrid(OctreeNode node) { if (node == null) { return; } VertexPositionColor[] vs = new VertexPositionColor[24]; int x = (int)node.position.X; int y = (int)node.position.Y; int z = (int)node.position.Z; Color c = Color.LightSteelBlue; Color v = Color.Red; float size = node.size; /*vs[0] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 0 * size), c); * vs[1] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 0 * size), c); * vs[2] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 0 * size), c); * vs[3] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 0 * size), c); * vs[4] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 0 * size), c); * vs[5] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 0 * size), c); * vs[6] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 0 * size), c); * vs[7] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 0 * size), c); * * vs[8] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 1 * size), c); * vs[9] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 1 * size), c); * vs[10] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 1 * size), c); * vs[11] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 1 * size), c); * vs[12] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 1 * size), c); * vs[13] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 1 * size), c); * vs[14] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 1 * size), c); * vs[15] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 1 * size), c); * * vs[16] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 0 * size), c); * vs[17] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 1 * size), c); * vs[18] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 0 * size), c); * vs[19] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 1 * size), c); * * vs[20] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 0 * size), c); * vs[21] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 1 * size), c); * vs[22] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 0 * size), c); * vs[23] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 1 * size), c); * * OutlineBuffer.SetData<VertexPositionColor>(OutlineLocation * VertexPositionColor.VertexDeclaration.VertexStride, vs, 0, 24, VertexPositionColor.VertexDeclaration.VertexStride); * OutlineLocation += 24;*/ /*if (node.type != OctreeNodeType.Leaf || node.draw_info.index == -1 || true) * { * OutlineBuffer.SetData<VertexPositionColor>(outline_location * VertexPositionColor.VertexDeclaration.VertexStride, vs, 0, 8, VertexPositionColor.VertexDeclaration.VertexStride); * outline_location += 8; * } * else * { * x += (int)(node.draw_info.position.X * (float)this.size); * y += (int)(node.draw_info.position.Y * (float)this.size); * float r = 2; * vs[8] = new VertexPositionColor(new Vector3(x - r, y - r, 0), v); * vs[9] = new VertexPositionColor(new Vector3(x + r, y - r, 0), v); * vs[10] = new VertexPositionColor(new Vector3(x + r, y - r, 0), v); * vs[11] = new VertexPositionColor(new Vector3(x + r, y + r, 0), v); * vs[12] = new VertexPositionColor(new Vector3(x + r, y + r, 0), v); * vs[13] = new VertexPositionColor(new Vector3(x - r, y + r, 0), v); * vs[14] = new VertexPositionColor(new Vector3(x - r, y + r, 0), v); * vs[15] = new VertexPositionColor(new Vector3(x - r, y - r, 0), v); * OutlineBuffer.SetData<VertexPositionColor>(outline_location * VertexPositionColor.VertexDeclaration.VertexStride, vs, 0, 16, VertexPositionColor.VertexDeclaration.VertexStride); * outline_location += 16; * }*/ if (node.type == NodeType.Internal && node.vertices.Length == 0) { for (int i = 0; i < 8; i++) { ConstructTreeGrid(node.children[i]); } } }
public static void ClusterFace(OctreeNode[] nodes, int direction, ref int surface_index, List <Vertex> collected_vertices) { if (nodes[0] == null || nodes[1] == null) { return; } if (nodes[0].type != NodeType.Leaf || nodes[1].type != NodeType.Leaf) { for (int i = 0; i < 4; i++) { OctreeNode[] face_nodes = new OctreeNode[2]; for (int j = 0; j < 2; j++) { if (nodes[j] == null) { continue; } if (nodes[j].type != NodeType.Internal) { face_nodes[j] = nodes[j]; } else { face_nodes[j] = nodes[j].children[Utilities.TFaceProcFaceMask[direction, i, j]]; } } ClusterFace(face_nodes, Utilities.TFaceProcFaceMask[direction, i, 2], ref surface_index, collected_vertices); } } int[,] orders = { { 0, 0, 1, 1 }, { 0, 1, 0, 1 }, }; for (int i = 0; i < 4; i++) { OctreeNode[] edge_nodes = new OctreeNode[4]; for (int j = 0; j < 4; j++) { if (nodes[orders[Utilities.TFaceProcEdgeMask[direction, i, 0], j]] == null) { continue; } if (nodes[orders[Utilities.TFaceProcEdgeMask[direction, i, 0], j]].type != NodeType.Internal) { edge_nodes[j] = nodes[orders[Utilities.TFaceProcEdgeMask[direction, i, 0], j]]; } else { edge_nodes[j] = nodes[orders[Utilities.TFaceProcEdgeMask[direction, i, 0], j]].children[Utilities.TFaceProcEdgeMask[direction, i, 1 + j]]; } } ClusterEdge(edge_nodes, Utilities.TFaceProcEdgeMask[direction, i, 5], ref surface_index, collected_vertices); } }
/* * 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 bool ConstructNodes(List <VertexPositionColorNormalNormal> vertices, ref int n_index, int threaded = 0) { if (size == 1) { return(ConstructLeaf(ref vertices, ref n_index)); } type = NodeType.Internal; int child_size = size / 2; bool has_children = false; //Task[] threads = new Task[8]; bool[] return_values = new bool[8]; for (int i = 0; i < 8; i++) { this.index = n_index++; Vector3 child_pos = Utilities.TCornerDeltas[i]; children[i] = new OctreeNode(position + child_pos * (float)child_size, child_size, NodeType.Internal); children[i].child_index = i; int index = i; /*if (threaded > 0 && size > 2) * { * threads[index] = Task.Factory.StartNew( * () => * { * int temp = 0; * return_values[index] = children[index].ConstructNodes(vertices, ref temp, threaded - 1); * if (!return_values[index]) * children[index] = null; * }, TaskCreationOptions.AttachedToParent); * //threads[index].Start(); * }*/ if (size > 2) { int temp = 0; return_values[index] = children[index].ConstructNodes(vertices, ref temp, threaded - 1); if (!return_values[index]) { children[index] = null; } //threads[index].Start(); } else { if (children[i].ConstructNodes(vertices, ref n_index, 0)) { has_children = true; } else { children[i] = null; } } } if (size > 2) { for (int i = 0; i < 8; i++) { //threads[i].Wait(); if (return_values[i]) { has_children = true; } } } /*if (threaded > 0 && size > 2) * { * for (int i = 0; i < 8; i++) * { * threads[i].Wait(); * if (return_values[i]) * has_children = true; * } * }*/ return(has_children); }
public bool ConstructNodes(List<VertexPositionColorNormalNormal> vertices, ref int n_index, int threaded = 0) { if (size == 1) return ConstructLeaf(ref vertices, ref n_index); type = NodeType.Internal; int child_size = size / 2; bool has_children = false; Task[] threads = new Task[8]; bool[] return_values = new bool[8]; for (int i = 0; i < 8; i++) { this.index = n_index++; Vector3 child_pos = Utilities.TCornerDeltas[i]; children[i] = new OctreeNode(position + child_pos * (float)child_size, child_size, NodeType.Internal); children[i].child_index = i; int index = i; if (threaded > 0 && size > 2) { threads[index] = Task.Factory.StartNew( () => { int temp = 0; return_values[index] = children[index].ConstructNodes(vertices, ref temp, threaded - 1); if (!return_values[index]) children[index] = null; }, TaskCreationOptions.AttachedToParent); //threads[index].Start(); } else { if (children[i].ConstructNodes(vertices, ref n_index, 0)) has_children = true; else children[i] = null; } } if (threaded > 0 && size > 2) { for (int i = 0; i < 8; i++) { threads[i].Wait(); if (return_values[i]) has_children = true; } } return has_children; }
/* * 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 static void ProcessFace(OctreeNode[] nodes, int direction, List<int> indexes, List<int> tri_count, float threshold) { if (nodes[0] == null || nodes[1] == null) return; if (nodes[0].type != NodeType.Leaf || nodes[1].type != NodeType.Leaf) { for (int i = 0; i < 4; i++) { OctreeNode[] face_nodes = new OctreeNode[2]; for (int j = 0; j < 2; j++) { if (nodes[j].type == NodeType.Leaf) face_nodes[j] = nodes[j]; else face_nodes[j] = nodes[j].children[Utilities.TFaceProcFaceMask[direction, i, j]]; } ProcessFace(face_nodes, Utilities.TFaceProcFaceMask[direction, i, 2], indexes, tri_count, threshold); } int[,] orders = { { 0, 0, 1, 1 }, { 0, 1, 0, 1 }, }; for (int i = 0; i < 4; i++) { OctreeNode[] edge_nodes = new OctreeNode[4]; for (int j = 0; j < 4; j++) { if (nodes[orders[Utilities.TFaceProcEdgeMask[direction, i, 0], j]].type == NodeType.Leaf) edge_nodes[j] = nodes[orders[Utilities.TFaceProcEdgeMask[direction, i, 0], j]]; else edge_nodes[j] = nodes[orders[Utilities.TFaceProcEdgeMask[direction, i, 0], j]].children[Utilities.TFaceProcEdgeMask[direction, i, 1 + j]]; } ProcessEdge(edge_nodes, Utilities.TFaceProcEdgeMask[direction, i, 5], indexes, tri_count, threshold); } } }
public static void ProcessIndexes(OctreeNode[] nodes, int direction, List<int> indexes, List<int> tri_count, float threshold) { int min_size = 10000000; int min_index = 0; int[] indices = { -1, -1, -1, -1 }; bool flip = false; bool sign_changed = false; int v_count = 0; //return; for (int i = 0; i < 4; i++) { 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 (nodes[i].size < min_size) { min_size = nodes[i].size; min_index = i; flip = m1 == 1; sign_changed = ((m1 == 0 && m2 != 0) || (m1 != 0 && m2 == 0)); } //if (!((m1 == 0 && m2 != 0) || (m1 != 0 && m2 == 0))) // continue; //find the vertex index int index = 0; bool skip = false; if (nodes[i].corners == 179) { } for (int k = 0; k < 16; k++) { int e = Utilities.TransformedEdgesTable[nodes[i].corners, k]; if (e == -1) { index++; continue; } if (e == -2) { skip = true; break; } if (e == edge) break; } if (skip) continue; if (nodes[i].index == 30733) { } v_count++; if (index >= nodes[i].vertices.Length) return; Vertex v = nodes[i].vertices[index]; Vertex highest = v; while (highest.parent != null) { if ((highest.parent.error <= threshold && (!EnforceManifold || (highest.parent.euler == 1 && highest.parent.face_prop2)))) highest = v = highest.parent; else highest = highest.parent; } //Vector3 p = v.qef.Solve(1e-6f, 4, 1e-6f); indices[i] = v.index; if (v.index == -1) { } //sign_changed = true; } if (v_count > 0 && v_count < 4) { } /* * Next generate the triangles. * Because we're generating from the finest levels that were collapsed, many triangles will collapse to edges or vertices. * That's why we check if the indices are different and discard the triangle, as mentioned in the paper. */ if (sign_changed) { int count = 0; if (!flip) { if (indices[0] != -1 && indices[1] != -1 && indices[2] != -1 && indices[0] != indices[1] && indices[1] != indices[3]) { indexes.Add(indices[0]); indexes.Add(indices[1]); indexes.Add(indices[3]); count++; } if (indices[0] != -1 && indices[2] != -1 && indices[3] != -1 && indices[0] != indices[2] && indices[2] != indices[3]) { indexes.Add(indices[0]); indexes.Add(indices[3]); indexes.Add(indices[2]); count++; } } else { if (indices[0] != -1 && indices[3] != -1 && indices[1] != -1 && indices[0] != indices[1] && indices[1] != indices[3]) { indexes.Add(0x10000000 | indices[0]); indexes.Add(0x10000000 | indices[3]); indexes.Add(0x10000000 | indices[1]); count++; } if (indices[0] != -1 && indices[2] != -1 && indices[3] != -1 && indices[0] != indices[2] && indices[2] != indices[3]) { indexes.Add(0x10000000 | indices[0]); indexes.Add(0x10000000 | indices[2]); indexes.Add(0x10000000 | indices[3]); count++; } } if (count > 0) tri_count.Add(count); } }
public static void ProcessEdge(OctreeNode[] nodes, int direction, List<int> indexes, List<int> tri_count, float threshold) { if (nodes[0] == null || nodes[1] == null || nodes[2] == null || nodes[3] == null) return; if (nodes[0].type == NodeType.Leaf && nodes[1].type == NodeType.Leaf && nodes[2].type == NodeType.Leaf && nodes[3].type == NodeType.Leaf) { ProcessIndexes(nodes, direction, indexes, tri_count, threshold); } else { for (int i = 0; i < 2; i++) { OctreeNode[] edge_nodes = new OctreeNode[4]; for (int j = 0; j < 4; j++) { if (nodes[j].type == NodeType.Leaf) edge_nodes[j] = nodes[j]; else edge_nodes[j] = nodes[j].children[Utilities.TEdgeProcEdgeMask[direction, i, j]]; } ProcessEdge(edge_nodes, Utilities.TEdgeProcEdgeMask[direction, i, 4], indexes, tri_count, threshold); } } }
public static void GatherVertices(OctreeNode n, List<Vertex> dest, ref int surface_index) { if (n == null) return; if (n.size > 1) { for (int i = 0; i < 8; i++) GatherVertices(n.children[i], dest, ref surface_index); } else { foreach (Vertex v in n.vertices) { if (v.surface_index == -1) { v.surface_index = surface_index++; dest.Add(v); } } } }
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; //} } }
public static void ClusterFace(OctreeNode[] nodes, int direction, ref int surface_index, List<Vertex> collected_vertices) { if (nodes[0] == null || nodes[1] == null) return; if (nodes[0].type != NodeType.Leaf || nodes[1].type != NodeType.Leaf) { for (int i = 0; i < 4; i++) { OctreeNode[] face_nodes = new OctreeNode[2]; for (int j = 0; j < 2; j++) { if (nodes[j] == null) continue; if (nodes[j].type != NodeType.Internal) face_nodes[j] = nodes[j]; else face_nodes[j] = nodes[j].children[Utilities.TFaceProcFaceMask[direction, i, j]]; } ClusterFace(face_nodes, Utilities.TFaceProcFaceMask[direction, i, 2], ref surface_index, collected_vertices); } } int[,] orders = { { 0, 0, 1, 1 }, { 0, 1, 0, 1 }, }; for (int i = 0; i < 4; i++) { OctreeNode[] edge_nodes = new OctreeNode[4]; for (int j = 0; j < 4; j++) { if (nodes[orders[Utilities.TFaceProcEdgeMask[direction, i, 0], j]] == null) continue; if (nodes[orders[Utilities.TFaceProcEdgeMask[direction, i, 0], j]].type != NodeType.Internal) edge_nodes[j] = nodes[orders[Utilities.TFaceProcEdgeMask[direction, i, 0], j]]; else edge_nodes[j] = nodes[orders[Utilities.TFaceProcEdgeMask[direction, i, 0], j]].children[Utilities.TFaceProcEdgeMask[direction, i, 1 + j]]; } ClusterEdge(edge_nodes, Utilities.TFaceProcEdgeMask[direction, i, 5], ref surface_index, collected_vertices); } }
public void ProcessCell(List<int> indexes, List<int> tri_count, float threshold) { if (type == NodeType.Internal) { for (int i = 0; i < 8; i++) { if (children[i] != null) children[i].ProcessCell(indexes, tri_count, threshold); } if (index == 31681) { } 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]; ProcessFace(face_nodes, Utilities.TEdgePairs[i, 2], indexes, tri_count, threshold); } 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]] }; ProcessEdge(edge_nodes, Utilities.TCellProcEdgeMask[i, 4], indexes, tri_count, threshold); } } }