Example #1
0
        public override void Initialize(ContentArchive content, Camera camera)
        {
            camera.Position = new Vector3(0, 10, 40);
            camera.Yaw      = 0;
            camera.Pitch    = 0;
            //Note the higher stiffness on contacts for this demo. That's not ideal for general stability at the demo timestep duration default of 60hz, but
            //this demo doesn't have any significant solver complexity and we want to see the CCD in action more clearly- which means more rigid contact.
            //Having objects bounce a bunch on impact makes it harder to see.
            //Also note that the PositionFirstTimestepper is the simplest timestepping mode, but since it integrates velocity into position at the start of the frame, directly modified velocities outside of the timestep
            //will be integrated before collision detection or the solver has a chance to intervene. That's fine in this demo. Other built-in options include the PositionLastTimestepper and the SubsteppingTimestepper.
            //Note that the timestepper also has callbacks that you can use for executing logic between processing stages, like BeforeCollisionDetection.
            Simulation = Simulation.Create(BufferPool, new DemoNarrowPhaseCallbacks()
            {
                ContactSpringiness = new SpringSettings(120, 1)
            }, new DemoPoseIntegratorCallbacks(new Vector3(0, -10, 0)), new PositionFirstTimestepper());

            var shape = new Box(1, 1, 1);

            shape.ComputeInertia(1, out var inertia);
            var shapeIndex = Simulation.Shapes.Add(shape);

            for (int i = 0; i < 10; ++i)
            {
                for (int j = 0; j < 10; ++j)
                {
                    //These two falling dynamics have pretty small speculative margins. The second one uses continuous collision detection sweeps to generate speculative contacts.
                    Simulation.Bodies.Add(BodyDescription.CreateDynamic(new Vector3(-4 - 2 * j, 100 + (i + j) * 2, i * 2), new BodyVelocity {
                        Linear = new Vector3(0, -150, 0)
                    }, inertia,
                                                                        new CollidableDescription(shapeIndex, 0.01f), new BodyActivityDescription(0.01f)));
                    //The minimum progression duration parameter at 1e-3 means the CCD sweep won't miss any collisions that last at least 1e-3 units of time- so, if time is measured in seconds,
                    //then this will capture any collision that an update rate of 1000hz would.
                    //Note also that the sweep convergence threshold is actually pretty loose at 100hz. Despite that, it can still lead to reasonably good speculative contacts with solid impact behavior.
                    //That's because the sweep does not directly generate contacts- it generates a time of impact estimate, and then the discrete contact generation
                    //runs to create the actual contact manifold. That provides high quality contact positions and speculative depths.
                    //If the ground that these boxes were smashing into was something like a mesh- which is infinitely thin- you may want to increase the sweep accuracy.
                    Simulation.Bodies.Add(BodyDescription.CreateDynamic(new Vector3(4 + 2 * j, 100 + (i + j) * 2, i * 2), new BodyVelocity {
                        Linear = new Vector3(0, -150, 0)
                    }, inertia,
                                                                        new CollidableDescription(shapeIndex, 0.01f, ContinuousDetectionSettings.Continuous(1e-3f, 1e-2f)), new BodyActivityDescription(0.01f)));
                }
            }
            rolloverInfo = new RolloverInfo();
            rolloverInfo.Add(new Vector3(-12, 2, 0), "Discrete");
            rolloverInfo.Add(new Vector3(12, 2, 0), "Continuous");

            //Build a couple of spinners to ram into each other to showcase angular CCD. Note that the spin speeds are slightly different- that helps avoid
            //synchronization that makes the blades frequently miss each other, which sorta ruins a CCD demo.
            spinnerMotorA = BuildSpinner(new Vector3(-5, 10, -5), 53);
            spinnerMotorB = BuildSpinner(new Vector3(5, 10, -5), 59);
            rolloverInfo.Add(new Vector3(0, 12, -5), "High angular velocity continuous detection");

            Simulation.Statics.Add(new StaticDescription(new Vector3(0, -5f, 0), new CollidableDescription(Simulation.Shapes.Add(new Box(300, 10, 300)), 0.1f)));
        }
        public unsafe override void Initialize(ContentArchive content, Camera camera)
        {
            camera.Position = new Vector3(0, 25, 80);
            camera.Yaw      = 0;
            camera.Pitch    = 0;
            timestepper     = new SubsteppingTimestepper(8);
            Simulation      = Simulation.Create(BufferPool, new DemoNarrowPhaseCallbacks()
            {
                ContactSpringiness = new SpringSettings(120, 120)
            }, new DemoPoseIntegratorCallbacks(new Vector3(0, -10, 0)), timestepper, 8);

            rolloverInfo = new RolloverInfo();
            {
                //We'll create a 0 level arm rope like the one from the RopeStabilityDemo. No skip constraints, though- and the mass ratio will be 1000:1 instead of 100:1!
                var         startLocation  = new Vector3(15, 40, 0);
                const float bodySpacing    = 0.3f;
                const float bodyRadius     = 0.5f;
                var         springSettings = new SpringSettings(240, 480);
                var         bodyHandles    = RopeStabilityDemo.BuildRope(Simulation, startLocation, 12, bodyRadius, bodySpacing, 0, 1, 0, springSettings);

                var bigWreckingBall = new Sphere(5);
                bigWreckingBall.ComputeInertia(1000, out var bigWreckingBallInertia);

                RopeStabilityDemo.AttachWreckingBall(Simulation, bodyHandles, bodyRadius, bodySpacing, 0, bigWreckingBall.Radius, bigWreckingBallInertia, Simulation.Shapes.Add(bigWreckingBall), springSettings);
                rolloverInfo.Add(startLocation + new Vector3(0, 2, 0), "1000:1 mass ratio");
            }

            {
                //Stack with a heavy block on top. Note that the contact springiness we chose in the DemoNarrowPhaseCallbacks above is important to making the stack resist the weight of the top block.
                //It's also the reason why we need higher substeps- 120hz frequency is too high for 60hz solving! Watch what happens when you drop the substep count to 3.
                //(Note that the demos timestep frequency is 60hz, so 4 substeps is a 240hz solve rate- twice the 120hz contact frequency.)
                var boxShape = new Box(4, 0.5f, 6f);
                boxShape.ComputeInertia(1, out var boxInertia);
                //Note that sleeping is disabled with a negative velocity threshold. We want to watch the stack as we change simulation settings; if it's inactive, it won't respond!
                var boxDescription = BodyDescription.CreateDynamic(new Vector3(), boxInertia, new CollidableDescription(Simulation.Shapes.Add(boxShape), 0.1f), new BodyActivityDescription(-1f));
                for (int i = 0; i < 20; ++i)
                {
                    boxDescription.Pose = new RigidPose(new Vector3(0, 0.5f + boxShape.Height * (i + 0.5f), 0), QuaternionEx.CreateFromAxisAngle(Vector3.UnitY, MathF.PI * 0.05f * i));
                    Simulation.Bodies.Add(boxDescription);
                }
                var topBlockShape = new Box(8, 2, 8);
                topBlockShape.ComputeInertia(200, out var topBlockInertia);
                Simulation.Bodies.Add(
                    BodyDescription.CreateDynamic(boxDescription.Pose.Position + new Vector3(0, boxShape.HalfHeight + 1f, 0), topBlockInertia,
                                                  new CollidableDescription(Simulation.Shapes.Add(topBlockShape), 0.1f), new BodyActivityDescription(-1f)));

                rolloverInfo.Add(boxDescription.Pose.Position + new Vector3(0, 4, 0), "200:1 mass ratio");
            }

            {
                //Now a weird rotating multi-arm thing. Long constraint sequences with high leverages under stress are a really tough problem for iterative velocity solvers.
                //(Fortunately, all 5 degrees of freedom of each hinge constraint are solved analytically, so the convergence issues aren't quite as bad as they could be.)
                var basePosition  = new Vector3(-20, 20, 0);
                var boxShape      = new Box(0.5f, 0.5f, 3f);
                var boxCollidable = new CollidableDescription(Simulation.Shapes.Add(boxShape), 0.1f);
                boxShape.ComputeInertia(1, out var boxInertia);
                var linkDescription = BodyDescription.CreateDynamic(new Vector3(), boxInertia, boxCollidable, new BodyActivityDescription(0.01f));


                for (int chainIndex = 0; chainIndex < 4; ++chainIndex)
                {
                    linkDescription.Pose.Position = basePosition + new Vector3(0, 0, chainIndex * 15);
                    var previousLinkHandle = Simulation.Bodies.Add(BodyDescription.CreateKinematic(linkDescription.Pose.Position, boxCollidable, new BodyActivityDescription(0.01f)));
                    for (int linkIndex = 0; linkIndex < 8; ++linkIndex)
                    {
                        var previousPosition = linkDescription.Pose.Position;
                        var offset           = new Vector3(boxShape.Width * 1.05f, 0, boxShape.Length - boxShape.Width);
                        linkDescription.Pose.Position += offset;
                        var linkHandle = Simulation.Bodies.Add(linkDescription);
                        Simulation.Solver.Add(previousLinkHandle, linkHandle, new Hinge
                        {
                            LocalHingeAxisA = Vector3.UnitX,
                            LocalHingeAxisB = Vector3.UnitX,
                            LocalOffsetA    = offset * 0.5f,
                            LocalOffsetB    = offset * -0.5f,
                            //Once again, the choice of high stiffness makes this potentially unstable without substepping.
                            SpringSettings = new SpringSettings(120, 1)
                        });
                        Simulation.Solver.Add(previousLinkHandle, linkHandle, new AngularAxisMotor
                        {
                            LocalAxisA     = Vector3.UnitX,
                            TargetVelocity = .25f,
                            Settings       = new MotorSettings(float.MaxValue, 0.0001f)
                        });
                        previousLinkHandle = linkHandle;
                    }
                }
                rolloverInfo.Add(basePosition + new Vector3(0, 4, 0), "High stiffness, long lever arm motorized chain");
            }


            Simulation.Statics.Add(new StaticDescription(new Vector3(0, 0, 0), new CollidableDescription(Simulation.Shapes.Add(new Box(200, 1, 200)), 0.1f)));
        }