Esempio n. 1
0
        private BodyDescription CreateBoxDescription(float width, float height, float lenght)
        {
            var boxShape      = new Box(width, height, lenght);
            var boxShapeIndex = Simulation.Shapes.Add(boxShape);

            boxShape.ComputeInertia(1, out var boxInertia);
            Symmetric3x3.Scale(boxInertia.InverseInertiaTensor, .5f, out boxInertia.InverseInertiaTensor);
            var boxDescription = new BodyDescription()
            {
                LocalInertia = boxInertia,
                Pose         = new RigidPose
                {
                    Position    = Vector3.Zero,
                    Orientation = Quaternion.Identity
                },
                Activity = new BodyActivityDescription {
                    MinimumTimestepCountUnderThreshold = 32, SleepThreshold = .01f
                },
                Collidable = new CollidableDescription {
                    Shape = boxShapeIndex, SpeculativeMargin = .1f
                },
            };

            return(boxDescription);
        }
Esempio n. 2
0
        public override void Initialize(ContentArchive content, Camera camera)
        {
            camera.Position = new Vector3(-30, 8, -60);
            camera.Yaw      = MathHelper.Pi * 3f / 4;
            camera.Pitch    = 0;


            _poseIntegrator = new DefaultPoseIntegratorCallbacks(BufferPool);

            Simulation = Simulation.Create(BufferPool, new DefaultNarrowPhaseCallbacks(), _poseIntegrator);


            var boxShape  = new Box(1, 1, 1);
            var baseShape = new Box(5, 1, 5);


            boxShape.ComputeInertia(1000, out var boxInertia);

            var boxShapeIndex  = Simulation.Shapes.Add(boxShape);
            var baseShapeIndex = Simulation.Shapes.Add(baseShape);

            Symmetric3x3.Scale(boxInertia.InverseInertiaTensor, .5f, out boxInertia.InverseInertiaTensor);

            var boxDescription = new BodyDescription
            {
                //Make the uppermost block kinematic to hold up the rest of the chain.
                LocalInertia = boxInertia,
                Pose         = new RigidPose
                {
                    Position    = new Vector3(0, -2, 0),
                    Orientation = Quaternion.Identity
                },
                Activity = new BodyActivityDescription {
                    MinimumTimestepCountUnderThreshold = 32, SleepThreshold = .01f
                },
                Collidable = new CollidableDescription {
                    Shape = boxShapeIndex, SpeculativeMargin = .1f
                },
            };


            var baseDescription = new BodyDescription
            {
                //Make the uppermost block kinematic to hold up the rest of the chain.
                LocalInertia = new BodyInertia(),
                Pose         = new RigidPose
                {
                    Position    = new Vector3(0, 0, 0),
                    Orientation = Quaternion.Identity
                },
                Activity = new BodyActivityDescription {
                    MinimumTimestepCountUnderThreshold = 32, SleepThreshold = .01f
                },
                Collidable = new CollidableDescription {
                    Shape = baseShapeIndex, SpeculativeMargin = .1f
                },
            };

            var boxIndex  = Simulation.Bodies.Add(boxDescription);
            var baseIndex = Simulation.Bodies.Add(baseDescription);

            _boxReference  = new BodyReference(boxIndex, Simulation.Bodies);
            _baseReference = new BodyReference(baseIndex, Simulation.Bodies);
        }
Esempio n. 3
0
        public static void Test()
        {
            var random = new Random(4);
            var timer  = new Stopwatch();
            var symmetricVectorSandwichTime        = 0.0;
            var symmetricWideVectorSandwichTime    = 0.0;
            var triangularWideVectorSandwichTime   = 0.0;
            var symmetricWide2x3SandwichTime       = 0.0;
            var triangularWide2x3SandwichTime      = 0.0;
            var symmetricSkewSandwichTime          = 0.0;
            var symmetricWideSkewSandwichTime      = 0.0;
            var triangularWideSkewSandwichTime     = 0.0;
            var symmetricRotationSandwichTime      = 0.0;
            var symmetricWideRotationSandwichTime  = 0.0;
            var triangularWideRotationSandwichTime = 0.0;
            var symmetricInvertTime      = 0.0;
            var symmetricWideInvertTime  = 0.0;
            var triangularWideInvertTime = 0.0;

            for (int i = 0; i < 1000; ++i)
            {
                var axis = Vector3.Normalize(new Vector3((float)random.NextDouble() * 2 - 1, (float)random.NextDouble() * 2 - 1, (float)random.NextDouble() * 2 - 1));
                Vector3Wide.Broadcast(axis, out var axisWide);
                var           rotation = Matrix3x3.CreateFromAxisAngle(axis, (float)random.NextDouble());
                Matrix3x3Wide rotationWide;
                Vector3Wide.Broadcast(rotation.X, out rotationWide.X);
                Vector3Wide.Broadcast(rotation.Y, out rotationWide.Y);
                Vector3Wide.Broadcast(rotation.Z, out rotationWide.Z);

                var m2x3Wide = new Matrix2x3Wide()
                {
                    X = axisWide, Y = new Vector3Wide {
                        X = -axisWide.Y, Y = axisWide.Z, Z = axisWide.X
                    }
                };

                var triangular = new Symmetric3x3
                {
                    XX = (float)random.NextDouble() * 2 + 1,
                    YX = (float)random.NextDouble() * 1 + 1,
                    YY = (float)random.NextDouble() * 2 + 1,
                    ZX = (float)random.NextDouble() * 1 + 1,
                    ZY = (float)random.NextDouble() * 1 + 1,
                    ZZ = (float)random.NextDouble() * 2 + 1,
                };
                Symmetric3x3Wide triangularWide;
                triangularWide.XX = new Vector <float>(triangular.XX);
                triangularWide.YX = new Vector <float>(triangular.YX);
                triangularWide.YY = new Vector <float>(triangular.YY);
                triangularWide.ZX = new Vector <float>(triangular.ZX);
                triangularWide.ZY = new Vector <float>(triangular.ZY);
                triangularWide.ZZ = new Vector <float>(triangular.ZZ);

                var symmetric = new Matrix3x3
                {
                    X = new Vector3(triangular.XX, triangular.YX, triangular.ZX),
                    Y = new Vector3(triangular.YX, triangular.YY, triangular.ZY),
                    Z = new Vector3(triangular.ZX, triangular.ZY, triangular.ZZ),
                };
                Matrix3x3Wide symmetricWide;
                Vector3Wide.Broadcast(symmetric.X, out symmetricWide.X);
                Vector3Wide.Broadcast(symmetric.Y, out symmetricWide.Y);
                Vector3Wide.Broadcast(symmetric.Z, out symmetricWide.Z);

                var symmetricVectorSandwich = new SymmetricVectorSandwich()
                {
                    v = axis, symmetric = symmetric
                };
                var symmetricWideVectorSandwich = new SymmetricWideVectorSandwich()
                {
                    v = axisWide, symmetric = symmetricWide
                };
                var triangularWideVectorSandwich = new TriangularWideVectorSandwich()
                {
                    v = axisWide, triangular = triangularWide
                };
                var symmetricWide2x3Sandwich = new SymmetricWide2x3Sandwich()
                {
                    m = m2x3Wide, symmetric = symmetricWide
                };
                var triangularWide2x3Sandwich = new TriangularWide2x3Sandwich()
                {
                    m = m2x3Wide, triangular = triangularWide
                };
                var symmetricSkewSandwich = new SymmetricSkewSandwich()
                {
                    v = axis, symmetric = symmetric
                };
                var symmetricWideSkewSandwich = new SymmetricWideSkewSandwich()
                {
                    v = axisWide, symmetric = symmetricWide
                };
                var triangularWideSkewSandwich = new TriangularWideSkewSandwich()
                {
                    v = axisWide, triangular = triangularWide
                };
                var symmetricSandwich = new SymmetricRotationSandwich()
                {
                    rotation = rotation, symmetric = symmetric
                };
                var symmetricWideSandwich = new SymmetricRotationSandwichWide()
                {
                    rotation = rotationWide, symmetric = symmetricWide
                };
                var triangularWideSandwich = new TriangularRotationSandwichWide()
                {
                    rotation = rotationWide, triangular = triangularWide
                };
                var symmetricInvert = new SymmetricInvert()
                {
                    symmetric = symmetric
                };
                var symmetricWideInvert = new SymmetricInvertWide()
                {
                    symmetric = symmetricWide
                };
                var triangularWideInvert = new TriangularInvertWide()
                {
                    triangular = triangularWide
                };


                const int innerIterations = 100000;
                symmetricVectorSandwichTime        += TimeTest(innerIterations, ref symmetricVectorSandwich);
                symmetricWideVectorSandwichTime    += TimeTest(innerIterations, ref symmetricWideVectorSandwich);
                triangularWideVectorSandwichTime   += TimeTest(innerIterations, ref triangularWideVectorSandwich);
                symmetricWide2x3SandwichTime       += TimeTest(innerIterations, ref symmetricWide2x3Sandwich);
                triangularWide2x3SandwichTime      += TimeTest(innerIterations, ref triangularWide2x3Sandwich);
                symmetricSkewSandwichTime          += TimeTest(innerIterations, ref symmetricSkewSandwich);
                symmetricWideSkewSandwichTime      += TimeTest(innerIterations, ref symmetricWideSkewSandwich);
                triangularWideSkewSandwichTime     += TimeTest(innerIterations, ref triangularWideSkewSandwich);
                symmetricRotationSandwichTime      += TimeTest(innerIterations, ref symmetricSandwich);
                symmetricWideRotationSandwichTime  += TimeTest(innerIterations, ref symmetricWideSandwich);
                triangularWideRotationSandwichTime += TimeTest(innerIterations, ref triangularWideSandwich);
                symmetricInvertTime      += TimeTest(innerIterations, ref symmetricInvert);
                symmetricWideInvertTime  += TimeTest(innerIterations, ref symmetricWideInvert);
                triangularWideInvertTime += TimeTest(innerIterations, ref triangularWideInvert);

                Compare(symmetricVectorSandwich.result, ref symmetricWideVectorSandwich.result);
                Compare(symmetricVectorSandwich.result, ref triangularWideVectorSandwich.result);
                Compare(ref symmetricWide2x3Sandwich.result, ref triangularWide2x3Sandwich.result);
                Compare(ref symmetricSkewSandwich.result, ref symmetricWideSkewSandwich.result);
                Compare(ref symmetricSkewSandwich.result, ref triangularWideSkewSandwich.result);
                Compare(ref symmetricSandwich.result, ref symmetricWideSandwich.result);
                Compare(ref symmetricSandwich.result, ref triangularWideSandwich.result);
                Compare(ref symmetricInvert.result, ref symmetricWideInvert.result);
                Compare(ref symmetricInvert.result, ref triangularWideInvert.result);
            }

            Console.WriteLine($"Symmetric vector sandwich:       {symmetricVectorSandwichTime}");
            Console.WriteLine($"Symmetric wide vector sandwich:  {symmetricWideVectorSandwichTime}");
            Console.WriteLine($"Triangular wide vector sandwich: {triangularWideVectorSandwichTime}");
            Console.WriteLine($"Symmetric wide 2x3 sandwich:  {symmetricWide2x3SandwichTime}");
            Console.WriteLine($"Triangular wide 2x3 sandwich: {triangularWide2x3SandwichTime}");
            Console.WriteLine($"Symmetric skew sandwich:       {symmetricSkewSandwichTime}");
            Console.WriteLine($"Symmetric wide skew sandwich:  {symmetricWideSkewSandwichTime}");
            Console.WriteLine($"Triangular wide skew sandwich: {triangularWideSkewSandwichTime}");
            Console.WriteLine($"Symmetric rotation sandwich:       {symmetricRotationSandwichTime}");
            Console.WriteLine($"Symmetric wide rotation sandwich:  {symmetricWideRotationSandwichTime}");
            Console.WriteLine($"Triangular wide rotation sandwich: {triangularWideRotationSandwichTime}");
            Console.WriteLine($"Symmetric invert:       {symmetricInvertTime}");
            Console.WriteLine($"Symmetric wide invert:  {symmetricWideInvertTime}");
            Console.WriteLine($"Triangular wide invert: {triangularWideInvertTime}");
        }
            public void ComputeAnalyticInertia(float mass, out BodyInertia inertia)
            {
                //Computing the inertia of a tetrahedron requires integrating across its volume.
                //While it's possible to do so directly given arbitrary plane equations, it's more convenient to integrate over a normalized tetrahedron with coordinates
                //at (0,0,0), (1,0,0), (0,1,0), and (0,0,1). The integration location can be transformed back to the original frame of reference using the tetrahedral edges.
                //That is, (1,0,0) in normalized space transforms to B-A in world space.
                //To make that explicit, we have an equation:
                // [1,0,0]               [ B - A ]
                // [0,1,0] * Transform = [ C - A ]
                // [0,0,1]               [ D - A ]
                //(Note that you could consider this to be an affine transform with a translation equal to A.)

                //Since the normalized edge directions compose the identity matrix, the transform is just the edge directions.
                //So, given function f that computes a point's contribution to the inertia tensor, the inertia tensor of the normalized tetrahedron with uniform unit density is:
                //Integrate[Integrate[Integrate[f[{i, j, k}], {k, 0, 1-i-j}], {j, 0, 1-i}], {i, 0, 1}];
                //Note the integration bounds- they are a result of the simple shape of the normalized tetrahedron making the plane equations easier to deal with.
                //Now, to integrate over the true tetrahedron's shape, the normalized coordinates are transformed to world coordinates:
                //Integrate[Integrate[Integrate[f[{i, j, k}.Transform + A] * Abs[Det[Transform]], {k, 0, 1-i-j}], {j, 0, 1-i}], {i, 0, 1}];

                //One key difference is the inclusion of the transform's jacobian's determinant, which in this case is just the volume of the tetrahedron times six.
                //For a geometric intuition for why that exists, consider that the normalized integration covers a tetrahedron with a volume of 1/6. The world space tetrahedron
                //has a volume of Abs[Det[Transform]]/6. So, the volume changes by a factor of exactly Abs[Det[Transform]].
                //That term compensates for the difference in integration domain.
                //It's also constant over the integration, so you can just pull it out.
                //Similarly, if you had a non-unit uniform density, you would multiply the integration by it too.

                //So, putting that together and assuming the scaling term is pulled out, here's a chunk of code you can plop into wolfram cloud and whatnot to recreate the results:
                //f[{x_, y_, z_}] := {{y^2 + z^2, -x * y, -x * z}, {-x * y, x^2 + z^2, -y * z}, {-x * z, -y * z, x^2 + y^2}}
                //a = { AX, AY, AZ};
                //b = { BX, BY, BZ};
                //c = { CX, CY, CZ};
                //d = { DX, DY, DZ};
                //ab = b - a;
                //ac = c - a;
                //ad = d - a;
                //A = { ab, ac, ad};
                //Integrate[Integrate[Integrate[f[{ i, j, k}.A + a], {k, 0, 1-i-j}], {j, 0, 1-i}],{i, 0, 1}]
                inertia.InverseMass = 1f / mass;
                var ab = B - A;
                var ac = C - A;
                var ad = D - A;
                //Revisiting the determinant, note that:
                //density * abs(determinant) = density * volume * 6 = mass * 6
                //So there's no need to actually compute the determinant/volume since we were given the mass directly.
                var          diagonalScaling = mass * (6f / 60f);
                Symmetric3x3 inertiaTensor;

                inertiaTensor.XX = diagonalScaling * (
                    A.Y * A.Y + A.Z * A.Z + B.Y * B.Y + B.Z * B.Z + C.Y * C.Y + C.Z * C.Z + D.Y * D.Y + D.Z * D.Z +
                    B.Y * C.Y + B.Z * C.Z +
                    (B.Y + C.Y) * D.Y + (B.Z + C.Z) * D.Z +
                    A.Y * (B.Y + C.Y + D.Y) + A.Z * (B.Z + C.Z + D.Z));
                inertiaTensor.YY = diagonalScaling * (
                    A.X * A.X + A.Z * A.Z + B.X * B.X + B.Z * B.Z + C.X * C.X + C.Z * C.Z + D.X * D.X + D.Z * D.Z +
                    B.X * C.X + B.Z * C.Z +
                    (B.X + C.X) * D.X + (B.Z + C.Z) * D.Z +
                    A.X * (B.X + C.X + D.X) + A.Z * (B.Z + C.Z + D.Z));
                inertiaTensor.ZZ = diagonalScaling * (
                    A.X * A.X + A.Y * A.Y + B.X * B.X + B.Y * B.Y + C.X * C.X + C.Y * C.Y + D.X * D.X + D.Y * D.Y +
                    B.X * C.X + B.Y * C.Y +
                    (B.X + C.X) * D.X + (B.Y + C.Y) * D.Y +
                    A.X * (B.X + C.X + D.X) + A.Y * (B.Y + C.Y + D.Y));
                var offScaling = mass * (6f / 120f);

                inertiaTensor.YX = offScaling * (
                    -2 * B.X * B.Y - 2 * C.X * C.Y -
                    B.Y * C.X - B.X * C.Y - B.Y * D.X - C.Y * D.X -
                    A.Y * (B.X + C.X + D.X) - (B.X + C.X + 2 * D.X) * D.Y - A.X * (2 * A.Y + B.Y + C.Y + D.Y));
                inertiaTensor.ZX = offScaling * (
                    -2 * B.X * B.Z - 2 * C.X * C.Z -
                    B.Z * C.X - B.X * C.Z - B.Z * D.X - C.Z * D.X -
                    A.Z * (B.X + C.X + D.X) - (B.X + C.X + 2 * D.X) * D.Z - A.X * (2 * A.Z + B.Z + C.Z + D.Z));
                inertiaTensor.ZY = offScaling * (
                    -2 * B.Y * B.Z - 2 * C.Y * C.Z -
                    B.Z * C.Y - B.Y * C.Z - B.Z * D.Y - C.Z * D.Y -
                    A.Z * (B.Y + C.Y + D.Y) - (B.Y + C.Y + 2 * D.Y) * D.Z - A.Y * (2 * A.Z + B.Z + C.Z + D.Z));
                //TODO: Note that the above implementation isn't exactly optimal. Assuming for now that the performance isn't going to be relevant.
                //That could change given certain convex hull use cases, but in that situation you should probably just jump to vectorizing over multiple tetrahedra at a time.
                //(Plus some basic term caching.)
                Symmetric3x3.Invert(inertiaTensor, out inertia.InverseInertiaTensor);
            }