public void GetAxisAlignedBoundingBox()
        {
            Assert.AreEqual(new Aabb(new Vector3F(0, -100, 0), new Vector3F(1000, 0, 1000)),
                            new HeightField().GetAabb(Pose.Identity));
            Assert.AreEqual(new Aabb(new Vector3F(1000, -101, 2000), new Vector3F(1100, 5, 2200)),
                            _field.GetAabb(Pose.Identity));
            Assert.AreEqual(new Aabb(new Vector3F(0, -1, 0), new Vector3F(10, 5, 20)),
                            new HeightField(0, 0, 10, 20, _samples, 3, 8)
            {
                Depth = 0
            }.GetAabb(Pose.Identity));

            // Now with pose.
            QuaternionF rotation = QuaternionF.CreateRotationX(0.2f);
            Pose        pose     = new Pose(new Vector3F(1, 1, 1), rotation);

            _field.Depth = 0;
            var box = new TransformedShape(
                new GeometricObject(new BoxShape(100, 6, 200), new Pose(new Vector3F(1050, 2, 2100))));

            Assert.IsTrue(Vector3F.AreNumericallyEqual(box.GetAabb(pose).Minimum, _field.GetAabb(pose).Minimum));
            _field.Depth = 4;
            box          = new TransformedShape(
                new GeometricObject(new BoxShape(100, 10, 200), new Pose(new Vector3F(1000, 0, 2000))));
            Assert.IsTrue(Vector3F.AreNumericallyEqual(box.GetAabb(pose).Minimum + rotation.Rotate(new Vector3F(50, 0, 100)), _field.GetAabb(pose).Minimum));
        }
        public void CreateRotationX()
        {
            float       angle = 0.3f;
            QuaternionF q     = QuaternionF.CreateRotation(Vector3F.UnitX, angle);
            QuaternionF qx    = QuaternionF.CreateRotationX(angle);

            Assert.AreEqual(q, qx);
        }
Beispiel #3
0
 public void PropertiesTest()
 {
     Assert.AreEqual(3, ((CircleShape)cs.ObjectA.Shape).Radius);
     Assert.AreEqual(new Vector3F(0, 5, 0), ((LineSegmentShape)cs.ObjectB.Shape).Start);
     Assert.AreEqual(new Vector3F(0, -5, 0), ((LineSegmentShape)cs.ObjectB.Shape).End);
     Assert.AreEqual(new Pose(new Vector3F(1, 0, 0), QuaternionF.CreateRotationX(ConstantsF.PiOver2)), cs.ObjectA.Pose);
     Assert.AreEqual(Pose.Identity, cs.ObjectB.Pose);
 }
Beispiel #4
0
        public void HasRotationTest()
        {
            var srt = new SrtTransform(new Vector3F(1, 1, 1), QuaternionF.Identity, Vector3F.Zero);

            Assert.IsFalse(srt.HasRotation);

            srt.Rotation = QuaternionF.CreateRotationX(0.000001f);
            Assert.IsFalse(srt.HasRotation);

            srt.Rotation = QuaternionF.CreateRotationX(0.1f);
            Assert.IsTrue(srt.HasRotation);
        }
 public void GetAxisAlignedBoundingBox()
 {
     Assert.AreEqual(new Aabb(), new RectangleShape().GetAabb(Pose.Identity));
     Assert.AreEqual(new Aabb(new Vector3F(10, 100, -13), new Vector3F(10, 100, -13)),
                     new RectangleShape().GetAabb(new Pose(new Vector3F(10, 100, -13),
                                                           QuaternionF.CreateRotation(new Vector3F(1, 1, 1), 0.7f))));
     Assert.AreEqual(new Aabb(new Vector3F(5, 90, 1000), new Vector3F(15, 110, 1000)),
                     new RectangleShape(10, 20).GetAabb(new Pose(new Vector3F(10, 100, 1000),
                                                                 QuaternionF.Identity)));
     Assert.AreEqual(new Aabb(new Vector3F(5, 100, 990), new Vector3F(15, 100, 1010)),
                     new RectangleShape(10, 20).GetAabb(new Pose(new Vector3F(10, 100, 1000),
                                                                 QuaternionF.CreateRotationX(ConstantsF.PiOver2))));
     // TODO: Test complex rotations.
 }
Beispiel #6
0
        public void ResetPose()
        {
            _currentYaw   = _defaultYaw;
            _currentPitch = _defaultPitch;

            if (IsLoaded)
            {
                // Also update SceneNode.LastPose - this is required for some effect, like
                // object motion blur.
                CameraNode.SetLastPose(true);

                CameraNode.PoseWorld = new Pose(
                    _defaultPosition,
                    QuaternionF.CreateRotationY(_currentYaw) * QuaternionF.CreateRotationX(_currentPitch));
            }
        }
Beispiel #7
0
        public void Test1()
        {
            Pose p = Pose.Identity;

            Assert.AreEqual(Matrix44F.Identity, p.ToMatrix44F());
            Assert.AreEqual(Matrix33F.Identity, p.Orientation);
            Assert.AreEqual(Vector3F.Zero, p.Position);

            p.Position = new Vector3F(1, 2, 3);

            p.Orientation = Matrix33F.CreateRotation(new Vector3F(3, -4, 9), 0.49f);
            Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToWorldDirection(Vector3F.UnitX), 0), p * new Vector4F(1, 0, 0, 0)));
            Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToWorldDirection(Vector3F.UnitY), 0), p * new Vector4F(0, 1, 0, 0)));
            Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToWorldDirection(Vector3F.UnitZ), 0), p * new Vector4F(0, 0, 1, 0)));
            Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToWorldPosition(Vector3F.UnitX), 1), p * new Vector4F(1, 0, 0, 1)));
            Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToWorldPosition(Vector3F.UnitY), 1), p * new Vector4F(0, 1, 0, 1)));
            Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToWorldPosition(Vector3F.UnitZ), 1), p * new Vector4F(0, 0, 1, 1)));
            Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToLocalDirection(Vector3F.UnitX), 0), p.Inverse * new Vector4F(1, 0, 0, 0)));
            Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToLocalDirection(Vector3F.UnitY), 0), p.Inverse * new Vector4F(0, 1, 0, 0)));
            Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToLocalDirection(Vector3F.UnitZ), 0), p.Inverse * new Vector4F(0, 0, 1, 0)));
            Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToLocalPosition(Vector3F.UnitX), 1), p.Inverse * new Vector4F(1, 0, 0, 1)));
            Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToLocalPosition(Vector3F.UnitY), 1), p.Inverse * new Vector4F(0, 1, 0, 1)));
            Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToLocalPosition(Vector3F.UnitZ), 1), p.Inverse * new Vector4F(0, 0, 1, 1)));

            Pose p2 = Pose.FromMatrix(new Matrix44F(p.Orientation, Vector3F.Zero));

            Assert.IsTrue(Matrix33F.AreNumericallyEqual(p.Orientation, p2.Orientation));
            Assert.IsTrue(Vector3F.AreNumericallyEqual(p2.Position, Vector3F.Zero));

            Matrix44F m = p2;

            m.SetColumn(3, new Vector4F(p.Position, 1));
            p2 = Pose.FromMatrix(m);
            Assert.IsTrue(Matrix33F.AreNumericallyEqual(p.Orientation, p2.Orientation));
            Assert.AreEqual(p.Position, p2.Position);
            //Assert.IsTrue(Vector3F.AreNumericallyEqual(p.Position, p2.Position));

            // Test other constructors.
            Assert.AreEqual(Vector3F.Zero, new Pose(QuaternionF.CreateRotationX(0.3f)).Position);
            Assert.AreEqual(Matrix33F.CreateRotationX(0.3f), new Pose(Matrix33F.CreateRotationX(0.3f)).Orientation);
            Assert.AreEqual(new Vector3F(1, 2, 3), new Pose(new Vector3F(1, 2, 3)).Position);
            Assert.AreEqual(Matrix33F.Identity, new Pose(new Vector3F(1, 2, 3)).Orientation);
        }
        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

            // Change rotation angle.
            if (_moveArmDown)
            {
                _upperArmAngle -= 0.3f * deltaTime;
            }
            else
            {
                _upperArmAngle += 0.3f * deltaTime;
            }

            // Change direction when a certain angle is reached.
            if (Math.Abs(_upperArmAngle) > 0.5f)
            {
                _moveArmDown = !_moveArmDown;
            }

            // Get the bone index of the upper arm bone.
            var skeleton      = _meshNode.Mesh.Skeleton;
            int upperArmIndex = skeleton.GetIndex("L_UpperArm");

            // Define the desired bone transform.
            SrtTransform boneTransform = new SrtTransform(QuaternionF.CreateRotationY(_upperArmAngle));

            // Set the new bone transform.
            var skeletonPose = _meshNode.SkeletonPose;

            skeletonPose.SetBoneTransform(upperArmIndex, boneTransform);

            // The class SkeletonHelper provides some useful extension methods.
            // One is SetBoneRotationAbsolute() which sets the orientation of a bone relative
            // to model space.
            int handIndex = skeleton.GetIndex("L_Hand");

            SkeletonHelper.SetBoneRotationAbsolute(skeletonPose, handIndex, QuaternionF.CreateRotationX(ConstantsF.Pi));
        }
        public void ResetPose()
        {
            positionFilter.Reset();
            orientationFilter.Reset();
            positionFilter.RawValue[0]    = _defaultPosition.X;
            positionFilter.RawValue[1]    = _defaultPosition.Y;
            positionFilter.RawValue[2]    = _defaultPosition.Z;
            orientationFilter.RawValue[0] = _defaultYaw;
            orientationFilter.RawValue[1] = _defaultPitch;

            if (IsLoaded)
            {
                // Also update SceneNode.LastPose - this is required for some effect, like
                // object motion blur.
                CameraNode.SetLastPose(true);

                CameraNode.PoseWorld = new Pose(
                    _defaultPosition,
                    QuaternionF.CreateRotationY(_defaultYaw) * QuaternionF.CreateRotationX(_defaultPitch));
            }
        }
        // This method shows how to safely compare vectors.
        private void CompareVectors()
        {
            var debugRenderer = GraphicsScreen.DebugRenderer2D;

            debugRenderer.DrawText("----- CompareVectors Example:");

            // Define a vector.
            Vector3F v0 = new Vector3F(1000, 2000, 3000);

            // Define a rotation quaternion that rotates 360° around the x axis.
            QuaternionF rotation = QuaternionF.CreateRotationX(MathHelper.ToRadians(360));

            // Rotate v0.
            Vector3F v1 = rotation.Rotate(v0);

            // The rotated vector v1 should be identical to v0 because a 360° rotation
            // should not change the vector. - But due to numerical errors v0 and v1 are
            // not equal.
            if (v0 == v1)
            {
                debugRenderer.DrawText("Vectors are equal.");
            }
            else
            {
                debugRenderer.DrawText("Vectors are not equal."); // This message is written.
            }
            // With Vector3F.AreNumericallyEqual() we can check if two vectors are equal
            // when we allow a small numeric tolerance. The tolerance that is applied is
            // Numeric.EpsilonF, e.g. 10^-5.
            if (Vector3F.AreNumericallyEqual(v0, v1))
            {
                debugRenderer.DrawText("Vectors are numerically equal.\n"); // This message is written.
            }
            else
            {
                debugRenderer.DrawText("Vectors are not numerically equal.\n");
            }
        }
Beispiel #11
0
        // OnLoad() is called when the GameObject is added to the IGameObjectService.
        protected override void OnLoad()
        {
            var content = _services.GetInstance <ContentManager>();

            _skyboxNode = new SkyboxNode(content.Load <TextureCube>("Sky2"))
            {
                Color = new Vector3F(SkyExposure),
            };

            // The ambient light.
            var ambientLight = new AmbientLight
            {
                Color     = new Vector3F(0.9f, 0.9f, 1f),
                HdrScale  = 0.1f,
                Intensity = 0.5f,
                HemisphericAttenuation = 0.8f,
            };

            _ambientLightNode = new LightNode(ambientLight)
            {
                Name = "Ambient",
            };

            // The main directional light.
            var sunlight = new DirectionalLight
            {
                Color             = new Vector3F(1, 0.9607844f, 0.9078432f),
                HdrScale          = 0.4f,
                DiffuseIntensity  = 1,
                SpecularIntensity = 1,
            };

            _sunlightNode = new LightNode(sunlight)
            {
                Name      = "Sunlight",
                Priority  = 10, // This is the most important light.
                PoseWorld = new Pose(QuaternionF.CreateRotationY(-1.4f) * QuaternionF.CreateRotationX(-0.6f)),

                // This light uses Cascaded Shadow Mapping.
                Shadow = new CascadedShadow
                {
#if XBOX
                    PreferredSize = 512,
#else
                    PreferredSize = 1024,
#endif
                    Prefer16Bit = true,
                }
            };

            // Add a lens flare for the key light.
            var lensFlare = new LensFlare(true)
            {
                QuerySize = 0.2f, Size = 0.2f, Name = "Sun Flare"
            };
            var lensFlareTexture = content.Load <Texture2D>("LensFlare/LensFlares");
            var circleTexture    = new PackedTexture("Circle", lensFlareTexture, new Vector2F(0, 0), new Vector2F(0.25f, 0.5f));
            var glowTexture      = new PackedTexture("Glow", lensFlareTexture, new Vector2F(0.25f, 0), new Vector2F(0.25f, 0.5f));
            var ringTexture      = new PackedTexture("Ring", lensFlareTexture, new Vector2F(0.5f, 0), new Vector2F(0.25f, 0.5f));
            var haloTexture      = new PackedTexture("Halo", lensFlareTexture, new Vector2F(0.75f, 0), new Vector2F(0.25f, 0.5f));
            var sunTexture       = new PackedTexture("Sun", lensFlareTexture, new Vector2F(0, 0.5f), new Vector2F(0.25f, 0.5f));
            var streaksTexture   = new PackedTexture("Streaks", lensFlareTexture, new Vector2F(0.25f, 0.5f), new Vector2F(0.25f, 0.5f));
            var flareTexture     = new PackedTexture("Flare", lensFlareTexture, new Vector2F(0.5f, 0.5f), new Vector2F(0.25f, 0.5f));
            lensFlare.Elements.Add(new LensFlareElement(-0.2f, 0.55f, 0.0f, new Color(175, 175, 255, 20), new Vector2F(0.5f, 0.5f), circleTexture));
            lensFlare.Elements.Add(new LensFlareElement(0.0f, 0.9f, 0.0f, new Color(255, 255, 255, 255), new Vector2F(0.5f, 0.5f), sunTexture));
            lensFlare.Elements.Add(new LensFlareElement(0.0f, 1.8f, 0.0f, new Color(255, 255, 255, 128), new Vector2F(0.5f, 0.5f), streaksTexture));
            lensFlare.Elements.Add(new LensFlareElement(0.0f, 2.6f, 0.0f, new Color(255, 255, 200, 64), new Vector2F(0.5f, 0.5f), glowTexture));
            lensFlare.Elements.Add(new LensFlareElement(0.5f, 0.12f, 0.0f, new Color(60, 60, 180, 35), new Vector2F(0.5f, 0.5f), circleTexture));
            lensFlare.Elements.Add(new LensFlareElement(0.55f, 0.46f, 0.0f, new Color(100, 100, 200, 60), new Vector2F(0.5f, 0.5f), circleTexture));
            lensFlare.Elements.Add(new LensFlareElement(0.6f, 0.17f, 0.0f, new Color(120, 120, 220, 40), new Vector2F(0.5f, 0.5f), circleTexture));
            lensFlare.Elements.Add(new LensFlareElement(0.85f, 0.2f, 0.0f, new Color(60, 60, 255, 100), new Vector2F(0.5f, 0.5f), ringTexture));
            lensFlare.Elements.Add(new LensFlareElement(1.5f, 0.2f, 0.0f, new Color(255, 60, 60, 130), new Vector2F(0.5f, 0.5f), flareTexture));
            lensFlare.Elements.Add(new LensFlareElement(0.15f, 0.15f, 0.0f, new Color(255, 60, 60, 90), new Vector2F(0.5f, 0.5f), flareTexture));
            lensFlare.Elements.Add(new LensFlareElement(1.3f, 0.6f, 0.0f, new Color(60, 60, 255, 180), new Vector2F(0.5f, 0.5f), haloTexture));
            lensFlare.Elements.Add(new LensFlareElement(1.4f, 0.2f, 0.0f, new Color(220, 80, 80, 98), new Vector2F(0.5f, 0.5f), haloTexture));
            lensFlare.Elements.Add(new LensFlareElement(1.5f, 0.1f, 0.0f, new Color(220, 80, 80, 85), new Vector2F(0.5f, 0.5f), circleTexture));
            lensFlare.Elements.Add(new LensFlareElement(1.6f, 0.5f, 0.0f, new Color(60, 60, 255, 80), new Vector2F(0.5f, 0.5f), haloTexture));
            lensFlare.Elements.Add(new LensFlareElement(1.8f, 0.3f, 0.0f, new Color(90, 60, 255, 110), new Vector2F(0.5f, 0.5f), ringTexture));
            lensFlare.Elements.Add(new LensFlareElement(1.95f, 0.5f, 0.0f, new Color(60, 60, 255, 120), new Vector2F(0.5f, 0.5f), haloTexture));
            lensFlare.Elements.Add(new LensFlareElement(2.0f, 0.15f, 0.0f, new Color(60, 60, 255, 85), new Vector2F(0.5f, 0.5f), circleTexture));

            // Add lens flare as a child of the sunlight.
            var lensFlareNode = new LensFlareNode(lensFlare);
            _sunlightNode.Children = new SceneNodeCollection();
            _sunlightNode.Children.Add(lensFlareNode);

            // Add scene nodes to scene graph.
            var scene = _services.GetInstance <IScene>();
            scene.Children.Add(_skyboxNode);
            scene.Children.Add(_ambientLightNode);
            scene.Children.Add(_sunlightNode);
        }
Beispiel #12
0
        public void TransformedShapeNonuniformScaleWithRotationNotSupported()
        {
            var       s = new TransformedShape(new GeometricObject(new BoxShape(3, 2, 1), new Vector3F(0.7f, 0.8f, 0.9f), new Pose(new Vector3F(-1, 7, 4), QuaternionF.CreateRotationX(1))));
            float     m0;
            Vector3F  com0;
            Matrix33F i0;

            MassHelper.GetMass(s, new Vector3F(2, 2.1f, 2.8f), 1, true, 0.001f, 10, out m0, out com0, out i0);
        }
        //--------------------------------------------------------------
        #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);
            }
        }
Beispiel #14
0
        public void CompressSrtKeyFrameAnimation()
        {
            var random = new Random(12345);

            float scaleThreshold       = 0.1f;
            float rotationThreshold    = 2; // [°]
            float translationThreshold = 0.2f;

            var srtKeyFrameAnimation = new SrtKeyFrameAnimation();

            // Define a view important keyframes.
            var time0  = TimeSpan.FromTicks(100000);
            var value0 = new SrtTransform(Vector3F.One, QuaternionF.Identity, Vector3F.Zero);

            var time1  = TimeSpan.FromTicks(200000);
            var value1 = new SrtTransform(new Vector3F(2, 2, 2), QuaternionF.CreateRotationX(MathHelper.ToRadians(10)), new Vector3F(1, 1, 1));

            var time2  = TimeSpan.FromTicks(400000);
            var value2 = new SrtTransform(new Vector3F(-1, -1, -1), QuaternionF.CreateRotationX(MathHelper.ToRadians(80)), new Vector3F(10, 10, 10));

            var time3  = TimeSpan.FromTicks(500000);
            var value3 = new SrtTransform(new Vector3F(3, 3, 3), QuaternionF.CreateRotationX(MathHelper.ToRadians(-10)), new Vector3F(-2, -2, -2));

            srtKeyFrameAnimation.KeyFrames.Add(new KeyFrame <SrtTransform>(time0, value0));
            srtKeyFrameAnimation.KeyFrames.Add(new KeyFrame <SrtTransform>(time1, value1));
            srtKeyFrameAnimation.KeyFrames.Add(new KeyFrame <SrtTransform>(time2, value2));
            srtKeyFrameAnimation.KeyFrames.Add(new KeyFrame <SrtTransform>(time3, value3));

            // Add random keyframes within tolerance.
            InsertRandomKeyFrames(random, srtKeyFrameAnimation, time0, time1, scaleThreshold, rotationThreshold, translationThreshold);
            InsertRandomKeyFrames(random, srtKeyFrameAnimation, time1, time2, scaleThreshold, rotationThreshold, translationThreshold);
            InsertRandomKeyFrames(random, srtKeyFrameAnimation, time2, time3, scaleThreshold, rotationThreshold, translationThreshold);

            // ---- Compress animation with tolerance.
            var srtAnimation = AnimationHelper.Compress(srtKeyFrameAnimation, scaleThreshold, rotationThreshold, translationThreshold);

            Assert.IsNotNull(srtAnimation);
            Assert.AreEqual(srtKeyFrameAnimation.GetTotalDuration(), srtAnimation.GetTotalDuration());
            Assert.IsNotNull(srtAnimation.Scale);

            Assert.AreEqual(4, ((KeyFrameAnimation <Vector3F>)srtAnimation.Scale).KeyFrames.Count);
            Assert.AreEqual(4, ((KeyFrameAnimation <QuaternionF>)srtAnimation.Rotation).KeyFrames.Count);
            Assert.AreEqual(4, ((KeyFrameAnimation <Vector3F>)srtAnimation.Translation).KeyFrames.Count);

            var defaultSource = SrtTransform.Identity;
            var defaultTarget = SrtTransform.Identity;
            var result        = new SrtTransform();

            srtAnimation.GetValue(time0, ref defaultSource, ref defaultTarget, ref result);
            Assert.AreEqual(value0, result);

            srtAnimation.GetValue(time1, ref defaultSource, ref defaultTarget, ref result);
            Assert.AreEqual(value1, result);

            srtAnimation.GetValue(time2, ref defaultSource, ref defaultTarget, ref result);
            Assert.AreEqual(value2, result);

            srtAnimation.GetValue(time3, ref defaultSource, ref defaultTarget, ref result);
            Assert.AreEqual(value3, result);

            // Take a view samples.
            const int numberOfSamples = 10;
            long      tickIncrement   = (time3 - time0).Ticks / (numberOfSamples + 1);

            for (int i = 0; i < numberOfSamples; i++)
            {
                var time = TimeSpan.FromTicks(time0.Ticks + (i + 1) * tickIncrement);

                var valueRef = new SrtTransform();
                srtKeyFrameAnimation.GetValue(time, ref defaultSource, ref defaultTarget, ref valueRef);

                var valueNew = new SrtTransform();
                srtAnimation.GetValue(time, ref defaultSource, ref defaultTarget, ref valueNew);

                Assert.IsTrue((valueRef.Scale - valueNew.Scale).Length <= scaleThreshold);
                Assert.IsTrue(QuaternionF.GetAngle(valueRef.Rotation, valueNew.Rotation) <= MathHelper.ToRadians(rotationThreshold));
                Assert.IsTrue((valueRef.Translation - valueNew.Translation).Length <= translationThreshold);
            }

            // ----- Compress animation with zero tolerance.
            srtAnimation = AnimationHelper.Compress(srtKeyFrameAnimation, 0, 0, 0);

            Assert.IsNotNull(srtAnimation);
            Assert.AreEqual(srtKeyFrameAnimation.GetTotalDuration(), srtAnimation.GetTotalDuration());
            Assert.IsNotNull(srtAnimation.Scale);

            Assert.AreEqual(srtKeyFrameAnimation.KeyFrames.Count, ((KeyFrameAnimation <Vector3F>)srtAnimation.Scale).KeyFrames.Count);
            Assert.AreEqual(srtKeyFrameAnimation.KeyFrames.Count, ((KeyFrameAnimation <QuaternionF>)srtAnimation.Rotation).KeyFrames.Count);
            Assert.AreEqual(srtKeyFrameAnimation.KeyFrames.Count, ((KeyFrameAnimation <Vector3F>)srtAnimation.Translation).KeyFrames.Count);

            // Take a view samples.
            for (int i = 0; i < numberOfSamples; i++)
            {
                var time = TimeSpan.FromTicks(time0.Ticks + (i + 1) * tickIncrement);

                var valueRef = new SrtTransform();
                srtKeyFrameAnimation.GetValue(time, ref defaultSource, ref defaultTarget, ref valueRef);

                var valueNew = new SrtTransform();
                srtAnimation.GetValue(time, ref defaultSource, ref defaultTarget, ref valueNew);

                Assert.IsTrue(SrtTransform.AreNumericallyEqual(valueRef, valueNew));
            }
        }
        /// <summary>
        /// Creates a <see cref="Ragdoll"/> for an Xbox LIVE Avatar. (Only available on Xbox 360.)
        /// </summary>
        /// <param name="skeleton">The skeleton of the Xbox LIVE Avatar.</param>
        /// <param name="simulation">The simulation.</param>
        /// <returns>The avatar ragdoll.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="skeleton"/> or <paramref name="simulation"/> is
        /// <see langword="null"/>.
        /// </exception>
        /// <remarks>
        /// This method is available only in the Xbox 360 build of the
        /// DigitalRune.Physics.Specialized.dll.
        /// </remarks>
        public static Ragdoll CreateAvatarRagdoll(Skeleton skeleton, Simulation simulation)
        {
            if (skeleton == null)
            {
                throw new ArgumentNullException("skeleton");
            }
            if (simulation == null)
            {
                throw new ArgumentNullException("simulation");
            }

            var ragdoll = new Ragdoll();

            // The lists ragdoll.Bodies, ragdoll.BodyOffsets and _motors contain one entry per bone - even if there
            // is no RigidBody for this bone. - This wastes memory but simplifies the code.
            for (int i = 0; i < AvatarRenderer.BoneCount; i++)
            {
                ragdoll.Bodies.Add(null);
                ragdoll.BodyOffsets.Add(Pose.Identity);
                ragdoll.Joints.Add(null);
                ragdoll.Limits.Add(null);
                ragdoll.Motors.Add(null);
            }

            // ----- Create bodies.
            // We use the same mass for all bodies. This is not physically correct but it makes the
            // simulation more stable, for several reasons:
            // - It is better to avoid large mass differences. Therefore, all limbs have the same mass.
            // - Capsule shapes have a low inertia value about their height axis. This causes instability
            //   and it is better to use larger inertia values.
            var massFrame = MassFrame.FromShapeAndMass(new SphereShape(0.2f), Vector3F.One, 4, 0.1f, 1);

            // Use standard material.
            var material = new UniformMaterial();

            // Create rigid bodies for the important bones. The shapes have been manually adapted to
            // produce useful results for thin and overweight avatars.
            // Without offset, the bodies are centered at the joint. ragdoll.BodyOffsets stores an offset pose
            // for each body. Instead, we could use TransformedShape but we can easily handle that
            // ourselves.
            // The collar bones are special, they use dummy shapes and are only used to connect the
            // shoulder bones.
            ragdoll.Bodies[(int)AvatarBone.Root]               = new RigidBody(new BoxShape(0.22f, 0.16f, 0.16f), massFrame, material);
            ragdoll.BodyOffsets[(int)AvatarBone.Root]          = new Pose(new Vector3F(0, -0.08f, -0.01f), QuaternionF.CreateRotationX(-0.0f));
            ragdoll.Bodies[(int)AvatarBone.BackLower]          = new RigidBody(new BoxShape(0.22f, 0.16f, 0.16f), massFrame, material);
            ragdoll.BodyOffsets[(int)AvatarBone.BackLower]     = new Pose(new Vector3F(0, 0.08f, -0.01f), QuaternionF.CreateRotationX(-0.0f));
            ragdoll.Bodies[(int)AvatarBone.BackUpper]          = new RigidBody(new BoxShape(0.22f, 0.16f, 0.16f), massFrame, material);
            ragdoll.BodyOffsets[(int)AvatarBone.BackUpper]     = new Pose(new Vector3F(0, 0.08f, -0.01f), QuaternionF.CreateRotationX(-0.1f));
            ragdoll.Bodies[(int)AvatarBone.Neck]               = new RigidBody(new CapsuleShape(0.04f, 0.09f), massFrame, material);
            ragdoll.Bodies[(int)AvatarBone.Head]               = new RigidBody(new SphereShape(0.15f), massFrame, material);
            ragdoll.BodyOffsets[(int)AvatarBone.Head]          = new Pose(new Vector3F(0, 0.1f, 0));
            ragdoll.Bodies[(int)AvatarBone.CollarLeft]         = new RigidBody(Shape.Empty, massFrame, material);
            ragdoll.Bodies[(int)AvatarBone.CollarRight]        = new RigidBody(Shape.Empty, massFrame, material);
            ragdoll.Bodies[(int)AvatarBone.ShoulderLeft]       = new RigidBody(new CapsuleShape(0.04f, 0.25f), massFrame, material);
            ragdoll.BodyOffsets[(int)AvatarBone.ShoulderLeft]  = new Pose(new Vector3F(0.08f, 0, -0.02f), QuaternionF.CreateRotationZ(ConstantsF.PiOver2));
            ragdoll.Bodies[(int)AvatarBone.ShoulderRight]      = new RigidBody(new CapsuleShape(0.04f, 0.25f), massFrame, material);
            ragdoll.BodyOffsets[(int)AvatarBone.ShoulderRight] = new Pose(new Vector3F(-0.08f, 0, -0.02f), QuaternionF.CreateRotationZ(ConstantsF.PiOver2));
            ragdoll.Bodies[(int)AvatarBone.ElbowLeft]          = new RigidBody(new CapsuleShape(0.04f, 0.21f), massFrame, material);
            ragdoll.BodyOffsets[(int)AvatarBone.ElbowLeft]     = new Pose(new Vector3F(0.06f, 0, -0.02f), QuaternionF.CreateRotationZ(ConstantsF.PiOver2));
            ragdoll.Bodies[(int)AvatarBone.ElbowRight]         = new RigidBody(new CapsuleShape(0.04f, 0.21f), massFrame, material);
            ragdoll.BodyOffsets[(int)AvatarBone.ElbowRight]    = new Pose(new Vector3F(-0.06f, 0, -0.02f), QuaternionF.CreateRotationZ(ConstantsF.PiOver2));
            ragdoll.Bodies[(int)AvatarBone.WristLeft]          = new RigidBody(new BoxShape(0.1f, 0.04f, 0.1f), massFrame, material);
            ragdoll.BodyOffsets[(int)AvatarBone.WristLeft]     = new Pose(new Vector3F(0.06f, -0.02f, -0.01f), QuaternionF.CreateRotationZ(0.0f));
            ragdoll.Bodies[(int)AvatarBone.WristRight]         = new RigidBody(new BoxShape(0.1f, 0.04f, 0.1f), massFrame, material);
            ragdoll.BodyOffsets[(int)AvatarBone.WristRight]    = new Pose(new Vector3F(-0.06f, -0.02f, -0.01f), QuaternionF.CreateRotationZ(0.0f));
            ragdoll.Bodies[(int)AvatarBone.HipLeft]            = new RigidBody(new CapsuleShape(0.06f, 0.34f), massFrame, material);
            ragdoll.BodyOffsets[(int)AvatarBone.HipLeft]       = new Pose(new Vector3F(0, -0.14f, -0.02f), QuaternionF.CreateRotationX(0.1f));
            ragdoll.Bodies[(int)AvatarBone.HipRight]           = new RigidBody(new CapsuleShape(0.06f, 0.34f), massFrame, material);
            ragdoll.BodyOffsets[(int)AvatarBone.HipRight]      = new Pose(new Vector3F(0, -0.14f, -0.02f), QuaternionF.CreateRotationX(0.1f));
            ragdoll.Bodies[(int)AvatarBone.KneeLeft]           = new RigidBody(new CapsuleShape(0.06f, 0.36f), massFrame, material);
            ragdoll.BodyOffsets[(int)AvatarBone.KneeLeft]      = new Pose(new Vector3F(0, -0.18f, -0.04f), QuaternionF.CreateRotationX(0.1f));
            ragdoll.Bodies[(int)AvatarBone.KneeRight]          = new RigidBody(new CapsuleShape(0.06f, 0.36f), massFrame, material);
            ragdoll.BodyOffsets[(int)AvatarBone.KneeRight]     = new Pose(new Vector3F(0, -0.18f, -0.04f), QuaternionF.CreateRotationX(0.1f));
            ragdoll.Bodies[(int)AvatarBone.AnkleLeft]          = new RigidBody(new BoxShape(0.1f, 0.06f, 0.22f), massFrame, material);
            ragdoll.BodyOffsets[(int)AvatarBone.AnkleLeft]     = new Pose(new Vector3F(0, -0.07f, 0.05f), QuaternionF.CreateRotationZ(0));
            ragdoll.Bodies[(int)AvatarBone.AnkleRight]         = new RigidBody(new BoxShape(0.1f, 0.06f, 0.22f), massFrame, material);
            ragdoll.BodyOffsets[(int)AvatarBone.AnkleRight]    = new Pose(new Vector3F(0, -0.07f, 0.05f), QuaternionF.CreateRotationZ(0));

            // ----- Add joint constraints.
            const float jointErrorReduction = 0.2f;
            const float jointSoftness       = 0.0001f;

            AddJoint(ragdoll, skeleton, AvatarBone.Root, AvatarBone.BackLower, jointErrorReduction, jointSoftness);
            AddJoint(ragdoll, skeleton, AvatarBone.BackLower, AvatarBone.BackUpper, jointErrorReduction, jointSoftness);
            AddJoint(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.Neck, 0.6f, 0.000001f);
            AddJoint(ragdoll, skeleton, AvatarBone.Neck, AvatarBone.Head, 0.6f, 0.000001f);
            AddJoint(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.CollarLeft, jointErrorReduction, jointSoftness);
            AddJoint(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.CollarRight, jointErrorReduction, jointSoftness);
            AddJoint(ragdoll, skeleton, AvatarBone.CollarLeft, AvatarBone.ShoulderLeft, jointErrorReduction, jointSoftness);
            AddJoint(ragdoll, skeleton, AvatarBone.CollarRight, AvatarBone.ShoulderRight, jointErrorReduction, jointSoftness);
            AddJoint(ragdoll, skeleton, AvatarBone.ShoulderLeft, AvatarBone.ElbowLeft, jointErrorReduction, jointSoftness);
            AddJoint(ragdoll, skeleton, AvatarBone.ShoulderRight, AvatarBone.ElbowRight, jointErrorReduction, jointSoftness);
            AddJoint(ragdoll, skeleton, AvatarBone.ElbowLeft, AvatarBone.WristLeft, jointErrorReduction, jointSoftness);
            AddJoint(ragdoll, skeleton, AvatarBone.ElbowRight, AvatarBone.WristRight, jointErrorReduction, jointSoftness);
            AddJoint(ragdoll, skeleton, AvatarBone.Root, AvatarBone.HipLeft, jointErrorReduction, jointSoftness);
            AddJoint(ragdoll, skeleton, AvatarBone.Root, AvatarBone.HipRight, jointErrorReduction, jointSoftness);
            AddJoint(ragdoll, skeleton, AvatarBone.HipLeft, AvatarBone.KneeLeft, jointErrorReduction, jointSoftness);
            AddJoint(ragdoll, skeleton, AvatarBone.HipRight, AvatarBone.KneeRight, jointErrorReduction, jointSoftness);
            AddJoint(ragdoll, skeleton, AvatarBone.KneeLeft, AvatarBone.AnkleLeft, jointErrorReduction, jointSoftness);
            AddJoint(ragdoll, skeleton, AvatarBone.KneeRight, AvatarBone.AnkleRight, jointErrorReduction, jointSoftness);

            // ----- Add constraint limits.
            // We use TwistSwingLimits to define an allowed twist and swing cone for the joints.
            // Exceptions are the back and knees, where we use AngularLimits to create hinges.
            // (We could also create a hinge with a TwistSwingLimit where the twist axis is the hinge
            // axis and no swing is allowed - but AngularLimits create more stable hinges.)
            // Another exception are the collar bones joint. We use AngularLimits to disallow any
            // rotations.
            AddAngularLimit(ragdoll, skeleton, AvatarBone.Root, AvatarBone.BackLower,
                            skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.BackLower).Rotation.Conjugated.ToRotationMatrix33(),
                            skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.BackLower).Rotation.Conjugated.ToRotationMatrix33(),
                            new Vector3F(-0.3f, 0, 0), new Vector3F(0.3f, 0, 0));

            AddAngularLimit(ragdoll, skeleton, AvatarBone.BackLower, AvatarBone.BackUpper,
                            skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.BackUpper).Rotation.Conjugated.ToRotationMatrix33(),
                            skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.BackUpper).Rotation.Conjugated.ToRotationMatrix33(),
                            new Vector3F(-0.3f, 0, 0), new Vector3F(0.4f, 0, 0));

            var rotationZ90Degrees = Matrix33F.CreateRotationZ(ConstantsF.PiOver2);

            AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.Neck, rotationZ90Degrees, rotationZ90Degrees, new Vector3F(-0.1f, -0.3f, -0.3f), new Vector3F(+0.1f, +0.3f, +0.3f));

            AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.Neck, AvatarBone.Head, rotationZ90Degrees, rotationZ90Degrees, new Vector3F(-0.1f, -0.6f, -0.6f), new Vector3F(+0.1f, +0.6f, +0.6f));

            AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.CollarLeft,
                               skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.CollarLeft).Rotation.Conjugated.ToRotationMatrix33(),
                               skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.CollarLeft).Rotation.Conjugated.ToRotationMatrix33(),
                               new Vector3F(0), new Vector3F(0));

            AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.CollarRight,
                               skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.CollarRight).Rotation.Conjugated.ToRotationMatrix33(),
                               skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.CollarRight).Rotation.Conjugated.ToRotationMatrix33(),
                               new Vector3F(0), new Vector3F(0));

            AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.CollarLeft, AvatarBone.ShoulderLeft, Matrix33F.Identity, Matrix33F.CreateRotationY(0.7f), new Vector3F(-0.7f, -1.2f, -1.2f), new Vector3F(+0.7f, +1.2f, +1.2f));
            AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.CollarRight, AvatarBone.ShoulderRight, Matrix33F.Identity, Matrix33F.CreateRotationY(-0.7f), new Vector3F(-0.7f, -1.2f, -1.2f), new Vector3F(+0.7f, +1.2f, +1.2f));
            AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.ShoulderLeft, AvatarBone.ElbowLeft, Matrix33F.Identity, Matrix33F.CreateRotationY(1.2f), new Vector3F(-0.7f, -1.2f, -1.2f), new Vector3F(+0.7f, +1.2f, +1.2f));
            AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.ShoulderRight, AvatarBone.ElbowRight, Matrix33F.Identity, Matrix33F.CreateRotationY(-1.2f), new Vector3F(-0.7f, -1.2f, -1.2f), new Vector3F(+0.7f, +1.2f, +1.2f));
            AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.ElbowLeft, AvatarBone.WristLeft, Matrix33F.Identity, Matrix33F.Identity, new Vector3F(-0.7f, -0.7f, -0.7f), new Vector3F(+0.7f, +0.7f, +0.7f));
            AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.ElbowRight, AvatarBone.WristRight, Matrix33F.Identity, Matrix33F.Identity, new Vector3F(-0.7f, -0.7f, -0.7f), new Vector3F(+0.7f, +0.7f, +0.7f));
            AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.Root, AvatarBone.HipLeft, rotationZ90Degrees, Matrix33F.CreateRotationX(-1.2f) * Matrix33F.CreateRotationZ(ConstantsF.PiOver2 + 0.2f), new Vector3F(-0.1f, -1.5f, -0.7f), new Vector3F(+0.1f, +1.5f, +0.7f));
            AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.Root, AvatarBone.HipRight, rotationZ90Degrees, Matrix33F.CreateRotationX(-1.2f) * Matrix33F.CreateRotationZ(ConstantsF.PiOver2 - 0.2f), new Vector3F(-0.1f, -1.5f, -0.7f), new Vector3F(+0.1f, +1.5f, +0.7f));

            AddAngularLimit(ragdoll, skeleton, AvatarBone.HipLeft, AvatarBone.KneeLeft,
                            skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.KneeLeft).Rotation.Conjugated.ToRotationMatrix33(),
                            skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.KneeLeft).Rotation.Conjugated.ToRotationMatrix33(),
                            new Vector3F(0, 0, 0), new Vector3F(2.2f, 0, 0));

            AddAngularLimit(ragdoll, skeleton, AvatarBone.HipRight, AvatarBone.KneeRight,
                            skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.KneeRight).Rotation.Conjugated.ToRotationMatrix33(),
                            skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.KneeRight).Rotation.Conjugated.ToRotationMatrix33(),
                            new Vector3F(0, 0, 0), new Vector3F(2.2f, 0, 0));

            AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.KneeLeft, AvatarBone.AnkleLeft, rotationZ90Degrees, rotationZ90Degrees, new Vector3F(-0.1f, -0.7f, -0.3f), new Vector3F(+0.1f, +0.7f, +0.3f));
            AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.KneeRight, AvatarBone.AnkleRight, rotationZ90Degrees, rotationZ90Degrees, new Vector3F(-0.1f, -0.7f, -0.3f), new Vector3F(+0.1f, +0.7f, +0.3f));

            // ----- Add motors
            // We use QuaternionMotors to create forces that rotate the bones into desired poses.
            // This can be used for damping, spring or animating the ragdoll.
            AddMotor(ragdoll, (AvatarBone)(-1), AvatarBone.Root);
            AddMotor(ragdoll, AvatarBone.Root, AvatarBone.BackLower);
            AddMotor(ragdoll, AvatarBone.BackLower, AvatarBone.BackUpper);
            AddMotor(ragdoll, AvatarBone.BackUpper, AvatarBone.Neck);
            AddMotor(ragdoll, AvatarBone.Neck, AvatarBone.Head);
            AddMotor(ragdoll, AvatarBone.BackUpper, AvatarBone.CollarLeft);
            AddMotor(ragdoll, AvatarBone.BackUpper, AvatarBone.CollarRight);
            AddMotor(ragdoll, AvatarBone.CollarLeft, AvatarBone.ShoulderLeft);
            AddMotor(ragdoll, AvatarBone.CollarRight, AvatarBone.ShoulderRight);
            AddMotor(ragdoll, AvatarBone.ShoulderLeft, AvatarBone.ElbowLeft);
            AddMotor(ragdoll, AvatarBone.ShoulderRight, AvatarBone.ElbowRight);
            AddMotor(ragdoll, AvatarBone.ElbowLeft, AvatarBone.WristLeft);
            AddMotor(ragdoll, AvatarBone.ElbowRight, AvatarBone.WristRight);
            AddMotor(ragdoll, AvatarBone.Root, AvatarBone.HipLeft);
            AddMotor(ragdoll, AvatarBone.Root, AvatarBone.HipRight);
            AddMotor(ragdoll, AvatarBone.HipLeft, AvatarBone.KneeLeft);
            AddMotor(ragdoll, AvatarBone.HipRight, AvatarBone.KneeRight);
            AddMotor(ragdoll, AvatarBone.KneeLeft, AvatarBone.AnkleLeft);
            AddMotor(ragdoll, AvatarBone.KneeRight, AvatarBone.AnkleRight);

            // ----- Set collision filters.
            // Collisions between connected bones have been disabled with Constraint.CollisionEnabled
            // = false in the joints. We need to disable a few other collisions.
            // Following bodies do not collide with anything. They are only used to connect other
            // bones.
            ragdoll.Bodies[(int)AvatarBone.Neck].CollisionObject.Enabled        = false;
            ragdoll.Bodies[(int)AvatarBone.CollarLeft].CollisionObject.Enabled  = false;
            ragdoll.Bodies[(int)AvatarBone.CollarRight].CollisionObject.Enabled = false;

            // We disable filters for following body pairs because they are usually penetrating each
            // other, which needs to be ignored.
            var filter = simulation.CollisionDomain.CollisionDetection.CollisionFilter as CollisionFilter;

            if (filter != null)
            {
                filter.Set(ragdoll.Bodies[(int)AvatarBone.BackUpper].CollisionObject, ragdoll.Bodies[(int)AvatarBone.ShoulderLeft].CollisionObject, false);
                filter.Set(ragdoll.Bodies[(int)AvatarBone.BackUpper].CollisionObject, ragdoll.Bodies[(int)AvatarBone.ShoulderRight].CollisionObject, false);
            }

            return(ragdoll);
        }
Beispiel #16
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);
        }
        public void SetUp()
        {
            child0 = new GeometricObject(new CircleShape(3), new Pose(new Vector3F(), QuaternionF.CreateRotationX(ConstantsF.PiOver2)));
            child1 = new GeometricObject(new LineSegmentShape(new Vector3F(0, 5, 0), new Vector3F(0, -5, 0)), Pose.Identity);

            cs = new MinkowskiSumShape
            {
                ObjectA = child0,
                ObjectB = child1
            };
        }
Beispiel #18
0
        public void Constructor()
        {
            Assert.AreEqual(Vector3F.Zero, ((PointShape) new MinkowskiDifferenceShape().ObjectA.Shape).Position);
            Assert.AreEqual(Vector3F.Zero, ((PointShape) new MinkowskiDifferenceShape().ObjectB.Shape).Position);
            Assert.AreEqual(Pose.Identity, new MinkowskiDifferenceShape().ObjectA.Pose);
            Assert.AreEqual(Pose.Identity, new MinkowskiDifferenceShape().ObjectB.Pose);

            var m = new MinkowskiDifferenceShape(
                new GeometricObject(new CircleShape(3), new Pose(new Vector3F(1, 0, 0), QuaternionF.CreateRotationX(ConstantsF.PiOver2))),
                new GeometricObject(new LineSegmentShape(new Vector3F(0, 5, 0), new Vector3F(0, -5, 0)), Pose.Identity));

            Assert.AreEqual(new Vector3F(1, 0, 0), m.ObjectA.Pose.Position);
            Assert.AreEqual(new Vector3F(0, 0, 0), m.ObjectB.Pose.Position);
        }
Beispiel #19
0
 public void SetUp()
 {
     cs         = new MinkowskiDifferenceShape();
     cs.ObjectA = new GeometricObject(new CircleShape(3), new Pose(new Vector3F(1, 0, 0), QuaternionF.CreateRotationX(ConstantsF.PiOver2)));
     cs.ObjectB = new GeometricObject(new LineSegmentShape(new Vector3F(0, 5, 0), new Vector3F(0, -5, 0)), Pose.Identity);
 }
Beispiel #20
0
        private bool _drawDebugInfo; // true if the collision shapes should be drawn for debugging.


        public ContentPipelineSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            GraphicsScreen.ClearBackground = true;
            GraphicsScreen.BackgroundColor = Color.CornflowerBlue;
            SetCamera(new Vector3F(0, 1, 10), 0, 0);

            // Initialize collision detection.
            // Note: The physics Simulation also has a collision domain (Simulation.CollisionDomain)
            // which we could use and which is updated together with the Simulation in
            // SampleGame.cs. But in this example we create our own CollisionDomain for demonstration
            // purposes.
            _collisionDomain = new CollisionDomain(new CollisionDetection());

            // Register CollisionDomain in service container.
            Services.Register(typeof(CollisionDomain), null, _collisionDomain);

            // Add game objects which manage graphics models and their collision representations.
            _saucerObject = new SaucerObject(Services)
            {
                Name = "Saucer"
            };
            _shipObjectA = new ShipObject(Services)
            {
                Name = "ShipA"
            };
            _shipObjectB = new ShipObject(Services)
            {
                Name = "ShipB"
            };

            GameObjectService.Objects.Add(_saucerObject);
            GameObjectService.Objects.Add(_shipObjectA);
            GameObjectService.Objects.Add(_shipObjectB);

            // Position the second ship right of the first ship with an arbitrary rotation.
            _shipObjectB.Pose = new Pose(new Vector3F(2, 0, 0), QuaternionF.CreateRotationY(0.7f) * QuaternionF.CreateRotationX(1.2f));

            // Position the saucer left of the first ship with an arbitrary rotation.
            _saucerObject.Pose = new Pose(new Vector3F(-2.5f, 0, 0), QuaternionF.CreateRotationY(0.2f) * QuaternionF.CreateRotationX(0.4f));
        }
Beispiel #21
0
        // Handle character-related input and move the character.
        private void ControlCharacter(float deltaTime)
        {
            // Compute new orientation from mouse movement.
            float deltaYaw = -InputService.MousePositionDelta.X;

            _yaw += deltaYaw * deltaTime * 0.1f;
            float deltaPitch = -InputService.MousePositionDelta.Y;

            _pitch += deltaPitch * deltaTime * 0.1f;

            // Limit the pitch angle.
            _pitch = MathHelper.Clamp(_pitch, -ConstantsF.PiOver2, ConstantsF.PiOver2);

            // Compute new orientation of the camera.
            QuaternionF cameraOrientation = QuaternionF.CreateRotationY(_yaw) * QuaternionF.CreateRotationX(_pitch);

            // Create velocity from WASD keys.
            // TODO: Diagonal movement is faster ;-). Fix this.
            Vector3F velocityVector = Vector3F.Zero;

            if (Keyboard.GetState().IsKeyDown(Keys.W))
            {
                velocityVector.Z--;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.S))
            {
                velocityVector.Z++;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.A))
            {
                velocityVector.X--;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.D))
            {
                velocityVector.X++;
            }
            velocityVector *= 10 * deltaTime;

            // Velocity vector is currently in view space. -z is the forward direction.
            // We have to convert this vector to world space by rotating it.
            velocityVector = QuaternionF.CreateRotationY(_yaw).Rotate(velocityVector);

            // New compute desired character controller position in world space:
            Vector3F targetPosition = _character.Position + velocityVector;

            // Check if user wants to jump.
            bool jump = Keyboard.GetState().IsKeyDown(Keys.Space);

            // Call character controller to compute a new valid position. The character
            // controller slides along obstacles, handles stepping up/down, etc.
            _character.Move(targetPosition, deltaTime, jump);

            // ----- Set view matrix for graphics.
            // For third person we move the eye position back, behind the body (+z direction is
            // the "back" direction).
            Vector3F thirdPersonDistance = cameraOrientation.Rotate(new Vector3F(0, 0, 6));

            // Compute camera pose (= position + orientation).
            _cameraNode.PoseWorld = new Pose
            {
                Position = _character.Position        // Floor position of character
                           + new Vector3F(0, 1.6f, 0) // + Eye height
                           + thirdPersonDistance,
                Orientation = cameraOrientation.ToRotationMatrix33()
            };
        }
Beispiel #22
0
        // OnUpdate() is called once per frame.
        protected override void OnUpdate(TimeSpan deltaTime)
        {
            // Mouse centering (controlled by the MenuComponent) is disabled if the game
            // is inactive or if the GUI is active. In these cases, we do not want to move
            // the player.
            if (!_inputService.EnableMouseCentering)
            {
                return;
            }

            if (!IsEnabled)
            {
                return;
            }

            float deltaTimeF = (float)deltaTime.TotalSeconds;

            // Compute new orientation from mouse movement, gamepad and touch.
            Vector2F     mousePositionDelta = _inputService.MousePositionDelta;
            GamePadState gamePadState       = _inputService.GetGamePadState(LogicalPlayerIndex.One);
            Vector2F     touchDelta         = Vector2F.Zero;

#if MONOGAME || WINDOWS_PHONE
            foreach (var gesture in _inputService.Gestures)
            {
                if (gesture.GestureType == GestureType.FreeDrag)
                {
                    touchDelta += (Vector2F)gesture.Delta;

                    // If we have touch input, we ignore the mouse movement
                    mousePositionDelta = Vector2F.Zero;
                }
            }
#endif

#if WINDOWS_PHONE || IOS
            // On Windows Phone touch input also sets the mouse input. --> Ignore mouse data.
            mousePositionDelta = Vector2F.Zero;
#endif

            float deltaYaw = -mousePositionDelta.X - touchDelta.X - gamePadState.ThumbSticks.Right.X * ThumbStickFactor;
            _currentYaw += deltaYaw * deltaTimeF * AngularVelocityMagnitude;

            float deltaPitch = -mousePositionDelta.Y - touchDelta.Y + gamePadState.ThumbSticks.Right.Y * ThumbStickFactor;
            _currentPitch += deltaPitch * deltaTimeF * AngularVelocityMagnitude;

            // Limit the pitch angle to +/- 90°.
            _currentPitch = MathHelper.Clamp(_currentPitch, -ConstantsF.PiOver2, ConstantsF.PiOver2);

            // Reset camera position if <Home> or <Right Stick> is pressed.
            if (_inputService.IsPressed(Keys.Home, false) ||
                _inputService.IsPressed(Buttons.RightStick, false, LogicalPlayerIndex.One))
            {
                ResetPose();
            }

            // Compute new orientation of the camera.
            QuaternionF orientation = QuaternionF.CreateRotationY(_currentYaw) * QuaternionF.CreateRotationX(_currentPitch);

            // Create velocity from <W>, <A>, <S>, <D> and <R>, <F> keys.
            // <R> or DPad up is used to move up ("rise").
            // <F> or DPad down is used to move down ("fall").
            Vector3F      velocity      = Vector3F.Zero;
            KeyboardState keyboardState = _inputService.KeyboardState;
            if (keyboardState.IsKeyDown(Keys.W))
            {
                velocity.Z--;
            }
            if (keyboardState.IsKeyDown(Keys.S))
            {
                velocity.Z++;
            }
            if (keyboardState.IsKeyDown(Keys.A))
            {
                velocity.X--;
            }
            if (keyboardState.IsKeyDown(Keys.D))
            {
                velocity.X++;
            }
            if (keyboardState.IsKeyDown(Keys.R) || gamePadState.DPad.Up == ButtonState.Pressed)
            {
                velocity.Y++;
            }
            if (keyboardState.IsKeyDown(Keys.F) || gamePadState.DPad.Down == ButtonState.Pressed)
            {
                velocity.Y--;
            }

            // Add velocity from gamepad sticks.
            velocity.X += gamePadState.ThumbSticks.Left.X;
            velocity.Z -= gamePadState.ThumbSticks.Left.Y;

            // Rotate the velocity vector from view space to world space.
            velocity = orientation.Rotate(velocity);

            if (keyboardState.IsKeyDown(Keys.LeftShift))
            {
                velocity *= SpeedBoost;
            }

            // Multiply the velocity by time to get the translation for this frame.
            Vector3F translation = velocity * LinearVelocityMagnitude * deltaTimeF;

            // Update SceneNode.LastPoseWorld - this is required for some effects, like
            // camera motion blur.
            CameraNode.LastPoseWorld = CameraNode.PoseWorld;

            // Set the new camera pose.
            CameraNode.PoseWorld = new Pose(
                CameraNode.PoseWorld.Position + translation,
                orientation);
        }
        public void SetUp()
        {
            child0 = new GeometricObject(new CircleShape(3), new Pose(new Vector3F(0, 5, 0), QuaternionF.CreateRotationX(ConstantsF.PiOver2)));
            child1 = new GeometricObject(new CircleShape(3), new Pose(new Vector3F(0, -5, 0), QuaternionF.CreateRotationX(ConstantsF.PiOver2)));

            cs = new ConvexHullOfShapes();
            cs.Children.Add(child0);
            cs.Children.Add(child1);
        }
Beispiel #24
0
        //--------------------------------------------------------------
        #region Creation & Cleanup
        //--------------------------------------------------------------

        /// <summary>
        /// Initializes a new instance of the <see cref="Spotlight"/> class.
        /// </summary>
        public Spotlight()
        {
            Color             = Vector3F.One;
            DiffuseIntensity  = 1;
            SpecularIntensity = 1;
            HdrScale          = 1;
            _falloffAngle     = 20.0f * ConstantsF.Pi / 180;
            Shape             = new TransformedShape(new GeometricObject(new ConeShape((float)Math.Tan(MathHelper.ToRadians(30)) * 5, 5), new Pose(new Vector3F(0, 0, -5), QuaternionF.CreateRotationX(ConstantsF.PiOver2))));
            Attenuation       = 2;
        }
Beispiel #25
0
        protected override void OnUpdate(TimeSpan deltaTime)
        {
            // Mouse centering (controlled by the MenuComponent) is disabled if the game
            // is inactive or if the GUI is active. In these cases, we do not want to move
            // the player.
            if (!_inputService.EnableMouseCentering)
            {
                return;
            }

            float deltaTimeF = (float)deltaTime.TotalSeconds;

            // ----- Hulk Mode
            // Toggle "Hulk" mode if <H> or <X> (gamepad) is pressed.
            if (_inputService.IsPressed(Keys.H, false) || _inputService.IsPressed(Buttons.X, false, LogicalPlayerIndex.One))
            {
                ToggleHulk();
            }

            // ----- Crouching
            if (_inputService.IsPressed(Keys.LeftShift, false) || _inputService.IsPressed(Buttons.RightTrigger, false, LogicalPlayerIndex.One))
            {
                Crouch();
            }
            else if (!_inputService.IsDown(Keys.LeftShift) && !_inputService.IsDown(Buttons.RightTrigger, LogicalPlayerIndex.One) && CharacterController.Height <= 1)
            {
                StandUp();
            }

            // ----- Update orientation
            // Update _yaw and _pitch.
            UpdateOrientation(deltaTimeF);

            // Compute the new orientation of the camera.
            QuaternionF orientation = QuaternionF.CreateRotationY(_yaw) * QuaternionF.CreateRotationX(_pitch);

            // ----- Compute translation
            // Create velocity from <W>, <A>, <S>, <D> and gamepad sticks.
            Vector3F moveDirection = Vector3F.Zero;

            if (Keyboard.GetState().IsKeyDown(Keys.W))
            {
                moveDirection.Z--;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.S))
            {
                moveDirection.Z++;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.A))
            {
                moveDirection.X--;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.D))
            {
                moveDirection.X++;
            }

            GamePadState gamePadState = _inputService.GetGamePadState(LogicalPlayerIndex.One);

            moveDirection.X += gamePadState.ThumbSticks.Left.X;
            moveDirection.Z -= gamePadState.ThumbSticks.Left.Y;

            // Rotate the velocity vector from view space to world space.
            moveDirection = orientation.Rotate(moveDirection);

            // Add velocity from <R>, <F> keys.
            // <R> or DPad up is used to move up ("rise").
            // <F> or DPad down is used to move down ("fall").
            if (Keyboard.GetState().IsKeyDown(Keys.R) || gamePadState.DPad.Up == ButtonState.Pressed)
            {
                moveDirection.Y++;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.F) || gamePadState.DPad.Down == ButtonState.Pressed)
            {
                moveDirection.Y--;
            }

            // ----- Climbing
            bool hasLadderContact = HasLadderContact();
            bool hasLedgeContact  = HasLedgeContact();

            CharacterController.IsClimbing = hasLadderContact || hasLedgeContact;

            // When the character is walking (gravity > 0) it cannot walk up/down - only on a ladder.
            if (CharacterController.Gravity != 0 && !hasLadderContact)
            {
                moveDirection.Y = 0;
            }

            // ----- Moving
            moveDirection.TryNormalize();
            Vector3F moveVelocity = moveDirection * LinearVelocityMagnitude;

            // ----- Jumping
            if ((_inputService.IsPressed(Keys.Space, false) || _inputService.IsPressed(Buttons.A, false, LogicalPlayerIndex.One)) &&
                (CharacterController.HasGroundContact || CharacterController.IsClimbing))
            {
                // Jump button was newly pressed and the character has support to start the jump.
                _timeSinceLastJump = 0;
            }

            float jumpVelocity = 0;

            if ((_inputService.IsDown(Keys.Space) || _inputService.IsDown(Buttons.A, LogicalPlayerIndex.One)))
            {
                // Jump button is still down.
                if (_timeSinceLastJump + deltaTimeF <= DynamicJumpTime)
                {
                    // The DynamicJumpTime has not been exceeded.
                    // Set a jump velocity to make the jump higher.
                    jumpVelocity = JumpVelocity;
                }
                else if (_timeSinceLastJump <= DynamicJumpTime)
                {
                    // The jump time exceeds DynamicJumpTime in this time step.
                    //   _timeSinceLastJump <= DynamicJumpTime
                    //   _timeSinceLastJump + deltaTime > DynamicJumpTime

                    // In order to achieve exact, reproducible jump heights we need to split
                    // the time step:
                    float deltaTime0 = DynamicJumpTime - _timeSinceLastJump;
                    float deltaTime1 = deltaTimeF - deltaTime0;

                    // The first part of the movement is a jump with active jump velocity.
                    jumpVelocity        = JumpVelocity;
                    _timeSinceLastJump += deltaTime0;
                    CharacterController.Move(moveVelocity, jumpVelocity, deltaTime0);

                    // The second part of the movement is a jump without jump velocity.
                    jumpVelocity = 0;
                    deltaTimeF   = deltaTime1;
                }
            }

            _timeSinceLastJump += deltaTimeF;

            // ----- Move the character.
            CharacterController.Move(moveVelocity, jumpVelocity, deltaTimeF);

            // Draw character controller capsule.
            // The character controller is also transparent The hulk is green, of course.
            var color = _isHulk ? Color.DarkGreen : Color.Gray;

            color.A = 128;
            _debugRenderer.DrawObject(CharacterController.Body, color, false, false);
        }
Beispiel #26
0
        // OnUpdate() is called once per frame.
        protected override void OnUpdate(TimeSpan deltaTime)
        {
#if !WINDOWS_PHONE
            // Mouse centering (controlled by the MenuComponent) is disabled if the game
            // is inactive or if the GUI is active. In these cases, we do not want to move
            // the player.
            if (!_inputService.EnableMouseCentering)
            {
                return;
            }
#endif

            if (!IsEnabled)
            {
                return;
            }

            float deltaTimeF = (float)deltaTime.TotalSeconds;

            // Compute new orientation from mouse movement and gamepad.
            Vector2F mousePositionDelta = _inputService.MousePositionDelta;

#if !WINDOWS_PHONE
            GamePadState gamePadState = _inputService.GetGamePadState(LogicalPlayerIndex.One);

            float deltaYaw = -mousePositionDelta.X - gamePadState.ThumbSticks.Right.X * ThumbStickFactor;
            _currentYaw += deltaYaw * deltaTimeF * AngularVelocityMagnitude;

            float deltaPitch = -mousePositionDelta.Y + gamePadState.ThumbSticks.Right.Y * ThumbStickFactor;
            _currentPitch += deltaPitch * deltaTimeF * AngularVelocityMagnitude;

            // Limit the pitch angle to +/- 90°.
            _currentPitch = MathHelper.Clamp(_currentPitch, -ConstantsF.PiOver2, ConstantsF.PiOver2);

            // Reset camera position if <Home> or <Right Stick> is pressed.
            if (_inputService.IsPressed(Keys.Home, false) ||
                _inputService.IsPressed(Buttons.RightStick, false, LogicalPlayerIndex.One))
            {
                ResetPose();
            }

            // Compute new orientation of the camera.
            QuaternionF orientation = QuaternionF.CreateRotationY(_currentYaw) * QuaternionF.CreateRotationX(_currentPitch);

            // Create velocity from <W>, <A>, <S>, <D> and <R>, <F> keys.
            // <R> or DPad up is used to move up ("rise").
            // <F> or DPad down is used to move down ("fall").
            Vector3F      velocity      = Vector3F.Zero;
            KeyboardState keyboardState = _inputService.KeyboardState;
            if (keyboardState.IsKeyDown(Keys.W))
            {
                velocity.Z--;
            }
            if (keyboardState.IsKeyDown(Keys.S))
            {
                velocity.Z++;
            }
            if (keyboardState.IsKeyDown(Keys.A))
            {
                velocity.X--;
            }
            if (keyboardState.IsKeyDown(Keys.D))
            {
                velocity.X++;
            }
            if (keyboardState.IsKeyDown(Keys.R) || gamePadState.DPad.Up == ButtonState.Pressed)
            {
                velocity.Y++;
            }
            if (keyboardState.IsKeyDown(Keys.F) || gamePadState.DPad.Down == ButtonState.Pressed)
            {
                velocity.Y--;
            }

            // Add velocity from gamepad sticks.
            velocity.X += gamePadState.ThumbSticks.Left.X;
            velocity.Z -= gamePadState.ThumbSticks.Left.Y;

            // Rotate the velocity vector from view space to world space.
            velocity = orientation.Rotate(velocity);

            if (keyboardState.IsKeyDown(Keys.LeftShift))
            {
                velocity *= SpeedBoost;
            }

            // Multiply the velocity by time to get the translation for this frame.
            Vector3F translation = velocity * LinearVelocityMagnitude * deltaTimeF;

            // Update SceneNode.LastPoseWorld - this is required for some effects, like
            // camera motion blur.
            CameraNode.LastPoseWorld = CameraNode.PoseWorld;

            // Set the new camera pose.
            CameraNode.PoseWorld = new Pose(
                CameraNode.PoseWorld.Position + translation,
                orientation);
#else
            // Only handle mouse movement is mouse button was down the last frame.
            if (!_inputService.IsPressed(MouseButtons.Left, false))
            {
                float deltaYaw = -mousePositionDelta.X;
                _currentYaw += deltaYaw * deltaTimeF * AngularVelocityMagnitude;
                float deltaPitch = -mousePositionDelta.Y;
                _currentPitch += deltaPitch * deltaTimeF * AngularVelocityMagnitude;

                // Limit the pitch angle.
                _currentPitch = MathHelper.Clamp(_currentPitch, -1, 1);

                // Compute new orientation of the camera.
                QuaternionF orientation = QuaternionF.CreateRotationY(_currentYaw) * QuaternionF.CreateRotationX(_currentPitch);

                var radius = CameraNode.PoseWorld.Position.Length;

                // Update SceneNode.LastPoseWorld - this is required for some effects, like
                // camera motion blur.
                CameraNode.LastPoseWorld = CameraNode.PoseWorld;

                // Set the new camera pose.
                CameraNode.PoseWorld = new Pose(orientation.Rotate(new Vector3F(0, 0, radius)), orientation);
            }
#endif
        }