Example #1
0
        public void TestCalculateAabbTransformedQuad()
        {
            float3[] vertices =
            {
                new float3(-4.5f, 0.0f, 1.0f),
                new float3(3.4f,  0.7f, 1.0f),
                new float3(3.4f,  2.7f, 1.0f),
                new float3(-3.4f, 1.2f, 1.0f)
            };

            float3     translation = new float3(-3.4f, -2.5f, -1.1f);
            quaternion rotation    = quaternion.AxisAngle(math.normalize(new float3(11.1f, 10.1f, -3.4f)), 178.0f);

            var  collider = PolygonCollider.CreateQuad(vertices[0], vertices[1], vertices[2], vertices[3]);
            Aabb aabb     = collider.Value.CalculateAabb(new RigidTransform(rotation, translation));

            for (int i = 0; i < 4; ++i)
            {
                vertices[i] = translation + math.mul(rotation, vertices[i]);
            }

            Aabb expected = Aabb.CreateFromPoints(new float3x4(vertices[0], vertices[1], vertices[2], vertices[3]));

            TestUtils.AreEqual(expected.Min, aabb.Min, 1e-3f);
            TestUtils.AreEqual(expected.Max, aabb.Max, 1e-3f);
        }
Example #2
0
        unsafe public void TestCreateQuad()
        {
            float3[] vertices =
            {
                new float3(-4.5f, 0.0f, 1.0f),
                new float3(3.4f,  0.7f, 1.0f),
                new float3(3.4f,  2.7f, 1.0f),
                new float3(-3.4f, 1.2f, 1.0f)
            };
            float3 normal = math.normalize(math.cross(vertices[2] - vertices[1], vertices[0] - vertices[1]));

            var collider     = PolygonCollider.CreateQuad(vertices[0], vertices[1], vertices[2], vertices[3]);
            var quadCollider = UnsafeUtility.AsRef <PolygonCollider>(collider.GetUnsafePtr());

            Assert.IsFalse(quadCollider.IsTriangle);
            Assert.IsTrue(quadCollider.IsQuad);

            TestUtils.AreEqual(quadCollider.Vertices[0], vertices[0], 1e-3f);
            TestUtils.AreEqual(quadCollider.Vertices[1], vertices[1], 1e-3f);
            TestUtils.AreEqual(quadCollider.Vertices[2], vertices[2], 1e-3f);
            TestUtils.AreEqual(quadCollider.Vertices[3], vertices[3], 1e-3f);
            Assert.AreEqual(2, quadCollider.Planes.Length);
            TestUtils.AreEqual(normal, quadCollider.Planes[0].Normal, 1e-3f);
            TestUtils.AreEqual(-normal, quadCollider.Planes[1].Normal, 1e-3f);
            Assert.AreEqual(ColliderType.Quad, quadCollider.Type);
            Assert.AreEqual(CollisionType.Convex, quadCollider.CollisionType);
        }
            public void Execute(int i)
            {
                var shapeData = ComputeData[ToComputeTable[i]];

                switch (shapeData.ShapeType)
                {
                case ShapeType.Box:
                {
                    BlobAssets[i] = BoxCollider.Create(
                        shapeData.BoxProperties, shapeData.CollisionFilter, shapeData.Material
                        );
                    return;
                }

                case ShapeType.Capsule:
                {
                    BlobAssets[i] = CapsuleCollider.Create(
                        shapeData.CapsuleProperties, shapeData.CollisionFilter, shapeData.Material
                        );
                    return;
                }

                case ShapeType.Cylinder:
                {
                    BlobAssets[i] = CylinderCollider.Create(
                        shapeData.CylinderProperties, shapeData.CollisionFilter, shapeData.Material
                        );
                    return;
                }

                case ShapeType.Plane:
                {
                    var v = shapeData.PlaneVertices;
                    BlobAssets[i] = PolygonCollider.CreateQuad(
                        v.c0, v.c1, v.c2, v.c3, shapeData.CollisionFilter, shapeData.Material
                        );
                    return;
                }

                case ShapeType.Sphere:
                {
                    BlobAssets[i] = SphereCollider.Create(
                        shapeData.SphereProperties, shapeData.CollisionFilter, shapeData.Material
                        );
                    return;
                }

                // Note : Mesh and Hull are not computed here as they are in a separated set of jobs
                default:
                    return;
                }
            }
Example #4
0
        public void TestCalculateAabbLocalQuad()
        {
            float3[] quadVertices =
            {
                new float3(-4.5f, 0.0f, 1.0f),
                new float3(3.4f,  0.7f, 1.0f),
                new float3(3.4f,  2.7f, 1.0f),
                new float3(-3.4f, 1.2f, 1.0f)
            };
            var  collider = PolygonCollider.CreateQuad(quadVertices[0], quadVertices[1], quadVertices[2], quadVertices[3]);
            Aabb aabb     = collider.Value.CalculateAabb();
            Aabb expected = Aabb.CreateFromPoints(new float3x4(quadVertices[0], quadVertices[1], quadVertices[2], quadVertices[3]));

            TestUtils.AreEqual(expected.Min, aabb.Min, 1e-3f);
            TestUtils.AreEqual(expected.Max, aabb.Max, 1e-3f);
        }
Example #5
0
        //[Test] // #TODO: Add test back in once we have implemented this in Physics
        public void TestMassPropertiesQuad()
        {
            float3[] vertices =
            {
                new float3(-1.1f, -0.4f, 0.0f),
                new float3(0.8f,  -0.1f, 0.0f),
                new float3(1.2f,   1.3f, 0.0f),
                new float3(-0.2f,  1.3f, 0.0f)
            };

            var collider = PolygonCollider.CreateQuad(vertices[0], vertices[1], vertices[2], vertices[3]);

            float3 inertiaTensor         = collider.Value.MassProperties.MassDistribution.InertiaTensor;
            float3 expectedInertiaTensor = calcQuadInertiaTensor(vertices[0], vertices[1], vertices[2], vertices[3]);

            TestUtils.AreEqual(expectedInertiaTensor, inertiaTensor, 1e-3f);
        }
Example #6
0
        public static unsafe BlobAssetReference <Collider> GenerateRandomConvex(ref Random rnd)
        {
            ColliderType colliderType = (ColliderType)rnd.NextInt((int)ColliderType.Box);
            float        radius       = (rnd.NextInt(4) > 0) ? rnd.NextFloat(0.5f) : 0.0f;

            switch (colliderType)
            {
            case ColliderType.Convex:
            {
                int numPoints = rnd.NextInt(1, 16);
                if (numPoints == 3)     // TODO - hull builder doesn't build faces for flat shapes, work around it for now to run the test
                {
                    numPoints++;
                }
                var points = new NativeArray <float3>(numPoints, Allocator.Temp);
                for (int i = 0; i < numPoints; i++)
                {
                    points[i] = rnd.NextFloat3(-1.0f, 1.0f);
                }
                var collider = ConvexCollider.Create(points, radius);
                points.Dispose();
                return(collider);
            }

            case ColliderType.Sphere:
            {
                float3 center = (rnd.NextInt(4) > 0) ? float3.zero : rnd.NextFloat3(-0.5f, 0.5f);
                return(SphereCollider.Create(center, rnd.NextFloat(0.01f, 0.5f)));
            }

            case ColliderType.Capsule:
            {
                float3 point0 = rnd.NextFloat3(0.0f, 1.0f);
                float3 point1 = (rnd.NextInt(4) > 0) ? -point0 : rnd.NextFloat3(-1.0f, 1.0f);
                return(CapsuleCollider.Create(point0, point1, rnd.NextFloat(0.01f, 0.5f)));
            }

            case ColliderType.Triangle:
            {
                return(PolygonCollider.CreateTriangle(rnd.NextFloat3(-1.0f, 1.0f), rnd.NextFloat3(-1.0f, 1.0f), rnd.NextFloat3(-1.0f, 1.0f)));
            }

            case ColliderType.Quad:
            {
                // Pick 3 totally random points, then choose a fourth that makes a flat and convex quad
                float3 point0 = rnd.NextFloat3(-1.0f, 1.0f);
                float3 point1 = rnd.NextFloat3(-1.0f, 1.0f);
                float3 point3 = rnd.NextFloat3(-1.0f, 1.0f);
                float  t0     = rnd.NextFloat(0.0f, 1.0f);
                float  t1     = rnd.NextFloat(0.0f, 1.0f);
                float3 e      = point1 + point1 - point0;
                float3 a      = math.lerp(point1, e, t0);
                float3 b      = math.lerp(point3, point3 + point3 - point0, t0);
                float3 point2 = math.lerp(a, b, t1);

                return(PolygonCollider.CreateQuad(point0, point1, point2, point3));
            }

            case ColliderType.Box:
            {
                float3     center      = (rnd.NextInt(4) > 0) ? float3.zero : rnd.NextFloat3(-0.5f, 0.5f);
                quaternion orientation = (rnd.NextInt(4) > 0) ? quaternion.identity : rnd.NextQuaternionRotation();
                return(BoxCollider.Create(center, orientation, rnd.NextFloat3(0.01f, 1.0f), radius));
            }

            default: throw new System.NotImplementedException();
            }
        }
        protected override BlobAssetReference <Collider> ProduceColliderBlob(PhysicsShape shape)
        {
            var material        = ProduceMaterial(shape);
            var collisionFilter = ProduceCollisionFilter(shape);

            var blob = new BlobAssetReference <Collider>();

            shape.GetBakeTransformation(out var linearScalar, out var radiusScalar);
            switch (shape.ShapeType)
            {
            case ShapeType.Box:
                shape.GetBoxProperties(out var center, out var size, out quaternion orientation);
                blob = BoxCollider.Create(
                    center * linearScalar,
                    orientation,
                    math.abs(size * linearScalar),
                    shape.ConvexRadius * radiusScalar,
                    collisionFilter,
                    material);
                break;

            case ShapeType.Capsule:
                shape.GetCapsuleProperties(out var v0, out var v1, out var radius);
                blob = CapsuleCollider.Create(
                    v0 * linearScalar,
                    v1 * linearScalar,
                    radius * radiusScalar,
                    collisionFilter,
                    material);
                break;

            case ShapeType.Sphere:
                shape.GetSphereProperties(out center, out radius, out orientation);
                blob = SphereCollider.Create(
                    center * linearScalar,
                    radius * radiusScalar,
                    collisionFilter,
                    material);
                break;

            case ShapeType.Cylinder:
                shape.GetCylinderProperties(out center, out var height, out radius, out orientation);
                var s = math.abs(math.mul(math.inverse(orientation), linearScalar));
                blob = CylinderCollider.Create(
                    center * linearScalar,
                    height * s.z,
                    radius * math.cmax(s.xy),
                    orientation,
                    shape.ConvexRadius * radiusScalar,
                    collisionFilter,
                    material);
                break;

            case ShapeType.Plane:
                shape.GetPlaneProperties(out v0, out v1, out var v2, out var v3);
                blob = PolygonCollider.CreateQuad(
                    v0 * linearScalar,
                    v1 * linearScalar,
                    v2 * linearScalar,
                    v3 * linearScalar,
                    collisionFilter,
                    material);
                break;

            case ShapeType.ConvexHull:
                var pointCloud = new NativeList <float3>(65535, Allocator.Temp);
                shape.GetConvexHullProperties(pointCloud);
                if (pointCloud.Length == 0)
                {
                    pointCloud.Dispose();
                    throw new InvalidOperationException(
                              $"No vertices associated with {shape.name}. Add a {typeof(MeshFilter)} component or assign {nameof(PhysicsShape.CustomMesh)}."
                              );
                }
                blob = ConvexCollider.Create(
                    pointCloud,
                    shape.ConvexRadius * radiusScalar,
                    linearScalar,
                    collisionFilter,
                    material);
                pointCloud.Dispose();
                break;

            case ShapeType.Mesh:
                // TODO: no convex radius?
                var mesh = shape.GetMesh();
                if (mesh == null)
                {
                    throw new InvalidOperationException(
                              $"No mesh associated with {shape.name}. Add a {typeof(MeshFilter)} component or assign {nameof(PhysicsShape.CustomMesh)}."
                              );
                }
                else
                {
                    blob = MeshCollider.Create(mesh.GetScaledVertices(linearScalar), mesh.triangles, collisionFilter, material);
                }
                break;

            default:
                throw new UnimplementedShapeException(shape.ShapeType);
            }
            return(blob);
        }
        private BlobAssetReference <Collider> CreateCollider(UnityEngine.Mesh mesh, ColliderType type)
        {
            switch (type)
            {
            case ColliderType.Sphere:
            {
                Bounds bounds = mesh.bounds;
                return(SphereCollider.Create(bounds.center, math.cmax(bounds.extents)));
            }

            case ColliderType.Triangle:
            {
                return(PolygonCollider.CreateTriangle(mesh.vertices[0], mesh.vertices[1], mesh.vertices[2]));
            }

            case ColliderType.Quad:
            {
                // We assume the first 2 triangles of the mesh are a quad with a shared edge
                // Work out a correct ordering for the triangle
                int[] orderedIndices = new int[4];

                // Find the vertex in first triangle that is not on the shared edge
                for (int i = 0; i < 3; i++)
                {
                    if ((mesh.triangles[i] != mesh.triangles[3]) &&
                        (mesh.triangles[i] != mesh.triangles[4]) &&
                        (mesh.triangles[i] != mesh.triangles[5]))
                    {
                        // Push in order or prev, unique, next
                        orderedIndices[0] = mesh.triangles[(i - 1 + 3) % 3];
                        orderedIndices[1] = mesh.triangles[i];
                        orderedIndices[2] = mesh.triangles[(i + 1) % 3];
                        break;
                    }
                }

                // Find the vertex in second triangle that is not on a shared edge
                for (int i = 3; i < 6; i++)
                {
                    if ((mesh.triangles[i] != orderedIndices[0]) &&
                        (mesh.triangles[i] != orderedIndices[1]) &&
                        (mesh.triangles[i] != orderedIndices[2]))
                    {
                        orderedIndices[3] = mesh.triangles[i];
                        break;
                    }
                }

                return(PolygonCollider.CreateQuad(
                           mesh.vertices[orderedIndices[0]],
                           mesh.vertices[orderedIndices[1]],
                           mesh.vertices[orderedIndices[2]],
                           mesh.vertices[orderedIndices[3]]));
            }

            case ColliderType.Box:
            {
                Bounds bounds = mesh.bounds;
                return(BoxCollider.Create(bounds.center, quaternion.identity, 2.0f * bounds.extents, 0.0f));
            }

            case ColliderType.Capsule:
            {
                Bounds bounds  = mesh.bounds;
                float  min     = math.cmin(bounds.extents);
                float  max     = math.cmax(bounds.extents);
                int    x       = math.select(math.select(2, 1, min == bounds.extents.y), 0, min == bounds.extents.x);
                int    z       = math.select(math.select(2, 1, max == bounds.extents.y), 0, max == bounds.extents.x);
                int    y       = math.select(math.select(2, 1, (1 != x) && (1 != z)), 0, (0 != x) && (0 != z));
                float  radius  = bounds.extents[y];
                float3 vertex0 = bounds.center; vertex0[z] = -(max - radius);
                float3 vertex1 = bounds.center; vertex1[z] = (max - radius);
                return(CapsuleCollider.Create(vertex0, vertex1, radius));
            }

            case ColliderType.Cylinder:
                // TODO: need someone to add
                throw new NotImplementedException();

            case ColliderType.Convex:
            {
                NativeArray <float3> points = new NativeArray <float3>(mesh.vertices.Length, Allocator.Temp);
                for (int i = 0; i < mesh.vertices.Length; i++)
                {
                    points[i] = mesh.vertices[i];
                }
                return(ConvexCollider.Create(points, 0.0f));
            }

            default:
                throw new System.NotImplementedException();
            }
        }
Example #9
0
        public static unsafe BlobAssetReference <Collider> GenerateRandomConvex(ref Random rnd)
        {
            ColliderType colliderType = (ColliderType)rnd.NextInt((int)ColliderType.Cylinder + 1);
            float        convexRadius = (rnd.NextInt(4) > 0) ? rnd.NextFloat(0.5f) : 0.0f;

            switch (colliderType)
            {
            case ColliderType.Convex:
            {
                int numPoints = rnd.NextInt(1, 16);
                if (numPoints == 3)     // TODO - hull builder doesn't build faces for flat shapes, work around it for now to run the test
                {
                    numPoints++;
                }
                var points = new NativeArray <float3>(numPoints, Allocator.TempJob);
                for (int i = 0; i < numPoints; i++)
                {
                    points[i] = rnd.NextFloat3(-1.0f, 1.0f);
                }
                var generationParameters = ConvexHullGenerationParameters.Default;
                generationParameters.BevelRadius = convexRadius;
                var collider = ConvexCollider.Create(points, generationParameters, CollisionFilter.Default);
                points.Dispose();
                return(collider);
            }

            case ColliderType.Sphere:
            {
                return(SphereCollider.Create(new SphereGeometry
                    {
                        Center = (rnd.NextInt(4) > 0) ? float3.zero : rnd.NextFloat3(-0.5f, 0.5f),
                        Radius = rnd.NextFloat(0.01f, 0.5f)
                    }));
            }

            case ColliderType.Capsule:
            {
                float3 point0 = rnd.NextFloat3(0.0f, 1.0f);
                float3 point1 = (rnd.NextInt(4) > 0) ? -point0 : rnd.NextFloat3(-1.0f, 1.0f);
                return(CapsuleCollider.Create(new CapsuleGeometry
                    {
                        Vertex0 = point0,
                        Vertex1 = point1,
                        Radius = rnd.NextFloat(0.01f, 0.5f)
                    }));
            }

            case ColliderType.Triangle:
            {
                return(PolygonCollider.CreateTriangle(rnd.NextFloat3(-1.0f, 1.0f), rnd.NextFloat3(-1.0f, 1.0f), rnd.NextFloat3(-1.0f, 1.0f)));
            }

            case ColliderType.Quad:
            {
                // Pick 3 totally random points, then choose a fourth that makes a flat and convex quad
                float3 point0 = rnd.NextFloat3(-1.0f, 1.0f);
                float3 point1 = rnd.NextFloat3(-1.0f, 1.0f);
                float3 point3 = rnd.NextFloat3(-1.0f, 1.0f);
                float  t0     = rnd.NextFloat(0.0f, 1.0f);
                float  t1     = rnd.NextFloat(0.0f, 1.0f);
                float3 e      = point1 + point1 - point0;
                float3 a      = math.lerp(point1, e, t0);
                float3 b      = math.lerp(point3, point3 + point3 - point0, t0);
                float3 point2 = math.lerp(a, b, t1);

                return(PolygonCollider.CreateQuad(point0, point1, point2, point3));
            }

            case ColliderType.Box:
            {
                float minSize     = 0.05f; // TODO - work around hull builder problems with small faces, sometimes doesn't extend 1D->2D based on face area
                var   boxGeometry = new BoxGeometry
                {
                    Center      = (rnd.NextInt(4) > 0) ? float3.zero : rnd.NextFloat3(-0.5f, 0.5f),
                    Orientation = (rnd.NextInt(4) > 0) ? quaternion.identity : rnd.NextQuaternionRotation(),
                    Size        = rnd.NextFloat3(minSize, 1.0f)
                };

                float maxBevelRadius = math.max(math.cmin((boxGeometry.Size - minSize) / (2.0f * (1.0f + float.Epsilon))), 0.0f);
                boxGeometry.BevelRadius = math.min(maxBevelRadius, convexRadius);

                return(BoxCollider.Create(boxGeometry));
            }

            case ColliderType.Cylinder:
            {
                float minSize          = 0.01f; // TODO - cylinder gets degenerate faces if radius-convexRadius=0 or height/2-convexRadius=0, decide how to handle this in CylinderCollider
                var   cylinderGeometry = new CylinderGeometry
                {
                    Center      = (rnd.NextInt(4) > 0) ? float3.zero : rnd.NextFloat3(-0.5f, 0.5f),
                    Orientation = (rnd.NextInt(4) > 0) ? quaternion.identity : rnd.NextQuaternionRotation(),
                    Height      = rnd.NextFloat(2.0f * minSize, 1f),
                    Radius      = rnd.NextFloat(minSize, 1.0f),
                    SideCount   = 20
                };

                var maxBevelRadius = math.max(math.min(cylinderGeometry.Height / 2, cylinderGeometry.Radius) - minSize, 0.0f);
                cylinderGeometry.BevelRadius = math.min(maxBevelRadius, convexRadius);

                return(CylinderCollider.Create(cylinderGeometry));
            }

            default:
                throw new NotImplementedException();
            }
        }
Example #10
0
        protected override BlobAssetReference <Collider> ProduceColliderBlob(PhysicsShapeAuthoring shape)
        {
            var material        = ProduceMaterial(shape);
            var collisionFilter = ProduceCollisionFilter(shape);

            BlobAssetReference <Collider> blob = default;

            switch (shape.ShapeType)
            {
            case ShapeType.Box:
                blob = BoxCollider.Create(
                    shape.GetBakedBoxProperties(),
                    collisionFilter,
                    material);
                break;

            case ShapeType.Capsule:
                blob = CapsuleCollider.Create(
                    shape.GetBakedCapsuleProperties(out var center, out var height, out var orientation),
                    collisionFilter,
                    material);
                break;

            case ShapeType.Sphere:
                blob = SphereCollider.Create(
                    shape.GetBakedSphereProperties(out orientation),
                    collisionFilter,
                    material);
                break;

            case ShapeType.Cylinder:
                blob = CylinderCollider.Create(
                    shape.GetBakedCylinderProperties(),
                    collisionFilter,
                    material);
                break;

            case ShapeType.Plane:
                shape.GetBakedPlaneProperties(out var v0, out var v1, out var v2, out var v3);
                blob = PolygonCollider.CreateQuad(
                    v0,
                    v1,
                    v2,
                    v3,
                    collisionFilter,
                    material);
                break;

            case ShapeType.ConvexHull:
                var pointCloud = new NativeList <float3>(65535, Allocator.Temp);
                shape.GetConvexHullProperties(pointCloud);
                if (pointCloud.Length == 0)
                {
                    throw new InvalidOperationException(
                              $"No vertices associated with {shape.name}. Add a {typeof(MeshFilter)} component or assign a readable {nameof(PhysicsShapeAuthoring.CustomMesh)}."
                              );
                }
                shape.GetBakedConvexProperties(pointCloud, out var hullGenerationParameters);
                RegisterConvexColliderDeferred(
                    shape, pointCloud, hullGenerationParameters.ToRunTime(), collisionFilter, material
                    );
                pointCloud.Dispose();
                break;

            case ShapeType.Mesh:
                const int defaultVertexCount = 2048;
                pointCloud = new NativeList <float3>(defaultVertexCount, Allocator.Temp);
                var triangles = new NativeList <int>((defaultVertexCount - 2) * 3, Allocator.Temp);
                shape.GetBakedMeshProperties(pointCloud, triangles);

                if (pointCloud.Length == 0 || triangles.Length == 0)
                {
                    triangles.Dispose();
                    pointCloud.Dispose();
                    throw new InvalidOperationException(
                              $"Invalid mesh data associated with {shape.name}. " +
                              $"Add a {typeof(MeshFilter)} component or assign a {nameof(PhysicsShapeAuthoring.CustomMesh)}. " +
                              "Ensure that you have enabled Read/Write on the mesh's import settings."
                              );
                }

                RegisterMeshColliderDeferred(shape, pointCloud, triangles, collisionFilter, material);
                triangles.Dispose();
                pointCloud.Dispose();
                break;

            default:
                throw new UnimplementedShapeException(shape.ShapeType);
            }
            return(blob);
        }
Example #11
0
 public void Execute() =>
 PolygonCollider.CreateQuad(new float3(-1f, 1f, 0f), new float3(1f, 1f, 0f), new float3(1f, -1f, 0f), new float3(-1f, -1f, 0f)).Dispose();
Example #12
0
        public void TestCreateInvalid()
        {
            // +inf vertex
            {
                float3[] vertices =
                {
                    new float3(-4.5f, float.PositiveInfinity, 1.0f),
                    new float3(3.4f,                    2.7f, 1.0f),
                    new float3(3.4f,                    0.7f, 1.0f),
                    new float3(-3.4f,                   1.2f, 1.1f)
                };
                TestUtils.ThrowsException <System.ArgumentException>(
                    () => PolygonCollider.CreateTriangle(vertices[0], vertices[1], vertices[2])
                    );
                TestUtils.ThrowsException <System.ArgumentException>(
                    () => PolygonCollider.CreateQuad(vertices[0], vertices[1], vertices[2], vertices[3])
                    );
            }

            // -inf vertex
            {
                float3[] vertices =
                {
                    new float3(-4.5f, float.NegativeInfinity, 1.0f),
                    new float3(3.4f,                    2.7f, 1.0f),
                    new float3(3.4f,                    0.7f, 1.0f),
                    new float3(-3.4f,                   1.2f, 1.1f)
                };
                TestUtils.ThrowsException <System.ArgumentException>(
                    () => PolygonCollider.CreateTriangle(vertices[0], vertices[1], vertices[2])
                    );
                TestUtils.ThrowsException <System.ArgumentException>(
                    () => PolygonCollider.CreateQuad(vertices[0], vertices[1], vertices[2], vertices[3])
                    );
            }

            // nan vertex
            {
                float3[] vertices =
                {
                    new float3(-4.5f, float.NaN, 1.0f),
                    new float3(3.4f,       2.7f, 1.0f),
                    new float3(3.4f,       0.7f, 1.0f),
                    new float3(-3.4f,      1.2f, 1.1f)
                };
                TestUtils.ThrowsException <System.ArgumentException>(
                    () => PolygonCollider.CreateTriangle(vertices[0], vertices[1], vertices[2])
                    );
                TestUtils.ThrowsException <System.ArgumentException>(
                    () => PolygonCollider.CreateQuad(vertices[0], vertices[1], vertices[2], vertices[3])
                    );
            }

            // non-planar quad
            {
                float3[] nonPlanarQuad =
                {
                    new float3(-4.5f, 0.0f, 1.0f),
                    new float3(3.4f,  0.7f, 1.0f),
                    new float3(3.4f,  2.7f, 1.0f),
                    new float3(-3.4f, 1.2f, 1.1f)
                };
                TestUtils.ThrowsException <System.ArgumentException>(
                    () => PolygonCollider.CreateQuad(nonPlanarQuad[0], nonPlanarQuad[1], nonPlanarQuad[2], nonPlanarQuad[3])
                    );
            }

            // non-planar quad unsorted
            {
                float3[] nonPlanarQuad =
                {
                    new float3(-4.5f, -0.30f, 1.0f),
                    new float3(3.4f,    2.7f, 1.0f),
                    new float3(3.4f,   -0.7f, 1.0f),
                    new float3(-3.4f,   1.2f, 1.1f)
                };
                TestUtils.ThrowsException <System.ArgumentException>(
                    () => PolygonCollider.CreateQuad(nonPlanarQuad[0], nonPlanarQuad[1], nonPlanarQuad[2], nonPlanarQuad[3])
                    );
            }
        }
        private BlobAssetReference <Collider> CreateCollider(ColliderType type)
        {
            int numMeshes = type == ColliderType.Compound ? 2 : 1;

            ColliderMeshes = new Mesh[numMeshes];
            BlobAssetReference <Collider> collider = default;

            switch (type)
            {
            case ColliderType.Sphere:
                collider = SphereCollider.Create(new SphereGeometry
                {
                    Center = float3.zero,
                    Radius = 0.5f
                });
                break;

            case ColliderType.Triangle:
                collider = PolygonCollider.CreateTriangle(k_TriangleVertices[0], k_TriangleVertices[1], k_TriangleVertices[2]);
                break;

            case ColliderType.Quad:
                collider = PolygonCollider.CreateQuad(k_QuadVertices[0], k_QuadVertices[1], k_QuadVertices[2], k_QuadVertices[3]);
                break;

            case ColliderType.Box:
                collider = BoxCollider.Create(new BoxGeometry
                {
                    Center      = float3.zero,
                    Orientation = quaternion.identity,
                    Size        = new float3(1.0f),
                    BevelRadius = 0.0f
                });
                break;

            case ColliderType.Capsule:
                collider = CapsuleCollider.Create(new CapsuleGeometry
                {
                    Vertex0 = new float3(0, -0.5f, 0),
                    Vertex1 = new float3(0, 0.5f, 0),
                    Radius  = 0.5f
                });
                break;

            case ColliderType.Cylinder:
                // TODO: need someone to add
                throw new NotImplementedException();

            case ColliderType.Convex:
                // Tetrahedron
                NativeArray <float3> points = new NativeArray <float3>(k_TetraherdonVertices, Allocator.TempJob);
                collider = ConvexCollider.Create(points, ConvexHullGenerationParameters.Default, CollisionFilter.Default);
                points.Dispose();
                break;

            case ColliderType.Compound:

                var child1 = SphereCollider.Create(new SphereGeometry
                {
                    Center = float3.zero,
                    Radius = 0.5f
                });
                ChildrenColliders.Add(child1);

                var child2 = BoxCollider.Create(new BoxGeometry
                {
                    Center      = float3.zero,
                    Orientation = quaternion.identity,
                    Size        = new float3(1.0f),
                    BevelRadius = 0.0f
                });
                ChildrenColliders.Add(child2);

                NativeArray <ColliderBlobInstance> childrenBlobs = new NativeArray <ColliderBlobInstance>(2, Allocator.TempJob);
                childrenBlobs[0] = new ColliderBlobInstance
                {
                    Collider          = child1,
                    CompoundFromChild = new RigidTransform
                    {
                        pos = new float3(0.5f, 0, 0),
                        rot = quaternion.identity
                    }
                };

                childrenBlobs[1] = new ColliderBlobInstance
                {
                    Collider          = child2,
                    CompoundFromChild = new RigidTransform
                    {
                        pos = new float3(-0.5f, 0, 0),
                        rot = quaternion.identity
                    }
                };

                ColliderMeshes[0] = SceneCreationUtilities.CreateMeshFromCollider(child1);
                ColliderMeshes[1] = SceneCreationUtilities.CreateMeshFromCollider(child2);

                collider = CompoundCollider.Create(childrenBlobs);
                childrenBlobs.Dispose();
                break;

            case ColliderType.Mesh:
                // Tetrahedron mesh
                NativeArray <float3> meshVertices  = new NativeArray <float3>(k_TetraherdonVertices, Allocator.TempJob);
                NativeArray <int3>   meshTriangles = new NativeArray <int3>(k_TetrahedronMeshTriangles, Allocator.TempJob);

                collider = MeshCollider.Create(meshVertices, meshTriangles);
                meshVertices.Dispose();
                meshTriangles.Dispose();
                break;

            case ColliderType.Terrain:
                int2   size  = 2;
                float3 scale = 1;
                Random rand  = new Random(0x9739);

                int numSamples = size.x * size.y;
                var heights    = new NativeArray <float>(numSamples, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
                for (int i = 0; i < numSamples; i++)
                {
                    heights[i] = rand.NextFloat(0, 1);
                }
                collider = TerrainCollider.Create(heights, size, scale, TerrainCollider.CollisionMethod.VertexSamples);
                heights.Dispose();
                break;

            default:
                throw new System.NotImplementedException();
            }

            if (ColliderType != ColliderType.Compound)
            {
                ColliderMeshes[0] = SceneCreationUtilities.CreateMeshFromCollider(collider);
            }

            return(collider);
        }