Example #1
0
        public void CutConvex()
        {
            var mesh = new BoxShape(1, 2, 3).GetMesh(0.01f, 1);
              var dcel = DcelMesh.FromTriangleMesh((ITriangleMesh)mesh);

              Assert.IsTrue(dcel.IsValid());
              Assert.IsTrue(dcel.IsConvex());
              Assert.IsTrue(dcel.IsClosed());

              bool result = dcel.CutConvex(new Plane(new Vector3F(0, 0, 1), 1.5f));
              Assert.IsFalse(result);

              result = dcel.CutConvex(new Plane(new Vector3F(0, 0, 1), -1.5f));
              Assert.IsTrue(result);
              Assert.IsNull(dcel.Vertex);
              Assert.AreEqual(0, dcel.Vertices.Count);

              dcel = DcelMesh.FromTriangleMesh((ITriangleMesh)mesh);
              result = dcel.CutConvex(new Plane(new Vector3F(0, 0, 1), 1f));
              Assert.IsTrue(result);
              Assert.IsTrue(dcel.IsValid());
              Assert.IsTrue(dcel.IsConvex());
              Assert.IsTrue(dcel.IsClosed());
              Assert.AreEqual(12, dcel.Vertices.Count);
              Assert.AreEqual(6 + 8 + 7 * 4, dcel.Edges.Count); // Bottom = 6 edges, new cap = 8 edges, cut sides = each 7 edges.
              Assert.AreEqual(12 - 1, dcel.Faces.Count);
        }
Example #2
0
    private void InitializeSimulation(Simulation simulation, Vector3F offset)
    {
      // Add default 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",
        MotionType = MotionType.Static,
      };
      simulation.RigidBodies.Add(groundPlane);

      // Add a stack of boxes.
      const float boxSize = 0.8f;
      float overlap = simulation.Settings.Constraints.AllowedPenetration * 0.5f;
      float yPosition = boxSize / 2 - overlap;
      BoxShape boxShape = new BoxShape(boxSize, boxSize, boxSize);
      for (int i = 0; i < 15; i++)
      {
        RigidBody stackBox = new RigidBody(boxShape)
        {
          Name = "StackBox" + i,
          Pose = new Pose(new Vector3F(0, yPosition, 0) + offset),
        };
        simulation.RigidBodies.Add(stackBox);
        yPosition += boxSize - overlap;
      }
    }
Example #3
0
    public BoxStackSample(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 stack of boxes.
      const int numberOfBoxes = 5;
      const float boxSize = 0.8f;
      BoxShape boxShape = new BoxShape(boxSize, boxSize, boxSize);

      // Optional: Use a small overlap between boxes to improve the stability.
      float overlap = Simulation.Settings.Constraints.AllowedPenetration * 0.5f;
      Vector3F position = new Vector3F(0, boxSize / 2 - overlap, 0);
      for (int i = 0; i < numberOfBoxes; i++)
      {
        RigidBody box = new RigidBody(boxShape)
        {
          Name = "Box" + i,
          Pose = new Pose(position),
        };
        Simulation.RigidBodies.Add(box);
        position.Y += boxSize - overlap;
      }
    }
Example #4
0
    public DumpContactSetSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      GraphicsScreen.ClearBackground = true;

      // Create two collision objects with triangle mesh shapes.
      var meshA = new SphereShape(1).GetMesh(0.01f, 4);
      var shapeA = new TriangleMeshShape(meshA, true) { Partition = new CompressedAabbTree() };
      var poseA = new Pose(new Vector3F(-1, 0, 0), RandomHelper.Random.NextQuaternionF());
      var collisionObjectA = new CollisionObject(new GeometricObject(shapeA, poseA));

      var meshB = new BoxShape(0.2f, 2, 1f).GetMesh(0.01f, 4);
      var shapeB = new TriangleMeshShape(meshB, true) { Partition = new CompressedAabbTree() };
      var poseB = new Pose(new Vector3F(0.1f, 0, 0), RandomHelper.Random.NextQuaternionF());
      var collisionObjectB = new CollisionObject(new GeometricObject(shapeB, poseB));

      // Explicitly create a contact set. (Normally you would get the contact set
      // from the collision domain...)
      var contactSet = ContactSet.Create(collisionObjectA, collisionObjectB);

      // Create a C# sample which visualizes the contact set.
      const string Filename = "DumpedContactSet001.cs";
      DumpContactSet(contactSet, Filename);

      GraphicsScreen.DebugRenderer2D.DrawText(
        "Contact set dumped into the file: " + Filename, 
        new Vector2F(300, 300), 
        Color.Black);
    }
Example #5
0
        public void BoxVolume()
        {
            var s = new BoxShape(1, 2, 3);
              Assert.AreEqual(1 * 2 * 3, s.GetVolume(0.0001f, 10));

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

              Assert.AreEqual(1 * 2 * 3, m.GetVolume());
        }
Example #6
0
        public void GetOutcode()
        {
            BoxShape box = new BoxShape(1, 2, 3);

              Assert.AreEqual(0, GeometryHelper.GetOutcode(box.Extent, new Vector3F(0.1f, 0.1f, 0.1f)));
              Assert.AreEqual(1 | 8, GeometryHelper.GetOutcode(box.Extent, new Vector3F(-1.1f, 2.1f, 0.1f)));
              Assert.AreEqual(2 | 4 | 32, GeometryHelper.GetOutcode(box.Extent, new Vector3F(1.1f, -2.1f, 3.1f)));
              Assert.AreEqual(16, GeometryHelper.GetOutcode(box.Extent, new Vector3F(0.1f, 0.9f, -3.1f)));
        }
Example #7
0
    public LockRotationSample(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);

      // Next, we add boxes and capsules in random positions and orientations.
      // For all bodies the flags LockRotationX/Y/Z are set. This will prevent all
      // rotation that would be caused by forces. (It is still allowed to manually 
      // change the rotation or to set an angular velocity.)

      BoxShape boxShape = new BoxShape(0.5f, 0.8f, 1.2f);
      for (int i = 0; i < 10; i++)
      {
        Vector3F position = RandomHelper.Random.NextVector3F(-10, 10);
        position.Y = 5;
        QuaternionF orientation = RandomHelper.Random.NextQuaternionF();

        RigidBody body = new RigidBody(boxShape)
        {
          Pose = new Pose(position, orientation),
          LockRotationX = true,
          LockRotationY = true,
          LockRotationZ = true,
        };
        Simulation.RigidBodies.Add(body);
      }

      CapsuleShape capsuleShape = new CapsuleShape(0.3f, 1.2f);
      for (int i = 0; i < 10; i++)
      {
        Vector3F randomPosition = RandomHelper.Random.NextVector3F(-10, 10);
        randomPosition.Y = 5;
        QuaternionF randomOrientation = RandomHelper.Random.NextQuaternionF();

        RigidBody body = new RigidBody(capsuleShape)
        {
          Pose = new Pose(randomPosition, randomOrientation),
          LockRotationX = true,
          LockRotationY = true,
          LockRotationZ = true,
        };
        Simulation.RigidBodies.Add(body);
      }
    }
Example #8
0
    public ResponseFilterSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      // Add basic force effects.
      Simulation.ForceEffects.Add(new Gravity());
      Simulation.ForceEffects.Add(new Damping());

      // Only disable collision response if you need collision detection info but no collision
      // response. If you can disable collision detection too, use 
      //   Simulation.CollisionDomain.CollisionDetection.CollisionFilter 
      // instead - this is more efficient!
      // (In this sample, a custom filter implementation is used. DigitalRune.Physics provides
      // a standard filter implementation: DigitalRune.Physics.CollisionResponseFilter.)
      Simulation.ResponseFilter = new MyCollisionResponseFilter();

      // 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 boxes at random poses.
      BoxShape boxShape = new BoxShape(0.5f, 0.8f, 1.2f);
      for (int i = 0; i < 20; i++)
      {
        Vector3F position = RandomHelper.Random.NextVector3F(-3, 3);
        position.Y = 5;
        QuaternionF orientation = RandomHelper.Random.NextQuaternionF();

        RigidBody body = new RigidBody(boxShape)
        {
          Pose = new Pose(position, orientation),
        };
        Simulation.RigidBodies.Add(body);
      }

      // ----- Add capsules at random poses.
      CapsuleShape capsuleShape = new CapsuleShape(0.3f, 1.2f);
      for (int i = 0; i < 20; i++)
      {
        Vector3F position = RandomHelper.Random.NextVector3F(-3, 3);
        position.Y = 5;
        QuaternionF orientation = RandomHelper.Random.NextQuaternionF();

        RigidBody body = new RigidBody(capsuleShape)
        {
          Pose = new Pose(position, orientation),
        };
        Simulation.RigidBodies.Add(body);
      }
    }
Example #9
0
        /// <summary>
        /// Computes a minimum bounding shape that contains all given points.
        /// </summary>
        /// <param name="points">The points.</param>
        /// <returns>A minimum bounding shape that contains all given points.</returns>
        /// <remarks>
        /// The returned shape will be a <see cref="SphereShape"/>, a <see cref="CapsuleShape"/>,
        /// a <see cref="BoxShape"/>, or a <see cref="TransformedShape"/> (containing a sphere, capsule,
        /// or a box). The bounding shape is not guaranteed to be optimal, it is only guaranteed that
        /// the bounding shape includes all given points.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="points"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="points"/> is empty.
        /// </exception>
        public static Shape CreateBoundingShape(IList<Vector3F> points)
        {
            if (points == null)
            throw new ArgumentNullException("points");
              if (points.Count == 0)
            throw new ArgumentException("The list of 'points' is empty.");

              // Compute minimal sphere.
              Vector3F center;
              float radius;
              ComputeBoundingSphere(points, out radius, out center);
              SphereShape sphere = new SphereShape(radius);
              float sphereVolume = sphere.GetVolume();

              // Compute minimal capsule.
              float height;
              Pose capsulePose;
              ComputeBoundingCapsule(points, out radius, out height, out capsulePose);
              CapsuleShape capsule = new CapsuleShape(radius, height);
              float capsuleVolume = capsule.GetVolume();

              // Compute minimal box.
              Vector3F boxExtent;
              Pose boxPose;
              ComputeBoundingBox(points, out boxExtent, out boxPose);
              var box = new BoxShape(boxExtent);
              float boxVolume = box.GetVolume();

              // Return the object with the smallest volume.
              // A TransformedShape is used if the shape needs to be translated or rotated.
              if (sphereVolume < boxVolume && sphereVolume < capsuleVolume)
              {
            if (center.IsNumericallyZero)
              return sphere;

            return new TransformedShape(new GeometricObject(sphere, new Pose(center)));
              }
              else if (capsuleVolume < boxVolume)
              {
            if (!capsulePose.HasTranslation && !capsulePose.HasRotation)
              return capsule;

            return new TransformedShape(new GeometricObject(capsule, capsulePose));
              }
              else
              {
            if (!boxPose.HasTranslation && !boxPose.HasRotation)
              return box;

            return new TransformedShape(new GeometricObject(box, boxPose));
              }
        }
Example #10
0
    public ContentPipelineHeightFieldSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      // Add basic force effects.
      Simulation.ForceEffects.Add(new Gravity());
      Simulation.ForceEffects.Add(new Damping());

      // Load height field model and add it to the graphics scene.
      _heightFieldModelNode = ContentManager.Load<ModelNode>("HeightField/TerrainHeights").Clone();
      GraphicsScreen.Scene.Children.Add(_heightFieldModelNode);

      // The UserData contains the collision shape of type HeightField.
      HeightField heightField = (HeightField)_heightFieldModelNode.UserData;

      _heightFieldModelNode.PoseWorld = new Pose(new Vector3F(-heightField.WidthX / 2, 0, -heightField.WidthZ / 2));

      // Create rigid body.
      _heightFieldBody = new RigidBody(heightField, null, null)
      {
        MotionType = MotionType.Static,
        Pose = _heightFieldModelNode.PoseWorld,

        // The PhysicsSample class should not draw the height field. 
        UserData = "NoDraw",
      };
      Simulation.RigidBodies.Add(_heightFieldBody);

      // Distribute a few spheres and boxes across the landscape.
      SphereShape sphereShape = new SphereShape(0.5f);
      for (int i = 0; i < 30; i++)
      {
        Vector3F position = RandomHelper.Random.NextVector3F(-30, 30);
        position.Y = 20;

        RigidBody body = new RigidBody(sphereShape) { Pose = new Pose(position) };
        Simulation.RigidBodies.Add(body);
      }

      BoxShape boxShape = new BoxShape(1, 1, 1);
      for (int i = 0; i < 30; i++)
      {
        Vector3F position = RandomHelper.Random.NextVector3F(-30, 30);
        position.Y = 20;

        RigidBody body = new RigidBody(boxShape) { Pose = new Pose(position) };
        Simulation.RigidBodies.Add(body);
      }
    }
Example #11
0
    public WallSample(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);

      // ----- Create a wall of boxes.
      const int wallHeight = 10;
      const int wallWidth = 10;
      const float boxWidth = 1.0f;
      const float boxDepth = 0.5f;
      const float boxHeight = 0.5f;
      BoxShape boxShape = new BoxShape(boxWidth, boxHeight, boxDepth);

      // Optional: Use a small overlap between boxes to improve the stability.
      float overlap = Simulation.Settings.Constraints.AllowedPenetration * 0.5f;

      float x;
      float y = boxHeight / 2 - overlap;
      float z = -5;

      for (int i = 0; i < wallHeight; i++)
      {
        for (int j = 0; j < wallWidth; j++)
        {
          // Tip: Leave a small gap between neighbor bricks. If the neighbors on the same
          // row do not touch, the simulation has less work to do!
          x = -boxWidth * wallWidth / 2 + j * (boxWidth + 0.02f) + (i % 2) * boxWidth / 2;
          RigidBody brick = new RigidBody(boxShape)
          {
            Name = "Brick" + i,
            Pose = new Pose(new Vector3F(x, y, z)),
          };
          Simulation.RigidBodies.Add(brick);
        }

        y += boxHeight - overlap;
      }
    }
Example #12
0
    public KinematicSample(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);

      // Create the kinematic body. (Kinematic means that the velocity of the body is not 
      // the result of simulated forces and constraints. Instead the velocity of the body 
      // is directly controlled by the application.)
      _kinematicBody = new RigidBody(new ConeShape(0.3f, 1))
      {
        MotionType = MotionType.Kinematic
      };
      Simulation.RigidBodies.Add(_kinematicBody);

      // Create a cyclic path.
      CreatePath();

      // Add a number of random boxes.
      const int numberOfBoxes = 20;
      BoxShape boxShape = new BoxShape(1, 1, 1);
      for (int i = 0; i < numberOfBoxes; i++)
      {
        Vector3F randomPosition = RandomHelper.Random.NextVector3F(-5, 5);
        randomPosition.Y = 5;
        QuaternionF randomOrientation = RandomHelper.Random.NextQuaternionF();

        RigidBody body = new RigidBody(boxShape)
        {
          Pose = new Pose(randomPosition, randomOrientation),
        };
        Simulation.RigidBodies.Add(body);
      }
    }
Example #13
0
    public RagdollSample(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 number of ragdolls.
      for (int i = 0; i < 5; i++)
      {
        Vector3F position = RandomHelper.Random.NextVector3F(-3, 3);
        position.Y = 1 + i;
        AddRagdoll(Simulation, 1, position, 0.0005f, true);
      }

      // Add some random, static boxes.
      BoxShape boxShape = new BoxShape(1, 1, 1);
      for (int i = 0; i < 10; i++)
      {
        Vector3F position = RandomHelper.Random.NextVector3F(-5, 5);
        position.Y = 0.5f;
        QuaternionF orientation = RandomHelper.Random.NextQuaternionF();

        RigidBody body = new RigidBody(boxShape)
        {
          Pose = new Pose(position, orientation),
          MotionType = MotionType.Static
        };
        Simulation.RigidBodies.Add(body);
      }
    }
Example #14
0
        public void BoxMass()
        {
            var b = new BoxShape(1, 2, 3);
              float m0;
              Vector3F com0;
              Matrix33F i0;
              MassHelper.GetMass(b, new Vector3F(1, -2, -3), 1, true, 0.001f, 10, out m0, out com0, out i0);

              var m = b.GetMesh(0.1f, 1);
              m.Transform(Matrix44F.CreateScale(1, -2, -3));
              float m1;
              Vector3F com1;
              Matrix33F i1;
              MassHelper.GetMass(m, out m1, out com1, out i1);

              Assert.AreEqual(m0, m1);
              Assert.AreEqual(com0, com1);
              Assert.AreEqual(i0, i1);

              // Try other density.
              float m2;
              Vector3F com2;
              Matrix33F i2;
              MassHelper.GetMass(b, new Vector3F(1, -2, -3), 0.7f, true, 0.001f, 10, out m2, out com2, out i2);
              Assert.AreEqual(m0 * 0.7f, m2);
              Assert.AreEqual(com0, com2);
              Assert.IsTrue(Matrix33F.AreNumericallyEqual(i0 * 0.7f, i2));

              const float e = 0.01f;

              // Try with target mass.
              float m3;
              Vector3F com3;
              Matrix33F i3;
              MassHelper.GetMass(b, new Vector3F(1, -2, -3), 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 #15
0
    public SmallerScaleSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      // The default simulation settings are optimized for game objects that are 1 unit in size.
      // These default settings are useful for standard game objects: crates, barrels, furniture, 
      // humans, rocks, etc. 
      // The simulation settings should be adapted if the average game object is more than 10 times
      // bigger or smaller. (Note: Future versions of DigitalRune.Physics will automatically 
      // adapt the simulation settings.)
      // If you are unsure which settings are relevant for your game scenario, just ask in our
      // support forums: http://www.digitalrune.com/Support/Forum.aspx
      // Nevertheless, it is strongly recommended to scale game objects so that the average game 
      // object is about 1 unit in size.

      // In this sample, the average game object is 0.05 units. 

      // Simulating small objects is a lot more difficult. Therefore, we decrease the time
      // step size to improve the simulation accuracy.
      Simulation.Settings.Timing.FixedTimeStep /= 5;
      Simulation.Settings.Timing.MaxNumberOfSteps *= 5;

      // Rigid bodies have an allowed penetration. Errors in this range are acceptable and not
      // corrected to improve stability and remove jittering. For small objects this limit
      // must be reduced.
      Simulation.Settings.Constraints.AllowedPenetration /= 5;

      // The collision detection settings are defined in the CollisionDetection class.
      // The collision detection uses a tolerance to define when two contacts near each other
      // can be considered the same contact. For small objects this limit must be reduced.
      Simulation.CollisionDomain.CollisionDetection.ContactPositionTolerance /= 5;

      // To improve stacking of small objects:
      Simulation.Settings.Constraints.StackingFactor = 10;

      // Add basic force effects.
      Simulation.ForceEffects.Add(new Gravity());
      Simulation.ForceEffects.Add(new Damping { AngularDamping = 0.9f });

      // Add a ground plane.
      RigidBody groundPlane = new RigidBody(new PlaneShape(Vector3F.UnitY, 0))
      {
        Name = "GroundPlane",
        MotionType = MotionType.Static,
      };
      Simulation.RigidBodies.Add(groundPlane);

      // ----- Add a stack of small boxes.
      const float boxSize = 0.05f;
      float overlap = Simulation.Settings.Constraints.AllowedPenetration * 0.5f;
      float yPosition = boxSize / 2 - overlap;
      BoxShape boxShape = new BoxShape(boxSize, boxSize, boxSize);
      for (int i = 0; i < 10; i++)
      {
        RigidBody stackBox = new RigidBody(boxShape)
        {
          Pose = new Pose(new Vector3F(0, yPosition, 0)),
        };
        Simulation.RigidBodies.Add(stackBox);
        yPosition += boxSize - overlap;
      }

      // ------ Add spheres at random positions.
      SphereShape sphereShape = new SphereShape(boxSize * 0.5f);
      for (int i = 0; i < 10; i++)
      {
        Vector3F position = RandomHelper.Random.NextVector3F(-0.5f, 0.5f);
        position.Y = 1;

        RigidBody body = new RigidBody(sphereShape)
        {
          Pose = new Pose(position),
        };
        Simulation.RigidBodies.Add(body);
      }
    }
Example #16
0
    // Creates a lot of random objects.
    private void CreateRandomObjects()
    {
      var random = new Random();

      var isFirstHeightField = true;

      int currentShape = 0;
      int numberOfObjects = 0;
      while (true)
      {
        numberOfObjects++;
        if (numberOfObjects > ObjectsPerType)
        {
          currentShape++;
          numberOfObjects = 0;
        }

        Shape shape;
        switch (currentShape)
        {
          case 0:
            // Box
            shape = new BoxShape(ObjectSize, ObjectSize * 2, ObjectSize * 3);
            break;
          case 1:
            // Capsule
            shape = new CapsuleShape(0.3f * ObjectSize, 2 * ObjectSize);
            break;
          case 2:
            // Cone
            shape = new ConeShape(1 * ObjectSize, 2 * ObjectSize);
            break;
          case 3:
            // Cylinder
            shape = new CylinderShape(0.4f * ObjectSize, 2 * ObjectSize);
            break;
          case 4:
            // Sphere
            shape = new SphereShape(ObjectSize);
            break;
          case 5:
            // Convex hull of several points.
            ConvexHullOfPoints hull = new ConvexHullOfPoints();
            hull.Points.Add(new Vector3F(-1 * ObjectSize, -2 * ObjectSize, -1 * ObjectSize));
            hull.Points.Add(new Vector3F(2 * ObjectSize, -1 * ObjectSize, -0.5f * ObjectSize));
            hull.Points.Add(new Vector3F(1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize));
            hull.Points.Add(new Vector3F(-1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize));
            hull.Points.Add(new Vector3F(-1 * ObjectSize, 0.7f * ObjectSize, -0.6f * ObjectSize));
            shape = hull;
            break;
          case 6:
            // A composite shape: two boxes that form a "T" shape.
            var composite = new CompositeShape();
            composite.Children.Add(
              new GeometricObject(
                new BoxShape(ObjectSize, 3 * ObjectSize, ObjectSize),
                new Pose(new Vector3F(0, 0, 0))));
            composite.Children.Add(
              new GeometricObject(
                new BoxShape(2 * ObjectSize, ObjectSize, ObjectSize),
                new Pose(new Vector3F(0, 2 * ObjectSize, 0))));
            shape = composite;
            break;
          case 7:
            shape = new CircleShape(ObjectSize);
            break;
          case 8:
            {
              var compBvh = new CompositeShape();
              compBvh.Children.Add(new GeometricObject(new BoxShape(0.5f, 1, 0.5f), new Pose(new Vector3F(0, 0.5f, 0), Matrix33F.Identity)));
              compBvh.Children.Add(new GeometricObject(new BoxShape(0.8f, 0.5f, 0.5f), new Pose(new Vector3F(0.5f, 0.7f, 0), Matrix33F.CreateRotationZ(-MathHelper.ToRadians(15)))));
              compBvh.Children.Add(new GeometricObject(new SphereShape(0.3f), new Pose(new Vector3F(0, 1.15f, 0), Matrix33F.Identity)));
              compBvh.Children.Add(new GeometricObject(new CapsuleShape(0.2f, 1), new Pose(new Vector3F(0.6f, 1.15f, 0), Matrix33F.CreateRotationX(0.3f))));
              compBvh.Partition = new AabbTree<int>();
              shape = compBvh;
              break;
            }
          case 9:
            CompositeShape comp = new CompositeShape();
            comp.Children.Add(new GeometricObject(new BoxShape(0.5f * ObjectSize, 1 * ObjectSize, 0.5f * ObjectSize), new Pose(new Vector3F(0, 0.5f * ObjectSize, 0), QuaternionF.Identity)));
            comp.Children.Add(new GeometricObject(new BoxShape(0.8f * ObjectSize, 0.5f * ObjectSize, 0.5f * ObjectSize), new Pose(new Vector3F(0.3f * ObjectSize, 0.7f * ObjectSize, 0), QuaternionF.CreateRotationZ(-MathHelper.ToRadians(45)))));
            comp.Children.Add(new GeometricObject(new SphereShape(0.3f * ObjectSize), new Pose(new Vector3F(0, 1.15f * ObjectSize, 0), QuaternionF.Identity)));
            shape = comp;
            break;
          case 10:
            shape = new ConvexHullOfPoints(new[]
            {
              new Vector3F(-1 * ObjectSize, -2 * ObjectSize, -1 * ObjectSize),
              new Vector3F(2 * ObjectSize, -1 * ObjectSize, -0.5f * ObjectSize),
              new Vector3F(1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize),
              new Vector3F(-1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize),
              new Vector3F(-1 * ObjectSize, 0.7f * ObjectSize, -0.6f * ObjectSize)
            });
            break;
          case 11:
            ConvexHullOfShapes shapeHull = new ConvexHullOfShapes();
            shapeHull.Children.Add(new GeometricObject(new SphereShape(0.3f * ObjectSize), new Pose(new Vector3F(0, 2 * ObjectSize, 0), Matrix33F.Identity)));
            shapeHull.Children.Add(new GeometricObject(new BoxShape(1 * ObjectSize, 2 * ObjectSize, 3 * ObjectSize), Pose.Identity));
            shape = shapeHull;
            break;
          case 12:
            shape = Shape.Empty;
            break;
          case 13:
            var numberOfSamplesX = 10;
            var numberOfSamplesZ = 10;
            var samples = new float[numberOfSamplesX * numberOfSamplesZ];
            for (int z = 0; z < numberOfSamplesZ; z++)
              for (int x = 0; x < numberOfSamplesX; x++)
                samples[z * numberOfSamplesX + x] = (float)(Math.Cos(z / 3f) * Math.Sin(x / 2f) * BoxSize / 6);
            HeightField heightField = new HeightField(0, 0, 2 * BoxSize, 2 * BoxSize, samples, numberOfSamplesX, numberOfSamplesZ);
            shape = heightField;
            break;
          //case 14:
          //shape = new LineShape(new Vector3F(0.1f, 0.2f, 0.3f), new Vector3F(0.1f, 0.2f, -0.3f).Normalized);
          //break;            
          case 15:
            shape = new LineSegmentShape(
              new Vector3F(0.1f, 0.2f, 0.3f), new Vector3F(0.1f, 0.2f, 0.3f) + 3 * ObjectSize * new Vector3F(0.1f, 0.2f, -0.3f));
            break;
          case 16:
            shape = new MinkowskiDifferenceShape
            {
              ObjectA = new GeometricObject(new SphereShape(0.1f * ObjectSize)),
              ObjectB = new GeometricObject(new BoxShape(1 * ObjectSize, 2 * ObjectSize, 3 * ObjectSize))
            };
            break;
          case 17:
            shape = new MinkowskiSumShape
            {
              ObjectA = new GeometricObject(new SphereShape(0.1f * ObjectSize)),
              ObjectB = new GeometricObject(new BoxShape(1 * ObjectSize, 2 * ObjectSize, 3 * ObjectSize)),
            };
            break;
          case 18:
            shape = new OrthographicViewVolume(0, ObjectSize, 0, ObjectSize, ObjectSize / 2, ObjectSize * 2);
            break;
          case 19:
            shape = new PerspectiveViewVolume(MathHelper.ToRadians(60f), 16f / 10, ObjectSize / 2, ObjectSize * 3);
            break;
          case 20:
            shape = new PointShape(0.1f, 0.3f, 0.2f);
            break;
          case 21:
            shape = new RayShape(new Vector3F(0.2f, 0, -0.12f), new Vector3F(1, 2, 3).Normalized, ObjectSize * 2);
            break;
          case 22:
            shape = new RayShape(new Vector3F(0.2f, 0, -0.12f), new Vector3F(1, 2, 3).Normalized, ObjectSize * 2)
            {
              StopsAtFirstHit = true
            };
            break;
          case 23:
            shape = new RectangleShape(ObjectSize, ObjectSize * 2);
            break;
          case 24:
            shape = new TransformedShape(
              new GeometricObject(
                new BoxShape(1 * ObjectSize, 2 * ObjectSize, 3 * ObjectSize),
                new Pose(new Vector3F(0.1f, 1, -0.2f))));
            break;
          case 25:
            shape = new TriangleShape(
              new Vector3F(ObjectSize, 0, 0), new Vector3F(0, ObjectSize, 0), new Vector3F(ObjectSize, ObjectSize, ObjectSize));
            break;
          //case 26:
          //  {
          //    // Create a composite object from which we get the mesh.
          //    CompositeShape compBvh = new CompositeShape();
          //    compBvh.Children.Add(new GeometricObject(new BoxShape(0.5f, 1, 0.5f), new Pose(new Vector3F(0, 0.5f, 0), Matrix33F.Identity)));
          //    compBvh.Children.Add(
          //      new GeometricObject(
          //        new BoxShape(0.8f, 0.5f, 0.5f),
          //        new Pose(new Vector3F(0.5f, 0.7f, 0), Matrix33F.CreateRotationZ(-(float)MathHelper.ToRadians(15)))));
          //    compBvh.Children.Add(new GeometricObject(new SphereShape(0.3f), new Pose(new Vector3F(0, 1.15f, 0), Matrix33F.Identity)));
          //    compBvh.Children.Add(
          //      new GeometricObject(new CapsuleShape(0.2f, 1), new Pose(new Vector3F(0.6f, 1.15f, 0), Matrix33F.CreateRotationX(0.3f))));

          //    TriangleMeshShape meshBvhShape = new TriangleMeshShape { Mesh = compBvh.GetMesh(0.01f, 3) };
          //    meshBvhShape.Partition = new AabbTree<int>();
          //    shape = meshBvhShape;
          //    break;
          //  }
          //case 27:
          //  {
          //    // Create a composite object from which we get the mesh.
          //    CompositeShape compBvh = new CompositeShape();
          //    compBvh.Children.Add(new GeometricObject(new BoxShape(0.5f, 1, 0.5f), new Pose(new Vector3F(0, 0.5f, 0), QuaternionF.Identity)));
          //    compBvh.Children.Add(
          //      new GeometricObject(
          //        new BoxShape(0.8f, 0.5f, 0.5f),
          //        new Pose(new Vector3F(0.5f, 0.7f, 0), QuaternionF.CreateRotationZ(-(float)MathHelper.ToRadians(15)))));
          //    compBvh.Children.Add(new GeometricObject(new SphereShape(0.3f), new Pose(new Vector3F(0, 1.15f, 0), QuaternionF.Identity)));
          //    compBvh.Children.Add(
          //      new GeometricObject(new CapsuleShape(0.2f, 1), new Pose(new Vector3F(0.6f, 1.15f, 0), QuaternionF.CreateRotationX(0.3f))));

          //    TriangleMeshShape meshBvhShape = new TriangleMeshShape { Mesh = compBvh.GetMesh(0.01f, 3) };
          //    meshBvhShape.Partition = new AabbTree<int>();
          //    shape = meshBvhShape;
          //    break;
          //  }
          case 28:
            shape = new ConvexPolyhedron(new[]
            {
              new Vector3F(-1 * ObjectSize, -2 * ObjectSize, -1 * ObjectSize),
              new Vector3F(2 * ObjectSize, -1 * ObjectSize, -0.5f * ObjectSize),
              new Vector3F(1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize),
              new Vector3F(-1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize),
              new Vector3F(-1 * ObjectSize, 0.7f * ObjectSize, -0.6f * ObjectSize)
            });
            break;
          case 29:
            return;
          default:
            currentShape++;
            continue;
        }

        // Create an object with the random shape, pose, color and velocity.
        Pose randomPose = new Pose(
          random.NextVector3F(-BoxSize + ObjectSize * 2, BoxSize - ObjectSize * 2),
          random.NextQuaternionF());
        var newObject = new MovingGeometricObject
        {
          Pose = randomPose,
          Shape = shape,
          LinearVelocity = random.NextQuaternionF().Rotate(new Vector3F(MaxLinearVelocity, 0, 0)),
          AngularVelocity = random.NextQuaternionF().Rotate(Vector3F.Forward)
                            * RandomHelper.Random.NextFloat(0, MaxAngularVelocity),
        };

        if (RandomHelper.Random.NextBool())
          newObject.LinearVelocity = Vector3F.Zero;
        if (RandomHelper.Random.NextBool())
          newObject.AngularVelocity = Vector3F.Zero;

        if (shape is LineShape || shape is HeightField)
        {
          // Do not move lines or the height field.
          newObject.LinearVelocity = Vector3F.Zero;
          newObject.AngularVelocity = Vector3F.Zero;
        }

        // Create only 1 heightField!
        if (shape is HeightField)
        {
          if (isFirstHeightField)
          {
            isFirstHeightField = true;
            newObject.Pose = new Pose(new Vector3F(-BoxSize, -BoxSize, -BoxSize));
          }
          else
          {
            currentShape++;
            numberOfObjects = 0;
            continue;
          }
        }

        // Add collision object to collision domain.
        _domain.CollisionObjects.Add(new CollisionObject(newObject));

        //co.Type = CollisionObjectType.Trigger;
        //co.Name = "Object" + shape.GetType().Name + "_" + i;
      }
    }
Example #17
0
        /// <summary>
        /// Gets a bounding shape that matches the specified AABB.
        /// </summary>
        /// <param name="aabb">The AABB.</param>
        /// <returns>A box or transformed box that matches the specified AABB.</returns>
        private Shape GetBoundingShape(Aabb aabb)
        {
            // The AABB of the LOD is real world size including scaling. We have to undo
              // the scale because this LodGroupNode also applies the same scale.
              var unscaledCenter = aabb.Center / ScaleWorld;
              var unscaledExtent = aabb.Extent / ScaleWorld;

              // Get existing shape objects to avoid unnecessary memory allocation.
              BoxShape boxShape;
              GeometricObject geometricObject = null;
              TransformedShape transformedShape = null;
              if (Shape is BoxShape)
              {
            boxShape = (BoxShape)Shape;
              }
              else if (Shape is TransformedShape)
              {
            transformedShape = (TransformedShape)Shape;
            geometricObject = (GeometricObject)transformedShape.Child;
            boxShape = (BoxShape)geometricObject.Shape;
              }
              else
              {
            boxShape = new BoxShape();
              }

              // Make bounding box the size of the unscaled AABB.
              boxShape.Extent = unscaledExtent;

              if (unscaledCenter.IsNumericallyZero)
              {
            // Bounding box is centered at origin.
            return boxShape;
              }

              // Apply offset to bounding box.
              if (transformedShape == null)
              {
            geometricObject = new GeometricObject(boxShape, new Pose(unscaledCenter));
            transformedShape = new TransformedShape(geometricObject);
              }
              else
              {
            geometricObject.Shape = boxShape;
            geometricObject.Pose = new Pose(unscaledCenter);
              }

              return transformedShape;
        }
Example #18
0
    private void InitializePhysics()
    {
      // 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",
        MotionType = MotionType.Static,
      };
      Simulation.RigidBodies.Add(groundPlane);

      // Add walls.
      RigidBody wall0 = new RigidBody(new BoxShape(10, 2, 0.5f))
      {
        Name = "Wall0",
        MotionType = MotionType.Static,
        Pose = new Pose(new Vector3F(0, 1, -5))
      };
      Simulation.RigidBodies.Add(wall0);

      RigidBody wall1 = new RigidBody(new BoxShape(10, 2, 0.5f))
      {
        Name = "Wall1",
        MotionType = MotionType.Static,
        Pose = new Pose(new Vector3F(0, 1, 5))
      };
      Simulation.RigidBodies.Add(wall1);

      RigidBody wall2 = new RigidBody(new BoxShape(0.5f, 2, 10))
      {
        Name = "Wall2",
        MotionType = MotionType.Static,
        Pose = new Pose(new Vector3F(-5, 1, 0))
      };
      Simulation.RigidBodies.Add(wall2);

      RigidBody wall3 = new RigidBody(new BoxShape(0.5f, 2, 10))
      {
        Name = "Wall3",
        MotionType = MotionType.Static,
        Pose = new Pose(new Vector3F(5, 1, 0))
      };
      Simulation.RigidBodies.Add(wall3);

      // Add sphere.
      RigidBody sphere = new RigidBody(new SphereShape(0.4f))
      {
        Name = "Sphere",
        Pose = new Pose(new Vector3F(1, 1, 1)),
      };
      Simulation.RigidBodies.Add(sphere);

      // Add a stack of boxes.
      const int numberOfBoxes = 3;
      const float boxSize = 0.8f;
      BoxShape boxShape = new BoxShape(boxSize, boxSize, boxSize);

      // Optional: Use a small overlap between boxes to improve the stability.
      float overlap = Simulation.Settings.Constraints.AllowedPenetration * 0.5f;
      Vector3F position = new Vector3F(0, boxSize / 2 - overlap, 0);
      for (int i = 0; i < numberOfBoxes; i++)
      {
        RigidBody box = new RigidBody(boxShape)
        {
          Name = "Box" + i,
          Pose = new Pose(position),
        };
        Simulation.RigidBodies.Add(box);
        position.Y += boxSize - overlap;
      }
    }
Example #19
0
    public HeightFieldSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      // Add basic force effects.
      Simulation.ForceEffects.Add(new Gravity());
      Simulation.ForceEffects.Add(new Damping());

      // Create a height field.
      // The height data consists of height samples with a resolution of 20 entries per dimension.
      // (Height samples are stored in a 1-dimensional array.)
      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++)
        {
          // Set the y values (height).
          samples[z * numberOfSamplesX  + x] = (float)(Math.Cos(z / 2f) * Math.Sin(x / 2f) * 5f + 5f);
        }
      }

      // The height field has a size of 100 m x 100 m.
      float widthX = 100;
      float widthZ = 100;

      // The origin is at (-50, -50) to center the height field at the world space origin.
      float originX = -50;
      float originZ = -50;

      // Create the height field shape.
      HeightField heightField = new HeightField(
        originX, originZ, widthX, widthZ, samples, numberOfSamplesX, numberOfSamplesZ);

      // We can set following flag to get a significant performance gain - but the collision
      // detection will be less accurate. For smooth height fields this flag can be set.
      heightField.UseFastCollisionApproximation = true;

      // Create a static rigid body using the height field and add it to the simulation.
      RigidBody landscape = new RigidBody(heightField)
      {
        Pose = Pose.Identity,
        MotionType = MotionType.Static,
      };
      Simulation.RigidBodies.Add(landscape);

      // Distribute a few spheres and boxes across the landscape.
      SphereShape sphereShape = new SphereShape(0.5f);
      for (int i = 0; i < 30; i++)
      {
        Vector3F position = RandomHelper.Random.NextVector3F(-30, 30);
        position.Y = 20;

        RigidBody body = new RigidBody(sphereShape)
        {
          Pose = new Pose(position),
        };
        Simulation.RigidBodies.Add(body);
      }

      BoxShape boxShape = new BoxShape(1, 1, 1);
      for (int i = 0; i < 30; i++)
      {
        Vector3F position = RandomHelper.Random.NextVector3F(-30, 30);
        position.Y = 20;

        RigidBody body = new RigidBody(boxShape)
        {
          Pose = new Pose(position),
        };
        Simulation.RigidBodies.Add(body);
      }
    }
Example #20
0
    protected override void OnLoad()
    {
      _scene = _services.GetInstance<IScene>();

      // Get a bounding shape for the cells. We use a box with the cell size and
      // make it bigger by some arbitrary values. The boxes must be bigger because
      // mesh instances can be placed on the cell boundary and when they are animated
      // tree branches can sway outside the cell bounds.
      var meshAabb = _mesh.BoundingShape.GetAabb();
      float meshWidth = new Vector2F(meshAabb.Extent.X, meshAabb.Extent.Z).Length * 1.5f;
      float meshHeight = meshAabb.Extent.Y * 1.7f;
      var boxShape = new BoxShape(_cellSize + meshWidth, meshHeight, _cellSize + meshWidth);

      // Create one MeshInstancingNode per cell and add random instances.
      _nodes = new MeshInstancingNode<InstanceData>[_numberOfCellsX, _numberOfCellsZ];
      float xOrigin = -(_numberOfCellsX * _cellSize) / 2;
      float zOrigin = -(_numberOfCellsZ * _cellSize) / 2;
      var random = new Random(_randomSeed);
      for (int x = 0; x < _numberOfCellsX; x++)
      {
        for (int z = 0; z < _numberOfCellsZ; z++)
        {
          var instances = new InstanceData[_numberOfInstancesPerCell];
          for (int i = 0; i < instances.Length; i++)
          {
            Vector3F scale = new Vector3F(random.NextFloat(0.5f, 1.5f));
            Pose pose = new Pose(new Vector3F(xOrigin + x * _cellSize + random.NextFloat(0, _cellSize),
                                              0,
                                              zOrigin + z * _cellSize + random.NextFloat(0, _cellSize)),
                                 Matrix33F.CreateRotationY(random.NextFloat(0, 10)));
            Vector4F color = new Vector4F(1);

            instances[i] = new InstanceData(scale, pose, color);
          }

          _nodes[x, z] = new MeshInstancingNode<InstanceData>(_mesh, instances)
          {
            PoseLocal = new Pose(new Vector3F(xOrigin + (0.5f + x) * _cellSize, 
                                              boxShape.WidthY / 2, 
                                              zOrigin + (0.5f + z) * _cellSize)),
            Shape = boxShape,
            CastsShadows = _castsShadows,
          };
          _scene.Children.Add(_nodes[x, z]);
        }
      }

      UpdateLodDistances();

      // ----- Add GUI controls to the Options window.
      var sampleFramework = _services.GetInstance<SampleFramework>();
      var optionsPanel = sampleFramework.AddOptions("Game Objects");
      var panel = SampleHelper.AddGroupBox(optionsPanel, "VegetationObject " + Name);

      SampleHelper.AddSlider(
        panel,
        "Min distance",
        "F2",
        0,
        100,
        MinDistance,
        value => MinDistance = value);

      SampleHelper.AddSlider(
        panel,
        "Max distance",
        "F2",
        0,
        100,
        MaxDistance,
        value => MaxDistance = value);
    }
Example #21
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);
    }
Example #22
0
    private void CreateObjects()
    {
      // Create two collision objects with triangle mesh shapes.
      var meshA = new TriangleMesh();
      meshA.Add(new Triangle(new Vector3F(0, 1, 0), new Vector3F(0, 1, 0), new Vector3F(0, 1, 0)));
      meshA.Add(new Triangle(new Vector3F(0, 1, 0), new Vector3F(0, 1, 0), new Vector3F(0, 1, 0)));
      var shapeA = new TriangleMeshShape() { Partition = new CompressedAabbTree() }; 
      var poseA = new Pose(new Vector3F(-1, 0, 0));
      _objectA = new CollisionObject(new GeometricObject(shapeA, poseA));

      var meshB = new BoxShape(0.2f, 2, 1f).GetMesh(0.05f, 4);
      var shapeB = new TriangleMeshShape(meshB, true) { Partition = new CompressedAabbTree() };
      var poseB = new Pose(new Vector3F(0.1f, 0, 0));
      _objectB = new CollisionObject(new GeometricObject(shapeB, poseB)); 
    }
Example #23
0
    public MaterialSample(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,
      };

      // Adjust the coefficient of restitution of the ground plane.
      // (By default, the material of a rigid body is of type UniformMaterial.)
      ((UniformMaterial)groundPlane.Material).Restitution = 1;  // Max. bounciness. (The simulation actually 
                                                                // accepts higher values, but these usually
                                                                // lead to unnatural bounciness.)

      Simulation.RigidBodies.Add(groundPlane);

      // Add a static inclined ground plane.
      RigidBody inclinedPlane = new RigidBody(new PlaneShape(new Vector3F(-0.3f, 1f, 0).Normalized, 0))
      {
        Name = "InclinedPlane",
        MotionType = MotionType.Static,
      };
      Simulation.RigidBodies.Add(inclinedPlane);

      // Create a few boxes with different coefficient of friction.
      BoxShape boxShape = new BoxShape(1, 1, 1);
      for (int i = 0; i < 5; i++)
      {
        // Each box gets a different friction value.
        UniformMaterial material = new UniformMaterial
        {
          DynamicFriction = i * 0.2f,
          StaticFriction = i * 0.2f,
        };

        RigidBody box = new RigidBody(boxShape, null, material) // The second argument (the mass frame) is null. The 
        {                                                       // simulation will automatically compute a default mass.
          Name = "Box" + i,
          Pose = new Pose(new Vector3F(5, 6, -5 + i * 2)),
        };

        Simulation.RigidBodies.Add(box);
      }

      // Create a few balls with different coefficient of restitution (= bounciness).
      Shape sphereShape = new SphereShape(0.5f);
      for (int i = 0; i < 6; i++)
      {
        // Vary restitution between 0 and 1.
        UniformMaterial material = new UniformMaterial
        {
          Restitution = i * 0.2f
        };

        RigidBody body = new RigidBody(sphereShape, null, material)
        {
          Name = "Ball" + i,
          Pose = new Pose(new Vector3F(-1 - i * 2, 5, 0)),
        };

        Simulation.RigidBodies.Add(body);
      }
    }
Example #24
0
    /// <summary>
    /// Gets a bounding shape that matches the specified AABB.
    /// </summary>
    /// <param name="aabb">The AABB.</param>
    /// <returns>A box or transformed box that matches the specified AABB.</returns>
    private Shape GetBoundingShape(Aabb aabb)
    {
      // Get existing shape objects to avoid unnecessary memory allocation.
      BoxShape boxShape;
      GeometricObject geometricObject = null;
      TransformedShape transformedShape = null;
      if (Shape is BoxShape)
      {
        boxShape = (BoxShape)Shape;
      }
      else if (Shape is TransformedShape)
      {
        transformedShape = (TransformedShape)Shape;
        geometricObject = (GeometricObject)transformedShape.Child;
        boxShape = (BoxShape)geometricObject.Shape;
      }
      else
      {
        boxShape = new BoxShape();
      }

      // Make box the size of the AABB.
      boxShape.Extent = aabb.Extent;

      if (aabb.Center.IsNumericallyZero)
      {
        // Bounding box is centered at origin.
        return boxShape;
      }
      
      // Apply offset to bounding box.
      if (transformedShape == null)
      {
        geometricObject = new GeometricObject(boxShape, new Pose(aabb.Center));
        transformedShape = new TransformedShape(geometricObject);
      }
      else
      {
        geometricObject.Shape = boxShape;
        geometricObject.Pose = new Pose(aabb.Center);
      }

      return transformedShape;
    }
Example #25
0
    public AdvancedAvatarRagdollSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      SampleFramework.IsMouseVisible = false;

      // This sample uses for a DebugRenderer to draw text and rigid bodies.
      _debugRenderer = new DebugRenderer(GraphicsService, SpriteFont)
      {
        DefaultColor = Color.Black,
        DefaultTextPosition = new Vector2F(10),
      };

      // Add a custom game object which controls the camera.
      _cameraObject = new CameraObject(Services);
      _cameraObject.ResetPose(new Vector3F(0, 1, -3), ConstantsF.Pi, 0);
      GameObjectService.Objects.Add(_cameraObject);

      // Add some objects which allow the user to interact with the rigid bodies.
      _grabObject = new GrabObject(Services);
      _ballShooterObject = new BallShooterObject(Services) { Speed = 20 };
      GameObjectService.Objects.Add(_grabObject);
      GameObjectService.Objects.Add(_ballShooterObject);

      // Add some default force effects.
      Simulation.ForceEffects.Add(new Gravity());
      Simulation.ForceEffects.Add(new Damping());

      // Create a random avatar.
      _avatarDescription = AvatarDescription.CreateRandom();
      _avatarRenderer = new AvatarRenderer(_avatarDescription);

      // Use the "Wave" animation preset.
      var avatarAnimation = new AvatarAnimation(AvatarAnimationPreset.Wave);
      _expressionAnimation = new AnimationClip<AvatarExpression>(new WrappedAvatarExpressionAnimation(avatarAnimation))
      {
        LoopBehavior = LoopBehavior.Cycle,
        Duration = TimeSpan.MaxValue,
      };
      _skeletonAnimation = new AnimationClip<SkeletonPose>(new WrappedAvatarSkeletonAnimation(avatarAnimation))
      {
        LoopBehavior = LoopBehavior.Cycle,
        Duration = TimeSpan.MaxValue,
      };

      // Add a ground plane in the simulation.
      Simulation.RigidBodies.Add(new RigidBody(new PlaneShape(Vector3F.UnitY, 0)) { MotionType = MotionType.Static });

      // Distribute a few dynamic spheres and boxes across the landscape.
      SphereShape sphereShape = new SphereShape(0.3f);
      for (int i = 0; i < 10; i++)
      {
        Vector3F position = RandomHelper.Random.NextVector3F(-10, 10);
        position.Y = 1;
        Simulation.RigidBodies.Add(new RigidBody(sphereShape) { Pose = new Pose(position) });
      }

      BoxShape boxShape = new BoxShape(0.6f, 0.6f, 0.6f);
      for (int i = 0; i < 10; i++)
      {
        Vector3F position = RandomHelper.Random.NextVector3F(-10, 10);
        position.Y = 1;
        Simulation.RigidBodies.Add(new RigidBody(boxShape) { Pose = new Pose(position) });
      }
    }
Example #26
0
 private static void GetMass(BoxShape box, Vector3F scale, float densityOrMass, bool isDensity, out float mass, out Matrix33F inertia)
 {
     scale = Vector3F.Absolute(scale);
       Vector3F extent = box.Extent * scale;
       GetMass(extent, densityOrMass, isDensity, out mass, out inertia);
 }
Example #27
0
    public ContentPipelineMeshSample(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);

      // ----- Load triangle mesh model.
      var sharedModelNode = ContentManager.Load<ModelNode>("Saucer/saucer");

      // Let's create a clone because we do not want to change the shared Saucer 
      // instance stored in the content manager.
      _modelNode = sharedModelNode.Clone();
      
      _modelNode.PoseWorld = new Pose(new Vector3F(0, 2, -5), Matrix33F.CreateRotationY(MathHelper.ToRadians(-30)));
      _modelNode.ScaleLocal = new Vector3F(8);

      // The UserData contains the collision shape of type TriangleMeshShape.
      TriangleMeshShape triangleMesh = (TriangleMeshShape)_modelNode.UserData;

      // Add model node to graphics scene.
      GraphicsScreen.Scene.Children.Add(_modelNode);

      // Create rigid body.
      // We explicitly specify a mass frame. We can use any mass frame for static bodies (because
      // static bodies are effectively treated as if they have infinite mass). If we do not specify
      // a mass frame in the rigid body constructor, the constructor will automatically compute an
      // approximate mass frame (which can take some time for large meshes).
      _rigidBody = new RigidBody(triangleMesh, new MassFrame(), null)
      {
        MotionType = MotionType.Static,
        Pose = _modelNode.PoseWorld,
        Scale = _modelNode.ScaleWorld,
        
        // The PhysicsSample class should not draw the height field. 
        UserData = "NoDraw",
      };
      Simulation.RigidBodies.Add(_rigidBody);

      // Distribute a few spheres and boxes across the triangle mesh.
      SphereShape sphereShape = new SphereShape(0.5f);
      for (int i = 0; i < 40; i++)
      {
        Vector3F position = RandomHelper.Random.NextVector3F(-15, 10);
        position.Y = RandomHelper.Random.NextFloat(20, 40);

        RigidBody body = new RigidBody(sphereShape) { Pose = new Pose(position) };
        Simulation.RigidBodies.Add(body);
      }

      BoxShape boxShape = new BoxShape(1, 1, 1);
      for (int i = 0; i < 40; i++)
      {
        Vector3F position = RandomHelper.Random.NextVector3F(-15, 10);
        position.Y = RandomHelper.Random.NextFloat(20, 40);

        RigidBody body = new RigidBody(boxShape) { Pose = new Pose(position) };
        Simulation.RigidBodies.Add(body);
      }
    }
Example #28
0
    /// <summary>
    /// Initializes the physics simulation.
    /// </summary>
    private void InitializePhysics()
    {
      // Define the timing of the physics simulation:
      // The Windows Phone runs with 30 FPS, so one frame takes 1/30 seconds.
      // We can run the simulation using the same timing.
      // However, 1/30 seconds is a very large time step for a physics simulation. A large
      // time step improves performance, but reduces the quality of the simulation.
      // Instead we can run the simulation with a time step of 1/60 seconds and compute 
      // 2 time steps per frame.
      // Additionally, we can reduce the number of constraint solver iterations to gain additional
      // performance. But if you want to simulate complex scene with stable stacks or walls, you
      // might want to leave the default value.
      // Below are two variants - you can comment/uncomment the variants to compare them.

      // -----  Variant #1: "Fast, less stable"
      Simulation.Settings.Timing.FixedTimeStep = 1.0f / 30.0f;
      Simulation.Settings.Timing.MaxNumberOfSteps = 1;
      Simulation.Settings.Constraints.NumberOfConstraintIterations = 6;

      // ----- Variant #2: "Slower, more stable"
      //_simulation.Settings.Timing.FixedTimeStep = 1.0f / 60.0f;
      //_simulation.Settings.Timing.MaxNumberOfSteps = 2;
      //_simulation.Settings.Constraints.NumberOfConstraintIterations = 10;
      
      // Add the typical force effect for gravity and damping.
      Simulation.ForceEffects.Add(new Gravity { Acceleration = new Vector3F(0, -10, 0) });
      Simulation.ForceEffects.Add(new Damping());

      // Add a ground plane (static object).
      var groundPlane = new RigidBody(new PlaneShape(Vector3F.UnitY, 0))
      {
        Name = "GroundPlane",
        MotionType = MotionType.Static,
      };
      Simulation.RigidBodies.Add(groundPlane);

      // Create a set of predefined shapes. 
      // The shapes are chosen randomly when a new rigid body is added.
      _shapes = new List<Shape>();
      _shapes.Add(new BoxShape(1.0f, 1.0f, 1.0f));
      _shapes.Add(new BoxShape(1.5f, 0.5f, 1.0f));
      _shapes.Add(new BoxShape(1.0f, 0.75f, 1.0f));
      _shapes.Add(new CapsuleShape(0.4f, 2.0f));
      _shapes.Add(new SphereShape(0.6f));

      // Add convex shape.
      var randomPoints = new List<Vector3F>();
      for (int i = 0; i < 20; i++)
        randomPoints.Add(RandomHelper.Random.NextVector3F(-1, 1));
      _shapes.Add(new ConvexPolyhedron(randomPoints));

      // Add a composite shape looking like table.
      var board = new BoxShape(2.0f, 0.3f, 1.2f);
      var leg = new BoxShape(0.2f, 1f, 0.2f);
      var table = new CompositeShape();
      table.Children.Add(new GeometricObject(board, new Pose(new Vector3F(0.0f, 1.0f, 0.0f))));
      table.Children.Add(new GeometricObject(leg, new Pose(new Vector3F(-0.7f, 0.5f, -0.4f))));
      table.Children.Add(new GeometricObject(leg, new Pose(new Vector3F(-0.7f, 0.5f, 0.4f))));
      table.Children.Add(new GeometricObject(leg, new Pose(new Vector3F(0.7f, 0.5f, 0.4f))));
      table.Children.Add(new GeometricObject(leg, new Pose(new Vector3F(0.7f, 0.5f, -0.4f))));
      _shapes.Add(table);
    }
Example #29
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>()
      {
        // 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,
      };

      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 #30
0
    public CompositeMaterialSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      // Add basic force effects.
      Simulation.ForceEffects.Add(new Gravity());
      Simulation.ForceEffects.Add(new Damping());

      // ----- Create a simple height field.
      // The height data consists of height samples with a resolution of 20 entries per dimension.
      // (Height samples are stored in a 1-dimensional array.)
      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++)
        {
          // Set the y values (height).
          samples[z * numberOfSamplesX + x] = 20 - z;
        }
      }

      // Set the size of the height field in world space. (WidthX/Z determine the extent
      // of the height field but not the resolution of the height samples.)
      float widthX = 40;
      float widthZ = 40;

      // The origin is at (-20, -20) to center the height field at the world space origin.
      float originX = -20;
      float originZ = -20;

      // Create the height field shape.
      HeightField heightField = new HeightField(
        originX, originZ, widthX, widthZ, samples, numberOfSamplesX, numberOfSamplesZ);

      RigidBody ground = new RigidBody(heightField)
      {
        Pose = new Pose(new Vector3F(0, -10, 0)),
        MotionType = MotionType.Static,
      };
      Simulation.RigidBodies.Add(ground);

      // Assign two different materials to the height field.
      // A rough material (high friction) should be used for the left cells of the height field.
      UniformMaterial roughMaterial = new UniformMaterial
      {
        DynamicFriction = 1,
        StaticFriction = 1,
      };

      // A slippery material (low friction) should be used for the right cells of the height field.
      UniformMaterial slipperyMaterial = new UniformMaterial
      {
        DynamicFriction = 0,
        StaticFriction = 0,
      };

      // Use a CompositeMaterial two assign the materials to the features of the height field.
      CompositeMaterial compositeMaterial = new CompositeMaterial();

      // A "feature" of a height field is a triangle:
      // The height field is triangulated. Each cell consists of two triangles. The triangles are 
      // numbered from left-to-right and top-to-bottom. 
      // (For more information: See the description of HeightField.)

      // Loop over the cells.
      // (If the resolution is 20, we have 20 height values in one row. Between these height
      // values are 19 cells.)
      for (int z = 0; z < numberOfSamplesZ - 1; z++)
      {
        for (int x = 0; x < numberOfSamplesX - 1; x++)
        {
          // Assign the rough material to the left cells and the slippery material to the 
          // right cells.
          if (x < numberOfSamplesX / 2)
          {
            // Each cell contains 2 triangles, therefore we have to add 2 entries to the 
            // CompositeMaterial.
            compositeMaterial.Materials.Add(roughMaterial);
            compositeMaterial.Materials.Add(roughMaterial);
          }
          else
          {
            compositeMaterial.Materials.Add(slipperyMaterial);
            compositeMaterial.Materials.Add(slipperyMaterial);
          }
        }
      }
      ground.Material = compositeMaterial;

      // Create a few boxes on the height field.
      // The left boxes will roll or stop on the height field because of the high friction.
      // The right boxes will slide down because of the low friction.
      BoxShape boxShape = new BoxShape(1, 1, 1);
      for (int i = 0; i < 10; i++)
      {
        RigidBody body = new RigidBody(boxShape, null, roughMaterial)
        {
          Pose = new Pose(new Vector3F(-19 + i * 4, 10, -10)),
        };
        Simulation.RigidBodies.Add(body);
      }
    }