protected override unsafe void Start()
    {
        init(); // no gravity

        Entity *entities = stackalloc Entity[2];

        entities[1] = Entity.Null;
        for (int i = 0; i < 1; i++)
        {
            CollisionFilter filter = new CollisionFilter
            {
                CollidesWith = (uint)(1 << i),
                BelongsTo    = (uint)~(1 << (1 - i))
            };
            BlobAssetReference <Collider> collider = BoxCollider.Create(
                new BoxGeometry
            {
                Center      = float3.zero,
                Orientation = quaternion.identity,
                Size        = new float3(1.0f, 0.2f, 0.2f),
                BevelRadius = 0.0f
            },
                filter, Material.Default);
            entities[i] = CreateDynamicBody(float3.zero, quaternion.identity, collider, float3.zero, new float3(0, 1 - i, 0), 1.0f);
        }

        var jointFrame = new BodyFrame {
            Axis = new float3(0, 1, 0), PerpendicularAxis = new float3(0, 0, 1)
        };
        PhysicsJoint hingeData =
            PhysicsJoint.CreateLimitedHinge(jointFrame, jointFrame, new FloatRange(-math.PI, -0.2f));

        CreateJoint(hingeData, entities[0], entities[1]);
    }
Ejemplo n.º 2
0
    public static PhysicsJoint CreateKnee(GameObject upperLeg, GameObject lowerLeg)
    {
        float upperLegHeight = 2.0f * upperLeg.transform.localScale.y;

        float3 pivotUpperLeg = new float3(0, -upperLegHeight / 2.0f, 0);

        var lowerLegTransform = new RigidTransform(lowerLeg.transform.rotation, lowerLeg.transform.position);
        var upperLegTransform = new RigidTransform(upperLeg.transform.rotation, upperLeg.transform.position);

        float3 pivotLowerLeg = math.transform(math.inverse(lowerLegTransform), math.transform(upperLegTransform, pivotUpperLeg));

        float3 axis          = new float3(1, 0, 0);
        float3 perpendicular = new float3(0, 0, 1);

        var jointFrameUpperLeg = new BodyFrame {
            Axis = axis, PerpendicularAxis = perpendicular, Position = pivotUpperLeg
        };
        var jointFrameLowerLeg = new BodyFrame {
            Axis = axis, PerpendicularAxis = perpendicular, Position = pivotLowerLeg
        };

        return(PhysicsJoint.CreateLimitedHinge(jointFrameUpperLeg, jointFrameLowerLeg, new FloatRange {
            Min = -1.2f
        }));
    }
Ejemplo n.º 3
0
    public static PhysicsJoint CreateElbow(GameObject upperArm, GameObject lowerArm)
    {
        float upperArmLength = 2 * upperArm.transform.localScale.y;
        float lowerArmLength = 2 * lowerArm.transform.localScale.y;

        float sign = math.sign(-1.0f * upperArm.transform.position.x);

        float3 pivotUpper = new float3(-1.0f * sign * upperArmLength / 2.0f, 0, 0);
        float3 pivotLower = new float3(sign * lowerArmLength / 2.0f, 0, 0);

        pivotUpper = math.rotate(math.inverse(upperArm.transform.rotation), pivotUpper);
        pivotLower = math.rotate(math.inverse(lowerArm.transform.rotation), pivotLower);
        float3 axis          = new float3(0, 0, 1);
        float3 perpendicular = new float3(0, 1, 0);

        var jointFrameUpperArm = new BodyFrame {
            Axis = axis, PerpendicularAxis = perpendicular, Position = pivotUpper
        };
        var jointFrameLowerArm = new BodyFrame {
            Axis = axis, PerpendicularAxis = perpendicular, Position = pivotLower
        };

        return(PhysicsJoint.CreateLimitedHinge(jointFrameUpperArm, jointFrameLowerArm, new FloatRange {
            Max = 3f
        }));
    }
Ejemplo n.º 4
0
    public static PhysicsJoint CreateWrist(GameObject lowerArm, GameObject hand)
    {
        float armLength  = 2.0f * lowerArm.transform.localScale.y;
        float handLength = 2.0f * hand.transform.localScale.y;

        float sign = math.sign(-1.0f * lowerArm.transform.position.x);

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

        var jointFrameForearm = new BodyFrame {
            Axis = axis, PerpendicularAxis = perpendicular, Position = pivotFore
        };
        var jointFrameHand = new BodyFrame {
            Axis = axis, PerpendicularAxis = perpendicular, Position = pivotHand
        };

        return(PhysicsJoint.CreateLimitedHinge(jointFrameForearm, jointFrameHand, new FloatRange(-0.3f, 0.6f)));
    }
Ejemplo n.º 5
0
    public static PhysicsJoint CreateAnkle(GameObject lowerLeg, GameObject foot)
    {
        float lowerLegLength = 2.0f * lowerLeg.transform.localScale.y;

        var lowerLegTransform = new RigidTransform(lowerLeg.transform.rotation, lowerLeg.transform.position);
        var footTransform     = new RigidTransform(foot.transform.rotation, foot.transform.position);

        float3 pivotLowerLeg = new float3(0, -lowerLegLength / 2.0f, 0);
        float3 pivotFoot     = math.transform(math.inverse(footTransform), math.transform(lowerLegTransform, pivotLowerLeg));

        float3 axis          = new float3(1, 0, 0);
        float3 perpendicular = new float3(0, 0, 1);

        var jointFrameLowerLeg = new BodyFrame {
            Axis = axis, PerpendicularAxis = perpendicular, Position = pivotLowerLeg
        };
        var jointFrameFoot = new BodyFrame {
            Axis = axis, PerpendicularAxis = perpendicular, Position = pivotFoot
        };

        return(PhysicsJoint.CreateLimitedHinge(jointFrameLowerLeg, jointFrameFoot, new FloatRange(-0.4f, 0.1f)));
    }
Ejemplo n.º 6
0
 public override void Create(EntityManager entityManager, GameObjectConversionSystem conversionSystem)
 {
     UpdateAuto();
     conversionSystem.World.GetOrCreateSystem <EndJointConversionSystem>().CreateJointEntity(
         this,
         GetConstrainedBodyPair(conversionSystem),
         PhysicsJoint.CreateLimitedHinge(
             new BodyFrame
     {
         Axis = math.normalize(HingeAxisLocal),
         PerpendicularAxis = math.normalize(PerpendicularAxisLocal),
         Position          = PositionLocal
     },
             new BodyFrame
     {
         Axis = math.normalize(HingeAxisInConnectedEntity),
         PerpendicularAxis = math.normalize(PerpendicularAxisInConnectedEntity),
         Position          = PositionInConnectedEntity
     },
             math.radians(new FloatRange(MinAngle, MaxAngle))
             )
         );
 }
Ejemplo n.º 7
0
        void ConvertHingeJoint(LegacyHinge joint)
        {
            RigidTransform worldFromBodyA = Math.DecomposeRigidBodyTransform(joint.transform.localToWorldMatrix);
            RigidTransform worldFromBodyB = joint.connectedBody == null
                ? RigidTransform.identity
                : Math.DecomposeRigidBodyTransform(joint.connectedBody.transform.localToWorldMatrix);

            Math.CalculatePerpendicularNormalized(joint.axis, out float3 perpendicularA, out _);
            var bodyAFromJoint = new BodyFrame
            {
                Axis = joint.axis,
                PerpendicularAxis = perpendicularA,
                Position          = joint.anchor
            };

            var connectedEntity          = GetPrimaryEntity(joint.connectedBody);
            var isConnectedBodyConverted =
                joint.connectedBody == null || connectedEntity != Entity.Null;

            RigidTransform bFromA       = isConnectedBodyConverted ? math.mul(math.inverse(worldFromBodyB), worldFromBodyA) : worldFromBodyA;
            RigidTransform bFromBSource =
                isConnectedBodyConverted ? RigidTransform.identity : worldFromBodyB;

            var bodyBFromJoint = new BodyFrame
            {
                Axis = math.mul(bFromA.rot, joint.axis),
                PerpendicularAxis = math.mul(bFromA.rot, perpendicularA),
                Position          = math.mul(bFromBSource, new float4(joint.connectedAnchor, 1f)).xyz
            };

            var limits    = math.radians(new FloatRange(joint.limits.min, joint.limits.max).Sorted());
            var jointData = joint.useLimits
                ? PhysicsJoint.CreateLimitedHinge(bodyAFromJoint, bodyBFromJoint, limits)
                : PhysicsJoint.CreateHinge(bodyAFromJoint, bodyBFromJoint);

            m_EndJointConversionSystem.CreateJointEntity(joint, GetConstrainedBodyPair(joint), jointData);
        }
    public static PhysicsJoint CreateJoint(GameObject parentBody, GameObject childBody, BasicJointInfo.BasicJointType jointType)
    {
        var bodyPBounds = parentBody.GetComponent <MeshRenderer>().bounds;
        var bodyCBounds = childBody.GetComponent <MeshRenderer>().bounds;

        var pointConPWorld = bodyPBounds.ClosestPoint(bodyCBounds.center);
        var pointPonCWorld = bodyCBounds.ClosestPoint(bodyPBounds.center);

        var bodyPTransform = new RigidTransform(parentBody.transform.rotation, parentBody.transform.position); // was torso
        var bodyCTransform = new RigidTransform(childBody.transform.rotation, childBody.transform.position);   // was head

        PhysicsJoint jointData = default;

        switch (jointType)
        {
        case BasicJointInfo.BasicJointType.BallAndSocket:
        {
            var pivotP = math.transform(math.inverse(bodyPTransform), pointConPWorld);
            var pivotC = math.transform(math.inverse(bodyCTransform), pointConPWorld);
            jointData = PhysicsJoint.CreateBallAndSocket(pivotP, pivotC);
        }
        break;

        case BasicJointInfo.BasicJointType.Distance:
        {
            var pivotP = math.transform(math.inverse(bodyPTransform), pointConPWorld);
            var pivotC = math.transform(math.inverse(bodyCTransform), pointPonCWorld);
            var range  = new FloatRange(0, math.distance(pointConPWorld, pointPonCWorld));
            jointData = PhysicsJoint.CreateLimitedDistance(pivotP, pivotC, range);
        }
        break;

        case BasicJointInfo.BasicJointType.Hinge:
        {
            var commonPivotPointWorld = math.lerp(pointConPWorld, pointPonCWorld, 0.5f);

            // assume a vertical hinge joint
            var axisP = math.rotate(math.inverse(bodyPTransform.rot), math.up());
            var axisC = math.rotate(math.inverse(bodyCTransform.rot), math.up());

            float3 perpendicularAxisA, perpendicularAxisB;
            Math.CalculatePerpendicularNormalized(axisP, out perpendicularAxisA, out _);
            Math.CalculatePerpendicularNormalized(axisC, out perpendicularAxisB, out _);

            var pivotP      = math.transform(math.inverse(bodyPTransform), commonPivotPointWorld);
            var pivotC      = math.transform(math.inverse(bodyCTransform), commonPivotPointWorld);
            var jointFrameP = new BodyFrame {
                Axis = axisP, PerpendicularAxis = perpendicularAxisA, Position = pivotP
            };
            var jointFrameC = new BodyFrame {
                Axis = axisC, PerpendicularAxis = perpendicularAxisB, Position = pivotC
            };
            var range = new FloatRange(math.radians(-90), math.radians(90.0f));
            jointData = PhysicsJoint.CreateLimitedHinge(jointFrameP, jointFrameC, range);
        }
        break;

        default:
            break;
        }
        return(jointData);
    }
Ejemplo n.º 9
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);
            }
        }
    }
    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 override void CreateScene(SoftJointDemoScene sceneSettings)
    {
        // Make soft ball and sockets
        {
            BlobAssetReference <Unity.Physics.Collider> collider = Unity.Physics.BoxCollider.Create(new BoxGeometry
            {
                Center      = float3.zero,
                Orientation = quaternion.identity,
                Size        = new float3(0.2f, 0.2f, 0.2f),
                BevelRadius = 0.0f
            });
            CreatedColliders.Add(collider);

            // Make joints with different spring frequency.  The leftmost joint should oscillate at 0.5hz, the next at 1hz, the next at 1.5hz, etc.
            for (int i = 0; i < 10; i++)
            {
                // Create a body
                float3 position = new float3((i - 4.5f) * 1.0f, 0, 0);
                float3 velocity = new float3(0, -10.0f, 0);
                Entity body     = CreateDynamicBody(
                    position, quaternion.identity, collider, velocity, float3.zero, 1.0f);

                // Create the ball and socket joint
                float3 pivotLocal   = float3.zero;
                float3 pivotInWorld = math.transform(GetBodyTransform(body), pivotLocal);

                var jointData   = PhysicsJoint.CreateBallAndSocket(pivotLocal, pivotInWorld);
                var constraints = jointData.GetConstraints();
                var constraint  = constraints[0];
                // Choose a small damping value instead of 0 to improve stability of the joints
                constraint.SpringDamping   = 0.05f;
                constraint.SpringFrequency = 0.5f * (float)(i + 1);
                constraints[0]             = constraint;
                jointData.SetConstraints(constraints);

                CreateJoint(jointData, body, Entity.Null);
            }
        }

        //Make soft limited hinges
        {
            BlobAssetReference <Unity.Physics.Collider> collider = Unity.Physics.BoxCollider.Create(new BoxGeometry
            {
                Center      = float3.zero,
                Orientation = quaternion.identity,
                Size        = new float3(0.4f, 0.1f, 0.6f),
                BevelRadius = 0.0f
            });
            CreatedColliders.Add(collider);

            // First row has soft limit with hard hinge + pivot, second row has everything soft
            for (int j = 0; j < 2; j++)
            {
                for (int i = 0; i < 10; i++)
                {
                    // Create a body
                    float3 position        = new float3((i - 4.5f) * 1.0f, 0, (j + 1) * 3.0f);
                    float3 velocity        = new float3(0, -10.0f, 0);
                    float3 angularVelocity = new float3(0, 0, -10.0f);
                    Entity body            = CreateDynamicBody(
                        position, quaternion.identity, collider, velocity, angularVelocity, 1.0f);

                    // Create the limited hinge joint
                    float3 pivotLocal           = new float3(0, 0, 0);
                    float3 pivotInWorld         = math.transform(GetBodyTransform(body), pivotLocal);
                    float3 axisLocal            = new float3(0, 0, 1);
                    float3 axisInWorld          = axisLocal;
                    float3 perpendicularLocal   = new float3(0, 1, 0);
                    float3 perpendicularInWorld = perpendicularLocal;

                    var frameLocal = new BodyFrame {
                        Axis = axisLocal, PerpendicularAxis = perpendicularLocal, Position = pivotLocal
                    };
                    var frameWorld = new BodyFrame {
                        Axis = axisInWorld, PerpendicularAxis = perpendicularInWorld, Position = pivotInWorld
                    };
                    var jointData = PhysicsJoint.CreateLimitedHinge(frameLocal, frameWorld, default);

                    // First constraint is the limit, next two are the hinge and pivot
                    var constraints = jointData.GetConstraints();
                    for (int k = 0; k < 1 + 2 * j; k++)
                    {
                        var constraint = constraints[k];
                        // Choose a small damping value instead of 0 to improve stability of the joints
                        constraint.SpringDamping   = 0.05f;
                        constraint.SpringFrequency = 0.5f * (i + 1);
                        constraints[k]             = constraint;
                    }
                    jointData.SetConstraints(constraints);

                    CreateJoint(jointData, body, Entity.Null);
                }
            }
        }

        // Make a soft prismatic
        {
            BlobAssetReference <Unity.Physics.Collider> collider = Unity.Physics.BoxCollider.Create(new BoxGeometry
            {
                Center      = float3.zero,
                Orientation = quaternion.identity,
                Size        = new float3(0.2f, 0.2f, 0.2f),
                BevelRadius = 0.0f
            });
            CreatedColliders.Add(collider);

            // Create a body
            float3 position = new float3(0, 0, 9.0f);
            float3 velocity = new float3(50.0f, 0, 0);
            Entity body     = CreateDynamicBody(
                position, quaternion.identity, collider, velocity, float3.zero, 1.0f);

            // Create the prismatic joint
            float3 pivotLocal           = float3.zero;
            float3 pivotInWorld         = math.transform(GetBodyTransform(body), pivotLocal);
            float3 axisLocal            = new float3(1, 0, 0);
            float3 axisInWorld          = axisLocal;
            float3 perpendicularLocal   = new float3(0, 1, 0);
            float3 perpendicularInWorld = perpendicularLocal;

            var localFrame = new BodyFrame {
                Axis = axisLocal, PerpendicularAxis = perpendicularLocal, Position = pivotLocal
            };
            var worldFrame = new BodyFrame {
                Axis = axisInWorld, PerpendicularAxis = perpendicularInWorld, Position = pivotInWorld
            };
            var jointData   = PhysicsJoint.CreatePrismatic(localFrame, worldFrame, new FloatRange(-2f, 2f));
            var constraints = jointData.GetConstraints();
            var constraint  = constraints[0];
            // Choose a small damping value instead of 0 to improve stability of the joints
            constraint.SpringDamping   = 0.05f;
            constraint.SpringFrequency = 5.0f;
            constraints[0]             = constraint;
            jointData.SetConstraints(constraints);
            CreateJoint(jointData, body, Entity.Null);
        }
    }