private void Polygonize(int x, int y, int z) { if (Cells[x, y, z] == null) { return; } int cube_index = 0; for (int i = 0; i < 8; i++) { if (Sampler.Sample(new Vector3(x, y, z) + CornerDeltas[i]) < 0) { cube_index |= 1 << i; } } if (cube_index == 0 || cube_index == 255) { return; } Cells[x, y, z].Vertices = new Vertex[VerticesNumberTable[cube_index]]; /*for (int i = 0; i < 12; i++) * { * Cells[x, y, z].Edges[i].A = new Vector3(x, y, z) + CornerDeltas[EdgePairs[i, 0]]; * Cells[x, y, z].Edges[i].B = new Vector3(x, y, z) + CornerDeltas[EdgePairs[i, 1]]; * * Cells[x, y, z].Edges[i].ValueA = Sampler.Sample(Cells[x, y, z].Edges[i].A); * Cells[x, y, z].Edges[i].ValueB = Sampler.Sample(Cells[x, y, z].Edges[i].B); * }*/ int v_index = 0; Cells[x, y, z].Vertices[0] = new Vertex(); for (int e = 0; e < EdgesTable.GetLength(1); e++) { if (EdgesTable[cube_index, e] == -2) { break; } if (EdgesTable[cube_index, e] == -1) { v_index++; if (v_index < Cells[x, y, z].Vertices.Length) { Cells[x, y, z].Vertices[v_index] = new Vertex(); } continue; } //Cells[x, y, z].Vertices[v_index].Index = v_index; Cells[x, y, z].Vertices[v_index].Edges.Add(EdgesTable[cube_index, e]); Cells[x, y, z].Edges[EdgesTable[cube_index, e]].Vertices.Add(Cells[x, y, z].Vertices[v_index]); //Cells[x, y, z].Edges[EdgesTable[cube_index, e]].Flipped = Cells[x, y, z].Edges[EdgesTable[cube_index, e]].ValueA < 0; } foreach (Vertex v in Cells[x, y, z].Vertices) { Vertex tx = v; if (v == null) //for edges 241/243, which were originally marked as having 2 vertices...? { continue; } Vector3 point = new Vector3(); if (VertexMode != VertexModes.Block) { //QEF3D qef = new QEF3D(); QEFProper.QEFSolver qef = new QEFProper.QEFSolver(); VertexPlacement qem = new VertexPlacement(); for (int e_i = 0; e_i < tx.Edges.Count; e_i++) { Edge e = Cells[x, y, z].Edges[tx.Edges[e_i]]; if (VertexMode == VertexModes.Edges) { point += e.GetIntersection(); } else if (VertexMode == VertexModes.QEF) { qef.Add(e.GetIntersection() - new Vector3(x, y, z), Sampler.GetNormal(e.GetIntersection())); } else { qem.AddPlane(e.GetIntersection() - new Vector3(x, y, z), Sampler.GetNormal(e.GetIntersection())); } } if (VertexMode == VertexModes.Edges) { point /= (float)tx.Edges.Count; } else if (VertexMode == VertexModes.QEF) { point = qef.Solve(1e-6f, 4, 1e-6f) + new Vector3(x, y, z); } else { point = qem.Solve() + new Vector3(x, y, z); } } else { point = new Vector3(x, y, z) + Vector3.One * 0.5f; } //point = Vector3.Clamp(point, new Vector3(x, y, z), new Vector3(x + 1, y + 1, z + 1)); tx.Position = point; Vector3 norm = Sampler.GetNormal(point); Vector3 c_v = norm * 0.5f + Vector3.One * 0.5f; c_v.Normalize(); Color clr = new Color(c_v); if (!UseFlatShading) { tx.Index = Vertices.Count; VertexPositionColorNormal pv = new VertexPositionColorNormal(tx.Position, clr, norm); Vertices.Add(pv); } else { tx.Index = CalculatedVertices.Count; VertexPositionColor pv = new VertexPositionColor(tx.Position, clr); CalculatedVertices.Add(pv); } VertexPositionColor[] vs = new VertexPositionColor[24]; Color c = Color.Red; float vx = tx.Position.X; float vy = tx.Position.Y; float vz = tx.Position.Z; float r = 0.25f; vs[0] = new VertexPositionColor(new Vector3((vx + 0), (vy + 0), (vz + 0)), c); vs[1] = new VertexPositionColor(new Vector3((vx + r), (vy + 0), (vz + 0)), c); vs[2] = new VertexPositionColor(new Vector3((vx + r), (vy + 0), (vz + 0)), c); vs[3] = new VertexPositionColor(new Vector3((vx + r), (vy + r), (vz + 0)), c); vs[4] = new VertexPositionColor(new Vector3((vx + r), (vy + r), (vz + 0)), c); vs[5] = new VertexPositionColor(new Vector3((vx + 0), (vy + r), (vz + 0)), c); vs[6] = new VertexPositionColor(new Vector3((vx + 0), (vy + r), (vz + 0)), c); vs[7] = new VertexPositionColor(new Vector3((vx + 0), (vy + 0), (vz + 0)), c); vs[8] = new VertexPositionColor(new Vector3((vx + 0), (vy + 0), (vz + r)), c); vs[9] = new VertexPositionColor(new Vector3((vx + r), (vy + 0), (vz + r)), c); vs[10] = new VertexPositionColor(new Vector3((vx + r), (vy + 0), (vz + r)), c); vs[11] = new VertexPositionColor(new Vector3((vx + r), (vy + r), (vz + r)), c); vs[12] = new VertexPositionColor(new Vector3((vx + r), (vy + r), (vz + r)), c); vs[13] = new VertexPositionColor(new Vector3((vx + 0), (vy + r), (vz + r)), c); vs[14] = new VertexPositionColor(new Vector3((vx + 0), (vy + r), (vz + r)), c); vs[15] = new VertexPositionColor(new Vector3((vx + 0), (vy + 0), (vz + r)), c); vs[16] = new VertexPositionColor(new Vector3((vx + 0), (vy + 0), (vz + 0)), c); vs[17] = new VertexPositionColor(new Vector3((vx + 0), (vy + 0), (vz + r)), c); vs[18] = new VertexPositionColor(new Vector3((vx + 0), (vy + r), (vz + 0)), c); vs[19] = new VertexPositionColor(new Vector3((vx + 0), (vy + r), (vz + r)), c); vs[20] = new VertexPositionColor(new Vector3((vx + r), (vy + 0), (vz + 0)), c); vs[21] = new VertexPositionColor(new Vector3((vx + r), (vy + 0), (vz + r)), c); vs[22] = new VertexPositionColor(new Vector3((vx + r), (vy + r), (vz + 0)), c); vs[23] = new VertexPositionColor(new Vector3((vx + r), (vy + r), (vz + r)), c); OutlineBuffer.SetData <VertexPositionColor>(OutlineLocation * VertexPositionColor.VertexDeclaration.VertexStride, vs, 0, 24, VertexPositionColor.VertexDeclaration.VertexStride); OutlineLocation += 24; } }
public void Simplify(float threshold, bool randomize = false) { if (type != OctreeNodeType.Internal) { return; } int[] signs = { -1, -1, -1, -1, -1, -1, -1, -1 }; int mid_sign = -1; bool is_collapsible = true; //QEF3D qef = new QEF3D(); QEFProper.QEFSolver qef = new QEFProper.QEFSolver(); Random rnd = new Random(); float t = threshold; for (int i = 0; i < 8; i++) { if (children[i] == null) { continue; } if (randomize) { t = (float)rnd.NextDouble() * (float)rnd.NextDouble() * 20.0f; } children[i].Simplify(t); OctreeNode child = children[i]; if (child.type == OctreeNodeType.Internal) { is_collapsible = false; } else { //qef.Add(child.draw_info.position, child.draw_info.averageNormal); //if (child.draw_info.qef != null) qef.Add(ref child.draw_info.qef.data); mid_sign = (child.draw_info.corners >> (7 - i)) & 1; signs[i] = (child.draw_info.corners >> i) & 1; } } if (size == 16) { } if (!is_collapsible) { return; } //Vector3 pos = qef.Solve2(0, 0, 0); Vector3 pos = qef.Solve(1e-6f, 4, 1e-6f); float error = qef.GetError(); if (error > threshold) { return; } OctreeDrawInfo draw_info = new OctreeDrawInfo(); for (int i = 0; i < 8; i++) { if (signs[i] == -1) { draw_info.corners |= mid_sign << i; } else { draw_info.corners |= signs[i] << i; } } Vector3 normal = new Vector3(); for (int i = 0; i < 8; i++) { if (children[i] != null) { OctreeNode child = children[i]; if (child.type == OctreeNodeType.Pseudo || child.type == OctreeNodeType.Leaf) { normal += child.draw_info.averageNormal; } } } normal.Normalize(); draw_info.averageNormal = normal; draw_info.position = pos; draw_info.qef = qef; for (int i = 0; i < 8; i++) { children[i] = null; } type = OctreeNodeType.Pseudo; this.draw_info = draw_info; }
/* * 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) { } }
/* The following code is more or less a copy/paste cleanup of the C++ implementation * It's not clean, or efficient, but it works and is fairly straightforward */ public bool ConstructLeaf(List <VertexPositionColorNormal> vertices, int grid_size) { if (size != 1) { return(false); } int corners = 0; float[, ,] samples = new float[2, 2, 2]; for (int i = 0; i < 8; i++) { if ((samples[i / 4, i % 4 / 2, i % 2] = Sampler.Sample(position + new Vector3(i / 4, i % 4 / 2, i % 2))) < 0) { corners |= 1 << i; } } if (corners == 0 || corners == 255) { return(false); } //type = OctreeNodeType.Leaf; //return true; QEF3D qef = new QEF3D(); QEFProper.QEFSolver qefp = new QEFProper.QEFSolver(); Vector3 average_normal = Vector3.Zero; for (int i = 0; i < 12; i++) { int c1 = edgevmap[i, 0]; int c2 = edgevmap[i, 1]; int m1 = (corners >> c1) & 1; int m2 = (corners >> c2) & 1; if (m1 == m2) { continue; } float d1 = samples[c1 / 4, c1 % 4 / 2, c1 % 2]; float d2 = samples[c2 / 4, c2 % 4 / 2, c2 % 2]; Vector3 p1 = new Vector3((float)((c1 / 4)), (float)((c1 % 4 / 2)), (float)((c1 % 2))); Vector3 p2 = new Vector3((float)((c2 / 4)), (float)((c2 % 4 / 2)), (float)((c2 % 2))); Vector3 intersection = Sampler.GetIntersection(p1, p2, d1, d2) + position; Vector3 normal = Sampler.GetNormal(intersection); //GetNormal(x, y); average_normal += normal; qef.Add(intersection, normal); qefp.Add(intersection, normal); } Vector3 n = average_normal / (float)qef.Intersections.Count; n.Normalize(); draw_info = new OctreeDrawInfo(); //draw_info.position = position + qef.Solve2(0, 0, 0); draw_info.position = qefp.Solve(1e-6f, 4, 1e-6f); draw_info.corners = corners; draw_info.averageNormal = n; draw_info.qef = qefp; //vertices.Add(new VertexPositionColorNormal(position + draw_info.position, Color.LightGreen, n)); type = OctreeNodeType.Leaf; return(true); }
public void Simplify(float threshold, bool randomize = false) { if (type != OctreeNodeType.Internal) return; int[] signs = { -1, -1, -1, -1, -1, -1, -1, -1 }; int mid_sign = -1; bool is_collapsible = true; //QEF3D qef = new QEF3D(); QEFProper.QEFSolver qef = new QEFProper.QEFSolver(); Random rnd = new Random(); float t = threshold; for (int i = 0; i < 8; i++) { if (children[i] == null) continue; if (randomize) t = (float)rnd.NextDouble() * (float)rnd.NextDouble() * 20.0f; children[i].Simplify(t); OctreeNode child = children[i]; if (child.type == OctreeNodeType.Internal) is_collapsible = false; else { //qef.Add(child.draw_info.position, child.draw_info.averageNormal); //if (child.draw_info.qef != null) qef.Add(ref child.draw_info.qef.data); mid_sign = (child.draw_info.corners >> (7 - i)) & 1; signs[i] = (child.draw_info.corners >> i) & 1; } } if (size == 16) { } if (!is_collapsible) return; //Vector3 pos = qef.Solve2(0, 0, 0); Vector3 pos = qef.Solve(1e-6f, 4, 1e-6f); float error = qef.GetError(); if (error > threshold) return; OctreeDrawInfo draw_info = new OctreeDrawInfo(); for (int i = 0; i < 8; i++) { if (signs[i] == -1) draw_info.corners |= mid_sign << i; else draw_info.corners |= signs[i] << i; } Vector3 normal = new Vector3(); for (int i = 0; i < 8; i++) { if (children[i] != null) { OctreeNode child = children[i]; if (child.type == OctreeNodeType.Pseudo || child.type == OctreeNodeType.Leaf) normal += child.draw_info.averageNormal; } } normal.Normalize(); draw_info.averageNormal = normal; draw_info.position = pos; draw_info.qef = qef; for (int i = 0; i < 8; i++) { children[i] = null; } type = OctreeNodeType.Pseudo; this.draw_info = draw_info; }
/* The following code is more or less a copy/paste cleanup of the C++ implementation * It's not clean, or efficient, but it works and is fairly straightforward */ public bool ConstructLeaf(List<VertexPositionColorNormal> vertices, int grid_size) { if (size != 1) return false; int corners = 0; float[, ,] samples = new float[2, 2, 2]; for (int i = 0; i < 8; i++) { if ((samples[i / 4, i % 4 / 2, i % 2] = Sampler.Sample(position + new Vector3(i / 4, i % 4 / 2, i % 2))) < 0) corners |= 1 << i; } if (corners == 0 || corners == 255) return false; //type = OctreeNodeType.Leaf; //return true; QEF3D qef = new QEF3D(); QEFProper.QEFSolver qefp = new QEFProper.QEFSolver(); Vector3 average_normal = Vector3.Zero; for (int i = 0; i < 12; i++) { int c1 = edgevmap[i, 0]; int c2 = edgevmap[i, 1]; int m1 = (corners >> c1) & 1; int m2 = (corners >> c2) & 1; if (m1 == m2) continue; float d1 = samples[c1 / 4, c1 % 4 / 2, c1 % 2]; float d2 = samples[c2 / 4, c2 % 4 / 2, c2 % 2]; Vector3 p1 = new Vector3((float)((c1 / 4)), (float)((c1 % 4 / 2)), (float)((c1 % 2))); Vector3 p2 = new Vector3((float)((c2 / 4)), (float)((c2 % 4 / 2)), (float)((c2 % 2))); Vector3 intersection = Sampler.GetIntersection(p1, p2, d1, d2) + position; Vector3 normal = Sampler.GetNormal(intersection);//GetNormal(x, y); average_normal += normal; qef.Add(intersection, normal); qefp.Add(intersection, normal); } Vector3 n = average_normal / (float)qef.Intersections.Count; n.Normalize(); draw_info = new OctreeDrawInfo(); //draw_info.position = position + qef.Solve2(0, 0, 0); draw_info.position = qefp.Solve(1e-6f, 4, 1e-6f); draw_info.corners = corners; draw_info.averageNormal = n; draw_info.qef = qefp; //vertices.Add(new VertexPositionColorNormal(position + draw_info.position, Color.LightGreen, n)); type = OctreeNodeType.Leaf; return true; }
private void Polygonize(int x, int y, int z) { if (Cells[x, y, z] == null) return; int cube_index = 0; for (int i = 0; i < 8; i++) { if (Sampler.Sample(new Vector3(x, y, z) + CornerDeltas[i]) < 0) cube_index |= 1 << i; } if (cube_index == 0 || cube_index == 255) return; Cells[x, y, z].Vertices = new Vertex[VerticesNumberTable[cube_index]]; /*for (int i = 0; i < 12; i++) { Cells[x, y, z].Edges[i].A = new Vector3(x, y, z) + CornerDeltas[EdgePairs[i, 0]]; Cells[x, y, z].Edges[i].B = new Vector3(x, y, z) + CornerDeltas[EdgePairs[i, 1]]; Cells[x, y, z].Edges[i].ValueA = Sampler.Sample(Cells[x, y, z].Edges[i].A); Cells[x, y, z].Edges[i].ValueB = Sampler.Sample(Cells[x, y, z].Edges[i].B); }*/ int v_index = 0; Cells[x, y, z].Vertices[0] = new Vertex(); for (int e = 0; e < EdgesTable.GetLength(1); e++) { if (EdgesTable[cube_index, e] == -2) break; if (EdgesTable[cube_index, e] == -1) { v_index++; if (v_index < Cells[x, y, z].Vertices.Length) Cells[x, y, z].Vertices[v_index] = new Vertex(); continue; } //Cells[x, y, z].Vertices[v_index].Index = v_index; Cells[x, y, z].Vertices[v_index].Edges.Add(EdgesTable[cube_index, e]); Cells[x, y, z].Edges[EdgesTable[cube_index, e]].Vertices.Add(Cells[x, y, z].Vertices[v_index]); //Cells[x, y, z].Edges[EdgesTable[cube_index, e]].Flipped = Cells[x, y, z].Edges[EdgesTable[cube_index, e]].ValueA < 0; } foreach (Vertex v in Cells[x, y, z].Vertices) { Vertex tx = v; if (v == null) //for edges 241/243, which were originally marked as having 2 vertices...? continue; Vector3 point = new Vector3(); if (VertexMode != VertexModes.Block) { //QEF3D qef = new QEF3D(); QEFProper.QEFSolver qef = new QEFProper.QEFSolver(); VertexPlacement qem = new VertexPlacement(); for (int e_i = 0; e_i < tx.Edges.Count; e_i++) { Edge e = Cells[x, y, z].Edges[tx.Edges[e_i]]; if (VertexMode == VertexModes.Edges) point += e.GetIntersection(); else if (VertexMode == VertexModes.QEF) qef.Add(e.GetIntersection() - new Vector3(x, y, z), Sampler.GetNormal(e.GetIntersection())); else qem.AddPlane(e.GetIntersection() - new Vector3(x, y, z), Sampler.GetNormal(e.GetIntersection())); } if (VertexMode == VertexModes.Edges) point /= (float)tx.Edges.Count; else if (VertexMode == VertexModes.QEF) point = qef.Solve(1e-6f, 4, 1e-6f) + new Vector3(x, y, z); else point = qem.Solve() + new Vector3(x, y, z); } else point = new Vector3(x, y, z) + Vector3.One * 0.5f; //point = Vector3.Clamp(point, new Vector3(x, y, z), new Vector3(x + 1, y + 1, z + 1)); tx.Position = point; Vector3 norm = Sampler.GetNormal(point); Vector3 c_v = norm * 0.5f + Vector3.One * 0.5f; c_v.Normalize(); Color clr = new Color(c_v); if (!UseFlatShading) { tx.Index = Vertices.Count; VertexPositionColorNormal pv = new VertexPositionColorNormal(tx.Position, clr, norm); Vertices.Add(pv); } else { tx.Index = CalculatedVertices.Count; VertexPositionColor pv = new VertexPositionColor(tx.Position, clr); CalculatedVertices.Add(pv); } VertexPositionColor[] vs = new VertexPositionColor[24]; Color c = Color.Red; float vx = tx.Position.X; float vy = tx.Position.Y; float vz = tx.Position.Z; float r = 0.25f; vs[0] = new VertexPositionColor(new Vector3((vx + 0), (vy + 0), (vz + 0)), c); vs[1] = new VertexPositionColor(new Vector3((vx + r), (vy + 0), (vz + 0)), c); vs[2] = new VertexPositionColor(new Vector3((vx + r), (vy + 0), (vz + 0)), c); vs[3] = new VertexPositionColor(new Vector3((vx + r), (vy + r), (vz + 0)), c); vs[4] = new VertexPositionColor(new Vector3((vx + r), (vy + r), (vz + 0)), c); vs[5] = new VertexPositionColor(new Vector3((vx + 0), (vy + r), (vz + 0)), c); vs[6] = new VertexPositionColor(new Vector3((vx + 0), (vy + r), (vz + 0)), c); vs[7] = new VertexPositionColor(new Vector3((vx + 0), (vy + 0), (vz + 0)), c); vs[8] = new VertexPositionColor(new Vector3((vx + 0), (vy + 0), (vz + r)), c); vs[9] = new VertexPositionColor(new Vector3((vx + r), (vy + 0), (vz + r)), c); vs[10] = new VertexPositionColor(new Vector3((vx + r), (vy + 0), (vz + r)), c); vs[11] = new VertexPositionColor(new Vector3((vx + r), (vy + r), (vz + r)), c); vs[12] = new VertexPositionColor(new Vector3((vx + r), (vy + r), (vz + r)), c); vs[13] = new VertexPositionColor(new Vector3((vx + 0), (vy + r), (vz + r)), c); vs[14] = new VertexPositionColor(new Vector3((vx + 0), (vy + r), (vz + r)), c); vs[15] = new VertexPositionColor(new Vector3((vx + 0), (vy + 0), (vz + r)), c); vs[16] = new VertexPositionColor(new Vector3((vx + 0), (vy + 0), (vz + 0)), c); vs[17] = new VertexPositionColor(new Vector3((vx + 0), (vy + 0), (vz + r)), c); vs[18] = new VertexPositionColor(new Vector3((vx + 0), (vy + r), (vz + 0)), c); vs[19] = new VertexPositionColor(new Vector3((vx + 0), (vy + r), (vz + r)), c); vs[20] = new VertexPositionColor(new Vector3((vx + r), (vy + 0), (vz + 0)), c); vs[21] = new VertexPositionColor(new Vector3((vx + r), (vy + 0), (vz + r)), c); vs[22] = new VertexPositionColor(new Vector3((vx + r), (vy + r), (vz + 0)), c); vs[23] = new VertexPositionColor(new Vector3((vx + r), (vy + r), (vz + r)), c); OutlineBuffer.SetData<VertexPositionColor>(OutlineLocation * VertexPositionColor.VertexDeclaration.VertexStride, vs, 0, 24, VertexPositionColor.VertexDeclaration.VertexStride); OutlineLocation += 24; } }
/* * 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) { } }