public ObiTriangleMeshHandle GetOrCreateTriangleMesh(Mesh source) { ObiTriangleMeshHandle handle = new ObiTriangleMeshHandle(null); if (source != null && !handles.TryGetValue(source, out handle)) { var sourceTris = source.triangles; var sourceVertices = source.vertices; // Build a bounding interval hierarchy from the triangles: IBounded[] t = new IBounded[sourceTris.Length / 3]; for (int i = 0; i < t.Length; ++i) { int t1 = sourceTris[i * 3]; int t2 = sourceTris[i * 3 + 1]; int t3 = sourceTris[i * 3 + 2]; t[i] = new Triangle(t1, t2, t3, sourceVertices[t1], sourceVertices[t2], sourceVertices[t3]); } var sourceBih = BIH.Build(ref t); Triangle[] tris = Array.ConvertAll(t, x => (Triangle)x); handle = new ObiTriangleMeshHandle(source, headers.count); handles.Add(source, handle); headers.Add(new TriangleMeshHeader(bihNodes.count, sourceBih.Length, triangles.count, tris.Length, vertices.count, sourceVertices.Length)); bihNodes.AddRange(sourceBih); triangles.AddRange(tris); vertices.AddRange(sourceVertices); } return(handle); }
public ObiEdgeMeshHandle GetOrCreateEdgeMesh(EdgeCollider2D source) { ObiEdgeMeshHandle handle; if (!handles.TryGetValue(source, out handle)) { Vector2[] sourceVertices = source.points; int[] sourceEdges = new int[source.edgeCount * 2]; for (int i = 0; i < source.edgeCount; ++i) { sourceEdges[i * 2] = i; sourceEdges[i * 2 + 1] = i + 1; } // Build a bounding interval hierarchy from the edges: IBounded[] t = new IBounded[source.edgeCount]; for (int i = 0; i < source.edgeCount; ++i) { t[i] = new Edge(i, i + 1, sourceVertices[i], sourceVertices[i + 1]); } var sourceBih = BIH.Build(ref t); Edge[] edgs = Array.ConvertAll(t, x => (Edge)x); handle = new ObiEdgeMeshHandle(source, headers.count); handles.Add(source, handle); headers.Add(new EdgeMeshHeader(bihNodes.count, sourceBih.Length, edges.count, edgs.Length, vertices.count, sourceVertices.Length)); bihNodes.AddRange(sourceBih); edges.AddRange(edgs); vertices.AddRange(sourceVertices); } return(handle); }
public static IEnumerator Build(float maxError, int maxDepth, Vector3[] vertexPositions, int[] triangleIndices, List <DFNode> nodes) { // Empty vertex or triangle lists, return. if (maxDepth <= 0 || nodes == null || vertexPositions == null || vertexPositions.Length == 0 || triangleIndices == null || triangleIndices.Length == 0) { yield break; } // Build a bounding interval hierarchy from the triangles, to speed up distance queries: IBounded[] t = new IBounded[triangleIndices.Length / 3]; for (int i = 0; i < t.Length; ++i) { int t1 = triangleIndices[i * 3]; int t2 = triangleIndices[i * 3 + 1]; int t3 = triangleIndices[i * 3 + 2]; t[i] = new Triangle(t1, t2, t3, vertexPositions[t1], vertexPositions[t2], vertexPositions[t3]); } var bih = BIH.Build(ref t); // Copy reordered triangles over to a new array: Triangle[] tris = Array.ConvertAll(t, x => (Triangle)x); // Build angle weighted normals, used to determine the sign of the distance field. Vector3[] angleNormals = ObiUtils.CalculateAngleWeightedNormals(vertexPositions, triangleIndices); // Calculate bounding box of the mesh: Bounds bounds = new Bounds(vertexPositions[0], Vector3.zero); for (int i = 1; i < vertexPositions.Length; ++i) { bounds.Encapsulate(vertexPositions[i]); } bounds.Expand(0.1f); // Auxiliar variables to keep track of current tree depth: int depth = 0; int nodesToNextLevel = 1; // Initialize node list: Vector4 center = bounds.center; Vector3 boundsExtents = bounds.extents; center[3] = Mathf.Max(boundsExtents[0], Math.Max(boundsExtents[1], boundsExtents[2])); nodes.Clear(); nodes.Add(new DFNode(center)); var queue = new Queue <int>(); queue.Enqueue(0); while (queue.Count > 0) { // get current node: int index = queue.Dequeue(); var node = nodes[index]; // measure distance at the 8 node corners: for (int i = 0; i < 8; ++i) { Vector4 point = node.center + corners[i] * node.center[3]; point[3] = 0; float distance = BIH.DistanceToSurface(bih, tris, vertexPositions, angleNormals, point); if (i < 4) { node.distancesA[i] = distance; } else { node.distancesB[i - 4] = distance; } } // only subdivide those nodes intersecting the surface: if (depth < maxDepth && Mathf.Abs(BIH.DistanceToSurface(bih, tris, vertexPositions, angleNormals, node.center)) < node.center[3] * sqrt3) { // calculate mean squared error between measured distances and interpolated ones: float mse = 0; for (int i = 0; i < samples.Length; ++i) { Vector4 point = node.center + samples[i] * node.center[3]; float d = BIH.DistanceToSurface(bih, tris, vertexPositions, angleNormals, point) - node.Sample(point); mse += d * d; } mse /= (float)samples.Length; // if error > threshold, subdivide the node: if (mse > maxError) { node.firstChild = nodes.Count; for (int i = 0; i < 8; ++i) { queue.Enqueue(nodes.Count); nodes.Add(new DFNode(node.center + corners[i] * node.center[3] * 0.5f)); } } // keep track of current depth: if (--nodesToNextLevel == 0) { depth++; nodesToNextLevel = queue.Count; } } // feed the modified node back: nodes[index] = node; yield return(0); } }