Example #1
0
        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);
        }
Example #2
0
        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);
        }
Example #3
0
        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);
            }
        }