public void TestConvexColliderCalculateAabbLocal()
        {
            var points = new NativeArray <float3>(6, Allocator.Temp)
            {
                [0] = new float3(1.45f, 8.67f, 3.45f),
                [1] = new float3(8.75f, 1.23f, 6.44f),
                [2] = new float3(100.34f, 5.33f, -2.55f),
                [3] = new float3(8.76f, 4.56f, -4.54f),
                [4] = new float3(9.75f, -0.45f, -8.99f),
                [5] = new float3(7.66f, 3.44f, 0.0f)
            };
            float convexRadius = 1.25f;

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

            expectedAabb.Include(points[4]);
            expectedAabb.Include(points[5]);

            // Currently the convex hull is not shrunk, so we have to expand by the convex radius
            expectedAabb.Expand(convexRadius);

            var collider = ConvexCollider.Create(points, convexRadius);

            points.Dispose();

            Aabb actualAabb = collider.Value.CalculateAabb();

            TestUtils.AreEqual(expectedAabb.Min, actualAabb.Min, 1e-3f);
            TestUtils.AreEqual(expectedAabb.Max, actualAabb.Max, 1e-3f);
        }
        public void TestConvexColliderMassProperties()
        {
            var points = new NativeArray <float3>(8, Allocator.Temp)
            {
                [0] = new float3(-1.56f, 8.89f, -10.76f),
                [1] = new float3(-4.74f, 80.11f, 10.56f),
                [2] = new float3(-100.60f, -4.93f, -10.76f),
                [3] = new float3(1.44f, 3.56f, 73.4f),
                [4] = new float3(17.66f, 18.43f, 0.0f),
                [5] = new float3(-1.32f, 9.99f, 80.4f),
                [6] = new float3(-17.45f, 3.22f, -3.22f),
                [7] = new float3(0.0f, 0.0f, 0.03f)
            };

            var collider = ConvexCollider.Create(points, convexRadius: 0.15f);

            points.Dispose();

            float3 expectedInertiaTensor = new float3(434.014862f, 824.963989f, 684.776672f);
            float3 inertiaTensor         = collider.Value.MassProperties.MassDistribution.InertiaTensor;

            // Given the number of FP operations, we do a percentage comparison in this case
            Assert.IsTrue(math.abs(expectedInertiaTensor.x - inertiaTensor.x) / expectedInertiaTensor.x < 0.01f);
            Assert.IsTrue(math.abs(expectedInertiaTensor.y - inertiaTensor.y) / expectedInertiaTensor.y < 0.01f);
            Assert.IsTrue(math.abs(expectedInertiaTensor.z - inertiaTensor.z) / expectedInertiaTensor.z < 0.01f);
        }
        protected override BlobAssetReference <Collider> ProduceColliderBlob(LegacyMesh shape)
        {
            if (shape.sharedMesh == null)
            {
                throw new InvalidOperationException(
                          $"No {nameof(LegacyMesh.sharedMesh)} assigned to {typeof(MeshCollider)} on {shape.name}."
                          );
            }

            var filter   = ProduceCollisionFilter(shape);
            var material = ProduceMaterial(shape);

            using (var pointCloud = new NativeList <float3>(shape.sharedMesh.vertexCount, Allocator.Temp))
            {
                // transform points into world space and back into shape space
                shape.sharedMesh.GetVertices(m_Vertices);
                var shapeFromWorld = math.inverse(
                    new float4x4(new RigidTransform(shape.transform.rotation, shape.transform.position))
                    );
                for (int i = 0, count = m_Vertices.Count; i < count; ++i)
                {
                    var worldPt = math.mul(shape.transform.localToWorldMatrix, new float4(m_Vertices[i], 1f));
                    pointCloud.Add(math.mul(shapeFromWorld, worldPt).xyz);
                }

                return(shape.convex
                    ? ConvexCollider.Create(pointCloud, PhysicsShape.k_DefaultConvexRadius, new float3(1f), filter, material)
                    : MeshCollider.Create(pointCloud.ToArray(), shape.sharedMesh.triangles, filter, material));
            }
        }
        public void Execute(int index)
        {
            var inputParameters = InputParameters[index];
            var points          = new NativeArray <float3>(
                inputParameters.PointCount, Allocator.Temp, NativeArrayOptions.UninitializedMemory
                );

            UnsafeUtility.MemCpy(
                points.GetUnsafePtr(),
                (float3 *)AllPoints.GetUnsafeReadOnlyPtr() + inputParameters.PointsStart,
                UnsafeUtility.SizeOf <float3>() * inputParameters.PointCount
                );
            Output[index] = new KeyValuePair <Entity, LeafShapeData>(
                inputParameters.BodyEntity,
                new LeafShapeData
            {
                LeafEntity           = inputParameters.LeafEntity,
                ColliderBlobInstance = new CompoundCollider.ColliderBlobInstance
                {
                    CompoundFromChild = inputParameters.CompoundFromChild,
                    Collider          = ConvexCollider.Create(
                        points, inputParameters.GenerationParameters, inputParameters.Filter, inputParameters.Material
                        )
                }
            }
                );
        }
Example #5
0
        public unsafe void TestConvexColliderCalculateAabbLocal([Values(0, 0.01f, 1.25f)] float maxShrinkMovement)
        {
            var points = new NativeArray <float3>(6, Allocator.TempJob)
            {
                [0] = new float3(1.45f, 8.67f, 3.45f),
                [1] = new float3(8.75f, 1.23f, 6.44f),
                [2] = new float3(100.34f, 5.33f, -2.55f),
                [3] = new float3(8.76f, 4.56f, -4.54f),
                [4] = new float3(9.75f, -0.45f, -8.99f),
                [5] = new float3(7.66f, 3.44f, 0.0f)
            };

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

            expectedAabb.Include(points[4]);
            expectedAabb.Include(points[5]);

            var collider = ConvexCollider.Create(
                points, new ConvexHullGenerationParameters {
                BevelRadius = maxShrinkMovement
            }, CollisionFilter.Default
                );

            points.Dispose();

            Aabb  actualAabb   = collider.Value.CalculateAabb();
            float convexRadius = ((ConvexCollider *)collider.GetUnsafePtr())->ConvexHull.ConvexRadius;
            float maxError     = 1e-3f + maxShrinkMovement - convexRadius;

            TestUtils.AreEqual(expectedAabb.Min, actualAabb.Min, maxError);
            TestUtils.AreEqual(expectedAabb.Max, actualAabb.Max, maxError);
        }
Example #6
0
            public void Execute()
            {
                var points = new NativeArray <float3>(1024, Allocator.Temp);
                var random = new Random(1234);

                for (var i = 0; i < points.Length; ++i)
                {
                    points[i] = random.NextFloat3(new float3(-1f), new float3(1f));
                }
                ConvexCollider.Create(points, ConvexHullGenerationParameters.Default).Release();
            }
        public void TestConvexColliderCreate()
        {
            var points   = new NativeArray <float3>(k_TestPoints, Allocator.Temp);
            var collider = ConvexCollider.Create(
                points, new ConvexHullGenerationParameters {
                BevelRadius = 0.15f
            }, CollisionFilter.Default
                );

            Assert.AreEqual(ColliderType.Convex, collider.Value.Type);
            Assert.AreEqual(CollisionType.Convex, collider.Value.CollisionType);
        }
            public void Execute(int index)
            {
                var inputParameters = InputValues[index];

                Output[index] = new KeyValuePair <Hash128, BlobAssetReference <Collider> >(
                    InputKeys[index],
                    ConvexCollider.Create(
                        AllPoints.GetSubArray(inputParameters.PointsStart, inputParameters.PointCount),
                        inputParameters.GenerationParameters, inputParameters.Filter, inputParameters.Material
                        )
                    );
            }
        public void ConvexCollider_Create_WhenGenerationParametersBevelRadiusInvalid_Throws(
            [Values(float.PositiveInfinity, float.NegativeInfinity, float.NaN, -1f)] float errantValue
            )
        {
            var points = new NativeArray <float3>(k_TestPoints, Allocator.Temp);
            var generationParameters = ConvexHullGenerationParameters.Default;

            generationParameters.BevelRadius = errantValue;

            var ex = Assert.Throws <ArgumentException>(() => ConvexCollider.Create(points, generationParameters));

            Assert.That(ex.ParamName, Is.EqualTo("generationParameters"));
        }
        public void ConvexCollider_Create_WhenPointsInvalid_Throws(
            [Values(float.PositiveInfinity, float.NegativeInfinity, float.NaN)] float errantValue
            )
        {
            var points = new NativeArray <float3>(k_TestPoints, Allocator.Temp)
            {
                [2] = new float3(errantValue)
            };

            var ex = Assert.Throws <ArgumentException>(() => ConvexCollider.Create(points, ConvexHullGenerationParameters.Default));

            Assert.That(ex.ParamName, Is.EqualTo("points"));
        }
Example #11
0
    private static PhysicsCollider CreateMeshCollider(Resource.Mesh mesh, float3 scale, CollisionFilter filter, PhysicsMaterial physicsMaterial)
    {
        UnityEngine.Vector3[] v3Verts = Resource.GetMesh(mesh).vertices;
        float3[] float3Verts          = new float3[v3Verts.Length];
        for (int i = 0; i < v3Verts.Length; i++)
        {
            float3Verts[i] = v3Verts[i] * scale;
        }
        NativeArray <float3> nativeVerts = new NativeArray <float3>(float3Verts, Allocator.Temp);

        return(new PhysicsCollider {
            Value = ConvexCollider.Create(nativeVerts, ConvexHullGenerationParameters.Default, filter, physicsMaterial)
        });
    }
Example #12
0
        private void SelectMultipleUnits()
        {
            _isDragging = false;

            var topLeft  = math.min(_mouseStartPos, Input.mousePosition);
            var botRight = math.max(_mouseStartPos, Input.mousePosition);

            var rect = Rect.MinMaxRect(topLeft.x, topLeft.y, botRight.x, botRight.y);

            var cornerRays = new[]
            {
                _mainCamera.ScreenPointToRay(rect.min),
                _mainCamera.ScreenPointToRay(rect.max),
                _mainCamera.ScreenPointToRay(new Vector2(rect.xMin, rect.yMax)),
                _mainCamera.ScreenPointToRay(new Vector2(rect.xMax, rect.yMin))
            };

            var vertices = new NativeArray <float3>(5, Allocator.Temp);

            for (var i = 0; i < cornerRays.Length; i++)
            {
                vertices[i] = cornerRays[i].GetPoint(50f);
            }

            vertices[4] = _mainCamera.transform.position;

            var collisionFilter = new CollisionFilter
            {
                BelongsTo    = (uint)CollisionLayers.Selection,
                CollidesWith = (uint)CollisionLayers.Units
            };

            var physicsMaterial = Unity.Physics.Material.Default;

            physicsMaterial.CollisionResponse = CollisionResponsePolicy.RaiseTriggerEvents;

            var selectionCollider = ConvexCollider.Create(vertices, ConvexHullGenerationParameters.Default,
                                                          collisionFilter, physicsMaterial);

            var newSelectionEntity = EntityManager.CreateEntity(_selectionArchetype);

            EntityManager.SetComponentData(newSelectionEntity, new PhysicsCollider {
                Value = selectionCollider
            });
        }
        public void TestConvexColliderCreate()
        {
            var points = new NativeArray <float3>(8, Allocator.Temp)
            {
                [0] = new float3(1.45f, 8.67f, 3.45f),
                [1] = new float3(8.75f, 1.23f, 6.44f),
                [2] = new float3(100.34f, 5.33f, -2.55f),
                [3] = new float3(8.76f, 4.56f, -4.54f),
                [4] = new float3(9.75f, -0.45f, -8.99f),
                [5] = new float3(7.66f, 3.44f, 0.0f)
            };
            var collider = ConvexCollider.Create(points, convexRadius: 0.15f);

            points.Dispose();

            Assert.AreEqual(ColliderType.Convex, collider.Value.Type);
            Assert.AreEqual(CollisionType.Convex, collider.Value.CollisionType);
        }
Example #14
0
            public void Execute(int index)
            {
                var inputParameters = InputValues[index];
                var points          = new NativeArray <float3>(
                    inputParameters.PointCount, Allocator.Temp, NativeArrayOptions.UninitializedMemory
                    );

                UnsafeUtility.MemCpy(
                    points.GetUnsafePtr(),
                    (float3 *)AllPoints.GetUnsafeReadOnlyPtr() + inputParameters.PointsStart,
                    UnsafeUtility.SizeOf <float3>() * inputParameters.PointCount
                    );

                Output[index] = new KeyValuePair <Hash128, BlobAssetReference <Collider> >(
                    InputKeys[index],
                    ConvexCollider.Create(points, inputParameters.GenerationParameters, inputParameters.Filter, inputParameters.Material)
                    );
            }
Example #15
0
        public unsafe void TestConvexColliderCalculateAabbTransformed([Values(0, 0.01f, 1.25f)] float maxShrinkMovement)
        {
            var points = new NativeArray <float3>(6, Allocator.TempJob)
            {
                [0] = new float3(1.45f, 8.67f, 3.45f),
                [1] = new float3(8.75f, 1.23f, 6.44f),
                [2] = new float3(100.34f, 5.33f, -2.55f),
                [3] = new float3(8.76f, 4.56f, -4.54f),
                [4] = new float3(9.75f, -0.45f, -8.99f),
                [5] = new float3(7.66f, 3.44f, 0.0f)
            };

            float3     translation = new float3(43.56f, -87.32f, -0.02f);
            quaternion rotation    = quaternion.AxisAngle(math.normalize(new float3(8.45f, -2.34f, 0.82f)), 43.21f);

            float3[] transformedPoints = new float3[points.Length];
            for (int i = 0; i < points.Length; ++i)
            {
                transformedPoints[i] = translation + math.mul(rotation, points[i]);
            }

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

            expectedAabb.Include(transformedPoints[4]);
            expectedAabb.Include(transformedPoints[5]);

            var collider = ConvexCollider.Create(
                points, new ConvexHullGenerationParameters {
                BevelRadius = maxShrinkMovement
            }, CollisionFilter.Default
                );

            points.Dispose();

            Aabb  actualAabb   = collider.Value.CalculateAabb(new RigidTransform(rotation, translation));
            float convexRadius = ((ConvexCollider *)collider.GetUnsafePtr())->ConvexHull.ConvexRadius;
            float maxError     = 1e-3f + maxShrinkMovement - convexRadius;

            TestUtils.AreEqual(expectedAabb.Min, actualAabb.Min, maxError);
            TestUtils.AreEqual(expectedAabb.Max, actualAabb.Max, maxError);
        }
        public void TestConvexColliderCalculateAabbTransformed()
        {
            var points = new NativeArray <float3>(6, Allocator.Temp)
            {
                [0] = new float3(1.45f, 8.67f, 3.45f),
                [1] = new float3(8.75f, 1.23f, 6.44f),
                [2] = new float3(100.34f, 5.33f, -2.55f),
                [3] = new float3(8.76f, 4.56f, -4.54f),
                [4] = new float3(9.75f, -0.45f, -8.99f),
                [5] = new float3(7.66f, 3.44f, 0.0f)
            };

            float      convexRadius = 1.25f;
            float3     translation  = new float3(43.56f, -87.32f, -0.02f);
            quaternion rotation     = quaternion.AxisAngle(math.normalize(new float3(8.45f, -2.34f, 0.82f)), 43.21f);

            float3[] transformedPoints = new float3[points.Length];
            for (int i = 0; i < points.Length; ++i)
            {
                transformedPoints[i] = translation + math.mul(rotation, points[i]);
            }

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

            expectedAabb.Include(transformedPoints[4]);
            expectedAabb.Include(transformedPoints[5]);

            // Currently the convex hull is not shrunk, so we have to expand by the convex radius
            expectedAabb.Expand(convexRadius);

            var collider = ConvexCollider.Create(points, convexRadius);

            points.Dispose();

            Aabb actualAabb = collider.Value.CalculateAabb(new RigidTransform(rotation, translation));

            TestUtils.AreEqual(expectedAabb.Min, actualAabb.Min, 1e-3f);
            TestUtils.AreEqual(expectedAabb.Max, actualAabb.Max, 1e-3f);
        }
Example #17
0
        public void TestConvexColliderCreate()
        {
            var points = new NativeArray <float3>(8, Allocator.TempJob)
            {
                [0] = new float3(1.45f, 8.67f, 3.45f),
                [1] = new float3(8.75f, 1.23f, 6.44f),
                [2] = new float3(100.34f, 5.33f, -2.55f),
                [3] = new float3(8.76f, 4.56f, -4.54f),
                [4] = new float3(9.75f, -0.45f, -8.99f),
                [5] = new float3(7.66f, 3.44f, 0.0f)
            };
            var collider = ConvexCollider.Create(
                points, new ConvexHullGenerationParameters {
                BevelRadius = 0.15f
            }, CollisionFilter.Default
                );

            points.Dispose();

            Assert.AreEqual(ColliderType.Convex, collider.Value.Type);
            Assert.AreEqual(CollisionType.Convex, collider.Value.CollisionType);
        }
Example #18
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 #21
0
    private void CreateRagdoll(Mesh torsoMesh, Mesh renderMesh,
                               float3 positionOffset, quaternion rotationOffset, float3 initialVelocity,
                               int ragdollIndex = 1, bool internalCollisions = false, float rangeGain = 1.0f)
    {
        var entities      = new NativeList <Entity>(Allocator.Temp);
        var rangeModifier = new float2(math.max(0, math.min(rangeGain, 1)));

        // Head
        float  headRadius   = 0.1f;
        float3 headPosition = new float3(0, 1.8f, headRadius);
        Entity head;

        {
            CollisionFilter filter = internalCollisions ? layerFilter(layer.Head, layer.Torso) : groupFilter(-ragdollIndex);
            BlobAssetReference <Collider> headCollider = Unity.Physics.CapsuleCollider.Create(new CapsuleGeometry
            {
                Vertex0 = new float3(0, 0, 0),
                Vertex1 = new float3(0, 0, headRadius / 4),
                Radius  = headRadius
            }, filter);
            CreatedColliders.Add(headCollider);
            head = CreateDynamicBody(headPosition, quaternion.identity, headCollider, float3.zero, float3.zero, 5.0f);
        }
        entities.Add(head);


        // Torso
        float3 torsoSize;
        float3 torsoPosition;
        Entity torso;

        {
            //UnityEngine.Mesh torsoMesh = (UnityEngine.Mesh)Resources.Load("torso", typeof(UnityEngine.Mesh));
            torsoSize     = torsoMesh.bounds.size;
            torsoPosition = headPosition - new float3(0, headRadius * 3.0f / 4.0f + torsoSize.y, 0);

            CollisionFilter filter = internalCollisions ? layerFilter(layer.Torso, layer.Thigh | layer.Head | layer.UpperArm | layer.Pelvis) : groupFilter(-ragdollIndex);

            NativeArray <float3> points = new NativeArray <float3>(torsoMesh.vertices.Length, Allocator.TempJob);
            for (int i = 0; i < torsoMesh.vertices.Length; i++)
            {
                points[i] = torsoMesh.vertices[i];
            }
            BlobAssetReference <Collider> collider = ConvexCollider.Create(
                points, ConvexHullGenerationParameters.Default, CollisionFilter.Default
                );
            CreatedColliders.Add(collider);
            points.Dispose();
            collider.Value.Filter = filter;
            torso = CreateDynamicBody(torsoPosition, quaternion.identity, collider, float3.zero, float3.zero, 20.0f);
        }
        entities.Add(torso);

        // Neck
        {
            float3     pivotHead          = new float3(0, -headRadius, 0);
            float3     pivotTorso         = math.transform(math.inverse(GetBodyTransform(torso)), math.transform(GetBodyTransform(head), pivotHead));
            float3     axisHead           = new float3(0, 0, 1);
            float3     perpendicular      = new float3(1, 0, 0);
            FloatRange coneAngle          = new FloatRange(math.radians(0), math.radians(45)) * rangeModifier;
            FloatRange perpendicularAngle = new FloatRange(math.radians(-30), math.radians(+30)) * rangeModifier;
            FloatRange twistAngle         = new FloatRange(math.radians(-5), math.radians(5)) * rangeModifier;

            var axisTorso = math.rotate(math.inverse(GetBodyTransform(torso).rot), math.rotate(GetBodyTransform(head).rot, axisHead));
            axisTorso = math.rotate(quaternion.AxisAngle(perpendicular, math.radians(10)), axisTorso);

            var headFrame = new BodyFrame {
                Axis = axisHead, PerpendicularAxis = perpendicular, Position = pivotHead
            };
            var torsoFrame = new BodyFrame {
                Axis = axisTorso, PerpendicularAxis = perpendicular, Position = pivotTorso
            };

            PhysicsJoint.CreateRagdoll(headFrame, torsoFrame, coneAngle.Max, perpendicularAngle, twistAngle, out var ragdoll0, out var ragdoll1);
            CreateJoint(ragdoll0, head, torso);
            CreateJoint(ragdoll1, head, torso);
        }

        // Arms
        {
            float           armLength      = 0.25f;
            float           armRadius      = 0.05f;
            CollisionFilter armUpperFilter = internalCollisions ? layerFilter(layer.UpperArm, layer.Torso | layer.Forearm) : groupFilter(-ragdollIndex);
            CollisionFilter armLowerFilter = internalCollisions ? layerFilter(layer.Forearm, layer.UpperArm | layer.Hand) : groupFilter(-ragdollIndex);

            BlobAssetReference <Collider> upperArmCollider = Unity.Physics.CapsuleCollider.Create(new CapsuleGeometry
            {
                Vertex0 = new float3(-armLength / 2, 0, 0),
                Vertex1 = new float3(armLength / 2, 0, 0),
                Radius  = armRadius
            }, armUpperFilter);
            BlobAssetReference <Collider> foreArmCollider = Unity.Physics.CapsuleCollider.Create(new CapsuleGeometry
            {
                Vertex0 = new float3(-armLength / 2, 0, 0),
                Vertex1 = new float3(armLength / 2, 0, 0),
                Radius  = armRadius
            }, armLowerFilter);

            float           handLength = 0.025f;
            float           handRadius = 0.055f;
            CollisionFilter handFilter = internalCollisions ? layerFilter(layer.Hand, layer.Forearm) : groupFilter(-ragdollIndex);

            BlobAssetReference <Collider> handCollider = Unity.Physics.CapsuleCollider.Create(new CapsuleGeometry
            {
                Vertex0 = new float3(-handLength / 2, 0, 0),
                Vertex1 = new float3(handLength / 2, 0, 0),
                Radius  = handRadius
            }, handFilter);

            CreatedColliders.Add(upperArmCollider);
            CreatedColliders.Add(foreArmCollider);
            CreatedColliders.Add(handCollider);


            for (int i = 0; i < 2; i++)
            {
                float s = i * 2 - 1.0f;

                float3 upperArmPosition = torsoPosition + new float3(s * (torsoSize.x + armLength) / 2.0f, 0.9f * torsoSize.y - armRadius, 0.0f);
                Entity upperArm         = CreateDynamicBody(upperArmPosition, quaternion.identity, upperArmCollider, float3.zero, float3.zero, 10.0f);
                float3 foreArmPosition  = upperArmPosition + new float3(armLength * s, 0, 0);
                Entity foreArm          = CreateDynamicBody(foreArmPosition, quaternion.identity, foreArmCollider, float3.zero, float3.zero, 5.0f);
                float3 handPosition     = foreArmPosition + new float3((armLength + handLength) / 2.0f * s, 0, 0);
                Entity hand             = CreateDynamicBody(handPosition, quaternion.identity, handCollider, float3.zero, float3.zero, 2.0f);

                entities.Add(upperArm);
                entities.Add(foreArm);
                entities.Add(hand);

                // shoulder
                {
                    float3     pivotArm           = new float3(-s * armLength / 2.0f, 0, 0);
                    float3     pivotTorso         = math.transform(math.inverse(GetBodyTransform(torso)), math.transform(GetBodyTransform(upperArm), pivotArm));
                    float3     axisArm            = new float3(-s, 0, 0);
                    float3     perpendicularArm   = new float3(0, 1, 0);
                    FloatRange coneAngle          = new FloatRange(math.radians(0), math.radians(80)) * rangeModifier;
                    FloatRange perpendicularAngle = new FloatRange(math.radians(-70), math.radians(20)) * rangeModifier;
                    FloatRange twistAngle         = new FloatRange(math.radians(-5), math.radians(5)) * rangeModifier;

                    var axisTorso = math.rotate(math.inverse(GetBodyTransform(torso).rot), math.rotate(GetBodyTransform(upperArm).rot, axisArm));
                    axisTorso = math.rotate(quaternion.AxisAngle(perpendicularArm, math.radians(-s * 45.0f)), axisTorso);

                    var armFrame = new BodyFrame {
                        Axis = axisArm, PerpendicularAxis = perpendicularArm, Position = pivotArm
                    };
                    var bodyFrame = new BodyFrame {
                        Axis = axisTorso, PerpendicularAxis = perpendicularArm, Position = pivotTorso
                    };

                    PhysicsJoint.CreateRagdoll(armFrame, bodyFrame, coneAngle.Max, perpendicularAngle, twistAngle, out var ragdoll0, out var ragdoll1);
                    CreateJoint(ragdoll0, upperArm, torso);
                    CreateJoint(ragdoll1, upperArm, torso);
                }

                // elbow
                {
                    float3 pivotUpper    = new float3(s * armLength / 2.0f, 0, 0);
                    float3 pivotFore     = -pivotUpper;
                    float3 axis          = new float3(0, -s, 0);
                    float3 perpendicular = new float3(-s, 0, 0);

                    var lowerArmFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotFore
                    };
                    var upperArmFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotUpper
                    };
                    var hingeRange = new FloatRange(math.radians(0), math.radians(100));
                    hingeRange = (hingeRange - new float2(hingeRange.Mid)) * rangeModifier + hingeRange.Mid;
                    PhysicsJoint hinge = PhysicsJoint.CreateLimitedHinge(lowerArmFrame, upperArmFrame, hingeRange);
                    CreateJoint(hinge, foreArm, upperArm);
                }

                // wrist
                {
                    float3 pivotFore     = new float3(s * armLength / 2.0f, 0, 0);
                    float3 pivotHand     = new float3(-s * handLength / 2.0f, 0, 0);
                    float3 axis          = new float3(0, 0, -s);
                    float3 perpendicular = new float3(0, 0, 1);

                    var handFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotHand
                    };
                    var forearmFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotFore
                    };
                    var          hingeRange = new FloatRange(math.radians(0), math.radians(135)) * rangeModifier;
                    PhysicsJoint hinge      = PhysicsJoint.CreateLimitedHinge(handFrame, forearmFrame, hingeRange);
                    CreateJoint(hinge, hand, foreArm);
                }
            }
        }

        // Pelvis
        float  pelvisRadius   = 0.08f;
        float  pelvisLength   = 0.22f;
        float3 pelvisPosition = torsoPosition - new float3(0, pelvisRadius * 0.75f, 0.0f);
        Entity pelvis;

        {
            CollisionFilter filter = internalCollisions ? layerFilter(layer.Pelvis, layer.Torso | layer.Thigh) : groupFilter(-ragdollIndex);
            BlobAssetReference <Collider> collider = Unity.Physics.CapsuleCollider.Create(new CapsuleGeometry
            {
                Vertex0 = new float3(-pelvisLength / 2, 0, 0),
                Vertex1 = new float3(pelvisLength / 2, 0, 0),
                Radius  = pelvisRadius
            }, filter);
            pelvis = CreateDynamicBody(pelvisPosition, quaternion.identity, collider, float3.zero, float3.zero, 15.0f);
            CreatedColliders.Add(collider);
        }
        entities.Add(pelvis);

        // Waist
        {
            float3     pivotTorso         = float3.zero;
            float3     pivotPelvis        = math.transform(math.inverse(GetBodyTransform(pelvis)), math.transform(GetBodyTransform(torso), pivotTorso));
            float3     axis               = new float3(0, 1, 0);
            float3     perpendicular      = new float3(0, 0, 1);
            FloatRange coneAngle          = new FloatRange(math.radians(0), math.radians(5)) * rangeModifier;
            FloatRange perpendicularAngle = new FloatRange(math.radians(-5), math.radians(90)) * rangeModifier;
            FloatRange twistAngle         = new FloatRange(-math.radians(-5), math.radians(5)) * rangeModifier;

            var pelvisFrame = new BodyFrame {
                Axis = axis, PerpendicularAxis = perpendicular, Position = pivotPelvis
            };
            var torsoFrame = new BodyFrame {
                Axis = axis, PerpendicularAxis = perpendicular, Position = pivotTorso
            };
            PhysicsJoint.CreateRagdoll(pelvisFrame, torsoFrame, coneAngle.Max, perpendicularAngle, twistAngle, out var ragdoll0, out var ragdoll1);
            CreateJoint(ragdoll0, pelvis, torso);
            CreateJoint(ragdoll1, pelvis, torso);
        }

        // Legs
        {
            float           thighLength = 0.32f;
            float           thighRadius = 0.08f;
            CollisionFilter thighFilter = internalCollisions ? layerFilter(layer.Thigh, layer.Pelvis | layer.Calf) : groupFilter(-ragdollIndex);
            BlobAssetReference <Collider> thighCollider = Unity.Physics.CapsuleCollider.Create(new CapsuleGeometry
            {
                Vertex0 = new float3(0, -thighLength / 2, 0),
                Vertex1 = new float3(0, thighLength / 2, 0),
                Radius  = thighRadius
            }, thighFilter);

            float           calfLength = 0.32f;
            float           calfRadius = 0.06f;
            CollisionFilter calfFilter = internalCollisions ? layerFilter(layer.Calf, layer.Thigh | layer.Foot) : groupFilter(-ragdollIndex);
            BlobAssetReference <Collider> calfCollider = Unity.Physics.CapsuleCollider.Create(new CapsuleGeometry
            {
                Vertex0 = new float3(0, -calfLength / 2, 0),
                Vertex1 = new float3(0, calfLength / 2, 0),
                Radius  = calfRadius
            }, calfFilter);

            float           footLength = 0.08f;
            float           footRadius = 0.06f;
            CollisionFilter footFilter = internalCollisions ? layerFilter(layer.Foot, layer.Calf) : groupFilter(-ragdollIndex);
            BlobAssetReference <Collider> footCollider = Unity.Physics.CapsuleCollider.Create(new CapsuleGeometry
            {
                Vertex0 = new float3(0),
                Vertex1 = new float3(0, 0, footLength),
                Radius  = footRadius
            }, footFilter);

            CreatedColliders.Add(thighCollider);
            CreatedColliders.Add(calfCollider);
            CreatedColliders.Add(footCollider);

            for (int i = 0; i < 2; i++)
            {
                float s = i * 2 - 1.0f;

                float3 thighPosition = pelvisPosition + new float3(s * pelvisLength / 2.0f, -thighLength / 2.0f, 0.0f);
                Entity thigh         = CreateDynamicBody(thighPosition, quaternion.identity, thighCollider, float3.zero, float3.zero, 10.0f);
                float3 calfPosition  = thighPosition + new float3(0, -(thighLength + calfLength) / 2.0f, 0);
                Entity calf          = CreateDynamicBody(calfPosition, quaternion.identity, calfCollider, float3.zero, float3.zero, 5.0f);
                float3 footPosition  = calfPosition + new float3(0, -calfLength / 2.0f, 0);
                Entity foot          = CreateDynamicBody(footPosition, quaternion.identity, footCollider, float3.zero, float3.zero, 2.0f);

                entities.Add(thigh);
                entities.Add(calf);
                entities.Add(foot);

                // hip
                {
                    float3     pivotThigh         = new float3(0, thighLength / 2.0f, 0);
                    float3     pivotPelvis        = math.transform(math.inverse(GetBodyTransform(pelvis)), math.transform(GetBodyTransform(thigh), pivotThigh));
                    float3     axisLeg            = new float3(0, -1, 0);
                    float3     perpendicularLeg   = new float3(-s, 0, 0);
                    FloatRange coneAngle          = new FloatRange(math.radians(0), math.radians(60)) * rangeModifier;
                    FloatRange perpendicularAngle = new FloatRange(math.radians(-10), math.radians(40)) * rangeModifier;
                    FloatRange twistAngle         = new FloatRange(-math.radians(5), math.radians(5)) * rangeModifier;

                    var axisPelvis = math.rotate(math.inverse(GetBodyTransform(pelvis).rot), math.rotate(GetBodyTransform(thigh).rot, axisLeg));
                    axisPelvis = math.rotate(quaternion.AxisAngle(perpendicularLeg, math.radians(s * 45.0f)), axisPelvis);

                    var upperLegFrame = new BodyFrame {
                        Axis = axisLeg, PerpendicularAxis = perpendicularLeg, Position = pivotThigh
                    };
                    var pelvisFrame = new BodyFrame {
                        Axis = axisPelvis, PerpendicularAxis = perpendicularLeg, Position = pivotPelvis
                    };

                    PhysicsJoint.CreateRagdoll(upperLegFrame, pelvisFrame, coneAngle.Max, perpendicularAngle, twistAngle, out var ragdoll0, out var ragdoll1);
                    CreateJoint(ragdoll0, thigh, pelvis);
                    CreateJoint(ragdoll1, thigh, pelvis);
                }

                // knee
                {
                    float3 pivotThigh    = new float3(0, -thighLength / 2.0f, 0);
                    float3 pivotCalf     = math.transform(math.inverse(GetBodyTransform(calf)), math.transform(GetBodyTransform(thigh), pivotThigh));
                    float3 axis          = new float3(-1, 0, 0);
                    float3 perpendicular = new float3(0, 0, 1);

                    var lowerLegFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotCalf
                    };
                    var upperLegFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotThigh
                    };
                    var hingeRange = new FloatRange(math.radians(-90), math.radians(0));
                    hingeRange = (hingeRange - new float2(hingeRange.Mid)) * rangeModifier + hingeRange.Mid;
                    PhysicsJoint hinge = PhysicsJoint.CreateLimitedHinge(lowerLegFrame, upperLegFrame, hingeRange);
                    CreateJoint(hinge, calf, thigh);
                }

                // ankle
                {
                    float3 pivotCalf     = new float3(0, -calfLength / 2.0f, 0);
                    float3 pivotFoot     = float3.zero;
                    float3 axis          = new float3(-1, 0, 0);
                    float3 perpendicular = new float3(0, 0, 1);

                    var footFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotFoot
                    };
                    var lowerLegFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotCalf
                    };
                    var          hingeRange = new FloatRange(math.radians(-5), math.radians(5)) * rangeModifier;
                    PhysicsJoint hinge      = PhysicsJoint.CreateLimitedHinge(footFrame, lowerLegFrame, hingeRange);
                    CreateJoint(hinge, foot, calf);
                }
            }
        }

        // reposition with offset information
        if (entities.Length > 0)
        {
            for (int i = 0; i < entities.Length; i++)
            {
                var e = entities[i];

                bool isTorso = (i == 1);
                SwapRenderMesh(e, isTorso, torsoMesh, renderMesh);

                Translation     positionComponent = EntityManager.GetComponentData <Translation>(e);
                Rotation        rotationComponent = EntityManager.GetComponentData <Rotation>(e);
                PhysicsVelocity velocityComponent = EntityManager.GetComponentData <PhysicsVelocity>(e);

                float3     position = positionComponent.Value;
                quaternion rotation = rotationComponent.Value;

                float3 localPosition = position - pelvisPosition;
                localPosition = math.rotate(rotationOffset, localPosition);

                position = localPosition + pelvisPosition + positionOffset;
                rotation = math.mul(rotation, rotationOffset);

                positionComponent.Value = position;
                rotationComponent.Value = rotation;

                velocityComponent.Linear = initialVelocity;

                EntityManager.SetComponentData <PhysicsVelocity>(e, velocityComponent);
                EntityManager.SetComponentData <Translation>(e, positionComponent);
                EntityManager.SetComponentData <Rotation>(e, rotationComponent);
            }
        }
    }
Example #22
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 #23
0
 public void Execute() => Output[0] = ConvexCollider.Create(Points, GenerationParameters, CollisionFilter.Default);
Example #24
0
        public void TestConvexColliderCreateInvalid()
        {
            // Invalid points
            {
                var validBevelRadius = new ConvexHullGenerationParameters {
                    BevelRadius = 0.15f
                };

                // invalid point, +inf
                {
                    var invalidPoints = new NativeArray <float3>(6, Allocator.TempJob)
                    {
                        [0] = new float3(1.45f, 8.67f, 3.45f),
                        [1] = new float3(8.75f, 1.23f, 6.44f),
                        [2] = new float3(float.PositiveInfinity, 5.33f, -2.55f),
                        [3] = new float3(8.76f, 4.56f, -4.54f),
                        [4] = new float3(9.75f, -0.45f, -8.99f),
                        [5] = new float3(7.66f, 3.44f, 0.0f)
                    };
                    TestUtils.ThrowsException <ArgumentException>(
                        () => ConvexCollider.Create(invalidPoints, validBevelRadius, CollisionFilter.Default)
                        );
                    invalidPoints.Dispose();
                }

                // invalid point, -inf
                {
                    var invalidPoints = new NativeArray <float3>(6, Allocator.TempJob)
                    {
                        [0] = new float3(1.45f, 8.67f, 3.45f),
                        [1] = new float3(8.75f, 1.23f, 6.44f),
                        [2] = new float3(float.NegativeInfinity, 5.33f, -2.55f),
                        [3] = new float3(8.76f, 4.56f, -4.54f),
                        [4] = new float3(9.75f, -0.45f, -8.99f),
                        [5] = new float3(7.66f, 3.44f, 0.0f)
                    };
                    TestUtils.ThrowsException <ArgumentException>(
                        () => ConvexCollider.Create(invalidPoints, validBevelRadius, CollisionFilter.Default)
                        );
                    invalidPoints.Dispose();
                }

                // invalid point, NaN
                {
                    var invalidPoints = new NativeArray <float3>(6, Allocator.TempJob)
                    {
                        [0] = new float3(1.45f, 8.67f, 3.45f),
                        [1] = new float3(8.75f, 1.23f, 6.44f),
                        [2] = new float3(float.NaN, 5.33f, -2.55f),
                        [3] = new float3(8.76f, 4.56f, -4.54f),
                        [4] = new float3(9.75f, -0.45f, -8.99f),
                        [5] = new float3(7.66f, 3.44f, 0.0f)
                    };
                    TestUtils.ThrowsException <ArgumentException>(
                        () => ConvexCollider.Create(invalidPoints, validBevelRadius, CollisionFilter.Default)
                        );
                    invalidPoints.Dispose();
                }
            }

            // invalid convex radius
            {
                var points = new NativeArray <float3>(6, Allocator.TempJob)
                {
                    [0] = new float3(1.45f, 8.67f, 3.45f),
                    [1] = new float3(8.75f, 1.23f, 6.44f),
                    [2] = new float3(7.54f, 5.33f, -2.55f),
                    [3] = new float3(8.76f, 4.56f, -4.54f),
                    [4] = new float3(9.75f, -0.45f, -8.99f),
                    [5] = new float3(7.66f, 3.44f, 0.0f)
                };
                float3 scale = new float3(1.0f, 1.0f, 1.0f);
                var    invalidBevelRadius = new ConvexHullGenerationParameters();

                // negative convex radius
                {
                    invalidBevelRadius.BevelRadius = -0.30f;
                    TestUtils.ThrowsException <ArgumentException>(
                        () => ConvexCollider.Create(points, invalidBevelRadius, CollisionFilter.Default)
                        );
                }

                // +inf convex radius
                {
                    invalidBevelRadius.BevelRadius = float.PositiveInfinity;
                    TestUtils.ThrowsException <ArgumentException>(
                        () => ConvexCollider.Create(points, invalidBevelRadius, CollisionFilter.Default)
                        );
                }

                // -inf convex radius
                {
                    invalidBevelRadius.BevelRadius = float.NegativeInfinity;
                    TestUtils.ThrowsException <ArgumentException>(
                        () => ConvexCollider.Create(points, invalidBevelRadius, CollisionFilter.Default)
                        );
                }

                // nan convex radius
                {
                    invalidBevelRadius.BevelRadius = float.NaN;
                    TestUtils.ThrowsException <ArgumentException>(
                        () => ConvexCollider.Create(points, invalidBevelRadius, CollisionFilter.Default)
                        );
                }

                points.Dispose();
            }
        }
        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);
        }
    private void CreateRagdoll(float3 positionOffset, quaternion rotationOffset, int ragdollIndex = 1, bool internalCollisions = false)
    {
        var entities = new NativeList <Entity>(Allocator.Temp);

        // Head
        float  headRadius   = 0.1f;
        float3 headPosition = new float3(0, 1.8f, 0);
        Entity head;

        {
            CollisionFilter filter = internalCollisions ? layerFilter(layer.Head, layer.Torso) : groupFilter(-ragdollIndex);
            BlobAssetReference <Unity.Physics.Collider> collider = Unity.Physics.SphereCollider.Create(new SphereGeometry
            {
                Center = float3.zero,
                Radius = headRadius
            }, filter);
            head = CreateDynamicBody(headPosition, quaternion.identity, collider, float3.zero, float3.zero, 5.0f);
        }
        entities.Add(head);

        // Torso
        float3 torsoSize;
        float3 torsoPosition;
        Entity torso;

        {
            //UnityEngine.Mesh torsoMesh = (UnityEngine.Mesh)Resources.Load("torso", typeof(UnityEngine.Mesh));
            torsoSize     = torsoMesh.bounds.size;
            torsoPosition = headPosition - new float3(0, headRadius * 3.0f / 4.0f + torsoSize.y, 0);

            CollisionFilter filter = internalCollisions ? layerFilter(layer.Torso, layer.Thigh | layer.Head | layer.UpperArm | layer.Pelvis) : groupFilter(-ragdollIndex);

            NativeArray <float3> points = new NativeArray <float3>(torsoMesh.vertices.Length, Allocator.TempJob);
            for (int i = 0; i < torsoMesh.vertices.Length; i++)
            {
                points[i] = torsoMesh.vertices[i];
            }
            BlobAssetReference <Unity.Physics.Collider> collider = ConvexCollider.Create(
                points, ConvexHullGenerationParameters.Default, CollisionFilter.Default
                );
            points.Dispose();
            collider.Value.Filter = filter;
            torso = CreateDynamicBody(torsoPosition, quaternion.identity, collider, float3.zero, float3.zero, 20.0f);
        }
        entities.Add(torso);

        // Neck
        {
            float3 pivotHead          = new float3(0, -headRadius, 0);
            float3 pivotBody          = math.transform(math.inverse(GetBodyTransform(torso)), math.transform(GetBodyTransform(head), pivotHead));
            float3 axis               = new float3(0, 1, 0);
            float3 perpendicular      = new float3(0, 0, 1);
            float  coneAngle          = (float)math.PI / 5.0f;
            var    perpendicularAngle = new FloatRange {
                Max = math.PI
            };                                                         // unlimited
            var twistAngle = new FloatRange(-math.PI / 3f, math.PI / 3f);

            var headFrame = new BodyFrame {
                Axis = axis, PerpendicularAxis = perpendicular, Position = pivotHead
            };
            var bodyFrame = new BodyFrame {
                Axis = axis, PerpendicularAxis = perpendicular, Position = pivotBody
            };
            PhysicsJoint.CreateRagdoll(headFrame, bodyFrame, coneAngle, perpendicularAngle, twistAngle, out var ragdoll0, out var ragdoll1);
            CreateJoint(ragdoll0, head, torso);
            CreateJoint(ragdoll1, head, torso);
        }

        // Arms
        {
            float           armLength      = 0.25f;
            float           armRadius      = 0.05f;
            CollisionFilter armUpperFilter = internalCollisions ? layerFilter(layer.UpperArm, layer.Torso | layer.Forearm) : groupFilter(-ragdollIndex);
            CollisionFilter armLowerFilter = internalCollisions ? layerFilter(layer.Forearm, layer.UpperArm | layer.Hand) : groupFilter(-ragdollIndex);

            BlobAssetReference <Unity.Physics.Collider> upperArmCollider = Unity.Physics.CapsuleCollider.Create(new CapsuleGeometry
            {
                Vertex0 = new float3(-armLength / 2, 0, 0),
                Vertex1 = new float3(armLength / 2, 0, 0),
                Radius  = armRadius
            }, armUpperFilter);
            BlobAssetReference <Unity.Physics.Collider> foreArmCollider = Unity.Physics.CapsuleCollider.Create(new CapsuleGeometry
            {
                Vertex0 = new float3(-armLength / 2, 0, 0),
                Vertex1 = new float3(armLength / 2, 0, 0),
                Radius  = armRadius
            }, armLowerFilter);

            float           handLength = 0.025f;
            float           handRadius = 0.055f;
            CollisionFilter handFilter = internalCollisions ? layerFilter(layer.Hand, layer.Forearm) : groupFilter(-ragdollIndex);

            BlobAssetReference <Unity.Physics.Collider> handCollider = Unity.Physics.CapsuleCollider.Create(new CapsuleGeometry
            {
                Vertex0 = new float3(-handLength / 2, 0, 0),
                Vertex1 = new float3(handLength / 2, 0, 0),
                Radius  = handRadius
            }, handFilter);

            for (int i = 0; i < 2; i++)
            {
                float s = i * 2 - 1.0f;

                float3 upperArmPosition = torsoPosition + new float3(s * (torsoSize.x + armLength) / 2.0f, 0.9f * torsoSize.y - armRadius, 0.0f);
                Entity upperArm         = CreateDynamicBody(upperArmPosition, quaternion.identity, upperArmCollider, float3.zero, float3.zero, 10.0f);
                float3 foreArmPosition  = upperArmPosition + new float3(armLength * s, 0, 0);
                Entity foreArm          = CreateDynamicBody(foreArmPosition, quaternion.identity, foreArmCollider, float3.zero, float3.zero, 5.0f);
                float3 handPosition     = foreArmPosition + new float3((armLength + handLength) / 2.0f * s, 0, 0);
                Entity hand             = CreateDynamicBody(handPosition, quaternion.identity, handCollider, float3.zero, float3.zero, 2.0f);

                entities.Add(upperArm);
                entities.Add(foreArm);
                entities.Add(hand);

                // shoulder
                {
                    float3 pivotArm           = new float3(-s * armLength / 2.0f, 0, 0);
                    float3 pivotBody          = math.transform(math.inverse(GetBodyTransform(torso)), math.transform(GetBodyTransform(upperArm), pivotArm));
                    float3 axis               = new float3(s, 0, 0);
                    float3 perpendicular      = new float3(0, 0, 1);
                    float  coneAngle          = (float)math.PI / 2.0f;
                    var    perpendicularAngle = new FloatRange {
                        Max = math.PI / 2f
                    };
                    var twistAngle = new FloatRange(-math.PI / 4f, math.PI / 4f);

                    var armFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotArm
                    };
                    var bodyFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotBody
                    };
                    PhysicsJoint.CreateRagdoll(armFrame, bodyFrame, coneAngle, perpendicularAngle, twistAngle, out var ragdoll0, out var ragdoll1);
                    CreateJoint(ragdoll0, upperArm, torso);
                    CreateJoint(ragdoll1, upperArm, torso);
                }

                // elbow
                {
                    float3 pivotUpper    = new float3(s * armLength / 2.0f, 0, 0);
                    float3 pivotFore     = -pivotUpper;
                    float3 axis          = new float3(0, -s, 0);
                    float3 perpendicular = new float3(s, 0, 0);

                    var lowerArmFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotFore
                    };
                    var upperArmFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotUpper
                    };
                    PhysicsJoint hinge =
                        PhysicsJoint.CreateLimitedHinge(lowerArmFrame, upperArmFrame, new FloatRange {
                        Max = 3f
                    });
                    CreateJoint(hinge, foreArm, upperArm);
                }

                // wrist
                {
                    float3 pivotFore     = new float3(s * armLength / 2.0f, 0, 0);
                    float3 pivotHand     = new float3(-s * handLength / 2.0f, 0, 0);
                    float3 axis          = new float3(0, -s, 0);
                    float3 perpendicular = new float3(s, 0, 0);

                    var handFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotHand
                    };
                    var forearmFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotFore
                    };
                    PhysicsJoint hinge =
                        PhysicsJoint.CreateLimitedHinge(handFrame, forearmFrame, new FloatRange(-0.3f, 0.6f));
                    CreateJoint(hinge, hand, foreArm);
                }
            }
        }

        // Pelvis
        float  pelvisRadius   = 0.08f;
        float  pelvisLength   = 0.22f;
        float3 pelvisPosition = torsoPosition - new float3(0, pelvisRadius * 0.75f, 0.0f);
        Entity pelvis;

        {
            CollisionFilter filter = internalCollisions ? layerFilter(layer.Pelvis, layer.Torso | layer.Thigh) : groupFilter(-ragdollIndex);
            BlobAssetReference <Unity.Physics.Collider> collider = Unity.Physics.CapsuleCollider.Create(new CapsuleGeometry
            {
                Vertex0 = new float3(-pelvisLength / 2, 0, 0),
                Vertex1 = new float3(pelvisLength / 2, 0, 0),
                Radius  = pelvisRadius
            }, filter);
            pelvis = CreateDynamicBody(pelvisPosition, quaternion.identity, collider, float3.zero, float3.zero, 15.0f);
        }
        entities.Add(pelvis);

        // Waist
        {
            float3 pivotTorso         = float3.zero;
            float3 pivotPelvis        = math.transform(math.inverse(GetBodyTransform(pelvis)), math.transform(GetBodyTransform(torso), pivotTorso));
            float3 axis               = new float3(0, -1, 0);
            float3 perpendicular      = new float3(0, 0, 1);
            float  coneAngle          = 0.1f;
            var    perpendicularAngle = new FloatRange(-0.1f, math.PI);
            var    twistAngle         = new FloatRange(-0.1f, 0.1f);

            var pelvisFrame = new BodyFrame {
                Axis = axis, PerpendicularAxis = perpendicular, Position = pivotPelvis
            };
            var torsoFrame = new BodyFrame {
                Axis = axis, PerpendicularAxis = perpendicular, Position = pivotTorso
            };
            PhysicsJoint.CreateRagdoll(pelvisFrame, torsoFrame, coneAngle, perpendicularAngle, twistAngle, out var ragdoll0, out var ragdoll1);
            CreateJoint(ragdoll0, pelvis, torso);
            CreateJoint(ragdoll1, pelvis, torso);
        }

        // Legs
        {
            float           thighLength = 0.32f;
            float           thighRadius = 0.08f;
            CollisionFilter thighFilter = internalCollisions ? layerFilter(layer.Thigh, layer.Pelvis | layer.Calf) : groupFilter(-ragdollIndex);
            BlobAssetReference <Unity.Physics.Collider> thighCollider = Unity.Physics.CapsuleCollider.Create(new CapsuleGeometry
            {
                Vertex0 = new float3(0, -thighLength / 2, 0),
                Vertex1 = new float3(0, thighLength / 2, 0),
                Radius  = thighRadius
            }, thighFilter);

            float           calfLength = 0.32f;
            float           calfRadius = 0.06f;
            CollisionFilter calfFilter = internalCollisions ? layerFilter(layer.Calf, layer.Thigh | layer.Foot) : groupFilter(-ragdollIndex);
            BlobAssetReference <Unity.Physics.Collider> calfCollider = Unity.Physics.CapsuleCollider.Create(new CapsuleGeometry
            {
                Vertex0 = new float3(0, -calfLength / 2, 0),
                Vertex1 = new float3(0, calfLength / 2, 0),
                Radius  = calfRadius
            }, calfFilter);

            float           footLength = 0.08f;
            float           footRadius = 0.06f;
            CollisionFilter footFilter = internalCollisions ? layerFilter(layer.Foot, layer.Calf) : groupFilter(-ragdollIndex);
            BlobAssetReference <Unity.Physics.Collider> footCollider = Unity.Physics.CapsuleCollider.Create(new CapsuleGeometry
            {
                Vertex0 = new float3(0),
                Vertex1 = new float3(0, 0, footLength),
                Radius  = footRadius
            }, footFilter);

            for (int i = 0; i < 2; i++)
            {
                float s = i * 2 - 1.0f;

                float3 thighPosition = pelvisPosition + new float3(s * pelvisLength / 2.0f, -thighLength / 2.0f, 0.0f);
                Entity thigh         = CreateDynamicBody(thighPosition, quaternion.identity, thighCollider, float3.zero, float3.zero, 10.0f);
                float3 calfPosition  = thighPosition + new float3(0, -(thighLength + calfLength) / 2.0f, 0);
                Entity calf          = CreateDynamicBody(calfPosition, quaternion.identity, calfCollider, float3.zero, float3.zero, 5.0f);
                float3 footPosition  = calfPosition + new float3(0, -calfLength / 2.0f, 0);
                Entity foot          = CreateDynamicBody(footPosition, quaternion.identity, footCollider, float3.zero, float3.zero, 2.0f);

                entities.Add(thigh);
                entities.Add(calf);
                entities.Add(foot);

                // hip
                {
                    float3 pivotThigh    = new float3(0, thighLength / 2.0f, 0);
                    float3 pivotBody     = math.transform(math.inverse(GetBodyTransform(torso)), math.transform(GetBodyTransform(thigh), pivotThigh));
                    float3 axis          = new float3(0, -1, 0);
                    float3 perpendicular = new float3(s, 0, 0);
                    float  coneAngle     = (float)math.PI / 4.0f;

                    var perpendicularAngle = new FloatRange {
                        Max = 0.2f + math.PI / 2.0f
                    };
                    var twistAngle = new FloatRange(-0.2f, 0.2f);

                    var upperLegFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotThigh
                    };
                    var bodyFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotBody
                    };
                    PhysicsJoint.CreateRagdoll(upperLegFrame, bodyFrame, coneAngle, perpendicularAngle, twistAngle, out var ragdoll0, out var ragdoll1);
                    CreateJoint(ragdoll0, thigh, torso);
                    CreateJoint(ragdoll1, thigh, torso);
                }

                // knee
                {
                    float3 pivotThigh    = new float3(0, -thighLength / 2.0f, 0);
                    float3 pivotCalf     = math.transform(math.inverse(GetBodyTransform(calf)), math.transform(GetBodyTransform(thigh), pivotThigh));
                    float3 axis          = new float3(-1, 0, 0);
                    float3 perpendicular = new float3(0, 0, 1);

                    var lowerLegFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotCalf
                    };
                    var upperLegFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotThigh
                    };
                    PhysicsJoint hinge =
                        PhysicsJoint.CreateLimitedHinge(lowerLegFrame, upperLegFrame, new FloatRange {
                        Min = -1.2f
                    });
                    CreateJoint(hinge, calf, thigh);
                }

                // ankle
                {
                    float3 pivotCalf     = new float3(0, -calfLength / 2.0f, 0);
                    float3 pivotFoot     = float3.zero;
                    float3 axis          = new float3(-1, 0, 0);
                    float3 perpendicular = new float3(0, 0, 1);

                    var footFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotFoot
                    };
                    var lowerLegFrame = new BodyFrame {
                        Axis = axis, PerpendicularAxis = perpendicular, Position = pivotCalf
                    };
                    PhysicsJoint hinge =
                        PhysicsJoint.CreateLimitedHinge(footFrame, lowerLegFrame, new FloatRange(-0.4f, 0.1f));
                    CreateJoint(hinge, foot, calf);
                }
            }
        }

        var entityManager = BasePhysicsDemo.DefaultWorld.EntityManager;

        // reposition with offset information
        if (entities.Length > 0)
        {
            float3 center = float3.zero;
            for (int i = 0; i < entities.Length; i++)
            {
                var e = entities[i];
                center += entityManager.GetComponentData <Translation>(e).Value;
            }
            center /= entities.Length;
            for (int i = 0; i < entities.Length; i++)
            {
                var         e = entities[i];
                Translation positionComponent = entityManager.GetComponentData <Translation>(e);
                Rotation    rotationComponent = entityManager.GetComponentData <Rotation>(e);

                float3     position = positionComponent.Value;
                quaternion rotation = rotationComponent.Value;

                float3 localPosition = position - center;
                localPosition = math.rotate(rotationOffset, localPosition);

                position = localPosition + center + positionOffset;
                rotation = math.mul(rotation, rotationOffset);

                positionComponent.Value = position;
                rotationComponent.Value = rotation;

                entityManager.SetComponentData <Translation>(e, positionComponent);
                entityManager.SetComponentData <Rotation>(e, rotationComponent);
            }
        }
    }
        public void TestConvexColliderCreateInvalid()
        {
            // Invalid points
            {
                float convexRadius = 0.15f;

                // invalid point, +inf
                {
                    var invalidPoints = new NativeArray <float3>(6, Allocator.Temp)
                    {
                        [0] = new float3(1.45f, 8.67f, 3.45f),
                        [1] = new float3(8.75f, 1.23f, 6.44f),
                        [2] = new float3(float.PositiveInfinity, 5.33f, -2.55f),
                        [3] = new float3(8.76f, 4.56f, -4.54f),
                        [4] = new float3(9.75f, -0.45f, -8.99f),
                        [5] = new float3(7.66f, 3.44f, 0.0f)
                    };
                    TestUtils.ThrowsException <System.ArgumentException>(
                        () => ConvexCollider.Create(invalidPoints, convexRadius)
                        );
                    invalidPoints.Dispose();
                }

                // invalid point, -inf
                {
                    var invalidPoints = new NativeArray <float3>(6, Allocator.Temp)
                    {
                        [0] = new float3(1.45f, 8.67f, 3.45f),
                        [1] = new float3(8.75f, 1.23f, 6.44f),
                        [2] = new float3(float.NegativeInfinity, 5.33f, -2.55f),
                        [3] = new float3(8.76f, 4.56f, -4.54f),
                        [4] = new float3(9.75f, -0.45f, -8.99f),
                        [5] = new float3(7.66f, 3.44f, 0.0f),
                    };
                    TestUtils.ThrowsException <System.ArgumentException>(
                        () => ConvexCollider.Create(invalidPoints, convexRadius)
                        );
                    invalidPoints.Dispose();
                }

                // invalid point, NaN
                {
                    var invalidPoints = new NativeArray <float3>(6, Allocator.Temp)
                    {
                        [0] = new float3(1.45f, 8.67f, 3.45f),
                        [1] = new float3(8.75f, 1.23f, 6.44f),
                        [2] = new float3(float.NaN, 5.33f, -2.55f),
                        [3] = new float3(8.76f, 4.56f, -4.54f),
                        [4] = new float3(9.75f, -0.45f, -8.99f),
                        [5] = new float3(7.66f, 3.44f, 0.0f)
                    };
                    TestUtils.ThrowsException <System.ArgumentException>(
                        () => ConvexCollider.Create(invalidPoints, convexRadius)
                        );
                    invalidPoints.Dispose();
                }
            }

            // invalid convex radius
            {
                var points = new NativeArray <float3>(6, Allocator.Temp)
                {
                    [0] = new float3(1.45f, 8.67f, 3.45f),
                    [1] = new float3(8.75f, 1.23f, 6.44f),
                    [2] = new float3(7.54f, 5.33f, -2.55f),
                    [3] = new float3(8.76f, 4.56f, -4.54f),
                    [4] = new float3(9.75f, -0.45f, -8.99f),
                    [5] = new float3(7.66f, 3.44f, 0.0f)
                };
                float3 scale = new float3(1.0f, 1.0f, 1.0f);

                // negative convex radius
                {
                    float invalidConvexRadius = -0.30f;
                    TestUtils.ThrowsException <System.ArgumentException>(
                        () => ConvexCollider.Create(points, invalidConvexRadius)
                        );
                }

                // +inf convex radius
                {
                    float invalidConvexRadius = float.PositiveInfinity;
                    TestUtils.ThrowsException <System.ArgumentException>(
                        () => ConvexCollider.Create(points, invalidConvexRadius)
                        );
                }

                // -inf convex radius
                {
                    float invalidConvexRadius = float.NegativeInfinity;
                    TestUtils.ThrowsException <System.ArgumentException>(
                        () => ConvexCollider.Create(points, invalidConvexRadius)
                        );
                }

                // nan convex radius
                {
                    float invalidConvexRadius = float.NaN;
                    TestUtils.ThrowsException <System.ArgumentException>(
                        () => ConvexCollider.Create(points, invalidConvexRadius)
                        );
                }

                points.Dispose();
            }
        }
    private void CreateRagdoll(float3 positionOffset, quaternion rotationOffset, int ragdollIndex = 1, bool internalCollisions = false)
    {
        NativeList <Entity> entities = new NativeList <Entity>(Allocator.Temp);

        // Head
        float  headRadius   = 0.1f;
        float3 headPosition = new float3(0, 1.8f, 0);
        Entity head;

        {
            CollisionFilter filter = internalCollisions ? layerFilter(layer.Head, layer.Torso) : groupFilter(-ragdollIndex);
            BlobAssetReference <Unity.Physics.Collider> collider = Unity.Physics.SphereCollider.Create(float3.zero, headRadius, filter);
            head = CreateDynamicBody(headPosition, quaternion.identity, collider, float3.zero, float3.zero, 5.0f);
        }
        entities.Add(head);

        // Torso
        float3 torsoSize;
        float3 torsoPosition;
        Entity torso;

        {
            //UnityEngine.Mesh torsoMesh = (UnityEngine.Mesh)Resources.Load("torso", typeof(UnityEngine.Mesh));
            torsoSize     = torsoMesh.bounds.size;
            torsoPosition = headPosition - new float3(0, headRadius * 3.0f / 4.0f + torsoSize.y, 0);

            CollisionFilter filter = internalCollisions ? layerFilter(layer.Torso, layer.Thigh | layer.Head | layer.UpperArm | layer.Pelvis) : groupFilter(-ragdollIndex);

            NativeArray <float3> points = new NativeArray <float3>(torsoMesh.vertices.Length, Allocator.Temp);
            for (int i = 0; i < torsoMesh.vertices.Length; i++)
            {
                points[i] = torsoMesh.vertices[i];
            }
            BlobAssetReference <Unity.Physics.Collider> collider = ConvexCollider.Create(points, 0.01f);
            collider.Value.Filter = filter;
            torso = CreateDynamicBody(torsoPosition, quaternion.identity, collider, float3.zero, float3.zero, 20.0f);
        }
        entities.Add(torso);

        // Neck
        {
            float3 pivotHead             = new float3(0, -headRadius, 0);
            float3 pivotBody             = math.transform(math.inverse(GetBodyTransform(torso)), math.transform(GetBodyTransform(head), pivotHead));
            float3 axis                  = new float3(0, 1, 0);
            float3 perpendicular         = new float3(0, 0, 1);
            float  coneAngle             = (float)math.PI / 5.0f;
            float  minPerpendicularAngle = 0.0f;           // unlimited
            float  maxPerpendicularAngle = (float)math.PI; // unlimited
            float  twistAngle            = (float)math.PI / 3.0f;

            BlobAssetReference <JointData> ragdoll0, ragdoll1;
            JointData.CreateRagdoll(pivotHead, pivotBody, axis, axis, perpendicular, perpendicular,
                                    coneAngle, minPerpendicularAngle, maxPerpendicularAngle, -twistAngle, twistAngle,
                                    out ragdoll0, out ragdoll1);
            CreateJoint(ragdoll0, head, torso);
            CreateJoint(ragdoll1, head, torso);
        }

        // Arms
        {
            float           armLength      = 0.25f;
            float           armRadius      = 0.05f;
            CollisionFilter armUpperFilter = internalCollisions ? layerFilter(layer.UpperArm, layer.Torso | layer.Forearm) : groupFilter(-ragdollIndex);
            CollisionFilter armLowerFilter = internalCollisions ? layerFilter(layer.Forearm, layer.UpperArm | layer.Hand) : groupFilter(-ragdollIndex);

            BlobAssetReference <Unity.Physics.Collider> upperArmCollider = Unity.Physics.CapsuleCollider.Create(new float3(-armLength / 2, 0, 0), new float3(armLength / 2, 0, 0), armRadius,
                                                                                                                armUpperFilter);
            BlobAssetReference <Unity.Physics.Collider> foreArmCollider = Unity.Physics.CapsuleCollider.Create(new float3(-armLength / 2, 0, 0), new float3(armLength / 2, 0, 0), armRadius,
                                                                                                               armLowerFilter);

            float           handLength = 0.025f;
            float           handRadius = 0.055f;
            CollisionFilter handFilter = internalCollisions ? layerFilter(layer.Hand, layer.Forearm) : groupFilter(-ragdollIndex);

            BlobAssetReference <Unity.Physics.Collider> handCollider = Unity.Physics.CapsuleCollider.Create(new float3(-handLength / 2, 0, 0), new float3(handLength / 2, 0, 0), handRadius,
                                                                                                            handFilter);

            for (int i = 0; i < 2; i++)
            {
                float s = i * 2 - 1.0f;

                float3 upperArmPosition = torsoPosition + new float3(s * (torsoSize.x + armLength) / 2.0f, 0.9f * torsoSize.y - armRadius, 0.0f);
                Entity upperArm         = CreateDynamicBody(upperArmPosition, quaternion.identity, upperArmCollider, float3.zero, float3.zero, 10.0f);
                float3 foreArmPosition  = upperArmPosition + new float3(armLength * s, 0, 0);
                Entity foreArm          = CreateDynamicBody(foreArmPosition, quaternion.identity, foreArmCollider, float3.zero, float3.zero, 5.0f);
                float3 handPosition     = foreArmPosition + new float3((armLength + handLength) / 2.0f * s, 0, 0);
                Entity hand             = CreateDynamicBody(handPosition, quaternion.identity, handCollider, float3.zero, float3.zero, 2.0f);

                entities.Add(upperArm);
                entities.Add(foreArm);
                entities.Add(hand);

                // shoulder
                {
                    float3 pivotArm              = new float3(-s * armLength / 2.0f, 0, 0);
                    float3 pivotBody             = math.transform(math.inverse(GetBodyTransform(torso)), math.transform(GetBodyTransform(upperArm), pivotArm));
                    float3 axis                  = new float3(s, 0, 0);
                    float3 perpendicular         = new float3(0, 0, 1);
                    float  coneAngle             = (float)math.PI / 2.0f;
                    float  minPerpendicularAngle = 0.0f;
                    float  maxPerpendicularAngle = (float)math.PI / 2.0f;
                    float  twistAngle            = (float)math.PI / 4.0f;

                    BlobAssetReference <JointData> ragdoll0, ragdoll1;
                    JointData.CreateRagdoll(pivotArm, pivotBody, axis, axis, perpendicular, perpendicular,
                                            coneAngle, minPerpendicularAngle, maxPerpendicularAngle, -twistAngle, twistAngle,
                                            out ragdoll0, out ragdoll1);
                    CreateJoint(ragdoll0, upperArm, torso);
                    CreateJoint(ragdoll1, upperArm, torso);
                }

                // elbow
                {
                    float3 pivotUpper    = new float3(s * armLength / 2.0f, 0, 0);
                    float3 pivotFore     = -pivotUpper;
                    float3 axis          = new float3(0, -s, 0);
                    float3 perpendicular = new float3(s, 0, 0);
                    float  minAngle      = 0.0f;
                    float  maxAngle      = 3.0f;

                    BlobAssetReference <JointData> hinge = JointData.CreateLimitedHinge(pivotFore, pivotUpper, axis, axis, perpendicular, perpendicular, minAngle, maxAngle);
                    CreateJoint(hinge, foreArm, upperArm);
                }

                // wrist
                {
                    float3 pivotFore     = new float3(s * armLength / 2.0f, 0, 0);
                    float3 pivotHand     = new float3(-s * handLength / 2.0f, 0, 0);
                    float3 axis          = new float3(0, -s, 0);
                    float3 perpendicular = new float3(s, 0, 0);
                    float  minAngle      = -0.3f;
                    float  maxAngle      = 0.6f;

                    BlobAssetReference <JointData> hinge = JointData.CreateLimitedHinge(pivotHand, pivotFore, axis, axis, perpendicular, perpendicular, minAngle, maxAngle);
                    CreateJoint(hinge, hand, foreArm);
                }
            }
        }

        // Pelvis
        float  pelvisRadius   = 0.08f;
        float  pelvisLength   = 0.22f;
        float3 pelvisPosition = torsoPosition - new float3(0, pelvisRadius * 0.75f, 0.0f);
        Entity pelvis;

        {
            CollisionFilter filter = internalCollisions ? layerFilter(layer.Pelvis, layer.Torso | layer.Thigh) : groupFilter(-ragdollIndex);
            BlobAssetReference <Unity.Physics.Collider> collider = Unity.Physics.CapsuleCollider.Create(new float3(-pelvisLength / 2.0f, 0, 0), new float3(pelvisLength / 2.0f, 0, 0), pelvisRadius,
                                                                                                        filter);
            pelvis = CreateDynamicBody(pelvisPosition, quaternion.identity, collider, float3.zero, float3.zero, 15.0f);
        }
        entities.Add(pelvis);

        // Waist
        {
            float3 pivotTorso            = float3.zero;
            float3 pivotPelvis           = math.transform(math.inverse(GetBodyTransform(pelvis)), math.transform(GetBodyTransform(torso), pivotTorso));
            float3 axis                  = new float3(0, -1, 0);
            float3 perpendicular         = new float3(0, 0, 1);
            float  coneAngle             = 0.1f;
            float  minPerpendicularAngle = -0.1f;
            float  maxPerpendicularAngle = (float)math.PI;
            float  twistAngle            = 0.1f;

            BlobAssetReference <JointData> ragdoll0, ragdoll1;
            JointData.CreateRagdoll(pivotPelvis, pivotTorso, axis, axis, perpendicular, perpendicular,
                                    coneAngle, minPerpendicularAngle, maxPerpendicularAngle, -twistAngle, twistAngle,
                                    out ragdoll0, out ragdoll1);
            CreateJoint(ragdoll0, pelvis, torso);
            CreateJoint(ragdoll1, pelvis, torso);
        }

        // Legs
        {
            float           thighLength = 0.32f;
            float           thighRadius = 0.08f;
            CollisionFilter thighFilter = internalCollisions ? layerFilter(layer.Thigh, layer.Pelvis | layer.Calf) : groupFilter(-ragdollIndex);
            BlobAssetReference <Unity.Physics.Collider> thighCollider = Unity.Physics.CapsuleCollider.Create(new float3(0, -thighLength / 2, 0), new float3(0, thighLength / 2, 0), thighRadius,
                                                                                                             thighFilter);

            float           calfLength = 0.32f;
            float           calfRadius = 0.06f;
            CollisionFilter calfFilter = internalCollisions ? layerFilter(layer.Calf, layer.Thigh | layer.Foot) : groupFilter(-ragdollIndex);
            BlobAssetReference <Unity.Physics.Collider> calfCollider = Unity.Physics.CapsuleCollider.Create(new float3(0, -calfLength / 2, 0), new float3(0, calfLength / 2, 0), calfRadius,
                                                                                                            calfFilter);

            float           footLength = 0.08f;
            float           footRadius = 0.06f;
            CollisionFilter footFilter = internalCollisions ? layerFilter(layer.Foot, layer.Calf) : groupFilter(-ragdollIndex);
            BlobAssetReference <Unity.Physics.Collider> footCollider = Unity.Physics.CapsuleCollider.Create(new float3(0, 0, 0), new float3(0, 0, footLength), footRadius,
                                                                                                            footFilter);

            for (int i = 0; i < 2; i++)
            {
                float s = i * 2 - 1.0f;

                float3 thighPosition = pelvisPosition + new float3(s * pelvisLength / 2.0f, -thighLength / 2.0f, 0.0f);
                Entity thigh         = CreateDynamicBody(thighPosition, quaternion.identity, thighCollider, float3.zero, float3.zero, 10.0f);
                float3 calfPosition  = thighPosition + new float3(0, -(thighLength + calfLength) / 2.0f, 0);
                Entity calf          = CreateDynamicBody(calfPosition, quaternion.identity, calfCollider, float3.zero, float3.zero, 5.0f);
                float3 footPosition  = calfPosition + new float3(0, -calfLength / 2.0f, 0);
                Entity foot          = CreateDynamicBody(footPosition, quaternion.identity, footCollider, float3.zero, float3.zero, 2.0f);

                entities.Add(thigh);
                entities.Add(calf);
                entities.Add(foot);

                // hip
                {
                    float3 pivotThigh            = new float3(0, thighLength / 2.0f, 0);
                    float3 pivotBody             = math.transform(math.inverse(GetBodyTransform(torso)), math.transform(GetBodyTransform(thigh), pivotThigh));
                    float3 axis                  = new float3(0, -1, 0);
                    float3 perpendicular         = new float3(s, 0, 0);
                    float  coneAngle             = (float)math.PI / 4.0f;
                    float  minPerpendicularAngle = 0.0f;
                    float  maxPerpendicularAngle = 0.2f + (float)math.PI / 2.0f;
                    float  twistAngle            = 0.2f;

                    BlobAssetReference <JointData> ragdoll0, ragdoll1;
                    JointData.CreateRagdoll(pivotThigh, pivotBody, axis, axis, perpendicular, perpendicular,
                                            coneAngle, minPerpendicularAngle, maxPerpendicularAngle, -twistAngle, twistAngle,
                                            out ragdoll0, out ragdoll1);
                    CreateJoint(ragdoll0, thigh, torso);
                    CreateJoint(ragdoll1, thigh, torso);
                }

                // knee
                {
                    float3 pivotThigh    = new float3(0, -thighLength / 2.0f, 0);
                    float3 pivotCalf     = math.transform(math.inverse(GetBodyTransform(calf)), math.transform(GetBodyTransform(thigh), pivotThigh));
                    float3 axis          = new float3(-1, 0, 0);
                    float3 perpendicular = new float3(0, 0, 1);
                    float  minAngle      = -1.2f;
                    float  maxAngle      = 0.0f;

                    BlobAssetReference <JointData> hinge = JointData.CreateLimitedHinge(pivotCalf, pivotThigh, axis, axis, perpendicular, perpendicular, minAngle, maxAngle);
                    CreateJoint(hinge, calf, thigh);
                }

                // ankle
                {
                    float3 pivotCalf     = new float3(0, -calfLength / 2.0f, 0);
                    float3 pivotFoot     = float3.zero;
                    float3 axis          = new float3(-1, 0, 0);
                    float3 perpendicular = new float3(0, 0, 1);
                    float  minAngle      = -0.4f;
                    float  maxAngle      = 0.1f;

                    BlobAssetReference <JointData> hinge = JointData.CreateLimitedHinge(pivotFoot, pivotCalf, axis, axis, perpendicular, perpendicular, minAngle, maxAngle);
                    CreateJoint(hinge, foot, calf);
                }
            }
        }

        // reposition with offset information
        if (entities.Length > 0)
        {
            float3 center = float3.zero;
            for (int i = 0; i < entities.Length; i++)
            {
                var e = entities[i];
                center += EntityManager.GetComponentData <Translation>(e).Value;
            }
            center /= entities.Length;
            for (int i = 0; i < entities.Length; i++)
            {
                var         e = entities[i];
                Translation positionComponent = EntityManager.GetComponentData <Translation>(e);
                Rotation    rotationComponent = EntityManager.GetComponentData <Rotation>(e);

                float3     position = positionComponent.Value;
                quaternion rotation = rotationComponent.Value;

                float3 localPosition = position - center;
                localPosition = math.rotate(rotationOffset, localPosition);

                position = localPosition + center + positionOffset;
                rotation = math.mul(rotation, rotationOffset);

                positionComponent.Value = position;
                rotationComponent.Value = rotation;

                EntityManager.SetComponentData <Translation>(e, positionComponent);
                EntityManager.SetComponentData <Rotation>(e, rotationComponent);
            }
        }
    }