Example #1
0
    public void UpdateMeshDisplay()
    {
        CompositeShape compShape = new CompositeShape(shapes);

        meshFilter.mesh = compShape.GetMesh();
        //if (meshFilter.sharedMesh)
        //meshCollider.sharedMesh = meshFilter.sharedMesh;

        meshCollider.sharedMesh = compShape.GetMesh();
    }
Example #2
0
        public void CompositeShapeWithRotatedChildren()
        {
            var s = new CompositeShape();

            s.Children.Add(new GeometricObject(new BoxShape(1, 2, 3), new Vector3F(1.1f, 0.3f, 0.8f), new Pose(new Vector3F(100, 10, 0), RandomHelper.Random.NextQuaternionF())));
            s.Children.Add(new GeometricObject(new ConeShape(1, 2), new Vector3F(1.1f, 0.3f, 0.8f), new Pose(new Vector3F(-10, -10, 0), RandomHelper.Random.NextQuaternionF())));
            float     m0;
            Vector3F  com0;
            Matrix33F i0;

            MassHelper.GetMass(s, new Vector3F(2), 1, true, 0.001f, 10, out m0, out com0, out i0);

            var m = s.GetMesh(0.001f, 6);

            m.Transform(Matrix44F.CreateScale(2));
            float     m1;
            Vector3F  com1;
            Matrix33F i1;

            MassHelper.GetMass(m, out m1, out com1, out i1);

            const float e = 0.01f;

            Assert.IsTrue(Numeric.AreEqual(m0, m1, e * (1 + m0)));
            Assert.IsTrue(Vector3F.AreNumericallyEqual(com0, com1, e * (1 + com0.Length)));
            Assert.IsTrue(Matrix33F.AreNumericallyEqual(i0, i1, e * (1 + i0.Trace)));
        }
Example #3
0
    public void UpdateMeshDisplay()
    {
        //if (shapes.Count < 1) { return; }
        //if (shapes[0].points == null) { return; }
        //if (shapes[0].points.Count < 1) { return; }
        CompositeShape compShape = new CompositeShape(shapes);

        meshFilter.mesh = compShape.GetMesh();
    }
Example #4
0
        public void CompositeShapeWithNonUniformScaling()
        {
            var s = new CompositeShape();

            s.Children.Add(new GeometricObject(new BoxShape(1, 2, 3), new Vector3F(1.1f, 0.3f, 0.8f), new Pose(new Vector3F(100, 10, 0))));
            s.Children.Add(new GeometricObject(new SphereShape(1), new Vector3F(1.1f, 0.3f, 0.8f), new Pose(new Vector3F(-10, -10, 0))));
            float     m0;
            Vector3F  com0;
            Matrix33F i0;

            MassHelper.GetMass(s, new Vector3F(2, 2.1f, 2.8f), 0.7f, true, 0.001f, 10, out m0, out com0, out i0);

            var m = s.GetMesh(0.001f, 6);

            m.Transform(Matrix44F.CreateScale(2, 2.1f, 2.8f));
            float     m1;
            Vector3F  com1;
            Matrix33F i1;

            MassHelper.GetMass(m, out m1, out com1, out i1);

            const float e = 0.01f;

            Assert.IsTrue(Numeric.AreEqual(m0, 0.7f * m1, e * (1 + m0)));
            Assert.IsTrue(Vector3F.AreNumericallyEqual(com0, com1, e * (1 + com0.Length)));
            Assert.IsTrue(Matrix33F.AreNumericallyEqual(i0, 0.7f * i1, e * (1 + i0.Trace)));

            // Try with target mass.
            float     m3;
            Vector3F  com3;
            Matrix33F i3;

            MassHelper.GetMass(s, new Vector3F(2, 2.1f, 2.8f), 23, false, 0.001f, 10, out m3, out com3, out i3);
            Assert.IsTrue(Numeric.AreEqual(23, m3, e * (1 + m0)));
            Assert.IsTrue(Vector3F.AreNumericallyEqual(com0, com3, e * (1 + com0.Length)));
            Assert.IsTrue(Matrix33F.AreNumericallyEqual(i0 * 23 / m0, i3, e * (1 + i0.Trace)));
        }
Example #5
0
    public void UpdateMeshDisplay()
    {
        CompositeShape comShape = new CompositeShape(shapes);

        meshFilter.mesh = comShape.GetMesh();
    }
        //--------------------------------------------------------------
        #region Methods
        //--------------------------------------------------------------

        protected override void OnLoad()
        {
            // Add rigid bodies to simulation.
            var simulation = _services.GetInstance <Simulation>();

            // We use a random number generator with a custom seed.
            RandomHelper.Random = new Random(123);

            // ----- Add a ground plane.
            AddBody(simulation, "GroundPlane", Pose.Identity, new PlaneShape(Vector3F.UnitY, 0), MotionType.Static);

            // ----- Create a small flying sphere.
            AddBody(simulation, "Sphere", new Pose(new Vector3F(0, 1f, 0)), new SphereShape(0.2f), MotionType.Static);

            // ----- Create small walls at the level boundary.
            AddBody(simulation, "WallLeft", new Pose(new Vector3F(-30, 1, 0)), new BoxShape(0.3f, 2, 60), MotionType.Static);
            AddBody(simulation, "WallRight", new Pose(new Vector3F(30, 1, 0)), new BoxShape(0.3f, 2, 60), MotionType.Static);
            AddBody(simulation, "WallFront", new Pose(new Vector3F(0, 1, -30)), new BoxShape(60, 2, 0.3f), MotionType.Static);
            AddBody(simulation, "WallBack", new Pose(new Vector3F(0, 1, 30)), new BoxShape(60, 2, 0.3f), MotionType.Static);

            // ----- Create a few bigger objects.
            // We position the boxes so that we have a few corners we can run into. Character controllers
            // should be stable when the user runs into corners.
            AddBody(simulation, "House0", new Pose(new Vector3F(10, 1, -10)), new BoxShape(8, 2, 8f), MotionType.Static);
            AddBody(simulation, "House1", new Pose(new Vector3F(13, 1, -4)), new BoxShape(2, 2, 4), MotionType.Static);
            AddBody(simulation, "House2", new Pose(new Vector3F(10, 2, -15), Matrix33F.CreateRotationY(-0.3f)), new BoxShape(8, 4, 2), MotionType.Static);

            // ----- Create stairs with increasing step height.
            // Each step is a box. With this object we can test if our character can climb up
            // stairs. The character controller has a step height limit. Increasing step heights
            // let us test if the step height limit works.
            float       startHeight = 0;
            const float stepDepth   = 1f;

            for (int i = 0; i < 10; i++)
            {
                float    stepHeight = 0.1f + i * 0.05f;
                Vector3F position   = new Vector3F(0, startHeight + stepHeight / 2, -2 - i * stepDepth);
                AddBody(simulation, "Step" + i, new Pose(position), new BoxShape(2, stepHeight, stepDepth), MotionType.Static);

                startHeight += stepHeight;
            }

            // ----- V obstacle to test if we get stuck.
            AddBody(simulation, "V0", new Pose(new Vector3F(-5.5f, 0, 10), QuaternionF.CreateRotationZ(0.2f)), new BoxShape(1f, 2f, 2), MotionType.Static);
            AddBody(simulation, "V1", new Pose(new Vector3F(-4, 0, 10), QuaternionF.CreateRotationZ(-0.2f)), new BoxShape(1f, 2f, 2), MotionType.Static);

            // ----- Create a height field.
            // Terrain that is uneven is best modeled with a height field. Height fields are faster
            // than general triangle meshes.
            // The height direction is the y direction.
            // The height field lies in the x/z plane.
            var numberOfSamplesX = 20;
            var numberOfSamplesZ = 20;
            var samples          = new float[numberOfSamplesX * numberOfSamplesZ];

            // Create arbitrary height values.
            for (int z = 0; z < numberOfSamplesZ; z++)
            {
                for (int x = 0; x < numberOfSamplesX; x++)
                {
                    if (x == 0 || z == 0 || x == 19 || z == 19)
                    {
                        // Set this boundary elements to a low height, so that the height field is connected
                        // to the ground.
                        samples[z * numberOfSamplesX + x] = -1;
                    }
                    else
                    {
                        // A sine/cosine function that creates some interesting waves.
                        samples[z * numberOfSamplesX + x] = 1.0f + (float)(Math.Cos(z / 2f) * Math.Sin(x / 2f) * 1.0f);
                    }
                }
            }
            var heightField = new HeightField(0, 0, 20, 20, samples, numberOfSamplesX, numberOfSamplesZ);

            AddBody(simulation, "HeightField", new Pose(new Vector3F(10, 0, 10)), heightField, MotionType.Static);

            // ----- Create rubble on the floor (small random objects on the floor).
            // Our character should be able to move over small bumps on the ground.
            for (int i = 0; i < 50; i++)
            {
                Vector3F    position    = new Vector3F(RandomHelper.Random.NextFloat(-5, 5), 0, RandomHelper.Random.NextFloat(10, 20));
                QuaternionF orientation = RandomHelper.Random.NextQuaternionF();
                Vector3F    size        = RandomHelper.Random.NextVector3F(0.05f, 0.8f);
                AddBody(simulation, "Stone" + i, new Pose(position, orientation), new BoxShape(size), MotionType.Static);
            }

            // ----- Create some slopes to see how our character performs on/under sloped surfaces.
            // Here we can test how the character controller behaves if the head touches an inclined
            // ceiling.
            AddBody(simulation, "SlopeGround", new Pose(new Vector3F(-2, 1.8f, -12), QuaternionF.CreateRotationX(0.4f)), new BoxShape(2, 0.5f, 10), MotionType.Static);
            AddBody(simulation, "SlopeRoof", new Pose(new Vector3F(-2, 5.6f, -12), QuaternionF.CreateRotationX(-0.4f)), new BoxShape(2, 0.5f, 10), MotionType.Static);

            // Create slopes with increasing tilt angles.
            // The character controller has a slope limit. Only flat slopes should be climbable.
            // Movement between slopes should be smooth.
            Vector3F slopePosition = new Vector3F(-17, -0.25f, 6);
            BoxShape slopeShape    = new BoxShape(8, 0.5f, 5);

            for (int i = 1; i < 8; i++)
            {
                Matrix33F oldRotation = Matrix33F.CreateRotationX((i - 1) * MathHelper.ToRadians(10));
                Matrix33F rotation    = Matrix33F.CreateRotationX(i * MathHelper.ToRadians(10));

                slopePosition += (oldRotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2
                                 + (rotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2;

                AddBody(simulation, "Slope" + i, new Pose(slopePosition, rotation), slopeShape, MotionType.Static);
            }

            // Create slopes with decreasing tilt angles.
            slopePosition = new Vector3F(-8, -2, 5);
            slopeShape    = new BoxShape(8f, 0.5f, 5);
            for (int i = 1; i < 8; i++)
            {
                Matrix33F oldRotation = Matrix33F.CreateRotationX(MathHelper.ToRadians(40) - (i - 1) * MathHelper.ToRadians(10));
                Matrix33F rotation    = Matrix33F.CreateRotationX(MathHelper.ToRadians(40) - i * MathHelper.ToRadians(10));

                slopePosition += (oldRotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2
                                 + (rotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2;
                Vector3F position = slopePosition - rotation * new Vector3F(0, slopeShape.WidthY / 2, 0);

                AddBody(simulation, "Slope2" + i, new Pose(position, rotation), slopeShape, MotionType.Static);
            }

            // ----- Create a slope with a wall on one side.
            // This objects let's us test how the character controller behaves while falling and
            // sliding along a vertical wall. (Run up the slope and then jump down while moving into
            // the wall.)
            AddBody(simulation, "LongSlope", new Pose(new Vector3F(-24, 3, -10), Matrix33F.CreateRotationX(0.4f)), new BoxShape(4, 5f, 30), MotionType.Static);
            AddBody(simulation, "LongSlopeWall", new Pose(new Vector3F(-26, 5, -10)), new BoxShape(0.5f, 10f, 25), MotionType.Static);

            // ----- Create a trigger object that represents a ladder.
            var ladder = AddBody(simulation, "Ladder", new Pose(new Vector3F(-25.7f, 5, 0)), new BoxShape(0.5f, 10f, 1), MotionType.Static);

            ladder.CollisionObject.Type = CollisionObjectType.Trigger;

            // ----- Create a mesh object to test walking on triangle meshes.
            // Normally, the mesh would be loaded from a file. Here, we make a composite shape and
            // let DigitalRune Geometry compute a mesh for it. Then we throw away the composite
            // shape and use only the mesh. (We do this to test triangle meshes. Using the composite
            // shape instead of the triangle mesh would be a lot faster.)
            CompositeShape compositeShape = new CompositeShape();

            compositeShape.Children.Add(new GeometricObject(heightField, Pose.Identity));
            compositeShape.Children.Add(new GeometricObject(new CylinderShape(1, 2), new Pose(new Vector3F(10, 1, 10))));
            compositeShape.Children.Add(new GeometricObject(new SphereShape(3), new Pose(new Vector3F(15, 0, 15))));
            compositeShape.Children.Add(new GeometricObject(new BoxShape(4, 4, 3), new Pose(new Vector3F(15, 1.5f, 5))));
            compositeShape.Children.Add(new GeometricObject(new BoxShape(4, 4, 3), new Pose(new Vector3F(15, 1.5f, 0))));
            ITriangleMesh     mesh      = compositeShape.GetMesh(0.01f, 3);
            TriangleMeshShape meshShape = new TriangleMeshShape(mesh);

            // Collision detection speed for triangle meshes can be improved by using a spatial
            // partition. Here, we assign an AabbTree to the triangle mesh shape. The tree is
            // built automatically when needed and it stores triangle indices (therefore the generic
            // parameter of the AabbTree is int).
            meshShape.Partition = new AabbTree <int>()
            {
                // The tree is automatically built using a mixed top-down/bottom-up approach. Bottom-up
                // building is slower but produces better trees. If the tree building takes too long,
                // we can lower the BottomUpBuildThreshold (default is 128).
                BottomUpBuildThreshold = 0,
            };

            // Contact welding creates smoother contact normals - but it costs a bit of performance.
            meshShape.EnableContactWelding = true;

            AddBody(simulation, "Mesh", new Pose(new Vector3F(-30, 0, 10)), meshShape, MotionType.Static);

            // ----- Create a seesaw.
            var seesawBase = AddBody(simulation, "SeesawBase", new Pose(new Vector3F(5, 0.5f, 0)), new BoxShape(0.2f, 1, 1), MotionType.Static);
            var seesaw     = AddBody(simulation, "Seesaw", new Pose(new Vector3F(5, 1.05f, 0)), new BoxShape(5, 0.1f, 1), MotionType.Dynamic);

            // Attach the seesaw to the base using a hinge joint.
            simulation.Constraints.Add(new HingeJoint
            {
                BodyA            = seesaw,
                BodyB            = seesawBase,
                AnchorPoseALocal = new Pose(new Vector3F(0, 0, 0),
                                            new Matrix33F(0, 0, -1,
                                                          0, 1, 0,
                                                          1, 0, 0)),
                AnchorPoseBLocal = new Pose(new Vector3F(0, 0.5f, 0),
                                            new Matrix33F(0, 0, -1,
                                                          0, 1, 0,
                                                          1, 0, 0)),
                CollisionEnabled = false,
            });

            // ----- A platform that is moving up/down.
            _elevator = AddBody(simulation, "Elevator", new Pose(new Vector3F(5, -1f, 5)), new BoxShape(3, 1f, 3), MotionType.Kinematic);
            _elevator.LinearVelocity = new Vector3F(2, 2, 0);

            // ----- A platform that is moving sideways.
            _pusher = AddBody(simulation, "Pusher", new Pose(new Vector3F(15, 0.5f, 0)), new BoxShape(3, 1f, 3), MotionType.Kinematic);
            _pusher.LinearVelocity = new Vector3F(0, 0, 2);

            // ----- Create conveyor belt with two static boxes on the sides.
            AddBody(simulation, "ConveyorSide0", new Pose(new Vector3F(19, 0.25f, 0)), new BoxShape(0.8f, 0.5f, 8f), MotionType.Static);
            AddBody(simulation, "ConveyorSide1", new Pose(new Vector3F(21, 0.25f, 0)), new BoxShape(0.8f, 0.5f, 8f), MotionType.Static);

            // The conveyor belt is a simple box with a special material.
            var             conveyorBelt = AddBody(simulation, "ConveyorBelt", new Pose(new Vector3F(20, 0.25f, 0)), new BoxShape(1f, 0.51f, 8f), MotionType.Static);
            UniformMaterial materialWithSurfaceMotion = new UniformMaterial("ConveyorBelt", true) // Important: The second parameter enables the surface
            {                                                                                     // motion. It has to be set to true in the constructor!
                SurfaceMotion = new Vector3F(0, 0, 1),                                            // The surface motion relative to the object.
            };

            conveyorBelt.Material = materialWithSurfaceMotion;

            // ----- Distribute a few dynamic spheres and boxes across the landscape.
            SphereShape sphereShape = new SphereShape(0.5f);

            for (int i = 0; i < 10; i++)
            {
                Vector3F position = RandomHelper.Random.NextVector3F(-15, 15);
                position.Y = 20;

                AddBody(simulation, "Sphere" + i, new Pose(position), sphereShape, MotionType.Dynamic);
            }

            BoxShape boxShape = new BoxShape(1, 1, 1);

            for (int i = 0; i < 10; i++)
            {
                Vector3F position = RandomHelper.Random.NextVector3F(-15, 15);
                position.Y = 20;

                AddBody(simulation, "Box" + i, new Pose(position), boxShape, MotionType.Dynamic);
            }
        }
        protected override void OnLoad()
        {
            // Add rigid bodies to simulation.
            var simulation = _services.GetInstance <Simulation>();

            // ----- Add a ground plane.
            AddBody(simulation, "GroundPlane", Pose.Identity, new PlaneShape(Vector3F.UnitY, 0), MotionType.Static);

            // ----- Create a height field.
            var numberOfSamplesX = 20;
            var numberOfSamplesZ = 20;
            var samples          = new float[numberOfSamplesX * numberOfSamplesZ];

            for (int z = 0; z < numberOfSamplesZ; z++)
            {
                for (int x = 0; x < numberOfSamplesX; x++)
                {
                    if (x == 0 || z == 0 || x == 19 || z == 19)
                    {
                        samples[z * numberOfSamplesX + x] = -1;
                    }
                    else
                    {
                        samples[z * numberOfSamplesX + x] = 1.0f + (float)(Math.Cos(z / 2f) * Math.Sin(x / 2f) * 1.0f);
                    }
                }
            }
            HeightField heightField = new HeightField(0, 0, 120, 120, samples, numberOfSamplesX, numberOfSamplesZ);

            //heightField.UseFastCollisionApproximation = true;
            AddBody(simulation, "HeightField", new Pose(new Vector3F(10, 0, 20)), heightField, MotionType.Static);

            // ----- Create rubble on the floor (small random objects on the floor).
            for (int i = 0; i < 60; i++)
            {
                Vector3F    position    = new Vector3F(RandomHelper.Random.NextFloat(-5, 5), 0, RandomHelper.Random.NextFloat(10, 20));
                QuaternionF orientation = RandomHelper.Random.NextQuaternionF();
                BoxShape    shape       = new BoxShape(RandomHelper.Random.NextVector3F(0.05f, 0.5f));
                AddBody(simulation, "Stone" + i, new Pose(position, orientation), shape, MotionType.Static);
            }

            // ----- Slopes with different tilt angles.
            // Create a loop.
            Vector3F slopePosition = new Vector3F(-20, -0.25f, -5);
            BoxShape slopeShape    = new BoxShape(8, 0.5f, 2);

            for (int i = 1; i < 33; i++)
            {
                Matrix33F oldRotation = Matrix33F.CreateRotationX((i - 1) * MathHelper.ToRadians(10));
                Matrix33F rotation    = Matrix33F.CreateRotationX(i * MathHelper.ToRadians(10));

                slopePosition += (oldRotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2
                                 + (rotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2;

                AddBody(simulation, "Loop" + i, new Pose(slopePosition, rotation), slopeShape, MotionType.Static);
            }

            // Create an arched bridge.
            slopePosition = new Vector3F(-10, -2, -15);
            slopeShape    = new BoxShape(8f, 0.5f, 5);
            for (int i = 1; i < 8; i++)
            {
                Matrix33F oldRotation = Matrix33F.CreateRotationX(MathHelper.ToRadians(40) - (i - 1) * MathHelper.ToRadians(10));
                Matrix33F rotation    = Matrix33F.CreateRotationX(MathHelper.ToRadians(40) - i * MathHelper.ToRadians(10));

                slopePosition += (oldRotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2
                                 + (rotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2;
                Vector3F position = slopePosition - rotation * new Vector3F(0, slopeShape.WidthY / 2, 0);

                AddBody(simulation, "Bridge" + i, new Pose(position, rotation), slopeShape, MotionType.Static);
            }

            // ----- Create a mesh object.
            // We first build a composite shape out of several primitives and then convert the
            // composite shape to a triangle mesh. (Just for testing.)
            CompositeShape compositeShape = new CompositeShape();

            compositeShape.Children.Add(new GeometricObject(heightField, Pose.Identity));
            compositeShape.Children.Add(new GeometricObject(new CylinderShape(1, 2), new Pose(new Vector3F(10, 1, 10))));
            compositeShape.Children.Add(new GeometricObject(new SphereShape(3), new Pose(new Vector3F(15, 0, 15))));
            compositeShape.Children.Add(new GeometricObject(new BoxShape(1, 2, 3), new Pose(new Vector3F(15, 0, 5))));
            ITriangleMesh     mesh      = compositeShape.GetMesh(0.01f, 3);
            TriangleMeshShape meshShape = new TriangleMeshShape(mesh, true);

            meshShape.Partition = new AabbTree <int>()
            {
                BottomUpBuildThreshold = 0
            };
            AddBody(simulation, "Mesh", new Pose(new Vector3F(-120, 0, 20)), meshShape, MotionType.Static);

            // ----- Create a seesaw.
            var seesawBase = AddBody(simulation, "SeesawBase", new Pose(new Vector3F(15, 0.5f, 0)), new BoxShape(0.2f, 1, 6), MotionType.Static);
            var seesaw     = AddBody(simulation, "Seesaw", new Pose(new Vector3F(16, 1.05f, 0)), new BoxShape(15, 0.1f, 6), MotionType.Dynamic);

            seesaw.MassFrame.Mass = 500;
            seesaw.CanSleep       = false;

            // Connect seesaw using a hinge joint.
            simulation.Constraints.Add(new HingeJoint
            {
                BodyA            = seesaw,
                BodyB            = seesawBase,
                AnchorPoseALocal = new Pose(new Vector3F(1.0f, 0, 0),
                                            new Matrix33F(0, 0, -1,
                                                          0, 1, 0,
                                                          1, 0, 0)),
                AnchorPoseBLocal = new Pose(new Vector3F(0, 0.5f, 0),
                                            new Matrix33F(0, 0, -1,
                                                          0, 1, 0,
                                                          1, 0, 0)),
                CollisionEnabled = false,
            });


            // ----- Distribute a few dynamic spheres and boxes across the landscape.
            SphereShape sphereShape = new SphereShape(0.5f);

            for (int i = 0; i < 40; i++)
            {
                Vector3F position = RandomHelper.Random.NextVector3F(-60, 60);
                position.Y = 10;
                AddBody(simulation, "Sphere" + i, new Pose(position), sphereShape, MotionType.Dynamic);
            }

            BoxShape boxShape = new BoxShape(1.0f, 1.0f, 1.0f);

            for (int i = 0; i < 40; i++)
            {
                Vector3F position = RandomHelper.Random.NextVector3F(-60, 60);
                position.Y = 1;
                AddBody(simulation, "Box" + i, new Pose(position), boxShape, MotionType.Dynamic);
            }
        }
Example #8
0
        public ShapesSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            // Add basic force effects.
            Simulation.ForceEffects.Add(new Gravity());
            Simulation.ForceEffects.Add(new Damping());

            // Add a ground plane.
            RigidBody groundPlane = new RigidBody(new PlaneShape(Vector3F.UnitY, 0))
            {
                Name       = "GroundPlane", // Names are not required but helpful for debugging.
                MotionType = MotionType.Static,
            };

            Simulation.RigidBodies.Add(groundPlane);

            // ----- Add a sphere.
            Shape sphere = new SphereShape(0.5f);

            Simulation.RigidBodies.Add(new RigidBody(sphere));

            // ----- Add a box.
            BoxShape box = new BoxShape(0.5f, 0.9f, 0.7f);

            Simulation.RigidBodies.Add(new RigidBody(box));

            // ----- Add a capsule.
            CapsuleShape capsule = new CapsuleShape(0.4f, 1.2f);

            Simulation.RigidBodies.Add(new RigidBody(capsule));

            // ----- Add a cone.
            ConeShape cone = new ConeShape(0.5f, 1f);

            Simulation.RigidBodies.Add(new RigidBody(cone));

            // ----- Add a cylinder.
            CylinderShape cylinder = new CylinderShape(0.3f, 1f);

            Simulation.RigidBodies.Add(new RigidBody(cylinder));

            // ----- Add a convex hull of random points.
            ConvexHullOfPoints convexHullOfPoints = new ConvexHullOfPoints();

            for (int i = 0; i < 20; i++)
            {
                convexHullOfPoints.Points.Add(RandomHelper.Random.NextVector3F(-0.5f, 0.5f));
            }
            Simulation.RigidBodies.Add(new RigidBody(convexHullOfPoints));

            // ----- Add a convex polyhedron.
            // (A ConvexPolyhedron is similar to the ConvexHullOfPoints. The difference is that
            // the points in a ConvexHullOfPoints can be changed at runtime. A ConvexPolyhedron
            // cannot be changed at runtime, but it is faster.)
            List <Vector3F> points = new List <Vector3F>();

            for (int i = 0; i < 20; i++)
            {
                points.Add(RandomHelper.Random.NextVector3F(-0.7f, 0.7f));
            }
            ConvexPolyhedron convexPolyhedron = new ConvexPolyhedron(points);

            Simulation.RigidBodies.Add(new RigidBody(convexPolyhedron));

            // ----- Add a composite shape (a table that consists of 5 boxes).
            CompositeShape composite = new CompositeShape();

            composite.Children.Add(new GeometricObject(new BoxShape(0.1f, 0.8f, 0.1f), new Pose(new Vector3F(-0.75f, 0.4f, -0.5f))));
            composite.Children.Add(new GeometricObject(new BoxShape(0.1f, 0.8f, 0.1f), new Pose(new Vector3F(0.75f, 0.4f, -0.5f))));
            composite.Children.Add(new GeometricObject(new BoxShape(0.1f, 0.8f, 0.1f), new Pose(new Vector3F(-0.75f, 0.4f, 0.5f))));
            composite.Children.Add(new GeometricObject(new BoxShape(0.1f, 0.8f, 0.1f), new Pose(new Vector3F(0.75f, 0.4f, 0.5f))));
            composite.Children.Add(new GeometricObject(new BoxShape(1.8f, 0.1f, 1.1f), new Pose(new Vector3F(0, 0.8f, 0))));
            Simulation.RigidBodies.Add(new RigidBody(composite));

            // ----- Add a convex hull of multiple shapes.
            ConvexHullOfShapes convexHullOfShapes = new ConvexHullOfShapes();

            convexHullOfShapes.Children.Add(new GeometricObject(new CylinderShape(0.2f, 0.8f), new Pose(new Vector3F(-0.4f, 0, 0))));
            convexHullOfShapes.Children.Add(new GeometricObject(new CylinderShape(0.2f, 0.8f), new Pose(new Vector3F(+0.4f, 0, 0))));
            Simulation.RigidBodies.Add(new RigidBody(convexHullOfShapes));

            // ----- Add the Minkowski sum of two shapes.
            // (The Minkowski sum is a mathematical operation that combines two shapes.
            // Here a circle is combined with a sphere. The result is a wheel.)
            MinkowskiSumShape minkowskiSum = new MinkowskiSumShape();

            minkowskiSum.ObjectA = new GeometricObject(new SphereShape(0.2f), Pose.Identity);
            minkowskiSum.ObjectB = new GeometricObject(new CircleShape(0.5f), Pose.Identity);
            Simulation.RigidBodies.Add(new RigidBody(minkowskiSum));

            // Create another Minkowski sum. (Here a small sphere is added to a box to create a
            // box with rounded corners.)
            minkowskiSum         = new MinkowskiSumShape();
            minkowskiSum.ObjectA = new GeometricObject(new SphereShape(0.1f), Pose.Identity);
            minkowskiSum.ObjectB = new GeometricObject(new BoxShape(0.2f, 0.5f, 0.8f), Pose.Identity);
            Simulation.RigidBodies.Add(new RigidBody(minkowskiSum));

            // ----- Add a triangle mesh.
            // A triangle mesh could be loaded from a file or built from an XNA model.
            // Here we first create a composite shape and convert the shape into a triangle
            // mesh. (Any Shape in DigitalRune.Geometry can be converted to a triangle mesh.)
            CompositeShape dumbbell = new CompositeShape();

            dumbbell.Children.Add(new GeometricObject(new SphereShape(0.4f), new Pose(new Vector3F(0.6f, 0.0f, 0.0f))));
            dumbbell.Children.Add(new GeometricObject(new SphereShape(0.4f), new Pose(new Vector3F(-0.6f, 0.0f, 0.0f))));
            dumbbell.Children.Add(new GeometricObject(new CylinderShape(0.1f, 0.6f), new Pose(Matrix33F.CreateRotationZ(ConstantsF.PiOver2))));

            TriangleMeshShape triangleMeshShape = new TriangleMeshShape(dumbbell.GetMesh(0.01f, 2));

            // Optional: We can enable "contact welding". When this flag is enabled, the triangle shape
            // precomputes additional internal information for the mesh. The collision detection will
            // be able to compute better contacts (e.g. better normal vectors at triangle edges).
            // Pro: Collision detection can compute better contact information.
            // Con: Contact welding information needs a bit of memory. And the collision detection is
            // a bit slower.
            triangleMeshShape.EnableContactWelding = true;

            // Optional: Assign a spatial partitioning scheme to the triangle mesh. (A spatial partition
            // adds an additional memory overhead, but it improves collision detection speed tremendously!)
            triangleMeshShape.Partition = new AabbTree <int>();

            Simulation.RigidBodies.Add(new RigidBody(triangleMeshShape));

            // ----- Set random positions/orientations.
            // (Start with the second object. The first object is the ground plane which should
            // not be changed.)
            for (int i = 1; i < Simulation.RigidBodies.Count; i++)
            {
                RigidBody body = Simulation.RigidBodies[i];

                Vector3F position = RandomHelper.Random.NextVector3F(-3, 3);
                position.Y = 3; // Position the objects 3m above ground.
                QuaternionF orientation = RandomHelper.Random.NextQuaternionF();
                body.Pose = new Pose(position, orientation);
            }
        }
Example #9
0
        public static void Load(CollisionDomain collisionDomain)
        {
            // Create a box for the ground.
            AddObject("Ground", new Pose(new Vector3F(0, -5, 0)), new BoxShape(60, 10, 60), collisionDomain);

            // Create a small flying sphere to visualize the approx. head height. - This is just
            // for debugging so that we have a feeling for heights.
            AddObject("Sphere", new Pose(new Vector3F(0, 1.5f, 0)), new SphereShape(0.2f), collisionDomain);

            // Create small walls at the level boundary.
            AddObject("WallLeft", new Pose(new Vector3F(-30, 1, 0)), new BoxShape(0.3f, 2, 60), collisionDomain);
            AddObject("WallRight", new Pose(new Vector3F(30, 1, 0)), new BoxShape(0.3f, 2, 60), collisionDomain);
            AddObject("WallFront", new Pose(new Vector3F(0, 1, -30)), new BoxShape(60, 2, 0.3f), collisionDomain);
            AddObject("WallBack", new Pose(new Vector3F(0, 1, 30)), new BoxShape(60, 2, 0.3f), collisionDomain);

            // Create a few bigger objects.
            // We position the boxes so that we have a few corners we can run into. Character controllers
            // should be stable when the user runs into corners.
            AddObject("House0", new Pose(new Vector3F(10, 1, -10)), new BoxShape(8, 2, 8f), collisionDomain);
            AddObject("House1", new Pose(new Vector3F(13, 1, -4)), new BoxShape(2, 2, 4), collisionDomain);
            AddObject("House2", new Pose(new Vector3F(10, 2, -15), Matrix33F.CreateRotationY(-0.3f)), new BoxShape(8, 4, 2), collisionDomain);

            //
            // Create stairs with increasing step height.
            //
            // Each step is a box. With this object we can test if our character can climb up
            // stairs. The character controller has a step height limit. Increasing step heights
            // let us test if the step height limit works.
            float       startHeight = 0;
            const float stepDepth   = 1f;

            for (int i = 0; i < 10; i++)
            {
                float    stepHeight = 0.1f + i * 0.05f;
                Pose     pose       = new Pose(new Vector3F(0, startHeight + stepHeight / 2, -2 - i * stepDepth));
                BoxShape shape      = new BoxShape(2, stepHeight, stepDepth);
                AddObject("Step" + i, pose, shape, collisionDomain);
                startHeight += stepHeight;
            }

            //
            // Create a height field.
            //
            // Terrain that is uneven is best modeled with a height field. Height fields are faster
            // than general triangle meshes.
            // The height direction is the y direction.
            // The height field lies in the x/z plane.
            var numberOfSamplesX = 20;
            var numberOfSamplesZ = 20;
            var samples          = new float[numberOfSamplesX * numberOfSamplesZ];

            // Create arbitrary height values.
            for (int z = 0; z < numberOfSamplesZ; z++)
            {
                for (int x = 0; x < numberOfSamplesX; x++)
                {
                    if (x == 0 || z == 0 || x == 19 || z == 19)
                    {
                        // Set this boundary elements to a low height, so that the height field is connected
                        // to the ground.
                        samples[z * numberOfSamplesX + x] = -1;
                    }
                    else
                    {
                        // A sine/cosine function that creates some interesting waves.
                        samples[z * numberOfSamplesX + x] = 1.0f + (float)(Math.Cos(z / 2f) * Math.Sin(x / 2f) * 1.0f);
                    }
                }
            }
            var heightField = new HeightField(0, 0, 20, 20, samples, numberOfSamplesX, numberOfSamplesZ);

            AddObject("Heightfield", new Pose(new Vector3F(10, 0, 10)), heightField, collisionDomain);

            // Create rubble on the floor (small random objects on the floor).
            // Our character should be able to move over small bumps on the ground.
            for (int i = 0; i < 50; i++)
            {
                Pose pose = new Pose(
                    new Vector3F(RandomHelper.Random.NextFloat(-5, 5), 0, RandomHelper.Random.NextFloat(10, 20)),
                    RandomHelper.Random.NextQuaternionF());
                BoxShape shape = new BoxShape(RandomHelper.Random.NextVector3F(0.05f, 0.8f));
                AddObject("Stone" + i, pose, shape, collisionDomain);
            }

            // Create some slopes to see how our character performs on/under sloped surfaces.
            // Here we can test how the character controller behaves if the head touches an inclined
            // ceiling.
            AddObject("SlopeGround", new Pose(new Vector3F(-2, 1.8f, -12), QuaternionF.CreateRotationX(0.4f)), new BoxShape(2, 0.5f, 10), collisionDomain);
            AddObject("SlopeRoof", new Pose(new Vector3F(-2, 5.6f, -12), QuaternionF.CreateRotationX(-0.4f)), new BoxShape(2, 0.5f, 10), collisionDomain);

            // Slopes with different tilt angles.
            // The character controller has a slope limit. Only flat slopes should be climbable.
            for (int i = 0; i < 10; i++)
            {
                float stepHeight = 0.1f + i * 0.1f;
                Pose  pose       = new Pose(
                    new Vector3F(-10, i * 0.5f, -i * 2),
                    Matrix33F.CreateRotationX(MathHelper.ToRadians(10) + i * MathHelper.ToRadians(10)));
                BoxShape shape = new BoxShape(8 * (1 - i * 0.1f), 0.5f, 30);
                AddObject("Slope" + i, pose, shape, collisionDomain);
                startHeight += stepHeight;
            }

            // Create a slope with a wall on one side.
            // This objects let's us test how the character controller behaves while falling and
            // sliding along a vertical wall. (Run up the slope and then jump down while moving into
            // the wall.)
            AddObject("LongSlope", new Pose(new Vector3F(-20, 3, -10), Matrix33F.CreateRotationX(0.4f)), new BoxShape(4, 5f, 30), collisionDomain);
            AddObject("LongSlopeWall", new Pose(new Vector3F(-22, 5, -10)), new BoxShape(0.5f, 10f, 25), collisionDomain);

            // Create a mesh object to test walking on triangle meshes.
            // Normally, the mesh would be loaded from a file. Here, we make a composite shape and
            // let DigitalRune Geometry compute a mesh for it. Then we throw away the composite
            // shape and use only the mesh. - We do this to test triangle meshes. Using the composite
            // shape instead of the triangle mesh would be a lot faster.
            CompositeShape compositeShape = new CompositeShape();

            compositeShape.Children.Add(new GeometricObject(heightField, Pose.Identity));
            compositeShape.Children.Add(new GeometricObject(new CylinderShape(1, 2), new Pose(new Vector3F(10, 1, 10))));
            compositeShape.Children.Add(new GeometricObject(new SphereShape(3), new Pose(new Vector3F(15, 0, 15))));
            compositeShape.Children.Add(new GeometricObject(new BoxShape(1, 2, 3), new Pose(new Vector3F(15, 0, 5))));
            ITriangleMesh     mesh      = compositeShape.GetMesh(0.01f, 3);
            TriangleMeshShape meshShape = new TriangleMeshShape(mesh);

            // Collision detection speed for triangle meshes can be improved by using a spatial
            // partition. Here, we assign an AabbTree to the triangle mesh shape. The tree is
            // built automatically when needed and it stores triangle indices (therefore the generic
            // parameter of the AabbTree is int).
            meshShape.Partition = new AabbTree <int>()
            {
                // The tree is automatically built using a mixed top-down/bottom-up approach. Bottom-up
                // building is slower but produces better trees. If the tree building takes too long,
                // we can lower the BottomUpBuildThreshold (default is 128).
                BottomUpBuildThreshold = 0,
            };

            AddObject("Mesh", new Pose(new Vector3F(-30, 0, 10)), meshShape, collisionDomain);
        }