protected override void OnLoad() { var contentManager = _services.GetInstance<ContentManager>(); // ----- Graphics // Load a graphics model and add it to the scene for rendering. _modelNode = contentManager.Load<ModelNode>("Ship/Ship").Clone(); _modelNode.PoseWorld = new Pose(Vector3F.Zero, Matrix33F.CreateRotationY(-ConstantsF.PiOver2)); var scene = _services.GetInstance<IScene>(); scene.Children.Add(_modelNode); // ----- Collision Detection // Create a collision object and add it to the collision domain. // Load collision shape from a separate model (created using the CollisionShapeProcessor). var shape = contentManager.Load<Shape>("Ship/Ship_CollisionModel"); // Create a GeometricObject (= Shape + Pose + Scale). _geometricObject = new GeometricObject(shape, _modelNode.PoseWorld); // Create a collision object and add it to the collision domain. _collisionObject = new CollisionObject(_geometricObject); // Important: We do not need detailed contact information when a collision // is detected. The information of whether we have contact or not is sufficient. // Therefore, we can set the type to "Trigger". This increases the performance // dramatically. _collisionObject.Type = CollisionObjectType.Trigger; // Add the collision object to the collision domain of the game. var collisionDomain = _services.GetInstance<CollisionDomain>(); collisionDomain.CollisionObjects.Add(_collisionObject); }
/// <summary> /// Creates a new <see cref="GeometricObject"/> that is a clone (deep copy) of the current /// instance. /// </summary> /// <returns> /// A new <see cref="GeometricObject"/> that is a clone (deep copy) of the current instance. /// </returns> /// <remarks> /// <strong>Notes to Inheritors:</strong> The method <see cref="Clone"/> calls /// <see cref="CreateInstanceCore"/> which is responsible for creating a new instance of the /// <see cref="GeometricObject"/> derived class and <see cref="CloneCore"/> to create a copy of /// the current instance. Classes that derive from <see cref="GeometricObject"/> need to /// implement <see cref="CreateInstanceCore"/> and <see cref="CloneCore"/>. /// </remarks> public GeometricObject Clone() { GeometricObject clone = CreateInstance(); clone.CloneCore(this); return(clone); }
protected override void OnLoad() { var contentManager = _services.GetInstance<ContentManager>(); // ----- Graphics // Load graphics model (created using the ModelWithCollisionMeshProcessor). 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(Vector3F.Zero, Matrix33F.CreateRotationY(-ConstantsF.PiOver2)); // The collision shape is stored in the UserData. var shape = (Shape)_modelNode.UserData; // Add model to the scene for rendering. var scene = _services.GetInstance<IScene>(); scene.Children.Add(_modelNode); // ----- Collision Detection // Create a collision object and add it to the collision domain. _geometricObject = new GeometricObject(shape, _modelNode.PoseWorld); _collisionObject = new CollisionObject(_geometricObject); // Important: We do not need detailed contact information when a collision // is detected. The information of whether we have contact or not is sufficient. // Therefore, we can set the type to "Trigger". This increases the performance // dramatically. _collisionObject.Type = CollisionObjectType.Trigger; var collisionDomain = _services.GetInstance<CollisionDomain>(); collisionDomain.CollisionObjects.Add(_collisionObject); }
//-------------------------------------------------------------- /// <summary> /// Initializes a new instance of the <see cref="Wheel"/> class. /// </summary> public Wheel() { Radius = 0.4f; SuspensionRestLength = 0.6f; MinSuspensionLength = float.NegativeInfinity; SuspensionLength = SuspensionRestLength; PreviousSuspensionLength = SuspensionRestLength; SuspensionStiffness = 20; SuspensionCompressionDamping = 4f; SuspensionRelaxationDamping = 3f; MaxSuspensionForce = 6000; RollingFrictionForce = 500; Friction = 0.9f; RollReduction = 0.3f; Vector3F rayOrigin = Vector3F.Zero; Vector3F rayDirection = -Vector3F.UnitY; float rayLength = Radius + SuspensionRestLength; Ray = new RayShape(rayOrigin, rayDirection, rayLength) { StopsAtFirstHit = true, }; GeometricObject = new GeometricObject(Ray); CollisionObject = new CollisionObject(GeometricObject); }
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); }
public CollisionDetectionSample(Microsoft.Xna.Framework.Game game) : base(game) { SampleFramework.IsMouseVisible = false; GraphicsScreen.ClearBackground = true; GraphicsScreen.BackgroundColor = Color.CornflowerBlue; SetCamera(new Vector3F(0, 1, 10), 0, 0); // ----- Initialize collision detection and create objects. // Create a geometric object with a box shape. // Position it on the left with an arbitrary rotation. var geometricObjectA = new GeometricObject( new BoxShape(1, 2, 3), new Pose(new Vector3F(-2, -1, 0), Matrix33F.CreateRotationZ(0.1f))); // Create a geometric object with a capsule shape. // Position it on the right with an arbitrary rotation. var geometricObjectB = new GeometricObject( new CapsuleShape(1, 3), new Pose(new Vector3F(2, -1, 0), Matrix33F.CreateRotationZ(-0.2f))); // Create a geometric object with a complex shape that is the convex hull of // a circle and a rectangle. Position it on the top with an arbitrary rotation. // (A ConvexHullOfShapes is a collection of different shapes with different // positions and orientations. The ConvexHullOfShapes combines these shapes // into a single shape by building their convex hull.) var complexShape = new ConvexHullOfShapes(); complexShape.Children.Add(new GeometricObject(new RectangleShape(1, 1), new Pose(new Vector3F(0, 0, 1)))); complexShape.Children.Add(new GeometricObject(new CircleShape(1), new Pose(new Vector3F(0, 0, -1)))); var geometricObjectC = new GeometricObject( complexShape, new Pose(new Vector3F(0, 2, 0), QuaternionF.CreateRotation(Vector3F.UnitZ, new Vector3F(1, 1, 1)))); // 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); _collisionObjectC = new CollisionObject(geometricObjectC); // Create a collision detection. // (The CollisionDetection stores general parameters and it can be used to // perform closest-point and contact queries.) _collisionDetection = new CollisionDetection(); // Create a new collision domain and add the collision objects. // (A CollisionDomain manages multiple collision objects. It improves the // performance of contact queries by reusing results of the last frame.) _domain = new CollisionDomain(_collisionDetection); _domain.CollisionObjects.Add(_collisionObjectA); _domain.CollisionObjects.Add(_collisionObjectB); _domain.CollisionObjects.Add(_collisionObjectC); }
SimpleFixture(DR.RigidBody wrappedRigidBody, FixtureDescriptor descriptor) { _wrappedRigidBody = wrappedRigidBody; _wrappedGeometricObject = new GeometricObject(new EmptyShape(), descriptor.Pose.ToDigitalRune()); _wrappedRigidBody.Shape = new TransformedShape(_wrappedGeometricObject); _wrappedRigidBody.Material = new UniformMaterial(); UserData = descriptor.UserData; _pose = descriptor.Pose; ShapeFactory = new SimpleFixtureShapeFactory(this); _root = true; MaterialFactory = new SimpleFixtureMaterialFactory(this); }
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)); }
public SimpleFixture(GeometricObject geometricObject, List<UniformMaterial> materialCollection, UniformMaterial material, FixtureDescriptor descriptor, Matrix4x4 realParentPose) { _wrappedGeometricObject = geometricObject; _materialCollection = materialCollection; _material = material; UserData = descriptor.UserData; ShapeFactory = new SimpleFixtureShapeFactory(this); MaterialFactory = new SimpleFixtureMaterialFactory(this); _pose = descriptor.Pose; _root = false; _realParentPose = realParentPose; }
private GeometricObject CreateInstance() { GeometricObject newInstance = CreateInstanceCore(); if (GetType() != newInstance.GetType()) { string message = String.Format( CultureInfo.InvariantCulture, "Cannot clone geometric object. The derived class {0} does not implement CreateInstanceCore().", GetType()); throw new InvalidOperationException(message); } return(newInstance); }
public DebugRendererSample(Microsoft.Xna.Framework.Game game) : base(game) { SampleFramework.IsMouseVisible = false; var delegateGraphicsScreen = new DelegateGraphicsScreen(GraphicsService) { RenderCallback = Render, }; GraphicsService.Screens.Insert(0, delegateGraphicsScreen); // Add a custom game object which controls the camera. _cameraObject = new CameraObject(Services); GameObjectService.Objects.Add(_cameraObject); // Load a sprite font. var spriteFont = UIContentManager.Load<SpriteFont>("UI Themes/BlendBlue/Default"); // Create a new debug renderer. _debugRenderer = new DebugRenderer(GraphicsService, spriteFont) { DefaultColor = Color.White, }; // A normal XNA model. _xnaModel = ContentManager.Load<Model>("Saucer3/saucer"); // A DigitalRune model. _modelNode = ContentManager.Load<ModelNode>("Dude/Dude").Clone(); _modelNode.PoseLocal = new Pose(new Vector3F(6, 0, -7)); // Create a geometric object with a height field shape. 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++) 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); _geometricObject = new GeometricObject(heightField, new Pose(new Vector3F(5, 0, -5))) { Scale = new Vector3F(0.01f, 0.05f, 0.02f), }; }
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(); }
protected virtual void CloneCore(GeometricObject source) { Pose = source.Pose; Shape = source.Shape.Clone(); Scale = source.Scale; }
public ShapePositioner(ShapePositionerDescriptor descriptor) { WrappedGeometricObject = new GeometricObject(); Descriptor = descriptor; ShapeFactory = new ShapePositionerShapeFactory(this); }
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); } }
public CollisionFilterSample(Microsoft.Xna.Framework.Game game) : base(game) { SampleFramework.IsMouseVisible = false; GraphicsScreen.ClearBackground = true; GraphicsScreen.BackgroundColor = Color.Gray; GraphicsScreen.DrawReticle = true; SetCamera(new Vector3F(0, 0, 10), 0, 0); // ----- Initialize collision detection system. // We use one collision domain that manages all objects. var domain = new CollisionDomain(); // Let's set a filter which disables collision between object in the same collision group. // We can use a broad phase or a narrow phase filter: // Option A) Broad phase filter // The collision detection broad phase computes bounding box overlaps. // A broad phase filter is best used if the filtering rules are simple and do not change // during the runtime of your application. //domain.BroadPhase.Filter = new DelegatePairFilter<CollisionObject>( // pair => pair.First.CollisionGroup != pair.Second.CollisionGroup); // Option B) Narrow phase filter // The collision detection narrow phase computes contacts between objects where the broad // phase has detected a bounding box overlap. Use a narrow phase filter if the filtering rules // are complex or can change during the runtime of your application. var filter = new CollisionFilter(); // Disable collision between objects in the same groups. filter.Set(0, 0, false); filter.Set(1, 1, false); filter.Set(2, 2, false); filter.Set(3, 3, false); domain.CollisionDetection.CollisionFilter = filter; // Create a random list of points. var points = new List<Vector3F>(); for (int i = 0; i < 100; i++) points.Add(RandomHelper.Random.NextVector3F(-1.5f, 1.5f)); // Add lots of spheres to the collision domain. Assign spheres to different collision groups. var random = new Random(); var sphereShape = new SphereShape(0.7f); for (int i = 0; i < 20; i++) { var randomPosition = new Vector3F(random.NextFloat(-6, 6), random.NextFloat(-3, 3), 0); var geometricObject = new GeometricObject(sphereShape, new Pose(randomPosition)); var collisionObject = new CollisionObject(geometricObject) { // A collision group is simply an integer. We can assign collision objects to collision // groups to control the collision filtering. CollisionGroup = random.NextInteger(0, 3), }; domain.CollisionObjects.Add(collisionObject); } // Compute collisions. (The objects do not move in this sample. Therefore, we only have to // call Update once.) domain.Update(0); // Draw objects. The color depends on the collision group. var debugRenderer = GraphicsScreen.DebugRenderer; debugRenderer.Clear(); foreach (var collisionObject in domain.CollisionObjects) { Color color; switch (collisionObject.CollisionGroup) { case 0: color = Color.LightBlue; break; case 1: color = Color.Yellow; break; case 2: color = Color.Orange; break; default: color = Color.LightGreen; break; } debugRenderer.DrawObject(collisionObject.GeometricObject, color, false, false); } debugRenderer.DrawContacts(domain.ContactSets, 0.1f, Color.Red, true); }
public void GetScreenSizeException() { var viewport = new Viewport(10, 10, 200, 100); var geometricObject = new GeometricObject(new SphereShape()); GraphicsHelper.GetScreenSize(null, viewport, geometricObject); }
private bool HasLedgeContact() { // Here is a primitive way to detect ledges and edges where the character can climb: // We use a box that is ~10 cm high and wider than the character capsule. We check for // collisions in the top part of the character and a second time on a lower positions. // If the top part is free of collisions and the lower part collides with something, then // we have found a ledge and let the character hang onto it. // Note: This objects should not be allocated in each frame. Create them once, add them // to the collision domain and move them with the character controller - like the ray // of the DynamicCharacterController. BoxShape box = new BoxShape(CharacterController.Width + 0.2f, 0.1f, CharacterController.Width + 0.2f); GeometricObject geometricObject = new GeometricObject(box) { Pose = new Pose(CharacterController.Position + new Vector3F(0, 1.6f, 0)) }; var collisionObject = new CollisionObject(geometricObject) { CollisionGroup = 4, // Should not collide with character. Type = CollisionObjectType.Trigger, // Use a trigger because we do not need to compute detailed }; // collision information. // First test: if (_simulation.CollisionDomain.HasContact(collisionObject)) return false; // Second test: geometricObject.Pose = new Pose(CharacterController.Position + new Vector3F(0, 1.5f, 0)); if (_simulation.CollisionDomain.HasContact(collisionObject)) return true; return false; }
private void SynchronizeShape() { Debug.Assert(ParticleSystem != null); // Note: Scene does not allow TransformedShapes with infinite shapes. // --> Handle infinite shapes explicitly. (The code below only checks for InfiniteShape. // LineShape or PlaneShape will raise an exception in Scene!) if (ParticleSystem.ReferenceFrame == ParticleReferenceFrame.Local || ParticleSystem.Shape is InfiniteShape) { Shape = ParticleSystem.Shape; } else { // Particles are simulated in world space. ParticleSystem.Shape must not be scale by // SceneNode.ScaleWorld. --> Add a TransformedShape that negates the scale. var transformedShape = Shape as TransformedShape; if (transformedShape == null) { transformedShape = new TransformedShape(new GeometricObject()); Shape = transformedShape; } var geometricObject = transformedShape.Child as GeometricObject; if (geometricObject == null) { geometricObject = new GeometricObject(); transformedShape.Child = geometricObject; } geometricObject.Shape = ParticleSystem.Shape; geometricObject.Scale = Vector3F.One / ScaleWorld; } }
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; } }
/// <summary> /// Gets a bounding shape that matches the specified AABB. /// </summary> /// <param name="aabb">The AABB.</param> /// <returns>A box or transformed box that matches the specified AABB.</returns> private Shape GetBoundingShape(Aabb aabb) { // The AABB of the LOD is real world size including scaling. We have to undo // the scale because this LodGroupNode also applies the same scale. var unscaledCenter = aabb.Center / ScaleWorld; var unscaledExtent = aabb.Extent / ScaleWorld; // Get existing shape objects to avoid unnecessary memory allocation. BoxShape boxShape; GeometricObject geometricObject = null; TransformedShape transformedShape = null; if (Shape is BoxShape) { boxShape = (BoxShape)Shape; } else if (Shape is TransformedShape) { transformedShape = (TransformedShape)Shape; geometricObject = (GeometricObject)transformedShape.Child; boxShape = (BoxShape)geometricObject.Shape; } else { boxShape = new BoxShape(); } // Make bounding box the size of the unscaled AABB. boxShape.Extent = unscaledExtent; if (unscaledCenter.IsNumericallyZero) { // Bounding box is centered at origin. return boxShape; } // Apply offset to bounding box. if (transformedShape == null) { geometricObject = new GeometricObject(boxShape, new Pose(unscaledCenter)); transformedShape = new TransformedShape(geometricObject); } else { geometricObject.Shape = boxShape; geometricObject.Pose = new Pose(unscaledCenter); } return transformedShape; }
public override void Update(GameTime gameTime) { var lastFileIndex = _fileIndex; if (InputService.IsPressed(Keys.NumPad7, true)) _fileIndex++; if (InputService.IsPressed(Keys.NumPad4, true)) _fileIndex--; if (_fileIndex < 0) _fileIndex = MaxFileIndex; if (_fileIndex > MaxFileIndex) _fileIndex = 0; if (lastFileIndex != _fileIndex) { LoadFile(); _pointIndex = -1; } var lastPointIndex = _pointIndex; if (InputService.IsPressed(Keys.Right, true)) _pointIndex++; if (InputService.IsPressed(Keys.Left, true)) _pointIndex--; if (_pointIndex <= 0) _pointIndex = _points.Count; if (_pointIndex > _points.Count) _pointIndex = 1; var lastSkinWidth = _skinWidth; if (InputService.IsDown(Keys.Up)) _skinWidth *= 1.1f; if (InputService.IsDown(Keys.Down)) _skinWidth /= 1.1f; if (lastPointIndex != _pointIndex || _skinWidth != lastSkinWidth) { var watch = Stopwatch.StartNew(); DcelMesh hull = GeometryHelper.CreateConvexHull(_points.Take(_pointIndex), int.MaxValue, _skinWidth); watch.Stop(); _loadTime = (float)watch.Elapsed.TotalMilliseconds; _mesh = hull.ToTriangleMesh(); _geometricObject = new GeometricObject(new TriangleMeshShape(_mesh)); } var debugRenderer = GraphicsScreen.DebugRenderer; debugRenderer.Clear(); debugRenderer.DrawAxes(Pose.Identity, 1, false); debugRenderer.DrawObject(_geometricObject, new Color(0.5f, 0.5f, 0.5f, 0.8f), false, false); debugRenderer.DrawObject(_geometricObject, Color.Black, true, true); foreach (var point in _points) debugRenderer.DrawPoint(point, Color.White, false); debugRenderer.DrawText( "\n\nFile: " + _fileIndex + "\n" + "Point Index: " + _pointIndex + "\n" + "Time: " + _loadTime + "\n"); }
// Adds a game object and adds a collision object to the collision domain. private static void AddObject(string name, Pose pose, Shape shape, CollisionDomain collisionDomain) { // Create game object. var geometricObject = new GeometricObject(shape, pose); // Create collision object. var collisionObject = new CollisionObject(geometricObject) { CollisionGroup = 1, }; // Add collision object to collision domain. collisionDomain.CollisionObjects.Add(collisionObject); }
private bool _cullingEnabled = true; // True to use frustum culling. False to disable frustum culling. public FrustumCullingSample(Microsoft.Xna.Framework.Game game) : base(game) { GraphicsScreen.ClearBackground = true; GraphicsScreen.BackgroundColor = Color.CornflowerBlue; // The top-down camera. var orthographicProjection = new OrthographicProjection(); orthographicProjection.Set( LevelSize * 1.1f * GraphicsService.GraphicsDevice.Viewport.AspectRatio, LevelSize * 1.1f, 1, 10000f); var topDownCamera = new Camera(orthographicProjection); _topDownCameraNode = new CameraNode(topDownCamera) { View = Matrix44F.CreateLookAt(new Vector3F(0, 1000, 0), new Vector3F(0, 0, 0), -Vector3F.UnitZ), }; // The perspective camera moving through the scene. var perspectiveProjection = new PerspectiveProjection(); perspectiveProjection.SetFieldOfView( MathHelper.ToRadians(45), GraphicsService.GraphicsDevice.Viewport.AspectRatio, 1, 500); var sceneCamera = new Camera(perspectiveProjection); _sceneCameraNode = new CameraNode(sceneCamera); // Initialize collision detection. // We use one collision domain that manages all objects. _domain = new CollisionDomain(new CollisionDetection()) { // We exchange the default broad phase with a DualPartition. The DualPartition // has special support for frustum culling. BroadPhase = new DualPartition<CollisionObject>(), }; // Create a lot of random objects and add them to the collision domain. RandomHelper.Random = new Random(12345); for (int i = 0; i < NumberOfObjects; i++) { // A real scene consists of a lot of complex objects such as characters, vehicles, // buildings, lights, etc. When doing frustum culling we need to test each objects against // the viewing frustum. If it intersects with the viewing frustum, the object is visible // from the camera's point of view. However, in practice we do not test the exact object // against the viewing frustum. Each objects is approximated by a simpler shape. In our // example, we assume that each object is approximated with an oriented bounding box. // (We could also use an other shape, such as a bounding sphere.) // Create a random box. Shape randomShape = new BoxShape(RandomHelper.Random.NextVector3F(1, 10)); // Create a random position. Vector3F randomPosition; randomPosition.X = RandomHelper.Random.NextFloat(-LevelSize / 2, LevelSize / 2); randomPosition.Y = RandomHelper.Random.NextFloat(0, 2); randomPosition.Z = RandomHelper.Random.NextFloat(-LevelSize / 2, LevelSize / 2); // Create a random orientation. QuaternionF randomOrientation = RandomHelper.Random.NextQuaternionF(); // Create object and add it to collision domain. var geometricObject = new GeometricObject(randomShape, new Pose(randomPosition, randomOrientation)); var collisionObject = new CollisionObject(geometricObject) { CollisionGroup = 0, }; _domain.CollisionObjects.Add(collisionObject); } // Per default, the collision domain computes collision between all objects. // In this sample we do not need this information and disable it with a collision // filter. // In a real application, we would use this collision information for rendering, // for example, to find out which lights overlap with which meshes, etc. var filter = new CollisionFilter(); // Disable collision between objects in collision group 0. filter.Set(0, 0, false); _domain.CollisionDetection.CollisionFilter = filter; // Start with the scene camera. GraphicsScreen.CameraNode = _sceneCameraNode; // We will collect a few statistics for debugging. Profiler.SetFormat("NoCull", 1000, "Time in ms to submit DebugRenderer draw jobs without frustum culling."); Profiler.SetFormat("WithCull", 1000, "Time in ms to submit DebugRenderer draw jobs with frustum culling."); }
private float _slopeLimit = ConstantsF.PiOver4; // = 45° #endregion Fields #region Constructors //-------------------------------------------------------------- /// <summary> /// Initializes a new instance of the <see cref="KinematicCharacterController"/> class. /// </summary> /// <param name="simulation">The simulation.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="simulation" /> is <see langword="null"/>. /// </exception> public DynamicCharacterController(Simulation simulation) { if (simulation == null) throw new ArgumentNullException("simulation"); Simulation = simulation; CapsuleShape shape = new CapsuleShape(0.4f, 1.8f); MassFrame mass = new MassFrame { Mass = 80 }; // Push strength is proportional to the mass! UniformMaterial material = new UniformMaterial { // The body should be frictionless, so that it can be easily pushed by the simulation to // valid positions. And it does not slow down when sliding along walls. StaticFriction = 0.0f, DynamicFriction = 0.0f, // The body should not bounce when being hit or pushed. Restitution = 0 }; Body = new RigidBody(shape, mass, material) { // We set the mass explicitly and it should not automatically change when the // shape is changed; e.g. a ducked character has a smaller shape, but still the same mass. AutoUpdateMass = false, // This body is under our control and should never be deactivated by the simulation. CanSleep = false, CcdEnabled = true, // The capsule does not rotate in any direction. LockRotationX = true, LockRotationY = true, LockRotationZ = true, Name = "CharacterController", Pose = new Pose(new Vector3F(0, shape.Height / 2, 0)), }; // Create a ray that senses the space below the capsule. The ray starts in the capsule // center (to detect penetrations) and extends 0.4 units below the capsule bottom. RayShape rayShape = new RayShape(Vector3F.Zero, -Vector3F.UnitY, shape.Height / 2 + 0.4f) { StopsAtFirstHit = true, }; GeometricObject rayGeometry = new GeometricObject(rayShape, Body.Pose); _ray = new CollisionObject(rayGeometry); // Whenever the Body moves, the ray moves with it. Body.PoseChanged += (s, e) => rayGeometry.Pose = Body.Pose; // Enable the character controller. (Adds body to simulation.) Enabled = true; }
private void StandUp() { // Similar to crouch - only we make the character capsule taller again. // Before we change the height of the capsule we need to check if there is enough // room to stand up. To check this we position a smaller capsule in this area and // test for collisions. CapsuleShape testCapsule = new CapsuleShape(0.38f, 1.6f); GeometricObject testObject = new GeometricObject(testCapsule, new Pose(CharacterController.Position + 1.0f * Vector3F.UnitY)); CollisionObject testCollisionObject = new CollisionObject(testObject) { CollisionGroup = 4, // Should not collide with the character. Type = CollisionObjectType.Trigger, // Use a trigger because we do not need to compute detailed }; // collision information. // Check whether the test capsule touches anything. if (!_simulation.CollisionDomain.HasContact(testCollisionObject)) { // No contact, enough room to stand up. CharacterController.Height = 1.8f; // The drawing data in the UserData (see RigidBodyRenderer) must be invalidated. CharacterController.Body.UserData = null; } }
/// <summary> /// Gets a bounding shape that matches the specified AABB. /// </summary> /// <param name="aabb">The AABB.</param> /// <returns>A box or transformed box that matches the specified AABB.</returns> private Shape GetBoundingShape(Aabb aabb) { // Get existing shape objects to avoid unnecessary memory allocation. BoxShape boxShape; GeometricObject geometricObject = null; TransformedShape transformedShape = null; if (Shape is BoxShape) { boxShape = (BoxShape)Shape; } else if (Shape is TransformedShape) { transformedShape = (TransformedShape)Shape; geometricObject = (GeometricObject)transformedShape.Child; boxShape = (BoxShape)geometricObject.Shape; } else { boxShape = new BoxShape(); } // Make box the size of the AABB. boxShape.Extent = aabb.Extent; if (aabb.Center.IsNumericallyZero) { // Bounding box is centered at origin. return boxShape; } // Apply offset to bounding box. if (transformedShape == null) { geometricObject = new GeometricObject(boxShape, new Pose(aabb.Center)); transformedShape = new TransformedShape(geometricObject); } else { geometricObject.Shape = boxShape; geometricObject.Pose = new Pose(aabb.Center); } return transformedShape; }
//-------------------------------------------------------------- #region Creation & Cleanup //-------------------------------------------------------------- public CharacterController(CollisionDomain domain) { _collisionDomain = domain; // Create a game object for the character controller. GeometricObject = new GeometricObject( new CapsuleShape(Width / 2, Height), new Pose(new Vector3F(0, Height / 2, 0))); // Create a collision object for the game object and add it to the collision domain. CollisionObject = new CollisionObject(GeometricObject); _collisionDomain.CollisionObjects.Add(CollisionObject); }