Beispiel #1
0
    public void Execute()
    {
        // Add points to the builder
        ConvexHullBuilder builder = Builder[0];

        for (int i = 0; i < Points.Length; i++)
        {
            builder.AddPoint(Points[i]);
        }
        builder.BuildFaceIndices();

        // Write back the builder
        Builder[0] = builder;
    }
        // followed by variable sized convex hull data

        #region Construction

        // Create a convex collider from the given point cloud.
        public static unsafe BlobAssetReference <Collider> Create(
            NativeArray <float3> points, float convexRadius,
            float3?scale = null, CollisionFilter?filter = null, Material?material = null)
        {
            if (convexRadius < 0.0f || !math.isfinite(convexRadius))
            {
                throw new ArgumentException("Tried to create ConvexCollider with invalid convex radius");
            }

            // Build convex hull
            int    verticesCapacity = points.Length;
            int    triangleCapacity = 2 * verticesCapacity;
            var    vertices         = (ConvexHullBuilder.Vertex *)UnsafeUtility.Malloc(verticesCapacity * sizeof(ConvexHullBuilder.Vertex), 16, Allocator.Temp);
            var    triangles        = (ConvexHullBuilder.Triangle *)UnsafeUtility.Malloc(triangleCapacity * sizeof(ConvexHullBuilder.Triangle), 16, Allocator.Temp);
            var    builder          = new ConvexHullBuilder(vertices, verticesCapacity, triangles, triangleCapacity);
            float3 s = scale ?? new float3(1);

            // Build the points' AABB and validate them
            var domain = new Aabb();

            foreach (var point in points)
            {
                if (math.any(!math.isfinite(point)))
                {
                    throw new ArgumentException("Tried to create ConvexCollider with invalid points");
                }
                domain.Include(point * s);
            }

            // Add points to the hull
            builder.IntegerSpaceAabb = domain;
            foreach (float3 point in points)
            {
                builder.AddPoint(point * s);
            }

            // TODO: shrink by convex radius

            // Build face information
            float maxAngle = 0.1f * (float)math.PI / 180.0f;

            builder.BuildFaceIndices(maxAngle);

            // Simplify the hull until it's under the max vertices requirement
            // TODO.ma this is just a failsafe. We need to think about user-controlled simplification settings & how to warn the user if their shape is too complex.
            {
                const int maxVertices = 252;    // as per Havok

                float maxSimplificationError = 1e-3f;
                int   iterations             = 0;
                while (builder.Vertices.PeakCount > maxVertices)
                {
                    if (iterations++ > 10) // don't loop forever
                    {
                        Assert.IsTrue(false);
                        return(new BlobAssetReference <Collider>());
                    }
                    builder.SimplifyVertices(maxSimplificationError);
                    builder.BuildFaceIndices();
                    maxSimplificationError *= 2.0f;
                }
            }

            // Convert hull to compact format
            var tempHull = new TempHull(ref builder);

            // Allocate collider
            int totalSize = UnsafeUtility.SizeOf <ConvexCollider>();

            totalSize += tempHull.Vertices.Count * sizeof(float3);
            totalSize  = Math.NextMultipleOf16(totalSize); // planes currently must be aligned for Havok
            totalSize += tempHull.Planes.Count * sizeof(Plane);
            totalSize += tempHull.Faces.Count * sizeof(ConvexHull.Face);
            totalSize += tempHull.FaceVertexIndices.Count * sizeof(short);
            totalSize += tempHull.VertexEdges.Count * sizeof(ConvexHull.Edge);
            totalSize += tempHull.FaceLinks.Count * sizeof(ConvexHull.Edge);
            ConvexCollider *collider = (ConvexCollider *)UnsafeUtility.Malloc(totalSize, 16, Allocator.Temp);

            // Initialize it
            {
                UnsafeUtility.MemClear(collider, totalSize);
                collider->MemorySize = totalSize;

                collider->m_Header.Type          = ColliderType.Convex;
                collider->m_Header.CollisionType = CollisionType.Convex;
                collider->m_Header.Version       = 0;
                collider->m_Header.Magic         = 0xff;
                collider->m_Header.Filter        = filter ?? CollisionFilter.Default;
                collider->m_Header.Material      = material ?? Material.Default;

                ref var hull = ref collider->ConvexHull;

                hull.ConvexRadius = convexRadius;

                // Initialize blob arrays
                {
                    byte *end = (byte *)collider + UnsafeUtility.SizeOf <ConvexCollider>();

                    hull.VerticesBlob.Offset = (int)(end - (byte *)UnsafeUtility.AddressOf(ref hull.VerticesBlob.Offset));
                    hull.VerticesBlob.Length = tempHull.Vertices.Count;
                    end += sizeof(float3) * tempHull.Vertices.Count;

                    end = (byte *)Math.NextMultipleOf16((ulong)end); // planes currently must be aligned for Havok

                    hull.FacePlanesBlob.Offset = (int)(end - (byte *)UnsafeUtility.AddressOf(ref hull.FacePlanesBlob.Offset));
                    hull.FacePlanesBlob.Length = tempHull.Planes.Count;
                    end += sizeof(Plane) * tempHull.Planes.Count;

                    hull.FacesBlob.Offset = (int)(end - (byte *)UnsafeUtility.AddressOf(ref hull.FacesBlob.Offset));
                    hull.FacesBlob.Length = tempHull.Faces.Count;
                    end += sizeof(ConvexHull.Face) * tempHull.Faces.Count;

                    hull.FaceVertexIndicesBlob.Offset = (int)(end - (byte *)UnsafeUtility.AddressOf(ref hull.FaceVertexIndicesBlob.Offset));
                    hull.FaceVertexIndicesBlob.Length = tempHull.FaceVertexIndices.Count;
                    end += sizeof(byte) * tempHull.FaceVertexIndices.Count;

                    hull.VertexEdgesBlob.Offset = (int)(end - (byte *)UnsafeUtility.AddressOf(ref hull.VertexEdgesBlob.Offset));
                    hull.VertexEdgesBlob.Length = tempHull.VertexEdges.Count;
                    end += sizeof(ConvexHull.Edge) * tempHull.VertexEdges.Count;

                    hull.FaceLinksBlob.Offset = (int)(end - (byte *)UnsafeUtility.AddressOf(ref hull.FaceLinksBlob.Offset));
                    hull.FaceLinksBlob.Length = tempHull.FaceLinks.Count;
                    end += sizeof(ConvexHull.Edge) * tempHull.FaceLinks.Count;
                }

                // Fill blob arrays
                {
                    for (int i = 0; i < tempHull.Vertices.Count; i++)
                    {
                        hull.Vertices[i]    = tempHull.Vertices[i];
                        hull.VertexEdges[i] = tempHull.VertexEdges[i];
                    }

                    for (int i = 0; i < tempHull.Faces.Count; i++)
                    {
                        hull.Planes[i] = tempHull.Planes[i];
                        hull.Faces[i]  = tempHull.Faces[i];
                    }

                    for (int i = 0; i < tempHull.FaceVertexIndices.Count; i++)
                    {
                        hull.FaceVertexIndices[i] = tempHull.FaceVertexIndices[i];
                        hull.FaceLinks[i]         = tempHull.FaceLinks[i];
                    }
                }

                // Fill mass properties
                {
                    var massProperties = builder.ComputeMassProperties();
                    Math.DiagonalizeSymmetricApproximation(massProperties.InertiaTensor, out float3x3 orientation, out float3 inertia);

                    float maxLengthSquared = 0.0f;
                    foreach (float3 vertex in hull.Vertices)
                    {
                        maxLengthSquared = math.max(maxLengthSquared, math.lengthsq(vertex - massProperties.CenterOfMass));
                    }

                    collider->MassProperties = new MassProperties
                    {
                        MassDistribution = new MassDistribution
                        {
                            Transform     = new RigidTransform(orientation, massProperties.CenterOfMass),
                            InertiaTensor = inertia
                        },
                        Volume = massProperties.Volume,
                        AngularExpansionFactor = math.sqrt(maxLengthSquared)
                    };
                }
            }
        private void UpdateMeshNow()
        {
            MassProperties = Hull.ComputeMassProperties();

            Hull.CompactVertices();
            Hull.BuildFaceIndices((float)(MaxFaceAngle * System.Math.PI / 180));

            {
                HullData.Faces        = new Face[Hull.NumFaces];
                HullData.FaceVertices = new int[Hull.NumFaceVertices];
                int nextVertex = 0;
                for (var faceEdge = Hull.GetFirstFace(); faceEdge.IsValid; faceEdge = Hull.GetNextFace(faceEdge))
                {
                    var  triangleIndex = ((ConvexHullBuilder.Edge)faceEdge).TriangleIndex;
                    Face newFace       = new Face
                    {
                        Plane       = Hull.ComputePlane(triangleIndex),
                        FirstVertex = nextVertex,
                        NumVertices = 0
                    };
                    for (var edge = faceEdge; edge.IsValid; edge = Hull.GetNextFaceEdge(edge))
                    {
                        HullData.FaceVertices[nextVertex++] = Hull.StartVertex(edge);
                    }
                    newFace.NumVertices = nextVertex - newFace.FirstVertex;
                    HullData.Faces[Hull.Triangles[triangleIndex].FaceIndex] = newFace;
                }

                var indices = new List <int>();
                var set     = new List <int>();
                HullData.VertexFaces = new VertexFaces[Hull.Vertices.PeakCount];
                for (int i = 0; i < Hull.Vertices.PeakCount; ++i)
                {
                    var cardinality = Hull.Vertices[i].Cardinality;
                    var edge        = Hull.GetVertexEdge(i);
                    for (int j = Hull.Vertices[i].Cardinality; j > 0; --j)
                    {
                        int faceIndex = Hull.Triangles[edge.TriangleIndex].FaceIndex;
                        if (set.IndexOf(faceIndex) == -1)
                        {
                            set.Add(faceIndex);
                        }
                        edge = Hull.GetLinkedEdge(edge).Next;
                    }
                    set.Sort();
                    HullData.VertexFaces[i] = new VertexFaces {
                        FirstFace = indices.Count, NumFaces = set.Count
                    };
                    indices.AddRange(set);
                    set.Clear();
                }
                HullData.FaceIndices = indices.ToArray();
            }

            Vector3[] vertices  = null;
            int[]     triangles = null;
            switch (Hull.Dimension)
            {
            case 2:
                vertices  = new Vector3[Hull.Vertices.PeakCount];
                triangles = new int[(Hull.Vertices.PeakCount - 2) * 2 * 3];
                for (int i = 0; i < Hull.Vertices.PeakCount; ++i)
                {
                    vertices[i] = Hull.Vertices[i].Position;
                }
                for (int i = 2; i < Hull.Vertices.PeakCount; ++i)
                {
                    int j = (i - 2) * 6;
                    triangles[j + 0] = 0; triangles[j + 1] = i - 1; triangles[j + 2] = i;
                    triangles[j + 3] = 0; triangles[j + 4] = i; triangles[j + 5] = i - 1;
                }
                break;

            case 3:
                vertices  = new Vector3[Hull.Triangles.PeakCount * 3];
                triangles = new int[Hull.Triangles.PeakCount * 3];
                for (int i = 0; i < Hull.Triangles.PeakCount; ++i)
                {
                    if (Hull.Triangles[i].IsAllocated)
                    {
                        vertices[i * 3 + 0]  = Hull.Vertices[Hull.Triangles[i].Vertex0].Position;
                        vertices[i * 3 + 1]  = Hull.Vertices[Hull.Triangles[i].Vertex1].Position;
                        vertices[i * 3 + 2]  = Hull.Vertices[Hull.Triangles[i].Vertex2].Position;
                        triangles[i * 3 + 0] = i * 3 + 0;
                        triangles[i * 3 + 1] = i * 3 + 1;
                        triangles[i * 3 + 2] = i * 3 + 2;
                    }
                    else
                    {
                        triangles[i * 3 + 0] = 0;
                        triangles[i * 3 + 1] = 0;
                        triangles[i * 3 + 2] = 0;
                    }
                }
                break;
            }

            var mesh = GetComponent <MeshFilter>().sharedMesh;

            mesh.Clear();
            mesh.vertices  = vertices;
            mesh.triangles = triangles;
            mesh.RecalculateBounds();
            mesh.RecalculateNormals();
            mesh.RecalculateTangents();
        }