//-------------------------------------------------------------- /// <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; }
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); }
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; } }
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); }
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); }
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); }
//-------------------------------------------------------------- #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)); }
/// <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)); } }
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. }
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); } }
//-------------------------------------------------------------- /// <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; }
// 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, }; } }
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); } }
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(); }
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()); }
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)); } }
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); } }
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) }); } }
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); } }
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))); }
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); } }
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(); }
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); } }
// 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 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); } }
//-------------------------------------------------------------- #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 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; }
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); }