public void ComputeCollision() { CollisionObject a = new CollisionObject(); CompositeShape compo = new CompositeShape(); compo.Children.Add(new GeometricObject(new SphereShape(2), Pose.Identity)); compo.Children.Add(new GeometricObject(new SphereShape(1), new Pose(new Vector3F(0, 3, 0)))); a.GeometricObject = new GeometricObject(compo, Pose.Identity); CollisionObject b = new CollisionObject(new GeometricObject { Shape = new PlaneShape(new Vector3F(0, 1, 0), 1), Pose = new Pose(new Vector3F(0, -1, 0)), }); ContactSet set; CompositeShapeAlgorithm algo = new CompositeShapeAlgorithm(new CollisionDetection()); set = algo.GetClosestPoints(a, b); Assert.AreEqual(true, algo.HaveContact(a, b)); Assert.AreEqual(true, algo.HaveContact(b, a)); Assert.AreEqual(1, set.Count); Assert.AreEqual(2, set[0].PenetrationDepth); Assert.AreEqual(new Vector3F(0, -2, 0), set[0].PositionAWorld); ((GeometricObject)a.GeometricObject).Pose = new Pose(new Vector3F(0, 2, 3), a.GeometricObject.Pose.Orientation); set = set.Swapped; algo.UpdateContacts(set, 0); Assert.AreEqual(true, algo.HaveContact(a, b)); Assert.AreEqual(true, algo.HaveContact(b, a)); Assert.AreEqual(1, set.Count); Assert.AreEqual(0, set[0].PenetrationDepth); Assert.AreEqual(new Vector3F(0, 0, 3), set[0].PositionBWorld); ((GeometricObject)a.GeometricObject).Pose = new Pose(new Vector3F(0, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); set = set.Swapped; // new order: (a, b) algo.UpdateContacts(set, 0); Assert.AreEqual(true, algo.HaveContact(a, b)); Assert.AreEqual(2, set.Count); Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(-2, 0, 0), set[0].PositionALocal)); Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(-1, 3, 0), set[1].PositionALocal)); Assert.AreEqual(new Vector3F(0, -1, 0), set[0].Normal); Assert.AreEqual(new Vector3F(0, -1, 0), set[1].Normal); Assert.AreEqual(2, set[0].PenetrationDepth); Assert.IsTrue(Numeric.AreEqual(1, set[1].PenetrationDepth)); algo.UpdateClosestPoints(set, 0); Assert.AreEqual(1, set.Count); ((GeometricObject)a.GeometricObject).Pose = new Pose(new Vector3F(0, 2.1f, 0), a.GeometricObject.Pose.Orientation); algo.UpdateContacts(set, 0); Assert.AreEqual(false, algo.HaveContact(a, b)); Assert.AreEqual(0, set.Count); algo.UpdateClosestPoints(set, 0); Assert.AreEqual(1, set.Count); Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(-2, 0, 0), set[0].PositionALocal)); Assert.AreEqual(new Vector3F(0, -1, 0), set[0].Normal); }
private CompositeFixture(CompositeShape wrappedCompositeShape, CompositeMaterial wrappedCompositeMaterial, Matrix4x4 realParentPose, FixtureDescriptor descriptor) { _root = false; _realParentPose = realParentPose; _pose = descriptor.Pose; _realPose = GMath.mul( _pose ,_realParentPose); UserData = descriptor.UserData; _wrappedCompositeMaterial = wrappedCompositeMaterial; _wrappedCompositeShape = wrappedCompositeShape; FixtureFactory = new CompositeFixtureFixtureFactory(this); }
public CompositeFixture(DR.RigidBody wrappedRigidBody, FixtureDescriptor descriptor) { _root = true; _pose = descriptor.Pose; _realPose = _pose; _wrappedCompositeMaterial = new CompositeMaterial(); wrappedRigidBody.Material = _wrappedCompositeMaterial; _wrappedCompositeShape = new CompositeShape(); wrappedRigidBody.Shape = _wrappedCompositeShape; UserData = descriptor.UserData; FixtureFactory = new CompositeFixtureFixtureFactory(this); }
public CompositeMaterial2Sample(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(new Vector3F(0, 1, 0.25f).Normalized, 0)) { Name = "GroundPlane", // Names are not required but helpful for debugging. MotionType = MotionType.Static, }; // Adjust the coefficients of friction of the ground plane. ((UniformMaterial)groundPlane.Material).DynamicFriction = 0.5f; ((UniformMaterial)groundPlane.Material).StaticFriction = 0.5f; Simulation.RigidBodies.Add(groundPlane); // Prepare two materials: a slippery material and a rough material. UniformMaterial slipperyMaterial = new UniformMaterial { DynamicFriction = 0.001f, StaticFriction = 0.001f, }; UniformMaterial roughMaterial = new UniformMaterial { DynamicFriction = 1, StaticFriction = 1, }; // Create a rigid body that consists of multiple shapes: Two boxes and a cylinder between them. CompositeShape compositeShape = new CompositeShape(); compositeShape.Children.Add(new GeometricObject(new BoxShape(1f, 1f, 1f), new Pose(new Vector3F(1.5f, 0f, 0f)))); compositeShape.Children.Add(new GeometricObject(new BoxShape(1f, 1, 1f), new Pose(new Vector3F(-1.5f, 0f, 0f)))); compositeShape.Children.Add(new GeometricObject(new CylinderShape(0.1f, 2), new Pose(Matrix33F.CreateRotationZ(ConstantsF.PiOver2)))); // A CompositeMaterial is used to assign a different material to each shape. CompositeMaterial compositeMaterial = new CompositeMaterial(); compositeMaterial.Materials.Add(roughMaterial); // Assign the rough material to the first box. compositeMaterial.Materials.Add(slipperyMaterial); // Assign the slippery material to the second box. compositeMaterial.Materials.Add(null); // Use whatever is default for the handle between the boxes. RigidBody body = new RigidBody(compositeShape, null, compositeMaterial) { Pose = new Pose(new Vector3F(0, 2.2f, -5)), }; Simulation.RigidBodies.Add(body); }
public ContinuousCollisionDetectionSample(Microsoft.Xna.Framework.Game game) : base(game) { GraphicsScreen.ClearBackground = true; SetCamera(new Vector3F(0, 1, 10), 0, 0); // ----- Initialize collision detection and create objects. // Create a geometric object with a capsule shape. // Position it on the top with an arbitrary rotation. _startPoseA = new Pose(new Vector3F(0, 2, 0), Matrix33F.CreateRotationZ(0.1f)); var geometricObjectA = new GeometricObject(new CapsuleShape(0.2f, 1), _startPoseA); _collisionObjectA = new CollisionObject(geometricObjectA); // Object A moves to the bottom of the screen. _targetPoseA = new Pose(new Vector3F(0, -2, 0), Matrix33F.CreateRotationZ(0.63f)); // Create a geometric object with a composite shape. // Position it on the left with an arbitrary rotation. _startPoseB = new Pose(new Vector3F(-3, -1, 0), Matrix33F.CreateRotationZ(0.2f)); var composite = new CompositeShape(); composite.Children.Add(new GeometricObject(new BoxShape(0.1f, 1, 0.1f), new Pose(new Vector3F(-0.75f, 0.5f, -0.5f)))); composite.Children.Add(new GeometricObject(new BoxShape(0.1f, 1, 0.1f), new Pose(new Vector3F(0.75f, 0.5f, -0.5f)))); composite.Children.Add(new GeometricObject(new BoxShape(0.1f, 1, 0.1f), new Pose(new Vector3F(-0.75f, 0.5f, 0.5f)))); composite.Children.Add(new GeometricObject(new BoxShape(0.1f, 1, 0.1f), new Pose(new Vector3F(0.75f, 0.5f, 0.5f)))); composite.Children.Add(new GeometricObject(new BoxShape(1.8f, 0.1f, 1.1f), new Pose(new Vector3F(0, 1f, 0)))); var geometricObjectB = new GeometricObject(composite, _startPoseB); // Object B moves to the left of the screen. _targetPoseB = new Pose(new Vector3F(3, -1, 0), Matrix33F.CreateRotationZ(0.3f)); // Create collision objects for the geometric objects. // (A collision object is just a wrapper around the geometric object that stores additional // information that is required by the collision detection.) _collisionObjectA = new CollisionObject(geometricObjectA); _collisionObjectB = new CollisionObject(geometricObjectB); // Create a collision detection. // (The CollisionDetection stores general parameters and it can be used to perform // closest-point and contact queries.) _collisionDetection = new CollisionDetection(); }
public void CompositeShapeTest() { var c = new CompositeShape(); Assert.AreEqual(0, c.GetVolume(0.1f, 10)); c.Children.Add( new GeometricObject( new BoxShape(1, 2, 3), new Vector3F(10, 10, 10), new Pose(new Vector3F(1, 2, 3), RandomHelper.Random.NextQuaternionF()))); c.Children.Add( new GeometricObject( new BoxShape(4, 5, 6), new Vector3F(2, 2, 2), new Pose(new Vector3F(10, -2, 0), RandomHelper.Random.NextQuaternionF()))); var v0 = c.GetVolume(0.001f, 10); Assert.AreEqual(10 * 20 * 30 + 8 * 10 * 12, v0); }
CompositeShape(CompositeShapeDescriptor descriptor) { WrappedCompositeShape = new DR.Geometry.Shapes.CompositeShape(); UserData = descriptor.UserData; ShapePositionerFactory = new CompositeShapeShapePositionerFactory(this); }
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); }
// 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; } }
public void CompositeShapeWithRotatedChildren() { var s = new CompositeShape(); s.Children.Add(new GeometricObject(new BoxShape(1, 2, 3), new Vector3F(1.1f, 0.3f, 0.8f), new Pose(new Vector3F(100, 10, 0), RandomHelper.Random.NextQuaternionF()))); s.Children.Add(new GeometricObject(new ConeShape(1, 2), new Vector3F(1.1f, 0.3f, 0.8f), new Pose(new Vector3F(-10, -10, 0), RandomHelper.Random.NextQuaternionF()))); float m0; Vector3F com0; Matrix33F i0; MassHelper.GetMass(s, new Vector3F(2), 1, true, 0.001f, 10, out m0, out com0, out i0); var m = s.GetMesh(0.001f, 6); m.Transform(Matrix44F.CreateScale(2)); float m1; Vector3F com1; Matrix33F i1; MassHelper.GetMass(m, out m1, out com1, out i1); const float e = 0.01f; Assert.IsTrue(Numeric.AreEqual(m0, m1, e * (1 + m0))); Assert.IsTrue(Vector3F.AreNumericallyEqual(com0, com1, e * (1 + com0.Length))); Assert.IsTrue(Matrix33F.AreNumericallyEqual(i0, i1, e * (1 + i0.Trace))); }
/// <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); }
public void CompositeShapeWithRigidBodies() { // The first composite shape does not use rigid bodies. var s = new CompositeShape(); s.Children.Add(new GeometricObject(new BoxShape(1, 2, 3), new Vector3F(1.1f, 0.3f, 0.8f), new Pose(new Vector3F(100, 10, 0), RandomHelper.Random.NextQuaternionF()))); s.Children.Add(new GeometricObject(new ConeShape(1, 2), new Vector3F(1.1f, 0.3f, 0.8f), new Pose(new Vector3F(-10, -10, 0), RandomHelper.Random.NextQuaternionF()))); float m0; Vector3F com0; Matrix33F i0; MassHelper.GetMass(s, new Vector3F(1), 0.7f, true, 0.001f, 10, out m0, out com0, out i0); // The second composite shape uses rigid bodies as children. var r0 = new RigidBody(s.Children[0].Shape); r0.Pose = s.Children[0].Pose; r0.Scale = s.Children[0].Scale; r0.MassFrame = MassFrame.FromShapeAndDensity(r0.Shape, r0.Scale, 0.7f, 0.001f, 10); var r1 = new RigidBody(s.Children[1].Shape); r1.Pose = s.Children[1].Pose; r1.Scale = s.Children[1].Scale; r1.MassFrame = MassFrame.FromShapeAndDensity(r1.Shape, r1.Scale, 0.7f, 0.001f, 10); var s1 = new CompositeShape(); s1.Children.Add(r0); s1.Children.Add(r1); float m1; Vector3F com1; Matrix33F i1; MassHelper.GetMass(s1, new Vector3F(1), 100, true, 0.001f, 10, 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))); }
public void CompositeShapeWithRigidBodiesDoesNotSupportScaling() { // The first composite shape does not use rigid bodies. var s = new CompositeShape(); s.Children.Add(new GeometricObject(new BoxShape(1, 2, 3), new Vector3F(1.1f, 0.3f, 0.8f), new Pose(new Vector3F(100, 10, 0), RandomHelper.Random.NextQuaternionF()))); s.Children.Add(new GeometricObject(new ConeShape(1, 2), new Vector3F(1.1f, 0.3f, 0.8f), new Pose(new Vector3F(-10, -10, 0), RandomHelper.Random.NextQuaternionF()))); // The second composite shape uses rigid bodies as children. var r0 = new RigidBody(s.Children[0].Shape); r0.Pose = s.Children[0].Pose; r0.Scale = s.Children[0].Scale; r0.MassFrame = MassFrame.FromShapeAndDensity(r0.Shape, r0.Scale, 0.7f, 0.001f, 10); var r1 = new RigidBody(s.Children[1].Shape); r1.Pose = s.Children[1].Pose; r1.Scale = s.Children[1].Scale; r1.MassFrame = MassFrame.FromShapeAndDensity(r1.Shape, r1.Scale, 0.7f, 0.001f, 10); var s1 = new CompositeShape(); s1.Children.Add(r0); s1.Children.Add(r1); float m1; Vector3F com1; Matrix33F i1; MassHelper.GetMass(s1, new Vector3F(2), // !!! 100, true, 0.001f, 10, out m1, out com1, out i1); }
//-------------------------------------------------------------- #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); } }
public void CompositeShapeWithNonUniformScaling() { var s = new CompositeShape(); s.Children.Add(new GeometricObject(new BoxShape(1, 2, 3), new Vector3F(1.1f, 0.3f, 0.8f), new Pose(new Vector3F(100, 10, 0)))); s.Children.Add(new GeometricObject(new SphereShape(1), new Vector3F(1.1f, 0.3f, 0.8f), new Pose(new Vector3F(-10, -10, 0)))); float m0; Vector3F com0; Matrix33F i0; MassHelper.GetMass(s, new Vector3F(2, 2.1f, 2.8f), 0.7f, true, 0.001f, 10, out m0, out com0, out i0); var m = s.GetMesh(0.001f, 6); m.Transform(Matrix44F.CreateScale(2, 2.1f, 2.8f)); float m1; Vector3F com1; Matrix33F i1; MassHelper.GetMass(m, out m1, out com1, out i1); const float e = 0.01f; Assert.IsTrue(Numeric.AreEqual(m0, 0.7f * m1, e * (1 + m0))); Assert.IsTrue(Vector3F.AreNumericallyEqual(com0, com1, e * (1 + com0.Length))); Assert.IsTrue(Matrix33F.AreNumericallyEqual(i0, 0.7f * i1, e * (1 + i0.Trace))); // Try with target mass. float m3; Vector3F com3; Matrix33F i3; MassHelper.GetMass(s, new Vector3F(2, 2.1f, 2.8f), 23, false, 0.001f, 10, out m3, out com3, out i3); Assert.IsTrue(Numeric.AreEqual(23, m3, e * (1 + m0))); Assert.IsTrue(Vector3F.AreNumericallyEqual(com0, com3, e * (1 + com0.Length))); Assert.IsTrue(Matrix33F.AreNumericallyEqual(i0 * 23 / m0, i3, e * (1 + i0.Trace))); }
public LightClipSample(Microsoft.Xna.Framework.Game game) : base(game) { SampleFramework.IsMouseVisible = false; _graphicsScreen = new DeferredGraphicsScreen(Services); _graphicsScreen.DrawReticle = true; GraphicsService.Screens.Insert(0, _graphicsScreen); GameObjectService.Objects.Add(new DeferredGraphicsOptionsObject(Services)); Services.Register(typeof(DebugRenderer), null, _graphicsScreen.DebugRenderer); Services.Register(typeof(IScene), null, _graphicsScreen.Scene); // Add gravity and damping to the physics simulation. Simulation.ForceEffects.Add(new Gravity()); Simulation.ForceEffects.Add(new Damping()); // Add a custom game object which controls the camera. var cameraGameObject = new CameraObject(Services); GameObjectService.Objects.Add(cameraGameObject); _graphicsScreen.ActiveCameraNode = cameraGameObject.CameraNode; GameObjectService.Objects.Add(new GrabObject(Services)); GameObjectService.Objects.Add(new DynamicSkyObject(Services, true, false, true)); GameObjectService.Objects.Add(new GroundObject(Services)); GameObjectService.Objects.Add(new DudeObject(Services)); GameObjectService.Objects.Add(new DynamicObject(Services, 1)); GameObjectService.Objects.Add(new DynamicObject(Services, 2)); GameObjectService.Objects.Add(new DynamicObject(Services, 3)); GameObjectService.Objects.Add(new DynamicObject(Services, 4)); GameObjectService.Objects.Add(new DynamicObject(Services, 6)); GameObjectService.Objects.Add(new DynamicObject(Services, 7)); GameObjectService.Objects.Add(new ObjectCreatorObject(Services)); GameObjectService.Objects.Add(new FogObject(Services)); // The LavaBalls class controls all lava ball instances. var lavaBalls = new LavaBallsObject(Services); GameObjectService.Objects.Add(lavaBalls); // Create a lava ball instance. lavaBalls.Spawn(); // Add a few palm trees. Random random = new Random(12345); for (int i = 0; i < 10; i++) { Vector3F position = new Vector3F(random.NextFloat(-3, -8), 0, random.NextFloat(0, -5)); Matrix33F orientation = Matrix33F.CreateRotationY(random.NextFloat(0, ConstantsF.TwoPi)); float scale = random.NextFloat(0.5f, 1.2f); GameObjectService.Objects.Add(new StaticObject(Services, "PalmTree/palm_tree", scale, new Pose(position, orientation))); } var boxShape = new BoxShape(3, 3, 3); var compositeShape = new CompositeShape { Children = { new GeometricObject(boxShape, new Pose(new Vector3F(-2, 1.4f, 0))), new GeometricObject(boxShape, new Pose(new Vector3F(2, 1.4f, 0))), } }; _clip = new GeometricObject(compositeShape, Pose.Identity); foreach (var lightNode in _graphicsScreen.Scene.GetDescendants().OfType<LightNode>()) { lightNode.Clip = _clip; //lightNode.InvertClip = true; } }
public override void Update(GameTime gameTime) { // If progress has changed significantly, get current decomposition. if (_newProgress - _oldProgress >= 10 || _newProgress > 90 && _newProgress - _oldProgress > 1) { _decomposition = _convexDecomposition.Decomposition; _oldProgress = _newProgress; } var debugRenderer = GraphicsScreen.DebugRenderer; debugRenderer.Clear(); // Draw a wireframe of the model. debugRenderer.DrawModel(_modelNode, Color.White, true, false); // Show current progress. debugRenderer.DrawText("\n\nProgress: " + _newProgress + " %"); // Draw the current convex hulls. if (_decomposition != null) { foreach (var childGeometry in _decomposition.Children) debugRenderer.DrawObject(childGeometry, GraphicsHelper.GetUniqueColor(childGeometry), false, false); debugRenderer.DrawText("Number of convex parts: " + _decomposition.Children.Count); } }
// Creates a lot of random objects. private void CreateRandomObjects() { var random = new Random(12345); for (int i = 0; i < NumberOfObjects; i++) { // Randomly choose a shape. Shape randomShape; switch (random.Next(0, 7)) { case 0: // Box randomShape = new BoxShape(ObjectSize, ObjectSize * 2, ObjectSize * 3); break; case 1: // Capsule randomShape = new CapsuleShape(0.3f * ObjectSize, 2 * ObjectSize); break; case 2: // Cone randomShape = new ConeShape(1 * ObjectSize, 2 * ObjectSize); break; case 3: // Cylinder randomShape = new CylinderShape(0.4f * ObjectSize, 2 * ObjectSize); break; case 4: // Sphere randomShape = 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)); randomShape = 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)))); randomShape = composite; break; default: #if WINDOWS Trace.Fail("Ups, we shouldn't land here :-("); #endif randomShape = new SphereShape(); break; } // 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 = randomShape, LinearVelocity = random.NextQuaternionF().Rotate(new Vector3F(MaxLinearVelocity, 0, 0)), AngularVelocity = random.NextQuaternionF().Rotate(Vector3F.Forward) * RandomHelper.Random.NextFloat(0, MaxAngularVelocity), }; // Add collision object to collision domain. _domain.CollisionObjects.Add(new CollisionObject(newObject)); // We will collect a few statistics for debugging. Profiler.SetFormat("NumObjects", 1, "The total number of objects."); Profiler.SetFormat("NumObjectPairs", 1, "The number of objects pairs, which have to be checked."); Profiler.SetFormat("BroadPhasePairs", 1, "The number of overlaps reported by the broad phase."); Profiler.SetFormat("ContactSetCount", 1, "The number of actual collisions."); } }
private void CreateCompositeShape() { // Convert islands into CompositeShape with convex children. _decomposition = new CompositeShape(); if (_islands == null) return; foreach (var island in _islands) { if (island.Vertices.Length <= 0) continue; // ReSharper disable EmptyGeneralCatchClause try { // ----- Get convex hull mesh. DcelMesh convexHullMesh; if (island.ConvexHullBuilder == null) { // Create convex hull from scratch. // Get all vertices of all island triangles. var points = island.Triangles.SelectMany(t => t.Vertices); // Create convex hull. convexHullMesh = GeometryHelper.CreateConvexHull(points, VertexLimit, SkinWidth); } else { // Use existing convex hull. convexHullMesh = island.ConvexHullBuilder.Mesh; if (convexHullMesh.Vertices.Count > VertexLimit || SkinWidth != 0) convexHullMesh.ModifyConvex(VertexLimit, SkinWidth); } // ----- Add a ConvexPolyhedron to CompositeShape. if (convexHullMesh.Vertices.Count > 0) { var convexHullPoints = convexHullMesh.Vertices.Select(v => v.Position); var convexPolyhedron = new ConvexPolyhedron(convexHullPoints); var geometricObject = new GeometricObject(convexPolyhedron); _decomposition.Children.Add(geometricObject); } } catch { // Could not generate convex hull. Ignore object. } // ReSharper restore EmptyGeneralCatchClause } }
private void DoWork() { // The locks are released regularly, so that the Decomposition property can be // accessed. Exception exception = null; try { if ((GlobalSettings.ValidationLevelInternal & GlobalSettings.ValidationLevelUserHighExpensive) != 0) ValidateInput(); lock (_syncRoot) { _decomposition = null; // Create the Dual graph. CreateDualGraph(); } // Partitioning process: MergeIslands(); // Each internal loop is locked. lock (_syncRoot) { if (!_cancel) CreateCompositeShape(); } if (!_cancel) OnProgressChanged(100); } catch (Exception e) { exception = e; if (!IsBusy) // Throw only when in synchronous decomposition. throw; } finally { _mesh = null; if (IsBusy) // IsBusy is only set for async operations. { IsBusy = false; // Raise completed event. var handler = Completed; if (handler != null) handler(this, new AsyncCompletedEventArgs(exception, _cancel, null)); } } }
private void MergeIslands() { List<CDIslandLink> newLinks = new List<CDIslandLink>(); List<CDIslandLink> obsoleteLinks = (EnableMultithreading) ? new List<CDIslandLink>() : null; while (_links.Count > 0 && !_cancel) { lock (_syncRoot) { // Find link with lowest decimation cost. CDIslandLink bestLink = _links[0]; int bestLinkIndex = 0; for (int i = 0; i < _links.Count; i++) { var link = _links[i]; if (link.DecimationCost < bestLink.DecimationCost) { bestLink = link; bestLinkIndex = i; } } // Remove the found link. _links.RemoveAt(bestLinkIndex); // Ignore links that have exceeded the concavity limit. if (bestLink.Concavity > AllowedConcavity) continue; // The created composite shape is now invalid again. _decomposition = null; // Remove island B _islands.Remove(bestLink.IslandB); // Merge the islands of the best link into island A. foreach (var triangle in bestLink.IslandB.Triangles) triangle.Island = bestLink.IslandA; bestLink.IslandA.Triangles = bestLink.IslandA.Triangles.Union(bestLink.IslandB.Triangles).ToArray(); bestLink.IslandA.Aabb = bestLink.Aabb; bestLink.IslandA.Vertices = bestLink.Vertices; bestLink.IslandA.ConvexHullBuilder = bestLink.ConvexHullBuilder; // Remove old links where A and B are involved and add new // links with A. if (!EnableMultithreading) { for (int i = _links.Count - 1; i >= 0; i--) { var link = _links[i]; CDIsland otherIsland = null; if (link.IslandA == bestLink.IslandA || link.IslandA == bestLink.IslandB) otherIsland = link.IslandB; else if (link.IslandB == bestLink.IslandA || link.IslandB == bestLink.IslandB) otherIsland = link.IslandA; // This link does not link to the merged islands. if (otherIsland == null) continue; // Remove link. _links.RemoveAt(i); // If _newLinks already contains a link with otherIsland we are done. bool linkExists = false; foreach (var newLink in newLinks) { if (newLink.IslandA == otherIsland || newLink.IslandB == otherIsland) { linkExists = true; break; } } if (linkExists) continue; // Create link between otherIsland and bestLink.IslandA. link = new CDIslandLink(otherIsland, bestLink.IslandA, AllowedConcavity, SmallIslandBoost, IntermediateVertexLimit, SampleTriangleVertices, SampleTriangleCenters); newLinks.Add(link); } } else { // Experimental multithreading hack. // Note: When multithreading is enabled the result is non-deterministic // because the order of the links in the _links list change... Parallel.ForEach(_links, link => { CDIsland otherIsland = null; if (link.IslandA == bestLink.IslandA || link.IslandA == bestLink.IslandB) otherIsland = link.IslandB; else if (link.IslandB == bestLink.IslandA || link.IslandB == bestLink.IslandB) otherIsland = link.IslandA; // This link does not link to the merged islands. if (otherIsland == null) return; // Remove link. lock (obsoleteLinks) obsoleteLinks.Add(link); // If _newLinks already contains a link with otherIsland we are done. lock (newLinks) { foreach (var newLink in newLinks) if (newLink.IslandA == otherIsland || newLink.IslandB == otherIsland) return; } // Create link between otherIsland and bestLink.IslandA. link = new CDIslandLink(otherIsland, bestLink.IslandA, AllowedConcavity, SmallIslandBoost, IntermediateVertexLimit, SampleTriangleVertices, SampleTriangleCenters); // Add link but only if another thread did not add a similar link. // TODO: Can this happen or can we remove this check. lock (newLinks) { foreach (var newLink in newLinks) if (newLink.IslandA == otherIsland || newLink.IslandB == otherIsland) return; newLinks.Add(link); } }); foreach (var link in obsoleteLinks) _links.Remove(link); obsoleteLinks.Clear(); } // Add new links. _links.AddRange(newLinks); newLinks.Clear(); OnProgressChanged((_mesh.NumberOfTriangles - _islands.Count) * 100 / _mesh.NumberOfTriangles); } } }
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 OnLoad() { // Add rigid bodies to simulation. var simulation = _services.GetInstance<Simulation>(); // ----- Add a ground plane. AddBody(simulation, "GroundPlane", Pose.Identity, new PlaneShape(Vector3F.UnitY, 0), MotionType.Static); // ----- Create a height field. var numberOfSamplesX = 20; var numberOfSamplesZ = 20; var samples = new float[numberOfSamplesX * numberOfSamplesZ]; for (int z = 0; z < numberOfSamplesZ; z++) { for (int x = 0; x < numberOfSamplesX; x++) { if (x == 0 || z == 0 || x == 19 || z == 19) { samples[z * numberOfSamplesX + x] = -1; } else { samples[z * numberOfSamplesX + x] = 1.0f + (float)(Math.Cos(z / 2f) * Math.Sin(x / 2f) * 1.0f); } } } HeightField heightField = new HeightField(0, 0, 120, 120, samples, numberOfSamplesX, numberOfSamplesZ); //heightField.UseFastCollisionApproximation = true; AddBody(simulation, "HeightField", new Pose(new Vector3F(10, 0, 20)), heightField, MotionType.Static); // ----- Create rubble on the floor (small random objects on the floor). for (int i = 0; i < 60; i++) { Vector3F position = new Vector3F(RandomHelper.Random.NextFloat(-5, 5), 0, RandomHelper.Random.NextFloat(10, 20)); QuaternionF orientation = RandomHelper.Random.NextQuaternionF(); BoxShape shape = new BoxShape(RandomHelper.Random.NextVector3F(0.05f, 0.5f)); AddBody(simulation, "Stone" + i, new Pose(position, orientation), shape, MotionType.Static); } // ----- Slopes with different tilt angles. // Create a loop. Vector3F slopePosition = new Vector3F(-20, -0.25f, -5); BoxShape slopeShape = new BoxShape(8, 0.5f, 2); for (int i = 1; i < 33; i++) { Matrix33F oldRotation = Matrix33F.CreateRotationX((i - 1) * MathHelper.ToRadians(10)); Matrix33F rotation = Matrix33F.CreateRotationX(i * MathHelper.ToRadians(10)); slopePosition += (oldRotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2 + (rotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2; AddBody(simulation, "Loop" + i, new Pose(slopePosition, rotation), slopeShape, MotionType.Static); } // Create an arched bridge. slopePosition = new Vector3F(-10, -2, -15); slopeShape = new BoxShape(8f, 0.5f, 5); for (int i = 1; i < 8; i++) { Matrix33F oldRotation = Matrix33F.CreateRotationX(MathHelper.ToRadians(40) - (i - 1) * MathHelper.ToRadians(10)); Matrix33F rotation = Matrix33F.CreateRotationX(MathHelper.ToRadians(40) - i * MathHelper.ToRadians(10)); slopePosition += (oldRotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2 + (rotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2; Vector3F position = slopePosition - rotation * new Vector3F(0, slopeShape.WidthY / 2, 0); AddBody(simulation, "Bridge" + i, new Pose(position, rotation), slopeShape, MotionType.Static); } // ----- Create a mesh object. // We first build a composite shape out of several primitives and then convert the // composite shape to a triangle mesh. (Just for testing.) CompositeShape compositeShape = new CompositeShape(); compositeShape.Children.Add(new GeometricObject(heightField, Pose.Identity)); compositeShape.Children.Add(new GeometricObject(new CylinderShape(1, 2), new Pose(new Vector3F(10, 1, 10)))); compositeShape.Children.Add(new GeometricObject(new SphereShape(3), new Pose(new Vector3F(15, 0, 15)))); compositeShape.Children.Add(new GeometricObject(new BoxShape(1, 2, 3), new Pose(new Vector3F(15, 0, 5)))); ITriangleMesh mesh = compositeShape.GetMesh(0.01f, 3); TriangleMeshShape meshShape = new TriangleMeshShape(mesh, true); meshShape.Partition = new AabbTree<int>() { BottomUpBuildThreshold = 0 }; AddBody(simulation, "Mesh", new Pose(new Vector3F(-120, 0, 20)), meshShape, MotionType.Static); // ----- Create a seesaw. var seesawBase = AddBody(simulation, "SeesawBase", new Pose(new Vector3F(15, 0.5f, 0)), new BoxShape(0.2f, 1, 6), MotionType.Static); var seesaw = AddBody(simulation, "Seesaw", new Pose(new Vector3F(16, 1.05f, 0)), new BoxShape(15, 0.1f, 6), MotionType.Dynamic); seesaw.MassFrame.Mass = 500; seesaw.CanSleep = false; // Connect seesaw using a hinge joint. simulation.Constraints.Add(new HingeJoint { BodyA = seesaw, BodyB = seesawBase, AnchorPoseALocal = new Pose(new Vector3F(1.0f, 0, 0), new Matrix33F(0, 0, -1, 0, 1, 0, 1, 0, 0)), AnchorPoseBLocal = new Pose(new Vector3F(0, 0.5f, 0), new Matrix33F(0, 0, -1, 0, 1, 0, 1, 0, 0)), CollisionEnabled = false, }); // ----- Distribute a few dynamic spheres and boxes across the landscape. SphereShape sphereShape = new SphereShape(0.5f); for (int i = 0; i < 40; i++) { Vector3F position = RandomHelper.Random.NextVector3F(-60, 60); position.Y = 10; AddBody(simulation, "Sphere" + i, new Pose(position), sphereShape, MotionType.Dynamic); } BoxShape boxShape = new BoxShape(1.0f, 1.0f, 1.0f); for (int i = 0; i < 40; i++) { Vector3F position = RandomHelper.Random.NextVector3F(-60, 60); position.Y = 1; AddBody(simulation, "Box" + i, new Pose(position), boxShape, MotionType.Dynamic); } }