Beispiel #1
0
 //--------------------------------------------------------------
 /// <summary>
 /// Initializes a new instance of the <see cref="Billboard" /> class.
 /// </summary>
 protected Billboard()
 {
     Shape = new SphereShape(0);
       Orientation = BillboardOrientation.ViewPlaneAligned;
       Color = new Vector3F(1, 1, 1);
       Alpha = 1;
 }
Beispiel #2
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);
    }
Beispiel #3
0
    public SphereStackSample(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 spheres.
      const int numberOfSpheres = 10;
      const float sphereRadius = 0.4f;
      Shape sphereShape = new SphereShape(sphereRadius);

      // Optional: Use a small overlap between spheres to improve the stability.
      float overlap = Simulation.Settings.Constraints.AllowedPenetration * 0.5f;
      Vector3F position = new Vector3F(0, sphereRadius - overlap, 0);
      for (int i = 0; i < numberOfSpheres; i++)
      {
        RigidBody sphere = new RigidBody(sphereShape)
        {
          Name = "Sphere" + i,
          Pose = new Pose(position),
        };
        Simulation.RigidBodies.Add(sphere);
        position.Y += 2 * sphereRadius - overlap;
      }
    }
Beispiel #4
0
        public void TestException()
        {
            var sphere0 = new SphereShape(1);
              var geo0 = new GeometricObject(sphere0);
              var geo1 = new GeometricObject(sphere0);
              var co0 = new CollisionObject(geo0);
              var co1 = new CollisionObject(geo1);

              geo0.Pose = Pose.Identity;
              geo1.Pose = new Pose(new Vector3F(10, 0, 0));

              float toi = CcdHelper.GetTimeOfImpactLinearSweep(co0, new Pose(new Vector3F(4, 0, 0)), co1, new Pose(new Vector3F(6, 0, 0)), 0.01f);
              Assert.AreEqual(1, toi);

              toi = CcdHelper.GetTimeOfImpactLinearCA(co0, new Pose(new Vector3F(4, 0, 0)), co1, new Pose(new Vector3F(6, 0, 0)), 0.01f, new CollisionDetection());
              Assert.AreEqual(1, toi);

              toi = CcdHelper.GetTimeOfImpactCA(co0, new Pose(new Vector3F(4, 0, 0)), co1, new Pose(new Vector3F(6, 0, 0)), 0.01f, new CollisionDetection());
              Assert.AreEqual(1, toi);

              toi = CcdHelper.GetTimeOfImpactLinearSweep(co0, new Pose(new Vector3F(4f, 0, 0)), co1, new Pose(new Vector3F(6f, 0, 0)), 0.01f);
              Assert.AreEqual(1, toi);

              toi = CcdHelper.GetTimeOfImpactLinearCA(co0, new Pose(new Vector3F(4f, 0, 0)), co1, new Pose(new Vector3F(6f, 0, 0)), 0.01f, new CollisionDetection());
              Assert.AreEqual(1, toi);

              toi = CcdHelper.GetTimeOfImpactCA(co0, new Pose(new Vector3F(4f, 0, 0)), co1, new Pose(new Vector3F(6f, 0, 0)), 0.01f, new CollisionDetection());
              Assert.AreEqual(1, toi);

              toi = CcdHelper.GetTimeOfImpactLinearSweep(co0, new Pose(new Vector3F(7f, 0, 0)), co1, new Pose(new Vector3F(4f, 0, 0)), 0.01f);
              Assert.IsTrue(toi > 0 && toi < 1);

              toi = CcdHelper.GetTimeOfImpactLinearCA(co0, new Pose(new Vector3F(7f, 0, 0)), co1, new Pose(new Vector3F(6f, 0, 0)), 0.01f, new CollisionDetection());
              Assert.IsTrue(toi > 0 && toi < 1);

              toi = CcdHelper.GetTimeOfImpactCA(co0, new Pose(new Vector3F(7f, 0, 0)), co1, new Pose(new Vector3F(4f, 0, 0)), 0.01f, new CollisionDetection());
              Assert.IsTrue(toi > 0 && toi < 1);

              // Moving away
              toi = CcdHelper.GetTimeOfImpactLinearSweep(co0, new Pose(new Vector3F(-1f, 0, 0)), co1, new Pose(new Vector3F(11f, 0, 0)), 0.01f);
              Assert.AreEqual(1, toi);

              toi = CcdHelper.GetTimeOfImpactLinearCA(co0, new Pose(new Vector3F(-1f, 0, 0)), co1, new Pose(new Vector3F(11f, 0, 0)), 0.01f, new CollisionDetection());
              Assert.AreEqual(1, toi);

              toi = CcdHelper.GetTimeOfImpactCA(co0, new Pose(new Vector3F(-1f, 0, 0)), co1, new Pose(new Vector3F(11f, 0, 0)), 0.01f, new CollisionDetection());
              Assert.AreEqual(1, toi);

              // Touching at start. => GetTimeOfImpact result is invalid when objects touch at the start.
              //geo0.Pose = new Pose(new Vector3F(9, 0, 0));
              //toi = CcdHelper.GetTimeOfImpactLinearSweep(co0, new Pose(new Vector3F(10f, 0, 0)), co1, new Pose(new Vector3F(5f, 0, 0)), 0.01f);
              //Assert.AreEqual(0, toi);

              //toi = CcdHelper.GetTimeOfImpactLinearCA(co0, new Pose(new Vector3F(10f, 0, 0)), co1, new Pose(new Vector3F(5f, 0, 0)), 0.01f, new CollisionDetection());
              //Assert.AreEqual(0, toi);

              //toi = CcdHelper.GetTimeOfImpactCA(co0, new Pose(new Vector3F(10f, 0, 0)), co1, new Pose(new Vector3F(5f, 0, 0)), 0.01f, new CollisionDetection());
              //Assert.AreEqual(0, toi);
        }
Beispiel #5
0
        public void ApproximateVolume()
        {
            var s = new SphereShape(1);
              var c = new MinkowskiSumShape(new GeometricObject(s), new GeometricObject(new PointShape()));
              var v = c.GetVolume(0.001f,
                          0); // !!!

              // v is AABB volume.
              Assert.AreEqual(2 * 2 * 2, v);
        }
Beispiel #6
0
    public SpatialPartitionSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      SampleFramework.IsMouseVisible = false;
      GraphicsScreen.ClearBackground = true;
      GraphicsScreen.BackgroundColor = Color.Gray;
      GraphicsScreen.DrawReticle = true;
      SetCamera(new Vector3F(0, 1, 10), 0, 0);

      // Create a spatial partition. DigitalRune Geometry supports several types, see also
      // http://digitalrune.github.io/DigitalRune-Documentation/html/e32cab3b-cc7c-42ee-8ec9-23dd4467edd0.htm#WhichPartition
      // An AabbTree is useful for static objects. A DynamicAabbTree is good for moving objects.
      // The spatial partition can manage different types of items. In this case it manages
      // GeometricObjects. A delegate has to inform the spatial partition how to get the AABB
      // of an object.
      //_spatialPartition = new DynamicAabbTree<GeometricObject>
      _spatialPartition = new AabbTree<GeometricObject>
      {
        GetAabbForItem = geometricObject => geometricObject.Aabb,

        // Optional: 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,

        // Optional: A filter can be set to disable certain kind of overlaps.
        //Filter = ...
      };

      // Create a triangle mesh.
      var triangleMesh = new SphereShape(1).GetMesh(0.01f, 4);
      var triangleMeshShape = new TriangleMeshShape(triangleMesh)
      {
        // TriangleMeshShapes can also use a spatial partition to manage triangle.
        // The items in the spatial partition are the triangle indices. The GetAabbForItem
        // delegate is set automatically.
        Partition = new AabbTree<int>(),
      };

      // Spatial partitions are built automatically when needed. However, it is still recommended
      // to call Update to initialize the spatial partition explicitly.
      triangleMeshShape.Partition.Update(false);

      // Add a lot of triangle mesh objects to _spatialPartition.
      var random = new Random();
      for (int i = 0; i < 50; i++)
      {
        var randomPosition = new Vector3F(random.NextFloat(-6, 6), random.NextFloat(-3, 3), random.NextFloat(-10, 0));
        var geometricObject = new GeometricObject(triangleMeshShape, new Pose(randomPosition));
        _spatialPartition.Add(geometricObject);
      }

      _spatialPartition.Update(false);
    }
Beispiel #7
0
    //--------------------------------------------------------------
    #region Creation & Cleanup
    //--------------------------------------------------------------

    /// <summary>
    /// Initializes a new instance of the <see cref="FogSphereNode"/> class.
    /// </summary>
    public FogSphereNode()
    {
      IsRenderable = true;
      Shape = new SphereShape(1);

      Color = new Vector3F(1, 1, 1);
      Density = 0.6f;
      BlendMode = 0;
      Falloff = 5;
      IntersectionSoftness = 1;
    }
        public void GetScreenSizeWithOrthographic()
        {
            // Camera
              var projection = new OrthographicProjection();
              projection.SetOffCenter(0, 4, 0, 2);
              var camera = new Camera(projection);
              var cameraNode = new CameraNode(camera);
              cameraNode.PoseWorld = new Pose(new Vector3F(123, 456, -789), Matrix33F.CreateRotation(new Vector3F(1, -2, 3), MathHelper.ToRadians(75)));

              // 2:1 viewport
              var viewport = new Viewport(10, 10, 200, 100);

              // Test object
              var shape = new SphereShape();
              var geometricObject = new GeometricObject(shape);

              // Empty sphere at camera position.
              shape.Radius = 0;
              geometricObject.Pose = cameraNode.PoseWorld;
              Vector2F screenSize = GraphicsHelper.GetScreenSize(cameraNode, viewport, geometricObject);
              Assert.AreEqual(0, screenSize.X);
              Assert.AreEqual(0, screenSize.Y);

              // Empty sphere centered at near plane.
              shape.Radius = 0;
              geometricObject.Pose = cameraNode.PoseWorld * new Pose(new Vector3F(0.123f, -0.543f, -1));
              screenSize = GraphicsHelper.GetScreenSize(cameraNode, viewport, geometricObject);
              Assert.AreEqual(0, screenSize.X);
              Assert.AreEqual(0, screenSize.Y);

              // Create sphere which as a bounding sphere of ~1 unit diameter:
              // Since the bounding sphere is based on the AABB, we need to make the
              // actual sphere a bit smaller.
              shape.Radius = 1 / (2 * (float)Math.Sqrt(3)) + Numeric.EpsilonF;

              // Sphere at camera position.
              geometricObject.Pose = cameraNode.PoseWorld;
              screenSize = GraphicsHelper.GetScreenSize(cameraNode, viewport, geometricObject);
              Assert.IsTrue(Numeric.AreEqual(screenSize.X, 50.0f, 10f));
              Assert.IsTrue(Numeric.AreEqual(screenSize.Y, 50.0f, 10f));

              // Sphere at near plane.
              geometricObject.Pose = cameraNode.PoseWorld * new Pose(new Vector3F(0.123f, -0.543f, -1));
              screenSize = GraphicsHelper.GetScreenSize(cameraNode, viewport, geometricObject);
              Assert.IsTrue(Numeric.AreEqual(screenSize.X, 50.0f, 10f));
              Assert.IsTrue(Numeric.AreEqual(screenSize.Y, 50.0f, 10f));

              // Double distance --> same size
              geometricObject.Pose = cameraNode.PoseWorld * new Pose(new Vector3F(0.123f, -0.543f, -2));
              screenSize = GraphicsHelper.GetScreenSize(cameraNode, viewport, geometricObject);
              Assert.IsTrue(Numeric.AreEqual(screenSize.X, 50.0f, 10f));
              Assert.IsTrue(Numeric.AreEqual(screenSize.Y, 50.0f, 10f));
        }
Beispiel #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));
              }
        }
Beispiel #10
0
    public ContinuousCollisionDetectionSample(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 thin wall.
      RigidBody body = new RigidBody(new BoxShape(10, 10, 0.1f))
      {
        MotionType = MotionType.Static,
        Pose = new Pose(new Vector3F(0, 5, -5))
      };
      Simulation.RigidBodies.Add(body);

      // ----- Add two fast bodies that move to the wall.
      // The first object does not use CCD. (Per default, RigidBody.CcdEnabled is false.)
      // The second object uses CCD.
      SphereShape bulletShape = new SphereShape(0.2f);
      body = new RigidBody(bulletShape)
      {
        Pose = new Pose(new Vector3F(-2, 5, 5.5f)),
        LinearVelocity = new Vector3F(0, 0, -100),
      };
      Simulation.RigidBodies.Add(body);

      body = new RigidBody(bulletShape)
      {
        Pose = new Pose(new Vector3F(2, 5, 5.5f)),
        LinearVelocity = new Vector3F(0, 0, -100),

        // Enable CCD for this body.
        CcdEnabled = true,
      };
      Simulation.RigidBodies.Add(body);

      // Note:
      // Global CCD settings can be changed in Simulation.Settings.Motion.
      // CCD can be globally enabled or disabled. 
      // Per default, Simulation.Settings.Motion.CcdEnabled is true. But RigidBody.CcdEnabled
      // is false. RigidBody.CcdEnabled should be set for critical game objects.
    }
Beispiel #11
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);
      }
    }
Beispiel #12
0
        //--------------------------------------------------------------
        /// <summary>
        /// Initializes a new instance of the <see cref="LensFlare" /> class.
        /// </summary>
        /// <param name="isDirectionalLight">
        /// If set to <see langword="true"/>, the lens flare is caused by a a directional light.
        /// (See <see cref="IsDirectional"/> for more info.)
        /// </param>
        public LensFlare(bool isDirectionalLight)
        {
            Elements = new LensFlareElementCollection();
              IsDirectional = isDirectionalLight;
              if (isDirectionalLight)
              {
            _querySize = 0.1f;
            Shape = Shape.Infinite;
              }
              else
              {
            _querySize = 0.5f;
            Shape = new SphereShape(0.5f / 2);
              }

              _intensity = 1;
              _size = 0.2f;
        }
Beispiel #13
0
    // OnLoad() is called when the GameObject is added to the IGameObjectService.
    protected override void OnLoad()
    {
      // Prepare n balls.
      const int n = 10;
      _balls = new RigidBody[n];
      var sphereShape = new SphereShape(0.25f);
      for (int i = 0; i < _balls.Length; i++)
      {
        _balls[i] = new RigidBody(sphereShape)  // Note: All rigid bodies share the same shape.
        {
          // Assign a name. (Just for debugging.)
          Name = "Ball" + i,

          // The balls are shot with a high velocity. We need to enable "Continuous Collision 
          // Detection" - otherwise, we could miss some collision.
          CcdEnabled = true,
        };
      }
    }
Beispiel #14
0
    public CustomGravitySample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      // Add basic force effects.
      Simulation.ForceEffects.Add(new CustomGravity());
      Simulation.ForceEffects.Add(new Damping());

      // Add a static sphere that represents the planet.
      RigidBody planet = new RigidBody(new SphereShape(5))
      {
        MotionType = MotionType.Static,
      };
      Simulation.RigidBodies.Add(planet);

      // ----- Add a few cylinder and sphere bodies at random positions above the planet.
      Shape cylinderShape = new CylinderShape(0.3f, 1);
      for (int i = 0; i < 10; i++)
      {
        // A random position 10 m above the planet center.
        Vector3F randomPosition = RandomHelper.Random.NextVector3F(-1, 1);
        randomPosition.Length = 10;

        RigidBody body = new RigidBody(cylinderShape)
        {
          Pose = new Pose(randomPosition),
        };
        Simulation.RigidBodies.Add(body);
      }

      Shape sphereShape = new SphereShape(0.5f);
      for (int i = 0; i < 10; i++)
      {
        Vector3F randomPosition = RandomHelper.Random.NextVector3F(-1, 1);
        randomPosition.Length = 10;

        RigidBody body = new RigidBody(sphereShape)
        {
          Pose = new Pose(randomPosition),
        };
        Simulation.RigidBodies.Add(body);
      }
    }
Beispiel #15
0
        public override void Initialize()
        {
            // Prepare 10 balls.
              _balls = new RigidBody[10];
              Shape sphereShape = new SphereShape(0.2f);
              for (int i = 0; i < _balls.Length; i++)
              {
            _balls[i] = new RigidBody(sphereShape)      // Note: All rigid bodies share the same shape.
            {
              // Assign a name. (Just for debugging.)
              Name = "Ball" + i,

              // The balls are shot with a high velocity. We need to enable "Continuous Collision
              // Detection" - otherwise, we could miss some collision.
              CcdEnabled = true,
            };
              }

              base.Initialize();
        }
Beispiel #16
0
        public void WeldVertices()
        {
            TriangleMesh mesh = new TriangleMesh();
              Assert.AreEqual(0, mesh.WeldVertices());

              mesh.Add(new Triangle(new Vector3F(1, 2, 3), new Vector3F(3, 4, 5), new Vector3F(1.00001f, 2.00001f, 3f)), false);

              Assert.AreEqual(3, mesh.Vertices.Count);

              Assert.Throws(typeof(ArgumentOutOfRangeException), () => mesh.WeldVertices(-0.1f));

              Assert.AreEqual(1, mesh.WeldVertices(0.0001f));
              Assert.AreEqual(2, mesh.Vertices.Count);

              var w = Stopwatch.StartNew();
              mesh = new SphereShape(0.5f).GetMesh(0.001f, 7);
              w.Stop();
              //Assert.AreEqual(0, w.Elapsed.TotalMilliseconds);

              for (int i = 0; i < mesh.Vertices.Count; i++)
              {
            for (int j = i + 1; j < mesh.Vertices.Count; j++)
            {
              Assert.IsFalse(Vector3F.AreNumericallyEqual(mesh.Vertices[i], mesh.Vertices[j]));
            }
              }

              // Second time does nothing.
              Assert.AreEqual(0, mesh.WeldVertices());
        }
Beispiel #17
0
        public void ReverseWindingOrder()
        {
            SphereShape sphere = new SphereShape(1);
              var mesh = sphere.GetMesh(0.1f, 3);

              var clone = mesh.Clone();
              clone.ReverseWindingOrder();

              // Test if all normal are inverted.
              for (int i = 0; i < mesh.NumberOfTriangles; i++)
              {
            var n0 = mesh.GetTriangle(i).Normal;
            var n1 = clone.GetTriangle(i).Normal;
            Assert.IsTrue(Vector3F.AreNumericallyEqual(n0, -n1));
              }
        }
Beispiel #18
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);
      }
    }
Beispiel #19
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) });
      }
    }
Beispiel #20
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);
      }
    }
Beispiel #21
0
        public void SphereMass()
        {
            var s = new SphereShape(2);
              float m0;
              Vector3F com0;
              Matrix33F i0;
              MassHelper.GetMass(s, new Vector3F(1, -2, -3), 1, true, 0.001f, 10, out m0, out com0, out i0);

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

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

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

              // Try with target mass.
              float m3;
              Vector3F com3;
              Matrix33F i3;
              MassHelper.GetMass(s, 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)));
        }
Beispiel #22
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);
      }
    }
Beispiel #23
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);
      }
    }
        protected override void LoadContent()
        {
            _avatarDescription = AvatarDescription.CreateRandom();
              _avatarRenderer = new AvatarRenderer(_avatarDescription);

              // Use the "Wave" animation preset.
              var avatarAnimation = new AvatarAnimation(AvatarAnimationPreset.Wave);
              _expressionAnimation = new AnimationClip<AvatarExpression>(new WrappedExpressionAnimation(avatarAnimation))
              {
            LoopBehavior = LoopBehavior.Cycle,
            Duration = TimeSpan.MaxValue,
              };
              _skeletonAnimation = new AnimationClip<SkeletonPose>(new WrappedSkeletonAnimation(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) });
              }

              base.LoadContent();
        }
Beispiel #25
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);
      }
    }
Beispiel #26
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;
      }
    }
Beispiel #27
0
    public BuoyancySample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      // Add basic force effects.
      Simulation.ForceEffects.Add(new Gravity());
      Simulation.ForceEffects.Add(new Damping());

      // ----- Buoyancy Force Effect
      // Buoyancy is a force effect that lets bodies swim in water. The water area is 
      // defined by two properties: 
      //  - Buoyancy.AreaOfEffect defines which objects are affected.
      //  - Buoyancy.Surface defines the water level within this area.

      // The area of effect can be defined in different ways. In this sample we will use 
      // a geometric object ("trigger volume").

      // First, define the shape of the water area. We will create simple pool.
      Shape poolShape = new BoxShape(16, 10, 16);
      Vector3F poolCenter = new Vector3F(0, -5, 0);

      // Then create a geometric object for the water area. (A GeometricObject is required
      // to position the shape in the world. A GeometricObject stores shape, scale, position,
      // orientation, ...)
      GeometricObject waterGeometry = new GeometricObject(poolShape, new Pose(poolCenter));

      // Then create a collision object for the geometric object. (A CollisionObject required
      // because the geometry should be used for collision detection with other objects.)
      _waterCollisionObject = new CollisionObject(waterGeometry)
      {
        // Assign the object to a different collision group:
        // The Grab component (see Grab.cs) uses a ray to perform hit tests. We don't want the ray
        // to collide with the water. Therefore, we need to assign the water collision object to a 
        // different collision group. The general geometry is in collision group 0. The rays are in 
        // collision group 2. Add the water to collision group 1. Collision between 0 and 2 are 
        // enabled. Collision between 1 and 2 need to be disabled - this collision filter was set 
        // in PhysicsGame.cs.
        CollisionGroup = 1,

        // Set the type to "Trigger". This improves the performance because the collision 
        // detection does not need to compute detailed contact information. The collision
        // detection only returns whether an objects has contact with the water.
        Type = CollisionObjectType.Trigger,
      };

      // The collision object needs to be added into the collision domain of the simulation.
      Simulation.CollisionDomain.CollisionObjects.Add(_waterCollisionObject);

      // Now we can add the buoyancy effect.
      Buoyancy buoyancy = new Buoyancy
      {
        AreaOfEffect = new GeometricAreaOfEffect(_waterCollisionObject),
        Surface = new Plane(Vector3F.Up, 0),

        Density = 1000f,    // The density of water (1000 kg/m³).
        AngularDrag = 0.4f,
        LinearDrag = 4f,

        // Optional: Let the objects drift in the water by setting a flow velocity. 
        //Velocity = new Vector3F(-0.5f, 0, 0.5f),
      };
      Simulation.ForceEffects.Add(buoyancy);


      // Add static area around the pool.
      RigidBody bottom = new RigidBody(new BoxShape(36, 2, 36))
      {
        MotionType = MotionType.Static,
        Pose = new Pose(new Vector3F(0, -11, 0)),
      };
      Simulation.RigidBodies.Add(bottom);
      RigidBody left = new RigidBody(new BoxShape(10, 10, 36))
      {
        MotionType = MotionType.Static,
        Pose = new Pose(new Vector3F(-13, -5, 0)),
      };
      Simulation.RigidBodies.Add(left);
      RigidBody right = new RigidBody(new BoxShape(10, 10, 36))
      {
        MotionType = MotionType.Static,
        Pose = new Pose(new Vector3F(13, -5, 0)),
      };
      Simulation.RigidBodies.Add(right);
      RigidBody front = new RigidBody(new BoxShape(16, 10, 10))
      {
        MotionType = MotionType.Static,
        Pose = new Pose(new Vector3F(0, -5, 13)),
      };
      Simulation.RigidBodies.Add(front);
      RigidBody back = new RigidBody(new BoxShape(16, 10, 10))
      {
        MotionType = MotionType.Static,
        Pose = new Pose(new Vector3F(0, -5, -13)),
      };
      Simulation.RigidBodies.Add(back);

      // ----- Add some random objects to test the effect.
      // Note: Objects swim if their density is less than the density of water. They sink
      // if the density is greater than the density of water.
      // We can define the density of objects by explicitly setting the mass.

      // Add a swimming board.
      BoxShape raftShape = new BoxShape(4, 0.3f, 4);
      MassFrame raftMass = MassFrame.FromShapeAndDensity(raftShape, Vector3F.One, 700, 0.01f, 3);
      RigidBody raft = new RigidBody(raftShape, raftMass, null)
      {
        Pose = new Pose(new Vector3F(0, 4, 0)),
      };
      Simulation.RigidBodies.Add(raft);

      // Add some boxes on top of the swimming board.
      BoxShape boxShape = new BoxShape(1, 1, 1);
      MassFrame boxMass = MassFrame.FromShapeAndDensity(boxShape, Vector3F.One, 700, 0.01f, 3);
      for (int i = 0; i < 5; i++)
      {
        RigidBody box = new RigidBody(boxShape, boxMass, null)
        {
          Pose = new Pose(new Vector3F(0, 5 + i * 1.1f, 0)),
        };
        Simulation.RigidBodies.Add(box);
      }

      // Add some "heavy stones" represented as spheres.
      SphereShape stoneShape = new SphereShape(0.5f);
      MassFrame stoneMass = MassFrame.FromShapeAndDensity(stoneShape, Vector3F.One, 2500, 0.01f, 3);
      for (int i = 0; i < 10; i++)
      {
        Vector3F position = RandomHelper.Random.NextVector3F(-9, 9);
        position.Y = 5;

        RigidBody stone = new RigidBody(stoneShape, stoneMass, null)
        {
          Pose = new Pose(position),
        };
        Simulation.RigidBodies.Add(stone);
      }

      // Add some very light objects.
      CylinderShape cylinderShape = new CylinderShape(0.3f, 1);
      MassFrame cylinderMass = MassFrame.FromShapeAndDensity(cylinderShape, Vector3F.One, 500, 0.01f, 3);
      for (int i = 0; i < 10; i++)
      {
        Vector3F position = RandomHelper.Random.NextVector3F(-9, 9);
        position.Y = 5;
        QuaternionF orientation = RandomHelper.Random.NextQuaternionF();

        RigidBody cylinder = new RigidBody(cylinderShape, cylinderMass, null)
        {
          Pose = new Pose(position, orientation),
        };
        Simulation.RigidBodies.Add(cylinder);
      }
    }
Beispiel #28
0
    //--------------------------------------------------------------
    #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 #29
0
    public RollingSphereSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      // To demonstrate the problems with triangle meshes we increase the gravity and let a
      // sphere roll over a curved surface.

      // Add basic force effects.
      Simulation.ForceEffects.Add(new Gravity { Acceleration = new Vector3F(0, -30, 0) });   // Higher gravity to make the problem more visible.
      Simulation.ForceEffects.Add(new Damping());

      // Use the custom contact filter to improve sphere contacts.
      _sphereContactFilter = new SphereContactFilter();
      Simulation.CollisionDomain.CollisionDetection.ContactFilter = _sphereContactFilter;

      // The triangle mesh could be loaded from a file, such as an XNA Model.
      // In this example will create a height field and convert the height field into a triangle mesh.
      var numberOfSamplesX = 60;
      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.Sin(x / 6f) * 10f + 5f);

      var heightField = new HeightField(0, 0, 70, 30, samples, numberOfSamplesX, numberOfSamplesZ);

      // Convert the height field to a triangle mesh.
      ITriangleMesh mesh = heightField.GetMesh(0.01f, 3);

      // Create a shape for the triangle mesh.
      _triangleMeshShape = new TriangleMeshShape(mesh);

      // Enable contact welding. And set the welding limit to 1 for maximal effect.
      _triangleMeshShape.EnableContactWelding = true;
      _originalWeldingLimit = TriangleMeshAlgorithm.WeldingLimit;
      TriangleMeshAlgorithm.WeldingLimit = 1;

      // 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 CompressedAabbTree() { BottomUpBuildThreshold = 0 };

      // Create a static rigid body using the shape and add it to the simulation.
      // 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).
      var ground = new RigidBody(_triangleMeshShape, new MassFrame(), null)
      {
        Pose = new Pose(new Vector3F(-34, 0, -40f)),
        MotionType = MotionType.Static,
      };
      Simulation.RigidBodies.Add(ground);

      SphereShape sphereShape = new SphereShape(0.5f);
      _sphere = new RigidBody(sphereShape);
      Simulation.RigidBodies.Add(_sphere);

      _enableSmoothMovement = true;
      _timeUntilReset = TimeSpan.Zero;
    }
Beispiel #30
0
        private static void GetMass(SphereShape sphere, Vector3F scale, float densityOrMass, bool isDensity, out float mass, out Matrix33F inertia)
        {
            scale = Vector3F.Absolute(scale);
              Vector3F radius = sphere.Radius * scale;
              Vector3F radiusSquared = radius * radius;

              mass = (isDensity) ? 4.0f / 3.0f * ConstantsF.Pi * radius.X * radius.Y * radius.Z * densityOrMass : densityOrMass;

              inertia = Matrix33F.Zero;
              inertia.M00 = 1.0f / 5.0f * mass * (radiusSquared.Y + radiusSquared.Z);
              inertia.M11 = 1.0f / 5.0f * mass * (radiusSquared.X + radiusSquared.Z);
              inertia.M22 = 1.0f / 5.0f * mass * (radiusSquared.X + radiusSquared.Y);
        }