Example #1
0
    private bool _drawDebugInfo;   // true if the collision shapes should be drawn for debugging.


    public ContentPipelineSample(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.
      // Note: The physics Simulation also has a collision domain (Simulation.CollisionDomain)
      // which we could use and which is updated together with the Simulation in
      // SampleGame.cs. But in this example we create our own CollisionDomain for demonstration
      // purposes.
      _collisionDomain = new CollisionDomain(new CollisionDetection());

      // Register CollisionDomain in service container.
      Services.Register(typeof(CollisionDomain), null, _collisionDomain);
      
      // Add game objects which manage graphics models and their collision representations.  
      _saucerObject = new SaucerObject(Services) { Name = "Saucer" };
      _shipObjectA = new ShipObject(Services) { Name = "ShipA" };
      _shipObjectB = new ShipObject(Services) { Name = "ShipB" };

      GameObjectService.Objects.Add(_saucerObject);
      GameObjectService.Objects.Add(_shipObjectA);
      GameObjectService.Objects.Add(_shipObjectB);

      // Position the second ship right of the first ship with an arbitrary rotation.
      _shipObjectB.Pose = new Pose(new Vector3F(2, 0, 0), QuaternionF.CreateRotationY(0.7f) * QuaternionF.CreateRotationX(1.2f));

      // Position the saucer left of the first ship with an arbitrary rotation.
      _saucerObject.Pose = new Pose(new Vector3F(-2.5f, 0, 0), QuaternionF.CreateRotationY(0.2f) * QuaternionF.CreateRotationX(0.4f));
    }
        public void UpdateSingle()
        {
            CollisionDomain domain = new CollisionDomain(new CollisionDetection());

            // Add 100 random objects.
            for (int i = 0; i < 100; i++)
            {
                domain.CollisionObjects.Add(new CollisionObject(new GeometricObject(new SphereShape(1), new Pose(RandomHelper.Random.NextVector3F(0, 20)))));
            }

            for (int i = 0; i < 100; i++)
            {
                domain.Update(domain.CollisionObjects[33]);

                for (int j = 0; j < domain.CollisionObjects.Count; j++)
                {
                    var a = domain.CollisionObjects[j];

                    for (int k = j + 1; k < domain.CollisionObjects.Count; k++)
                    {
                        var b = domain.CollisionObjects[k];

                        Assert.AreEqual(domain.InternalBroadPhase.CandidatePairs.Contains(a, b),
                                        GeometryHelper.HaveContact(a.GeometricObject.Aabb, b.GeometricObject.Aabb));
                    }
                }

                // Set new random position for one.
                ((GeometricObject)domain.CollisionObjects[33].GeometricObject).Pose = new Pose(RandomHelper.Random.NextVector3F(0, 20));

                Console.WriteLine("Candidate pairs: " + domain.InternalBroadPhase.CandidatePairs.Count);
            }
        }
Example #3
0
        public FigurePickerObject(IGraphicsService graphicsService, Scene scene, Editor2DCameraObject cameraObject, DebugRenderer debugRenderer)
        {
            _cameraObject = cameraObject;
            _scene = scene;
            _debugRenderer = debugRenderer;

            // Create a collision domain which manages all collision objects used for
            // picking: the picking object and the collision objects for figure nodes.
            _collisionDomain = new CollisionDomain(new CollisionDetection());

            // Create the picking object:
            // The picking object represents the mouse cursor or the reticle. Usually 
            // a ray is used, but in this example we want to use a cylinder/cone. This 
            // allows to check which objects within a certain radius of the reticle. A 
            // picking cylinder/cone is helpful for touch devices where the picking is 
            // done with an imprecise input method like the human finger.

            // We want to pick objects in 10 pixel radius around the reticle. To determine 
            // the world space size of the required cylinder/cone, we can use the projection
            // and the viewport. 
            const float pickingRadius = 0.25f;
            var projection = _cameraObject.CameraNode.Camera.Projection;
            var viewport = graphicsService.GraphicsDevice.Viewport;

            Shape pickingShape;
            if (projection is OrthographicProjection)
            {
                // Use cylinder for orthographic projections:
                // The cylinder is centered at the camera position and reaches from the 
                // camera position to the camera far plane. A TransformedShape is used
                // to rotate and translate the cylinder.
                float radius = projection.Width / viewport.Width * pickingRadius;
                pickingShape = new TransformedShape(
                  new GeometricObject(
                    new CylinderShape(radius, projection.Far),
                    new Pose(new Vector3F(0, 0, -projection.Far / 2), Matrix33F.CreateRotationX(ConstantsF.PiOver2))));
            }
            else
            {
                // Use cone for perspective projections:
                // The cone tip is at the camera position and the cone base is at the 
                // camera far plane. 

                // Compute the radius at the far plane that projects to 10 pixels in screen space.
                float radius = viewport.Unproject(
                  new Vector3(viewport.Width / 2.0f + pickingRadius, viewport.Height / 2.0f, 1),
                  (Matrix)_cameraObject.CameraNode.Camera.Projection.ToMatrix44F(),
                  Matrix.Identity,
                  Matrix.Identity).X;

                // A transformed shape is used to rotate and translate the cone.
                pickingShape = new TransformedShape(
                  new GeometricObject(
                    new ConeShape(radius, projection.Far),
                    new Pose(new Vector3F(0, 0, -projection.Far), Matrix33F.CreateRotationX(ConstantsF.PiOver2))));
            }

            // Create collision object with the picking shape.
            _pickingObject = new CollisionObject(new GeometricObject(pickingShape, _cameraObject.CameraNode.PoseWorld));
        }
Example #4
0
        //--------------------------------------------------------------
        #region Creation & Cleanup
        //--------------------------------------------------------------

        /// <summary>
        /// Initializes a new instance of the <see cref="Scene"/> class.
        /// </summary>
        public Scene()
        {
            Children = new SceneNodeCollection();

            if ((GlobalSettings.ValidationLevelInternal & GlobalSettings.ValidationLevelUserHighExpensive) != 0)
            {
                SceneChanged += OnSceneChangedValidation;
            }

            // Create a default collision filter.
            var filter = new SceneNodeCollisionFilter(this);

            filter.Set(1, 1, false); // Ignore camera vs. camera.
            filter.Set(2, 3, false); // Ignore light vs. lens flare.
            filter.Set(3, 3, false); // Ignore lens flare vs. lens flare.
            filter.Set(3, 4, false); // Ignore lens flare vs. mesh.
            filter.Set(4, 4, false); // Ignore mesh vs. mesh.
            _filter = filter;
            _collisionObjectFilter = new SceneCollisionObjectFilter(filter);
            var collisionDetection = new CollisionDetection {
                CollisionFilter = null,
            };

            // DualPartition is better for frustum culling.
            _collisionDomain = new CollisionDomain(collisionDetection)
            {
                BroadPhase = new DualPartition <CollisionObject> {
                    Filter = _collisionObjectFilter
                },
            };
        }
        public MassCollisionsTest(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            SampleFramework.IsMouseVisible = false;
            GraphicsScreen.ClearBackground = true;
            GraphicsScreen.BackgroundColor = Color.CornflowerBlue;
            SetCamera(new Vector3F(0, 0, 20), 0, 0);

            // We use one collision domain that manages all objects.
            _domain = new CollisionDomain {
                EnableMultithreading = false
            };
            //_domain.BroadPhase = new AabbTree<CollisionObject>();
            //_domain.BroadPhase = new DynamicAabbTree<CollisionObject> { EnableMotionPrediction = true, OptimizationPerFrame = 0.01f };
            //_domain.BroadPhase = new DualPartition<CollisionObject>();
            //_domain.BroadPhase = new DualPartition<CollisionObject>(new AdaptiveAabbTree<CollisionObject>(), new AdaptiveAabbTree<CollisionObject>());
            //_domain.BroadPhase = new DualPartition<CollisionObject>(new AdaptiveAabbTree<CollisionObject>(), new DynamicAabbTree<CollisionObject> { EnableMotionPrediction = true, OptimizationPerFrame = 0.01f });
            //_domain.BroadPhase = new DebugSpatialPartition<CollisionObject>();
            //_domain.BroadPhase = new AdaptiveAabbTree<CollisionObject>();

            // Create the 6 box planes.
            CreateBoundaryPlanes();

            // Create a lot of random objects.
            CreateRandomObjects();
        }
        public void TestEnabledDisabledStochastic()
        {
            // Test random Enabled and Pose values.

            int numberOfObjects = 20;
            int numberOfSteps   = 1000;

            Shape shape = new SphereShape(1);
            //var meshShape = new TriangleMeshShape(shape.GetMesh(0.01f, 4));
            //meshShape.Partition = new AabbTree<int>();
            //shape = meshShape;

            var geometricObjects = new GeometricObject[numberOfObjects];
            var collisionObjects = new CollisionObject[numberOfObjects];

            var domain = new CollisionDomain(new CollisionDetection());

            for (int i = 0; i < numberOfObjects; i++)
            {
                geometricObjects[i] = new GeometricObject(shape);
                collisionObjects[i] = new CollisionObject(geometricObjects[i]);
                domain.CollisionObjects.Add(collisionObjects[i]);
            }

            for (int i = 0; i < numberOfSteps; i++)
            {
                for (int j = 0; j < numberOfObjects; j++)
                {
                    collisionObjects[j].Enabled = RandomHelper.Random.NextBool();

                    domain.Update(0);

                    if (RandomHelper.Random.NextFloat(0, 1) > 0.5f)
                    {
                        geometricObjects[j].Pose = new Pose(RandomHelper.Random.NextVector3(-2, 2));
                    }

                    domain.Update(0);
                }

                domain.Update(0);
                domain.Update(0);
                domain.Update(0);
                domain.Update(0);
                domain.Update(0);
                domain.Update(0);
                domain.Update(0);

                // Compare result with brute-force check.
                for (int j = 0; j < numberOfObjects; j++)
                {
                    for (int k = j + 1; k < numberOfObjects; k++)
                    {
                        var haveContact = domain.CollisionDetection.HaveContact(collisionObjects[j], collisionObjects[k]);
                        Assert.AreEqual(haveContact, domain.ContactSets.GetContacts(collisionObjects[j], collisionObjects[k]) != null);
                    }
                }
            }
        }
Example #7
0
        public CharacterControllerSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            SampleFramework.IsMouseVisible = false;
            GraphicsScreen.ClearBackground = true;
            GraphicsScreen.BackgroundColor = Color.CornflowerBlue;

            // Create a camera.
            var projection = new PerspectiveProjection();

            projection.SetFieldOfView(
                ConstantsF.PiOver4,
                GraphicsService.GraphicsDevice.Viewport.AspectRatio,
                0.1f,
                1000.0f);
            _cameraNode = new CameraNode(new Camera(projection));
            GraphicsScreen.CameraNode = _cameraNode;

            // We use one collision domain that computes collision info for all game objects.
            _domain = new CollisionDomain(new CollisionDetection());

            // Create collision objects for a test level.
            CharacterControllerLevel.Load(_domain);

            // Add collision filter:
            // The _domain contains a lot of collision objects for obstacles in the level.
            // We do not need to compute contacts between these static obstacles. To avoid
            // this, the CharacterControllerLevel puts all level collision objects into
            // the collision group 1. We add a broad phase collision filter which filters out
            // collision checks between objects of collision group 1.
            _domain.BroadPhase.Filter = new DelegatePairFilter <CollisionObject>(
                pair =>
            {
                if (pair.First.CollisionGroup == 1 && pair.Second.CollisionGroup == 1)
                {
                    return(false);
                }

                return(true);
            });

            // Create character controller.
            _character          = new CharacterController(_domain);
            _character.Position = new Vector3F(0, 0, 1);

            // Create the trigger volume.
            _triggerVolume = new CollisionObject(
                new GeometricObject(new SphereShape(3), new Pose(new Vector3F(-5, 0, 5))))
            {
                // We do not want to compute detailed contact information (contact points, contact
                // normal vectors, etc.). We are only interested if the object touches another object or not.
                // Therefore, we set the collision object type to "trigger". Trigger objects are better for
                // performance than normal collision objects. Additionally, the character controller should
                // be able to walk through the trigger volume. The character controller treats objects as
                // solids if it finds contact information (contact positions with contact normal vectors).
                Type = CollisionObjectType.Trigger
            };
            _domain.CollisionObjects.Add(_triggerVolume);
        }
        public void ToStringTest()
        {
            CollisionDomain cd = new CollisionDomain(new CollisionDetection());

            cd.CollisionObjects.Add(new CollisionObject());
            cd.CollisionObjects.Add(new CollisionObject());
            Assert.AreEqual("CollisionDomain { Count = 2 }", cd.ToString());
        }
        public void Test3()
        {
            CollisionDomain domain = new CollisionDomain(new CollisionDetection());

            RandomHelper.Random = new Random(123456);

            const float testAreaSize = 20;

            // Add 100 random objects.
            for (int i = 0; i < 100; i++)
            {
                domain.CollisionObjects.Add(new CollisionObject(new GeometricObject(new SphereShape(1), new Pose(RandomHelper.Random.NextVector3F(0, testAreaSize)))));
            }

            for (int i = 0; i < 100; i++)
            {
                domain.Update(0.03f);

                for (int j = 0; j < domain.CollisionObjects.Count; j++)
                {
                    var a = domain.CollisionObjects[j];

                    for (int k = j + 1; k < domain.CollisionObjects.Count; k++)
                    {
                        var b = domain.CollisionObjects[k];

                        bool contained   = domain.InternalBroadPhase.CandidatePairs.Contains(a, b);
                        bool haveContact = GeometryHelper.HaveContact(a.GeometricObject.Aabb, b.GeometricObject.Aabb);
                        //if (contained != haveContact)
                        //Debugger.Break();
                        Assert.AreEqual(contained, haveContact);
                    }

                    // Set new random position for a few.
                    if (RandomHelper.Random.NextFloat(0, 1) < 0.7f)
                    {
                        ((GeometricObject)a.GeometricObject).Pose = new Pose(RandomHelper.Random.NextVector3F(0, testAreaSize));
                    }
                }

                // Add new object.
                domain.CollisionObjects.Add(new CollisionObject
                {
                    GeometricObject = new GeometricObject
                    {
                        Shape = new SphereShape(1),
                        Pose  = new Pose(RandomHelper.Random.NextVector3F(0, testAreaSize)),
                    }
                });

                // Remove random object.
                domain.CollisionObjects.Remove(domain.CollisionObjects[RandomHelper.Random.NextInteger(0, domain.CollisionObjects.Count - 1)]);

                Console.WriteLine("Candidate pairs: " + domain.InternalBroadPhase.CandidatePairs.Count);
            }
        }
Example #10
0
    /// <overloads>
    /// <summary>
    /// Advances the simulation by the given time.
    /// </summary>
    /// </overloads>
    /// 
    /// <summary>
    /// Advances the simulation by the given time.
    /// </summary>
    /// <param name="deltaTime">The size of the time step.</param>
    /// <remarks>
    /// See <see cref="Simulation"/> for more information.
    /// </remarks>
    public void Update(TimeSpan deltaTime)
    {
      if (deltaTime == TimeSpan.Zero)
        return;

      // Apply speedup factor.
      deltaTime = new TimeSpan((long)(deltaTime.Ticks * TimeScaling));

      _fixedTimeStep = Settings.Timing.FixedTimeStep;
      TimeSpan fixedTimeStep = new TimeSpan((long)(_fixedTimeStep * TimeSpan.TicksPerSecond));

      // Negative time steps are not allowed. MaxNumberOfSteps limits the max allowed time step. 
      // If deltaTime is larger, then some time is lost.
      TimeSpan minTimeStep = TimeSpan.Zero;
      TimeSpan maxTimeStep = new TimeSpan(fixedTimeStep.Ticks * Settings.Timing.MaxNumberOfSteps);
      deltaTime = MathHelper.Clamp(deltaTime, minTimeStep, maxTimeStep);

      // Update target time.
      TargetTime += deltaTime;

      //if (Settings.Timing.UseFixedTimeStep)
      //  TimeStep = Settings.Timing.FixedTimeStep;
      //else
      //  TimeStep = deltaTime;

      // Loop until target time is reached or the difference to target time is less than 
      // the time step size.
      while (TargetTime - Time >= fixedTimeStep)
      {
        if (Settings.EnableMultithreading)
        {
          SubTimeStep_Multithreaded(fixedTimeStep);
        }
        else
        {
          SubTimeStep_Singlethreaded(fixedTimeStep);
        }
      }

      if (Settings.SynchronizeCollisionDomain)
      {
        // Update collision domain so that user sees new contacts. But don't recycle
        // the old contact sets because they are still referenced by contact constraints.
        CollisionDomain.Update(0, false);
      }

      // Reset user forces. 
      {
        int numberOfRigidBodies = RigidBodies.Count;
        for (int i = 0; i < numberOfRigidBodies; i++)
        {
          RigidBody body = RigidBodies[i];
          body.ClearForces();
        }
      }
    }
Example #11
0
    public CharacterControllerSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      SampleFramework.IsMouseVisible = false;
      GraphicsScreen.ClearBackground = true;
      GraphicsScreen.BackgroundColor = Color.CornflowerBlue;

      // Create a camera.
      var projection = new PerspectiveProjection();
      projection.SetFieldOfView(
        ConstantsF.PiOver4,
        GraphicsService.GraphicsDevice.Viewport.AspectRatio,
        0.1f,
        1000.0f);
      _cameraNode = new CameraNode(new Camera(projection));
      GraphicsScreen.CameraNode = _cameraNode;

      // We use one collision domain that computes collision info for all game objects.
      _domain = new CollisionDomain(new CollisionDetection());

      // Create collision objects for a test level.
      CharacterControllerLevel.Load(_domain);

      // Add collision filter:
      // The _domain contains a lot of collision objects for obstacles in the level.
      // We do not need to compute contacts between these static obstacles. To avoid
      // this, the CharacterControllerLevel puts all level collision objects into
      // the collision group 1. We add a broad phase collision filter which filters out
      // collision checks between objects of collision group 1.
      _domain.BroadPhase.Filter = new DelegatePairFilter<CollisionObject>(
        pair =>
        {
          if (pair.First.CollisionGroup == 1 && pair.Second.CollisionGroup == 1)
            return false;

          return true;
        });

      // Create character controller. 
      _character = new CharacterController(_domain);
      _character.Position = new Vector3F(0, 0, 1);

      // Create the trigger volume. 
      _triggerVolume = new CollisionObject(
        new GeometricObject(new SphereShape(3), new Pose(new Vector3F(-5, 0, 5))))
      {
        // We do not want to compute detailed contact information (contact points, contact 
        // normal vectors, etc.). We are only interested if the object touches another object or not.
        // Therefore, we set the collision object type to "trigger". Trigger objects are better for 
        // performance than normal collision objects. Additionally, the character controller should
        // be able to walk through the trigger volume. The character controller treats objects as 
        // solids if it finds contact information (contact positions with contact normal vectors).
        Type = CollisionObjectType.Trigger
      };
      _domain.CollisionObjects.Add(_triggerVolume);
    }
Example #12
0
        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);
        }
        public void TestEnabledDisabled()
        {
            var shape = new SphereShape(1);
            var goA   = new GeometricObject(shape, Pose.Identity);
            var coA   = new CollisionObject(goA);

            var goB = new GeometricObject(shape, Pose.Identity);
            var coB = new CollisionObject(goB);

            var cd = new CollisionDomain(new CollisionDetection());

            cd.CollisionObjects.Add(coA);
            cd.CollisionObjects.Add(coB);

            // not touching
            goB.Pose = new Pose(new Vector3(3, 3, 0));
            cd.Update(0);
            Assert.AreEqual(0, cd.ContactSets.Count);

            // not touching, disabled
            coB.Enabled = false;
            cd.Update(0);
            Assert.AreEqual(0, cd.ContactSets.Count);

            // touching, disabled
            goB.Pose = new Pose(new Vector3(1, 1, 1));
            cd.Update(0);
            Assert.AreEqual(0, cd.ContactSets.Count);

            // touching, enabled
            coB.Enabled = true;
            cd.Update(0);
            Assert.AreEqual(1, cd.ContactSets.Count);

            // not touching - but broadphase overlap, enabled
            goB.Pose = new Pose(new Vector3(1.8f, 1.8f, 0));
            cd.Update(0);
            Assert.AreEqual(0, cd.ContactSets.Count);

            // not touching, disabled
            coB.Enabled = false;
            cd.Update(0);
            Assert.AreEqual(0, cd.ContactSets.Count);

            // touching, disabled
            goB.Pose = new Pose(new Vector3(1, 1, 1));
            cd.Update(0);
            Assert.AreEqual(0, cd.ContactSets.Count);

            // touching, enabled
            coB.Enabled = true;
            cd.Update(0);
            Assert.AreEqual(1, cd.ContactSets.Count);
        }
Example #14
0
    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);
    }
        public void ValidateNewObjectWithInvalidShape()
        {
            GlobalSettings.ValidationLevel = 0xff;

            CollisionDomain cd              = new CollisionDomain(new CollisionDetection());
            var             shape           = new SphereShape(1);
            var             geometricObject = new GeometricObject(shape, Pose.Identity);
            var             co              = new CollisionObject(geometricObject);

            shape.Radius = float.NaN;
            Assert.Throws <GeometryException>(() => cd.CollisionObjects.Add(co));
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="CollisionDetectionBroadPhase"/> class.
        /// </summary>
        public CollisionDetectionBroadPhase(CollisionDomain collisionDomain)
        {
            _collisionDomain = collisionDomain;

            // Register event handler.
            _collisionDomain.CollisionObjects.CollectionChanged += OnCollisionObjectsChanged;

            // Per default we use Sweep and Prune.
            SpatialPartition = new SweepAndPruneSpace <CollisionObject>();

            CandidatePairs = new ContactSetCollection();
        }
        public void ValidateInvalidScaleChange()
        {
            GlobalSettings.ValidationLevel = 0xff;

            CollisionDomain cd              = new CollisionDomain(new CollisionDetection());
            var             shape           = new SphereShape(1);
            var             geometricObject = new GeometricObject(shape, Pose.Identity);
            var             co              = new CollisionObject(geometricObject);

            cd.CollisionObjects.Add(co);
            Assert.Throws <GeometryException>(() => geometricObject.Scale = new Vector3(1, 1, float.NaN));
        }
Example #18
0
 /// <summary>
 /// Resets the collision object. (For internal use only.)
 /// </summary>
 internal void ResetInternal()
 {
     Changed          = true;
     CollisionGroup   = 0;
     _domain          = null;
     Enabled          = true;
     _geometricObject = null;
     _type            = CollisionObjectType.Default;
     _shapeType       = ShapeType.Default;
     _shape           = null;
     ShapeTypeChanged = true;
 }
Example #19
0
    private void ComputeTimeOfImpact_Singlethreaded(ContactSet contactSet)
    {
      RigidBody bodyA = contactSet.ObjectA.GeometricObject as RigidBody;
      RigidBody bodyB = contactSet.ObjectB.GeometricObject as RigidBody;

      // Note: We do CCD only between rigid bodies. 
      // TODO: Support CCD between RigidBody and general CollisionObject of the user.
      if (bodyA != null && bodyB != null)
      {
        // Check if at least one object needs CCD.
        if (bodyA.IsCcdActive || bodyB.IsCcdActive)
        {
          // Check CCD filter. (We check this filter first because it hopefully filters out a lot
          // of unnecessary checks (e.g. body against debris).)
          Func<RigidBody, RigidBody, bool> ccdFilter = Settings.Motion.CcdFilter;
          if (ccdFilter != null && !ccdFilter(bodyA, bodyB))
            return;

          // Check collision filter. (Using the internal method CanCollide that uses a cache.)
          if (!CollisionDomain.CanCollide(contactSet))
            return;

          // If convex bodies are touching we do not need to compute TOI because they are either
          // moving more toward each other (TOI = 0) or separating (TOI = 1). If they are moving
          // toward each other, then the contact constraint has failed and CCD is not the problem.
          // For objects vs. concave objects we still have to make a check because the bullet
          // could be separating and colliding with another part of the concave object. 
          // To avoid that objects stick: GetTimeOfImpact() should not return 0 for separating 
          // objects and we use 2 * AllowedPenetration so that the current contact does not 
          // count.

          if (!(bodyA.Shape is ConvexShape)
              || !(bodyB.Shape is ConvexShape)
              || !CollisionDomain.HaveContact(contactSet.ObjectA, contactSet.ObjectB))
          {
            // Get time of impact.
            float timeOfImpact = CollisionDomain.CollisionDetection.GetTimeOfImpact(
              contactSet.ObjectA,
              bodyA.IsCcdActive ? bodyA.TargetPose : bodyA.Pose,
              contactSet.ObjectB,
              bodyB.IsCcdActive ? bodyB.TargetPose : bodyB.Pose,
              Settings.Constraints.AllowedPenetration * 2f);

            // Store minimal time of impact.
            if (timeOfImpact < bodyA.TimeOfImpact)
              bodyA.TimeOfImpact = timeOfImpact;

            if (timeOfImpact < bodyB.TimeOfImpact)
              bodyB.TimeOfImpact = timeOfImpact;
          }
        }
      }
    }
Example #20
0
        //--------------------------------------------------------------
        #region Methods
        //--------------------------------------------------------------

        #region ----- Internal -----

        // The following methods are used internally by the collision detection to make direct
        // changes to a CollisionObject during collision checks.

        /// <summary>
        /// Copies the data from the specified <see cref="CollisionObject"/> and sets the specified
        /// <see cref="IGeometricObject"/>. (For internal use only.)
        /// </summary>
        /// <param name="collisionObject">The collision object.</param>
        /// <param name="geometricObject">The geometric object.</param>
        internal void SetInternal(CollisionObject collisionObject, IGeometricObject geometricObject)
        {
            Changed          = collisionObject.Changed;
            CollisionGroup   = collisionObject.CollisionGroup;
            _domain          = collisionObject._domain;
            Enabled          = collisionObject.Enabled;
            _geometricObject = geometricObject;
            _type            = collisionObject._type;
            _shapeType       = collisionObject._shapeType;
            _shape           = geometricObject.Shape;
            ShapeTypeChanged = collisionObject.ShapeTypeChanged;
        }
Example #21
0
        //--------------------------------------------------------------
        #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);
        }
Example #22
0
        public RuneTriggerVolume(Simulation simulation, Shape shape, string nameOfTarget)
        {
            this.collisionDomain = simulation.CollisionDomain;
            this.nameOfTarget    = nameOfTarget;

            this.GeometricObject = new GeometricObject(shape, new Pose(simulation.World.Aabb.Center));
            this.CollisionObject = new CollisionObject(GeometricObject)
            {
                Type = CollisionObjectType.Trigger
            };

            simulation.CollisionDomain.CollisionObjects.Add(CollisionObject);
        }
        public void NoValidation1()
        {
            GlobalSettings.ValidationLevel = 0;

            CollisionDomain cd              = new CollisionDomain(new CollisionDetection());
            var             shape           = new SphereShape(1);
            var             geometricObject = new GeometricObject(shape, Pose.Identity);
            var             co              = new CollisionObject(geometricObject);

            // No exception with validation level 0.
            shape.Radius = float.NaN;
            cd.CollisionObjects.Add(co);
        }
        public void Test2()
        {
            // All objects touch.
            CollisionObject a = new CollisionObject(new GeometricObject(new SphereShape(1), new Pose(new Vector3F(0, 0, 0))));
            CollisionObject b = new CollisionObject(new GeometricObject(new SphereShape(1), new Pose(new Vector3F(1, 1, 0))));
            CollisionObject c = new CollisionObject(new GeometricObject(new SphereShape(1), new Pose(new Vector3F(10, 10, 10))));
            CollisionObject d = new CollisionObject(new GeometricObject(new SphereShape(1), new Pose(new Vector3F(0, 0, -1))));

            CollisionDomain domain = new CollisionDomain(new CollisionDetection());

            Assert.AreEqual(0, domain.InternalBroadPhase.CandidatePairs.Count);

            domain.InternalBroadPhase.Update();
            Assert.AreEqual(0, domain.InternalBroadPhase.CandidatePairs.Count);

            domain.CollisionObjects.Add(a);
            domain.InternalBroadPhase.Update();
            Assert.AreEqual(0, domain.InternalBroadPhase.CandidatePairs.Count);

            domain.CollisionObjects.Add(b);
            domain.InternalBroadPhase.Update();
            Assert.AreEqual(1, domain.InternalBroadPhase.CandidatePairs.Count);

            domain.CollisionObjects.Add(c);
            domain.InternalBroadPhase.Update();
            Assert.AreEqual(1, domain.InternalBroadPhase.CandidatePairs.Count);

            domain.CollisionObjects.Add(d);
            domain.InternalBroadPhase.Update();
            Assert.AreEqual(3, domain.InternalBroadPhase.CandidatePairs.Count);

            foreach (ContactSet set in domain.InternalBroadPhase.CandidatePairs)
            {
                Assert.AreNotEqual(set.ObjectA, set.ObjectB);
            }

            domain.CollisionObjects.Remove(b);
            domain.InternalBroadPhase.Update();
            Assert.AreEqual(1, domain.InternalBroadPhase.CandidatePairs.Count);

            domain.CollisionObjects.Remove(a);
            domain.CollisionObjects.Remove(a);
            domain.InternalBroadPhase.Update();
            Assert.AreEqual(0, domain.InternalBroadPhase.CandidatePairs.Count);

            domain.CollisionObjects.Remove(d);
            domain.CollisionObjects.Remove(d);
            domain.InternalBroadPhase.Update();
            Assert.AreEqual(0, domain.InternalBroadPhase.CandidatePairs.Count);
        }
Example #25
0
        // 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);
        }
Example #26
0
        public void Test1()
        {
            // All objects touch.
              CollisionObject a = new CollisionObject { GeometricObject = new GeometricObject { Shape = new SphereShape(1) } };
              CollisionObject b = new CollisionObject { GeometricObject = new GeometricObject { Shape = new SphereShape(1) } };
              CollisionObject c = new CollisionObject { GeometricObject = new GeometricObject { Shape = new SphereShape(1) } };
              CollisionObject d = new CollisionObject { GeometricObject = new GeometricObject { Shape = new SphereShape(1) } };

              CollisionDomain domain = new CollisionDomain(new CollisionDetection());
              Assert.AreEqual(0, domain.InternalBroadPhase.CandidatePairs.Count);

              domain.InternalBroadPhase.Update();
              Assert.AreEqual(0, domain.InternalBroadPhase.CandidatePairs.Count);

              domain.CollisionObjects.Add(a);
              domain.InternalBroadPhase.Update();
              Assert.AreEqual(0, domain.InternalBroadPhase.CandidatePairs.Count);

              domain.CollisionObjects.Add(b);
              domain.InternalBroadPhase.Update();
              Assert.AreEqual(1, domain.InternalBroadPhase.CandidatePairs.Count);

              domain.CollisionObjects.Add(c);
              domain.InternalBroadPhase.Update();
              Assert.AreEqual(3, domain.InternalBroadPhase.CandidatePairs.Count);

              domain.CollisionObjects.Add(d);
              domain.InternalBroadPhase.Update();
              Assert.AreEqual(6, domain.InternalBroadPhase.CandidatePairs.Count);

              foreach (ContactSet set in domain.InternalBroadPhase.CandidatePairs)
            Assert.AreNotEqual(set.ObjectA, set.ObjectB);

              domain.CollisionObjects.Remove(b);
              domain.CollisionObjects.Remove(b);
              domain.InternalBroadPhase.Update();
              Assert.AreEqual(3, domain.InternalBroadPhase.CandidatePairs.Count);

              domain.CollisionObjects.Remove(a);
              domain.CollisionObjects.Remove(a);
              domain.InternalBroadPhase.Update();
              Assert.AreEqual(1, domain.InternalBroadPhase.CandidatePairs.Count);

              domain.CollisionObjects.Remove(d);
              domain.CollisionObjects.Remove(d);
              domain.InternalBroadPhase.Update();
              Assert.AreEqual(0, domain.InternalBroadPhase.CandidatePairs.Count);
        }
Example #27
0
        public MassCollisionsSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            GraphicsScreen.ClearBackground = true;
            GraphicsScreen.BackgroundColor = Color.CornflowerBlue;
            SetCamera(new Vector3F(0, 0, 20), 0, 0);

            // We use one collision domain that manages all objects.
            _domain = new CollisionDomain(new CollisionDetection());

            // Create the 6 box planes.
            CreateBoundaryPlanes();

            // Create a lot of random objects.
            CreateRandomObjects();
        }
        public void ValidateInvalidPoseChange()
        {
            GlobalSettings.ValidationLevel = 0xff;

            CollisionDomain cd              = new CollisionDomain(new CollisionDetection());
            var             shape           = new SphereShape(1);
            var             geometricObject = new GeometricObject(shape, Pose.Identity);
            var             co              = new CollisionObject(geometricObject);

            cd.CollisionObjects.Add(co);

            var matrix = Matrix33F.Identity;

            matrix.M11 = float.NaN;
            Assert.Throws <GeometryException>(() => geometricObject.Pose = new Pose(new Vector3F(), matrix));
        }
Example #29
0
    public MassCollisionsSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      SampleFramework.IsMouseVisible = false;
      GraphicsScreen.ClearBackground = true;
      GraphicsScreen.BackgroundColor = Color.CornflowerBlue;
      SetCamera(new Vector3F(0, 0, 20), 0, 0);

      // We use one collision domain that manages all objects.
      _domain = new CollisionDomain(new CollisionDetection());

      // Create the 6 box planes.
      CreateBoundaryPlanes();

      // Create a lot of random objects.
      CreateRandomObjects();
    }
        public void RayCastStopsAtFirstHitWhenChangingFilter()
        {
            CollisionDomain domain = new CollisionDomain(new CollisionDetection());

            domain.CollisionDetection.CollisionFilter = new CollisionFilter();

            // 1 ray: at origin shooting into +x
            CollisionObject ray = new CollisionObject();

            ((GeometricObject)ray.GeometricObject).Shape = new RayShape(new Vector3(), new Vector3(1, 0, 0), 100)
            {
                StopsAtFirstHit = true,
            };
            //ray.Name = "Ray";

            // 2 spheres: at at x=10, b at x=20
            CollisionObject a = new CollisionObject();

            ((GeometricObject)a.GeometricObject).Shape = new SphereShape(1);
            ((GeometricObject)a.GeometricObject).Pose  = new Pose(new Vector3(10, 0, 0f));
            //a.Name = "b";
            CollisionObject b = new CollisionObject();

            ((GeometricObject)b.GeometricObject).Shape = new SphereShape(1);
            ((GeometricObject)b.GeometricObject).Pose  = new Pose(new Vector3(20, 0, 0f));
            //b.Name = "c";

            domain.CollisionObjects.Add(ray);
            domain.CollisionObjects.Add(a);
            domain.CollisionObjects.Add(b);

            // Ray touches b.
            domain.Update(0.01f);
            Assert.AreEqual(1, domain.GetContacts(ray).Count());
            Assert.AreEqual(true, domain.HaveContact(ray, a));
            Assert.AreEqual(false, domain.HaveContact(ray, b));

            // Disable collisions between ray and a.
            // Then ray must hit b.
            ((CollisionFilter)domain.CollisionDetection.CollisionFilter).Set(ray, a, false);
            domain.Update(0.01f);
            Assert.AreEqual(1, domain.GetContacts(ray).Count());
            Assert.AreEqual(false, domain.HaveContact(ray, a));
            Assert.AreEqual(true, domain.HaveContact(ray, b));
        }
        private bool _drawDebugInfo; // true if the collision shapes should be drawn for debugging.


        public ContentPipelineSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            SampleFramework.IsMouseVisible = false;
            GraphicsScreen.ClearBackground = true;
            GraphicsScreen.BackgroundColor = Color.CornflowerBlue;
            SetCamera(new Vector3(0, 1, 10), 0, 0);

            // Initialize collision detection.
            // Note: The physics Simulation also has a collision domain (Simulation.CollisionDomain)
            // which we could use and which is updated together with the Simulation in
            // SampleGame.cs. But in this example we create our own CollisionDomain for demonstration
            // purposes.
            _collisionDomain = new CollisionDomain(new CollisionDetection());

            // Register CollisionDomain in service container.
            Services.Register(typeof(CollisionDomain), null, _collisionDomain);

            // Add game objects which manage graphics models and their collision representations.
            _saucerObject = new SaucerObject(Services)
            {
                Name = "Saucer"
            };
            _shipObjectA = new ShipObject(Services)
            {
                Name = "ShipA"
            };
            _shipObjectB = new ShipObject(Services)
            {
                Name = "ShipB"
            };

            GameObjectService.Objects.Add(_saucerObject);
            GameObjectService.Objects.Add(_shipObjectA);
            GameObjectService.Objects.Add(_shipObjectB);

            // Position the second ship right of the first ship with an arbitrary rotation.
            _shipObjectB.Pose = new Pose(new Vector3(2, 0, 0), Quaternion.CreateRotationY(0.7f) * Quaternion.CreateRotationX(1.2f));

            // Position the saucer left of the first ship with an arbitrary rotation.
            _saucerObject.Pose = new Pose(new Vector3(-2.5f, 0, 0), Quaternion.CreateRotationY(0.2f) * Quaternion.CreateRotationX(0.4f));
        }
        public void Filtering()
        {
            CollisionDomain domain = new CollisionDomain(new CollisionDetection());

            domain.CollisionDetection.CollisionFilter = new CollisionFilter();

            CollisionObject a = new CollisionObject();

            ((GeometricObject)a.GeometricObject).Shape = new SphereShape(1);
            ((GeometricObject)a.GeometricObject).Pose  = new Pose(new Vector3(0, 0, 0));
            //a.Name = "a";

            CollisionObject b = new CollisionObject();

            ((GeometricObject)b.GeometricObject).Shape = new SphereShape(1);
            ((GeometricObject)b.GeometricObject).Pose  = new Pose(new Vector3(1, 0, 0f));
            //b.Name = "b";

            domain.CollisionObjects.Add(a);
            domain.CollisionObjects.Add(b);
            domain.Update(0.01f);
            Assert.AreEqual(1, domain.ContactSets.Count);

            b.Enabled = false;
            domain.Update(0.01f);
            Assert.AreEqual(0, domain.ContactSets.Count);

            a.Enabled = false;
            b.Enabled = true;
            domain.Update(0.01f);
            Assert.AreEqual(0, domain.ContactSets.Count);

            a.Enabled = true;
            ((CollisionFilter)domain.CollisionDetection.CollisionFilter).Set(a, b, false);
            domain.Update(0.01f);
            Assert.AreEqual(0, domain.ContactSets.Count);

            ((CollisionFilter)domain.CollisionDetection.CollisionFilter).Set(a, b, true);
            domain.Update(0.01f);
            Assert.AreEqual(1, domain.ContactSets.Count);
        }
Example #33
0
        public void Filtering()
        {
            CollisionDomain domain = new CollisionDomain(new CollisionDetection());
              domain.CollisionDetection.CollisionFilter = new CollisionFilter();

              CollisionObject a = new CollisionObject();
              ((GeometricObject)a.GeometricObject).Shape = new SphereShape(1);
              ((GeometricObject)a.GeometricObject).Pose = new Pose(new Vector3F(0, 0, 0));
              //a.Name = "a";

              CollisionObject b = new CollisionObject();
              ((GeometricObject)b.GeometricObject).Shape = new SphereShape(1);
              ((GeometricObject)b.GeometricObject).Pose = new Pose(new Vector3F(1, 0, 0f));
              //b.Name = "b";

              domain.CollisionObjects.Add(a);
              domain.CollisionObjects.Add(b);
              domain.Update(0.01f);
              Assert.AreEqual(1, domain.ContactSets.Count);

              b.Enabled = false;
              domain.Update(0.01f);
              Assert.AreEqual(0, domain.ContactSets.Count);

              a.Enabled = false;
              b.Enabled = true;
              domain.Update(0.01f);
              Assert.AreEqual(0, domain.ContactSets.Count);

              a.Enabled = true;
              ((CollisionFilter) domain.CollisionDetection.CollisionFilter).Set(a, b, false);
              domain.Update(0.01f);
              Assert.AreEqual(0, domain.ContactSets.Count);

              ((CollisionFilter) domain.CollisionDetection.CollisionFilter).Set(a, b, true);
              domain.Update(0.01f);
              Assert.AreEqual(1, domain.ContactSets.Count);
        }
Example #34
0
    public MassCollisionsTest(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      SampleFramework.IsMouseVisible = false;
      GraphicsScreen.ClearBackground = true;
      GraphicsScreen.BackgroundColor = Color.CornflowerBlue;
      SetCamera(new Vector3F(0, 0, 20), 0, 0);

      // We use one collision domain that manages all objects.
      _domain = new CollisionDomain { EnableMultithreading = false };
      //_domain.BroadPhase = new AabbTree<CollisionObject>();
      //_domain.BroadPhase = new DynamicAabbTree<CollisionObject> { EnableMotionPrediction = true, OptimizationPerFrame = 0.01f };
      //_domain.BroadPhase = new DualPartition<CollisionObject>();
      //_domain.BroadPhase = new DualPartition<CollisionObject>(new AdaptiveAabbTree<CollisionObject>(), new AdaptiveAabbTree<CollisionObject>());
      //_domain.BroadPhase = new DualPartition<CollisionObject>(new AdaptiveAabbTree<CollisionObject>(), new DynamicAabbTree<CollisionObject> { EnableMotionPrediction = true, OptimizationPerFrame = 0.01f });
      //_domain.BroadPhase = new DebugSpatialPartition<CollisionObject>();
      //_domain.BroadPhase = new AdaptiveAabbTree<CollisionObject>();

      // Create the 6 box planes.
      CreateBoundaryPlanes();

      // Create a lot of random objects.
      CreateRandomObjects();
    }
Example #35
0
        //--------------------------------------------------------------
        /// <summary>
        /// Initializes a new instance of the <see cref="Simulation"/> class.
        /// </summary>
        public Simulation()
        {
            Settings = new SimulationSettings();

              var collisionDetection = new CollisionDetection
              {
            CollisionFilter = new CollisionFilter(),
            FullContactSetPerFrame = true
              };
              CollisionDomain = new CollisionDomain(collisionDetection);

              ConstraintSolver = new SequentialImpulseBasedSolver(this);

              Constraints = new ConstraintCollection();
              Constraints.CollectionChanged += OnConstraintsChanged;

              ForceEffects = new ForceEffectCollection();
              ForceEffects.CollectionChanged += OnForceEffectsChanged;

              RigidBodies = new RigidBodyCollection();
              RigidBodies.CollectionChanged += OnRigidBodiesChanged;

              ContactConstraintsInternal = new List<ContactConstraint>();

              IslandManager = new SimulationIslandManager(this);

              // Define the "World" as a rigid body.
              //   - World is an imaginary body that is used to define the space of the simulation.
              //   - The user can use World in constraints e.g. to anchor objects in the world.
              //   - No contacts are computed for World.
              World = new RigidBody(new BoxShape(20000, 20000, 20000))
              {
            CollisionResponseEnabled = false,
            CollisionObject = { Type = CollisionObjectType.Trigger },
            MotionType = MotionType.Static,
            Name = "World",
            Simulation = this,
              };

              // Remove "World" from the collision domain.
              CollisionDomain.CollisionObjects.Remove(World.CollisionObject);

            #if STOPWATCH
              Diagnostics = new SimulationDiagnostics();
            #endif

              // Store delegate methods to avoid garbage when multithreading.
              _updateVelocityMethod = i =>
              {
            var body = RigidBodies[i];
            body.UpdateVelocity(_fixedTimeStep);
              };
              _solveIslandMethod = SolveIsland;
              _updatePoseMethod = i =>
              {
            var body = RigidBodies[i];
            body.UpdatePose(_fixedTimeStep);
              };
              _computeTimeOfImpactMethod = ComputeTimeOfImpact_Multithreaded;
              _moveToTimeOfImpactMethod = MoveToTimeOfImpact;
        }
Example #36
0
    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.");
    }
Example #37
0
        public void NoValidation1()
        {
            GlobalSettings.ValidationLevel = 0;

              CollisionDomain cd = new CollisionDomain(new CollisionDetection());
              var shape = new SphereShape(1);
              var geometricObject = new GeometricObject(shape, Pose.Identity);
              var co = new CollisionObject(geometricObject);

              // No exception with validation level 0.
              shape.Radius = float.NaN;
              cd.CollisionObjects.Add(co);
        }
Example #38
0
    public PickingSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      SampleFramework.IsMouseVisible = false;
      GraphicsScreen.ClearBackground = true;
      GraphicsScreen.BackgroundColor = Color.CornflowerBlue;
      GraphicsScreen.DrawReticle = true;
      SetCamera(new Vector3F(0, 1, 10), 0, 0);

      // ----- Initialize collision detection system.
      // We use one collision domain that manages all objects.
      _domain = new CollisionDomain
      {
        // Optional: Change the broad phase type. The default type is the SweepAndPruneSpace, 
        // which is very fast for physics simulation. The DualPartition is better for ray casts.
        // See also http://digitalrune.github.io/DigitalRune-Documentation/html/e32cab3b-cc7c-42ee-8ec9-23dd4467edd0.htm#WhichPartition
        BroadPhase = new DualPartition<CollisionObject>(),
      };

      // Optional: Set a broad phase filter.
      // Per default, the collision domain computes contacts between all collision objects. If we
      // are only interested in ray vs non-ray-shape contacts, we can set a filter to avoid 
      // unnecessary intersection computations and improve performance.
      _domain.BroadPhase.Filter = new DelegatePairFilter<CollisionObject>(
        pair =>
        {
          var firstIsRay = pair.First.GeometricObject.Shape is RayShape;
          var secondIsRay = pair.Second.GeometricObject.Shape is RayShape;
          return firstIsRay != secondIsRay;
        });

      // Create a collision object with a box shape at position (0, 0, 0) with a random rotation.
      _box = new CollisionObject(
        new GeometricObject(
          new BoxShape(1, 2, 3),
          new Pose(new Vector3F(0, 0, 0), RandomHelper.Random.NextQuaternionF())));

      // Create a collision object with a sphere shape at position (-5, 0, 0).
      _sphere = new CollisionObject(new GeometricObject(new SphereShape(1), new Pose(new Vector3F(-5, 0, 0))));

      // 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));

      // Create a triangle mesh of the convex hull.
      // (See also the ConvexHullSample for info on convex hull creation.)
      TriangleMesh triangleMesh = GeometryHelper.CreateConvexHull(points).ToTriangleMesh();

      // We use this random triangle mesh to define a shape.
      TriangleMeshShape meshShape = new TriangleMeshShape(triangleMesh);

      // Optional: We can use a spatial partitioning method, to speed up collision
      // detection for large meshes. AABB trees are good for static triangle meshes.
      // To use spatial partitioning we have to set a valid spatial partition instance
      // in the Partition property.
      // The spatial partition will store indices of the mesh triangles, therefore
      // the generic type argument is "int".
      meshShape.Partition = new AabbTree<int>()
      {
        // 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: Build the AABB tree. (This is done automatically when the AABB tree is used for
      // the first time, but Update can also be called explicitly to control when the tree is built.)
      meshShape.Partition.Update(false);


      // Create a collision object with the random triangle mesh shape.
      _mesh = new CollisionObject(new GeometricObject(meshShape, new Pose(new Vector3F(5, 0, 0))));

      // Add collision object to collision domain.
      _domain.CollisionObjects.Add(_box);
      _domain.CollisionObjects.Add(_sphere);
      _domain.CollisionObjects.Add(_mesh);

      // For picking we create a ray.
      // The ray shoot from its local origin in +x direction.
      // (Note: The last parameter is the length of the ray. In theory, rays have
      // an infinite length. However, in the collision detection we use rays with
      // a finite length. This increases the performance and improves the numerical
      // stability of the algorithms.)
      RayShape rayShape = new RayShape(Vector3F.Zero, Vector3F.Forward, 1000);
      _ray = new CollisionObject(new GeometricObject(rayShape, Pose.Identity));

      // The ray is just one additional collision object in our collision domain.
      _domain.CollisionObjects.Add(_ray);

      // The collision domain manages now 4 objects: a box, a sphere, a triangle mesh and a ray.
    }
Example #39
0
        public static void Load(CollisionDomain collisionDomain)
        {
            // Create a box for the ground.
            AddObject("Ground", new Pose(new Vector3F(0, -5, 0)), new BoxShape(60, 10, 60), collisionDomain);

            // Create a small flying sphere to visualize the approx. head height. - This is just
            // for debugging so that we have a feeling for heights.
            AddObject("Sphere", new Pose(new Vector3F(0, 1.5f, 0)), new SphereShape(0.2f), collisionDomain);

            // Create small walls at the level boundary.
            AddObject("WallLeft", new Pose(new Vector3F(-30, 1, 0)), new BoxShape(0.3f, 2, 60), collisionDomain);
            AddObject("WallRight", new Pose(new Vector3F(30, 1, 0)), new BoxShape(0.3f, 2, 60), collisionDomain);
            AddObject("WallFront", new Pose(new Vector3F(0, 1, -30)), new BoxShape(60, 2, 0.3f), collisionDomain);
            AddObject("WallBack", new Pose(new Vector3F(0, 1, 30)), new BoxShape(60, 2, 0.3f), collisionDomain);

            // Create a few bigger objects.
            // We position the boxes so that we have a few corners we can run into. Character controllers
            // should be stable when the user runs into corners.
            AddObject("House0", new Pose(new Vector3F(10, 1, -10)), new BoxShape(8, 2, 8f), collisionDomain);
            AddObject("House1", new Pose(new Vector3F(13, 1, -4)), new BoxShape(2, 2, 4), collisionDomain);
            AddObject("House2", new Pose(new Vector3F(10, 2, -15), Matrix33F.CreateRotationY(-0.3f)), new BoxShape(8, 4, 2), collisionDomain);

            //
            // Create stairs with increasing step height.
            //
            // Each step is a box. With this object we can test if our character can climb up
            // stairs. The character controller has a step height limit. Increasing step heights
            // let us test if the step height limit works.
            float       startHeight = 0;
            const float stepDepth   = 1f;

            for (int i = 0; i < 10; i++)
            {
                float    stepHeight = 0.1f + i * 0.05f;
                Pose     pose       = new Pose(new Vector3F(0, startHeight + stepHeight / 2, -2 - i * stepDepth));
                BoxShape shape      = new BoxShape(2, stepHeight, stepDepth);
                AddObject("Step" + i, pose, shape, collisionDomain);
                startHeight += stepHeight;
            }

            //
            // Create a height field.
            //
            // Terrain that is uneven is best modeled with a height field. Height fields are faster
            // than general triangle meshes.
            // The height direction is the y direction.
            // The height field lies in the x/z plane.
            var numberOfSamplesX = 20;
            var numberOfSamplesZ = 20;
            var samples          = new float[numberOfSamplesX * numberOfSamplesZ];

            // Create arbitrary height values.
            for (int z = 0; z < numberOfSamplesZ; z++)
            {
                for (int x = 0; x < numberOfSamplesX; x++)
                {
                    if (x == 0 || z == 0 || x == 19 || z == 19)
                    {
                        // Set this boundary elements to a low height, so that the height field is connected
                        // to the ground.
                        samples[z * numberOfSamplesX + x] = -1;
                    }
                    else
                    {
                        // A sine/cosine function that creates some interesting waves.
                        samples[z * numberOfSamplesX + x] = 1.0f + (float)(Math.Cos(z / 2f) * Math.Sin(x / 2f) * 1.0f);
                    }
                }
            }
            var heightField = new HeightField(0, 0, 20, 20, samples, numberOfSamplesX, numberOfSamplesZ);

            AddObject("Heightfield", new Pose(new Vector3F(10, 0, 10)), heightField, collisionDomain);

            // Create rubble on the floor (small random objects on the floor).
            // Our character should be able to move over small bumps on the ground.
            for (int i = 0; i < 50; i++)
            {
                Pose pose = new Pose(
                    new Vector3F(RandomHelper.Random.NextFloat(-5, 5), 0, RandomHelper.Random.NextFloat(10, 20)),
                    RandomHelper.Random.NextQuaternionF());
                BoxShape shape = new BoxShape(RandomHelper.Random.NextVector3F(0.05f, 0.8f));
                AddObject("Stone" + i, pose, shape, collisionDomain);
            }

            // Create some slopes to see how our character performs on/under sloped surfaces.
            // Here we can test how the character controller behaves if the head touches an inclined
            // ceiling.
            AddObject("SlopeGround", new Pose(new Vector3F(-2, 1.8f, -12), QuaternionF.CreateRotationX(0.4f)), new BoxShape(2, 0.5f, 10), collisionDomain);
            AddObject("SlopeRoof", new Pose(new Vector3F(-2, 5.6f, -12), QuaternionF.CreateRotationX(-0.4f)), new BoxShape(2, 0.5f, 10), collisionDomain);

            // Slopes with different tilt angles.
            // The character controller has a slope limit. Only flat slopes should be climbable.
            for (int i = 0; i < 10; i++)
            {
                float stepHeight = 0.1f + i * 0.1f;
                Pose  pose       = new Pose(
                    new Vector3F(-10, i * 0.5f, -i * 2),
                    Matrix33F.CreateRotationX(MathHelper.ToRadians(10) + i * MathHelper.ToRadians(10)));
                BoxShape shape = new BoxShape(8 * (1 - i * 0.1f), 0.5f, 30);
                AddObject("Slope" + i, pose, shape, collisionDomain);
                startHeight += stepHeight;
            }

            // Create a slope with a wall on one side.
            // This objects let's us test how the character controller behaves while falling and
            // sliding along a vertical wall. (Run up the slope and then jump down while moving into
            // the wall.)
            AddObject("LongSlope", new Pose(new Vector3F(-20, 3, -10), Matrix33F.CreateRotationX(0.4f)), new BoxShape(4, 5f, 30), collisionDomain);
            AddObject("LongSlopeWall", new Pose(new Vector3F(-22, 5, -10)), new BoxShape(0.5f, 10f, 25), collisionDomain);

            // Create a mesh object to test walking on triangle meshes.
            // Normally, the mesh would be loaded from a file. Here, we make a composite shape and
            // let DigitalRune Geometry compute a mesh for it. Then we throw away the composite
            // shape and use only the mesh. - We do this to test triangle meshes. Using the composite
            // shape instead of the triangle mesh would be a lot faster.
            CompositeShape compositeShape = new CompositeShape();

            compositeShape.Children.Add(new GeometricObject(heightField, Pose.Identity));
            compositeShape.Children.Add(new GeometricObject(new CylinderShape(1, 2), new Pose(new Vector3F(10, 1, 10))));
            compositeShape.Children.Add(new GeometricObject(new SphereShape(3), new Pose(new Vector3F(15, 0, 15))));
            compositeShape.Children.Add(new GeometricObject(new BoxShape(1, 2, 3), new Pose(new Vector3F(15, 0, 5))));
            ITriangleMesh     mesh      = compositeShape.GetMesh(0.01f, 3);
            TriangleMeshShape meshShape = new TriangleMeshShape(mesh);

            // Collision detection speed for triangle meshes can be improved by using a spatial
            // partition. Here, we assign an AabbTree to the triangle mesh shape. The tree is
            // built automatically when needed and it stores triangle indices (therefore the generic
            // parameter of the AabbTree is int).
            meshShape.Partition = new AabbTree <int>()
            {
                // The tree is automatically built using a mixed top-down/bottom-up approach. Bottom-up
                // building is slower but produces better trees. If the tree building takes too long,
                // we can lower the BottomUpBuildThreshold (default is 128).
                BottomUpBuildThreshold = 0,
            };

            AddObject("Mesh", new Pose(new Vector3F(-30, 0, 10)), meshShape, collisionDomain);
        }
Example #40
0
    public static void Load(CollisionDomain collisionDomain)
    {
      // Create a box for the ground.
      AddObject("Ground", new Pose(new Vector3F(0, -5, 0)), new BoxShape(60, 10, 60), collisionDomain);

      // Create a small flying sphere to visualize the approx. head height. - This is just
      // for debugging so that we have a feeling for heights.
      AddObject("Sphere", new Pose(new Vector3F(0, 1.5f, 0)), new SphereShape(0.2f), collisionDomain);

      // Create small walls at the level boundary.
      AddObject("WallLeft", new Pose(new Vector3F(-30, 1, 0)), new BoxShape(0.3f, 2, 60), collisionDomain);
      AddObject("WallRight", new Pose(new Vector3F(30, 1, 0)), new BoxShape(0.3f, 2, 60), collisionDomain);
      AddObject("WallFront", new Pose(new Vector3F(0, 1, -30)), new BoxShape(60, 2, 0.3f), collisionDomain);
      AddObject("WallBack", new Pose(new Vector3F(0, 1, 30)), new BoxShape(60, 2, 0.3f), collisionDomain);

      // Create a few bigger objects.
      // We position the boxes so that we have a few corners we can run into. Character controllers
      // should be stable when the user runs into corners.
      AddObject("House0", new Pose(new Vector3F(10, 1, -10)), new BoxShape(8, 2, 8f), collisionDomain);
      AddObject("House1", new Pose(new Vector3F(13, 1, -4)), new BoxShape(2, 2, 4), collisionDomain);
      AddObject("House2", new Pose(new Vector3F(10, 2, -15), Matrix33F.CreateRotationY(-0.3f)), new BoxShape(8, 4, 2), collisionDomain);

      //
      // Create stairs with increasing step height.
      //
      // Each step is a box. With this object we can test if our character can climb up
      // stairs. The character controller has a step height limit. Increasing step heights
      // let us test if the step height limit works.
      float startHeight = 0;
      const float stepDepth = 1f;
      for (int i = 0; i < 10; i++)
      {
        float stepHeight = 0.1f + i * 0.05f;
        Pose pose = new Pose(new Vector3F(0, startHeight + stepHeight / 2, -2 - i * stepDepth));
        BoxShape shape = new BoxShape(2, stepHeight, stepDepth);
        AddObject("Step" + i, pose, shape, collisionDomain);
        startHeight += stepHeight;
      }

      //
      // Create a height field.
      //
      // Terrain that is uneven is best modeled with a height field. Height fields are faster
      // than general triangle meshes.
      // The height direction is the y direction. 
      // The height field lies in the x/z plane.
      var numberOfSamplesX = 20;
      var numberOfSamplesZ = 20;
      var samples = new float[numberOfSamplesX * numberOfSamplesZ];
      // Create arbitrary height values. 
      for (int z = 0; z < numberOfSamplesZ; z++)
      {
        for (int x = 0; x < numberOfSamplesX; x++)
        {
          if (x == 0 || z == 0 || x == 19 || z == 19)
          {
            // Set this boundary elements to a low height, so that the height field is connected
            // to the ground.
            samples[z * numberOfSamplesX + x] = -1;
          }
          else
          {
            // A sine/cosine function that creates some interesting waves.
            samples[z * numberOfSamplesX + x] = 1.0f + (float)(Math.Cos(z / 2f) * Math.Sin(x / 2f) * 1.0f);
          }
        }
      }
      var heightField = new HeightField(0, 0, 20, 20, samples, numberOfSamplesX, numberOfSamplesZ);
      AddObject("Heightfield", new Pose(new Vector3F(10, 0, 10)), heightField, collisionDomain);

      // Create rubble on the floor (small random objects on the floor).
      // Our character should be able to move over small bumps on the ground.
      for (int i = 0; i < 50; i++)
      {
        Pose pose = new Pose(
          new Vector3F(RandomHelper.Random.NextFloat(-5, 5), 0, RandomHelper.Random.NextFloat(10, 20)),
          RandomHelper.Random.NextQuaternionF());
        BoxShape shape = new BoxShape(RandomHelper.Random.NextVector3F(0.05f, 0.8f));
        AddObject("Stone" + i, pose, shape, collisionDomain);
      }

      // Create some slopes to see how our character performs on/under sloped surfaces.
      // Here we can test how the character controller behaves if the head touches an inclined
      // ceiling.
      AddObject("SlopeGround", new Pose(new Vector3F(-2, 1.8f, -12), QuaternionF.CreateRotationX(0.4f)), new BoxShape(2, 0.5f, 10), collisionDomain);
      AddObject("SlopeRoof", new Pose(new Vector3F(-2, 5.6f, -12), QuaternionF.CreateRotationX(-0.4f)), new BoxShape(2, 0.5f, 10), collisionDomain);

      // Slopes with different tilt angles.
      // The character controller has a slope limit. Only flat slopes should be climbable. 
      for (int i = 0; i < 10; i++)
      {
        float stepHeight = 0.1f + i * 0.1f;
        Pose pose = new Pose(
          new Vector3F(-10, i * 0.5f, -i * 2),
          Matrix33F.CreateRotationX(MathHelper.ToRadians(10) + i * MathHelper.ToRadians(10)));
        BoxShape shape = new BoxShape(8 * (1 - i * 0.1f), 0.5f, 30);
        AddObject("Slope" + i, pose, shape, collisionDomain);
        startHeight += stepHeight;
      }

      // Create a slope with a wall on one side.
      // This objects let's us test how the character controller behaves while falling and
      // sliding along a vertical wall. (Run up the slope and then jump down while moving into
      // the wall.)
      AddObject("LongSlope", new Pose(new Vector3F(-20, 3, -10), Matrix33F.CreateRotationX(0.4f)), new BoxShape(4, 5f, 30), collisionDomain);
      AddObject("LongSlopeWall", new Pose(new Vector3F(-22, 5, -10)), new BoxShape(0.5f, 10f, 25), collisionDomain);

      // Create a mesh object to test walking on triangle meshes.
      // Normally, the mesh would be loaded from a file. Here, we make a composite shape and 
      // let DigitalRune Geometry compute a mesh for it. Then we throw away the composite
      // shape and use only the mesh. - We do this to test triangle meshes. Using the composite
      // shape instead of the triangle mesh would be a lot faster.
      CompositeShape compositeShape = new CompositeShape();
      compositeShape.Children.Add(new GeometricObject(heightField, Pose.Identity));
      compositeShape.Children.Add(new GeometricObject(new CylinderShape(1, 2), new Pose(new Vector3F(10, 1, 10))));
      compositeShape.Children.Add(new GeometricObject(new SphereShape(3), new Pose(new Vector3F(15, 0, 15))));
      compositeShape.Children.Add(new GeometricObject(new BoxShape(1, 2, 3), new Pose(new Vector3F(15, 0, 5))));
      ITriangleMesh mesh = compositeShape.GetMesh(0.01f, 3);
      TriangleMeshShape meshShape = new TriangleMeshShape(mesh);

      // Collision detection speed for triangle meshes can be improved by using a spatial 
      // partition. Here, we assign an AabbTree to the triangle mesh shape. The tree is
      // built automatically when needed and it stores triangle indices (therefore the generic 
      // parameter of the AabbTree is int).
      meshShape.Partition = new AabbTree<int>()
      {
        // The tree is automatically built using a mixed top-down/bottom-up approach. Bottom-up
        // building is slower but produces better trees. If the tree building takes too long,
        // we can lower the BottomUpBuildThreshold (default is 128).
        BottomUpBuildThreshold = 0,
      };

      AddObject("Mesh", new Pose(new Vector3F(-30, 0, 10)), meshShape, collisionDomain);
    }
Example #41
0
        public void RayCastStopsAtFirstHit()
        {
            CollisionDomain domain = new CollisionDomain(new CollisionDetection());

              CollisionObject ray = new CollisionObject();
              ((GeometricObject)ray.GeometricObject).Shape = new RayShape(new Vector3F(), new Vector3F(1, 0, 0), 100)
              {
            StopsAtFirstHit = true,
              };
              //ray.Name = "Ray";

              CollisionObject b = new CollisionObject();
              ((GeometricObject)b.GeometricObject).Shape = new SphereShape(1);
              ((GeometricObject)b.GeometricObject).Pose = new Pose(new Vector3F(-10, 0, 0f));
              //b.Name = "b";

              CollisionObject c = new CollisionObject();
              ((GeometricObject)c.GeometricObject).Shape = new SphereShape(1);
              ((GeometricObject)c.GeometricObject).Pose = new Pose(new Vector3F(0, 0, 0f));
              //c.Name = "c";

              CollisionObject d = new CollisionObject();
              ((GeometricObject)d.GeometricObject).Shape = new SphereShape(1);
              ((GeometricObject)d.GeometricObject).Pose = new Pose(new Vector3F(10, 0, 0f));
              //d.Name = "d";

              CollisionObject e = new CollisionObject();
              ((GeometricObject)e.GeometricObject).Shape = new SphereShape(1);
              ((GeometricObject)e.GeometricObject).Pose = new Pose(new Vector3F(20, 0, 0f));
              //e.Name = "e";

              CollisionObject f = new CollisionObject();
              ((GeometricObject)f.GeometricObject).Shape = new SphereShape(1);
              ((GeometricObject)f.GeometricObject).Pose = new Pose(new Vector3F(110, 0, 0f));
              //f.Name = "f";

              // Positions: b=-10, c=0, d=10, e=20, f=110
              domain.CollisionObjects.Add(ray);
              domain.CollisionObjects.Add(b);
              domain.CollisionObjects.Add(d);
              domain.CollisionObjects.Add(c);
              domain.CollisionObjects.Add(e);
              domain.CollisionObjects.Add(f);

              domain.Update(0.01f);
              Assert.AreEqual(1, domain.GetContacts(ray).Count());
              Assert.AreEqual(true, domain.HaveContact(ray, c));

              ((GeometricObject)c.GeometricObject).Pose = new Pose(new Vector3F(30));
              // Positions: b=-10, d=10, e=20, c=30, f=110
              domain.Update(0.01f);
              Assert.AreEqual(1, domain.GetContacts(ray).Count());
              Assert.AreEqual(true, domain.HaveContact(ray, d));

              ((GeometricObject)d.GeometricObject).Pose = new Pose(new Vector3F(40));
              // Positions: b=-10, e=20, c=30, d=40, f=110
              domain.Update(0.01f);
              Assert.AreEqual(1, domain.GetContacts(ray).Count());
              Assert.AreEqual(true, domain.HaveContact(ray, e));

              ((GeometricObject)ray.GeometricObject).Pose = new Pose(((GeometricObject)ray.GeometricObject).Pose.Position, QuaternionF.CreateRotationZ(ConstantsF.PiOver2));
              domain.Update(0.01f);
              Assert.AreEqual(0, domain.GetContacts(ray).Count());

              ((GeometricObject)ray.GeometricObject).Pose = new Pose(((GeometricObject)ray.GeometricObject).Pose.Position, QuaternionF.CreateRotationZ(ConstantsF.Pi));
              domain.Update(0.01f);
              Assert.AreEqual(1, domain.GetContacts(ray).Count());
              Assert.AreEqual(true, domain.HaveContact(ray, b));

              ((GeometricObject)ray.GeometricObject).Pose = new Pose(((GeometricObject)ray.GeometricObject).Pose.Position, QuaternionF.Identity);
              domain.Update(0.01f);

              // Positions: b=-10, e=20, c=30, d=40, f=110
              CollisionObject gNotInDomain = new CollisionObject();
              ((GeometricObject)gNotInDomain.GeometricObject).Shape = new SphereShape(1);
              ((GeometricObject)gNotInDomain.GeometricObject).Pose = new Pose(new Vector3F(10, 0, 0f));
              Assert.AreEqual(true, domain.HaveContact(ray, gNotInDomain));
              Assert.AreEqual(1, domain.GetContacts(gNotInDomain).Count());
              Assert.AreEqual(1, domain.GetContacts(ray, gNotInDomain).Count);
              Assert.AreEqual(true, domain.HasContact(gNotInDomain));
              ((GeometricObject)gNotInDomain.GeometricObject).Pose = new Pose(new Vector3F(25, 0, 0f)); // behind e
              Assert.AreEqual(false, domain.HaveContact(ray, gNotInDomain));
              Assert.AreEqual(false, domain.HaveContact(gNotInDomain, ray));
              Assert.AreEqual(false, domain.HasContact(gNotInDomain));
              Assert.AreEqual(0, domain.GetContacts(gNotInDomain).Count());
              Assert.IsNull(domain.GetContacts(ray, gNotInDomain));
              Assert.IsNull(domain.GetContacts(gNotInDomain, ray));

              // Remove ray from domain.
              domain.CollisionObjects.Remove(ray);
              domain.Update(0.01f);
              Assert.AreEqual(0, domain.ContactSets.Count);

              // Positions: b=-10, e=20, g=25, c=30, d=40, f=110
              domain.Update(0.01f);
              Assert.AreEqual(1, domain.GetContacts(ray).Count());
              Assert.AreEqual(true, domain.HaveContact(ray, e));
              Assert.AreEqual(false, domain.HaveContact(ray, c));
              Assert.AreEqual(false, domain.HaveContact(ray, gNotInDomain));
              Assert.IsNull(domain.GetContacts(ray, gNotInDomain));
        }
Example #42
0
        public void RayCastStopsAtFirstHitWhenChangingFilter()
        {
            CollisionDomain domain = new CollisionDomain(new CollisionDetection());
              domain.CollisionDetection.CollisionFilter = new CollisionFilter();

              // 1 ray: at origin shooting into +x
              CollisionObject ray = new CollisionObject();
              ((GeometricObject)ray.GeometricObject).Shape = new RayShape(new Vector3F(), new Vector3F(1, 0, 0), 100)
              {
            StopsAtFirstHit = true,
              };
              //ray.Name = "Ray";

              // 2 spheres: at at x=10, b at x=20
              CollisionObject a = new CollisionObject();
              ((GeometricObject)a.GeometricObject).Shape = new SphereShape(1);
              ((GeometricObject)a.GeometricObject).Pose = new Pose(new Vector3F(10, 0, 0f));
              //a.Name = "b";
              CollisionObject b = new CollisionObject();
              ((GeometricObject)b.GeometricObject).Shape = new SphereShape(1);
              ((GeometricObject)b.GeometricObject).Pose = new Pose(new Vector3F(20, 0, 0f));
              //b.Name = "c";

              domain.CollisionObjects.Add(ray);
              domain.CollisionObjects.Add(a);
              domain.CollisionObjects.Add(b);

              // Ray touches b.
              domain.Update(0.01f);
              Assert.AreEqual(1, domain.GetContacts(ray).Count());
              Assert.AreEqual(true, domain.HaveContact(ray, a));
              Assert.AreEqual(false, domain.HaveContact(ray, b));

              // Disable collisions between ray and a.
              // Then ray must hit b.
              ((CollisionFilter)domain.CollisionDetection.CollisionFilter).Set(ray, a, false);
              domain.Update(0.01f);
              Assert.AreEqual(1, domain.GetContacts(ray).Count());
              Assert.AreEqual(false, domain.HaveContact(ray, a));
              Assert.AreEqual(true, domain.HaveContact(ray, b));
        }
Example #43
0
        public void Test1()
        {
            Assert.NotNull(new CollisionDomain().CollisionDetection);
              Assert.NotNull(new CollisionDomain(null).CollisionDetection);

              CollisionDomain cd = new CollisionDomain(new CollisionDetection());
              CollisionObject a = new CollisionObject();
              ((GeometricObject)a.GeometricObject).Shape = new SphereShape(1);
              ((GeometricObject)a.GeometricObject).Pose = new Pose(new Vector3F(0, 0, 0));
              //a.Name = "a";

              CollisionObject b = new CollisionObject();
              ((GeometricObject)b.GeometricObject).Shape = new SphereShape(1);
              ((GeometricObject)b.GeometricObject).Pose = new Pose(new Vector3F(4, 0, 2f));
              //b.Name = "b";

              CollisionObject c = new CollisionObject();
              ((GeometricObject)c.GeometricObject).Shape = new SphereShape(1);
              ((GeometricObject)c.GeometricObject).Pose = new Pose(new Vector3F(6, 2, 2f));
              //c.Name = "c";

              CollisionObject d = new CollisionObject();
              ((GeometricObject)d.GeometricObject).Shape = new SphereShape(1);
              ((GeometricObject)d.GeometricObject).Pose = new Pose(new Vector3F(8, 3f, 4f));
              //d.Name = "d";

              Assert.AreEqual(0, cd.CollisionObjects.Count);

              cd.CollisionObjects.Add(a);
              Assert.AreEqual(1, cd.CollisionObjects.Count);

              cd.CollisionObjects.Add(b);
              Assert.AreEqual(2, cd.CollisionObjects.Count);

              cd.CollisionObjects.Add(c);
              Assert.AreEqual(3, cd.CollisionObjects.Count);

              cd.CollisionObjects.Add(d);
              Assert.AreEqual(4, cd.CollisionObjects.Count);

              cd.Update(0.01f);
              Assert.AreEqual(0, cd.ContactSets.Count);

              ((GeometricObject)a.GeometricObject).Pose = new Pose(((GeometricObject)a.GeometricObject).Pose.Position + new Vector3F(3.5f, 0, 0.5f));
              cd.Update(0.01f);
              Assert.AreEqual(1, cd.ContactSets.Count);

              ((GeometricObject)c.GeometricObject).Pose = new Pose(((GeometricObject)c.GeometricObject).Pose.Position + new Vector3F(2, 1, 0));
              cd.Update(0.01f);
              Assert.AreEqual(2, cd.ContactSets.Count);

              ((GeometricObject)a.GeometricObject).Pose = new Pose(((GeometricObject)a.GeometricObject).Pose.Position + new Vector3F(3, 0, 0));
              ((GeometricObject)b.GeometricObject).Pose = new Pose(((GeometricObject)b.GeometricObject).Pose.Position + new Vector3F(2, 0, 0));
              cd.Update(0.01f);
              Assert.AreEqual(2, cd.ContactSets.Count);

              ((GeometricObject)d.GeometricObject).Pose = new Pose(((GeometricObject)d.GeometricObject).Pose.Position + new Vector3F(-0.5f, 0, 0));
              ((GeometricObject)b.GeometricObject).Pose = new Pose(((GeometricObject)b.GeometricObject).Pose.Position + new Vector3F(0, 1, 0));
              cd.Update(0.01f);
              Assert.AreEqual(1, cd.ContactSets.Count);

              ((GeometricObject)a.GeometricObject).Pose = new Pose(new Vector3F(0, 0, 0));
              ((GeometricObject)b.GeometricObject).Pose = new Pose(new Vector3F(0, 0, 0));
              ((GeometricObject)c.GeometricObject).Pose = new Pose(new Vector3F(1, 0, 1));
              ((GeometricObject)d.GeometricObject).Pose = new Pose(new Vector3F(0, 1, 0));
              cd.Update(0.01f);
              Assert.AreEqual(6, cd.ContactSets.Count);
        }
Example #44
0
        public void Test3()
        {
            CollisionDomain domain = new CollisionDomain(new CollisionDetection());

              RandomHelper.Random = new Random(123456);

              const float testAreaSize = 20;

              // Add 100 random objects.
              for (int i = 0; i < 100; i++)
            domain.CollisionObjects.Add(new CollisionObject(new GeometricObject(new SphereShape(1), new Pose(RandomHelper.Random.NextVector3F(0, testAreaSize)))));

              for (int i = 0; i < 100; i++)
              {
            domain.Update(0.03f);

            for (int j = 0; j < domain.CollisionObjects.Count; j++)
            {
              var a = domain.CollisionObjects[j];

              for (int k = j + 1; k < domain.CollisionObjects.Count; k++)
              {
            var b = domain.CollisionObjects[k];

            bool contained = domain.InternalBroadPhase.CandidatePairs.Contains(a, b);
            bool haveContact = GeometryHelper.HaveContact(a.GeometricObject.Aabb, b.GeometricObject.Aabb);
            //if (contained != haveContact)
              //Debugger.Break();
            Assert.AreEqual(contained, haveContact);
              }

              // Set new random position for a few.
              if (RandomHelper.Random.NextFloat(0, 1) < 0.7f)
            ((GeometricObject)a.GeometricObject).Pose = new Pose(RandomHelper.Random.NextVector3F(0, testAreaSize));
            }

            // Add new object.
            domain.CollisionObjects.Add(new CollisionObject
            {
              GeometricObject = new GeometricObject
              {
            Shape = new SphereShape(1),
            Pose = new Pose(RandomHelper.Random.NextVector3F(0, testAreaSize)),
              }
            });

            // Remove random object.
            domain.CollisionObjects.Remove(domain.CollisionObjects[RandomHelper.Random.NextInteger(0, domain.CollisionObjects.Count - 1)]);

            Console.WriteLine("Candidate pairs: " + domain.InternalBroadPhase.CandidatePairs.Count);
              }
        }
Example #45
0
        public void TestEnabledDisabled()
        {
            var shape = new SphereShape(1);
              var goA = new GeometricObject(shape, Pose.Identity);
              var coA = new CollisionObject(goA);

              var goB = new GeometricObject(shape, Pose.Identity);
              var coB = new CollisionObject(goB);

              var cd = new CollisionDomain(new CollisionDetection());

              cd.CollisionObjects.Add(coA);
              cd.CollisionObjects.Add(coB);

              // not touching
              goB.Pose = new Pose(new Vector3F(3, 3, 0));
              cd.Update(0);
              Assert.AreEqual(0, cd.ContactSets.Count);

              // not touching, disabled
              coB.Enabled = false;
              cd.Update(0);
              Assert.AreEqual(0, cd.ContactSets.Count);

              // touching, disabled
              goB.Pose = new Pose(new Vector3F(1, 1, 1));
              cd.Update(0);
              Assert.AreEqual(0, cd.ContactSets.Count);

              // touching, enabled
              coB.Enabled = true;
              cd.Update(0);
              Assert.AreEqual(1, cd.ContactSets.Count);

              // not touching - but broadphase overlap, enabled
              goB.Pose = new Pose(new Vector3F(1.8f, 1.8f, 0));
              cd.Update(0);
              Assert.AreEqual(0, cd.ContactSets.Count);

              // not touching, disabled
              coB.Enabled = false;
              cd.Update(0);
              Assert.AreEqual(0, cd.ContactSets.Count);

              // touching, disabled
              goB.Pose = new Pose(new Vector3F(1, 1, 1));
              cd.Update(0);
              Assert.AreEqual(0, cd.ContactSets.Count);

              // touching, enabled
              coB.Enabled = true;
              cd.Update(0);
              Assert.AreEqual(1, cd.ContactSets.Count);
        }
Example #46
0
 public void ToStringTest()
 {
     CollisionDomain cd = new CollisionDomain(new CollisionDetection());
       cd.CollisionObjects.Add(new CollisionObject());
       cd.CollisionObjects.Add(new CollisionObject());
       Assert.AreEqual("CollisionDomain { Count = 2 }", cd.ToString());
 }
Example #47
0
        public void UpdateSingle()
        {
            CollisionDomain domain = new CollisionDomain(new CollisionDetection());

              // Add 100 random objects.
              for (int i = 0; i < 100; i++)
            domain.CollisionObjects.Add(new CollisionObject(new GeometricObject(new SphereShape(1), new Pose(RandomHelper.Random.NextVector3F(0, 20)))));

              for (int i = 0; i < 100; i++)
              {
            domain.Update(domain.CollisionObjects[33]);

            for (int j = 0; j < domain.CollisionObjects.Count; j++)
            {
              var a = domain.CollisionObjects[j];

              for (int k = j + 1; k < domain.CollisionObjects.Count; k++)
              {
            var b = domain.CollisionObjects[k];

            Assert.AreEqual(domain.InternalBroadPhase.CandidatePairs.Contains(a, b),
                            GeometryHelper.HaveContact(a.GeometricObject.Aabb, b.GeometricObject.Aabb));
              }
            }

            // Set new random position for one.
            ((GeometricObject)domain.CollisionObjects[33].GeometricObject).Pose = new Pose(RandomHelper.Random.NextVector3F(0, 20));

            Console.WriteLine("Candidate pairs: " + domain.InternalBroadPhase.CandidatePairs.Count);
              }
        }
Example #48
0
 /// <summary>
 /// Resets the collision object. (For internal use only.)
 /// </summary>
 internal void ResetInternal()
 {
     Changed = true;
       CollisionGroup = 0;
       _domain = null;
       Enabled = true;
       _geometricObject = null;
       _type = CollisionObjectType.Default;
       _shapeType = ShapeType.Default;
       _shape = null;
       ShapeTypeChanged = true;
 }
Example #49
0
    // 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);
    }
Example #50
0
 // The following methods are used internally by the collision detection to make direct
 // changes to a CollisionObject during collision checks.
 /// <summary>
 /// Copies the data from the specified <see cref="CollisionObject"/> and sets the specified
 /// <see cref="IGeometricObject"/>. (For internal use only.)
 /// </summary>
 /// <param name="collisionObject">The collision object.</param>
 /// <param name="geometricObject">The geometric object.</param>
 internal void SetInternal(CollisionObject collisionObject, IGeometricObject geometricObject)
 {
     Changed = collisionObject.Changed;
       CollisionGroup = collisionObject.CollisionGroup;
       _domain = collisionObject._domain;
       Enabled = collisionObject.Enabled;
       _geometricObject = geometricObject;
       _type = collisionObject._type;
       _shapeType = collisionObject._shapeType;
       _shape = geometricObject.Shape;
       ShapeTypeChanged = collisionObject.ShapeTypeChanged;
 }
Example #51
0
        public void ValidateInvalidScaleChange()
        {
            GlobalSettings.ValidationLevel = 0xff;

              CollisionDomain cd = new CollisionDomain(new CollisionDetection());
              var shape = new SphereShape(1);
              var geometricObject = new GeometricObject(shape, Pose.Identity);
              var co = new CollisionObject(geometricObject);

              cd.CollisionObjects.Add(co);
              Assert.Throws<GeometryException>(() => geometricObject.Scale = new Vector3F(1, 1, float.NaN));
        }
Example #52
0
        public void ValidateInvalidPoseChange()
        {
            GlobalSettings.ValidationLevel = 0xff;

              CollisionDomain cd = new CollisionDomain(new CollisionDetection());
              var shape = new SphereShape(1);
              var geometricObject = new GeometricObject(shape, Pose.Identity);
              var co = new CollisionObject(geometricObject);

              cd.CollisionObjects.Add(co);

              var matrix = Matrix33F.Identity;
              matrix.M11 = float.NaN;
              Assert.Throws<GeometryException>(() => geometricObject.Pose = new Pose(new Vector3F(), matrix));
        }
Example #53
0
        public PickingSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            SampleFramework.IsMouseVisible = false;
            GraphicsScreen.ClearBackground = true;
            GraphicsScreen.BackgroundColor = Color.CornflowerBlue;
            GraphicsScreen.DrawReticle     = true;
            SetCamera(new Vector3(0, 1, 10), 0, 0);

            // ----- Initialize collision detection system.
            // We use one collision domain that manages all objects.
            _domain = new CollisionDomain
            {
                // Optional: Change the broad phase type. The default type is the SweepAndPruneSpace,
                // which is very fast for physics simulation. The DualPartition is better for ray casts.
                // See also http://digitalrune.github.io/DigitalRune-Documentation/html/e32cab3b-cc7c-42ee-8ec9-23dd4467edd0.htm#WhichPartition
                BroadPhase = new DualPartition <CollisionObject>(),
            };

            // Optional: Set a broad phase filter.
            // Per default, the collision domain computes contacts between all collision objects. If we
            // are only interested in ray vs non-ray-shape contacts, we can set a filter to avoid
            // unnecessary intersection computations and improve performance.
            _domain.BroadPhase.Filter = new DelegatePairFilter <CollisionObject>(
                pair =>
            {
                var firstIsRay  = pair.First.GeometricObject.Shape is RayShape;
                var secondIsRay = pair.Second.GeometricObject.Shape is RayShape;
                return(firstIsRay != secondIsRay);
            });

            // Create a collision object with a box shape at position (0, 0, 0) with a random rotation.
            _box = new CollisionObject(
                new GeometricObject(
                    new BoxShape(1, 2, 3),
                    new Pose(new Vector3(0, 0, 0), RandomHelper.Random.NextQuaternion())));

            // Create a collision object with a sphere shape at position (-5, 0, 0).
            _sphere = new CollisionObject(new GeometricObject(new SphereShape(1), new Pose(new Vector3(-5, 0, 0))));

            // Create a random list of points.
            var points = new List <Vector3>();

            for (int i = 0; i < 100; i++)
            {
                points.Add(RandomHelper.Random.NextVector3(-1.5f, 1.5f));
            }

            // Create a triangle mesh of the convex hull.
            // (See also the ConvexHullSample for info on convex hull creation.)
            TriangleMesh triangleMesh = GeometryHelper.CreateConvexHull(points).ToTriangleMesh();

            // We use this random triangle mesh to define a shape.
            TriangleMeshShape meshShape = new TriangleMeshShape(triangleMesh);

            // Optional: We can use a spatial partitioning method, to speed up collision
            // detection for large meshes. AABB trees are good for static triangle meshes.
            // To use spatial partitioning we have to set a valid spatial partition instance
            // in the Partition property.
            // The spatial partition will store indices of the mesh triangles, therefore
            // the generic type argument is "int".
            meshShape.Partition = new AabbTree <int>()
            {
                // 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: Build the AABB tree. (This is done automatically when the AABB tree is used for
            // the first time, but Update can also be called explicitly to control when the tree is built.)
            meshShape.Partition.Update(false);


            // Create a collision object with the random triangle mesh shape.
            _mesh = new CollisionObject(new GeometricObject(meshShape, new Pose(new Vector3(5, 0, 0))));

            // Add collision object to collision domain.
            _domain.CollisionObjects.Add(_box);
            _domain.CollisionObjects.Add(_sphere);
            _domain.CollisionObjects.Add(_mesh);

            // For picking we create a ray.
            // The ray shoot from its local origin in +x direction.
            // (Note: The last parameter is the length of the ray. In theory, rays have
            // an infinite length. However, in the collision detection we use rays with
            // a finite length. This increases the performance and improves the numerical
            // stability of the algorithms.)
            RayShape rayShape = new RayShape(Vector3.Zero, Vector3.Forward, 1000);

            _ray = new CollisionObject(new GeometricObject(rayShape, Pose.Identity));

            // The ray is just one additional collision object in our collision domain.
            _domain.CollisionObjects.Add(_ray);

            // The collision domain manages now 4 objects: a box, a sphere, a triangle mesh and a ray.
        }
Example #54
0
        public void HaveContact()
        {
            CollisionDomain domain = new CollisionDomain(new CollisionDetection());
              domain.CollisionDetection.CollisionFilter = new CollisionFilter();

              CollisionObject a = new CollisionObject();
              ((GeometricObject)a.GeometricObject).Shape = new SphereShape(1);
              ((GeometricObject)a.GeometricObject).Pose = new Pose(new Vector3F(0, 0, 0));
              //a.Name = "a";

              CollisionObject b = new CollisionObject();
              ((GeometricObject)b.GeometricObject).Shape = new SphereShape(1);
              ((GeometricObject)b.GeometricObject).Pose = new Pose(new Vector3F(1, 0, 0f));
              //b.Name = "b";

              CollisionObject c = new CollisionObject();
              ((GeometricObject)c.GeometricObject).Shape = new SphereShape(1);
              ((GeometricObject)c.GeometricObject).Pose = new Pose(new Vector3F(1, 0, 0f));
              //c.Name = "c";

              domain.CollisionObjects.Add(a);
              domain.CollisionObjects.Add(b);
              domain.Update(0.01f);
              Assert.AreEqual(true, domain.HaveContact(a, b));
              Assert.AreEqual(true, domain.HaveContact(a, c));
              Assert.AreEqual(true, domain.HasContact(a));
              Assert.AreEqual(true, domain.HasContact(b));
              Assert.AreEqual(true, domain.HasContact(c));
              Assert.AreEqual(1, domain.GetContacts(a, b).Count);
              Assert.AreEqual(1, domain.GetContacts(a, c).Count);
              Assert.AreEqual(1, domain.GetContacts(a).Count());
              Assert.AreEqual(2, domain.GetContacts(c).Count());
              Assert.AreEqual(1, domain.ContactSets.Count);

              b.Enabled = false;
              domain.Update(0.01f);
              Assert.AreEqual(false, domain.HaveContact(a, b));
              Assert.AreEqual(true, domain.HaveContact(a, c));
              Assert.AreEqual(false, domain.HasContact(a));
              Assert.AreEqual(false, domain.HasContact(b));
              Assert.AreEqual(true, domain.HasContact(c));
              Assert.AreEqual(null, domain.GetContacts(a, b));
              Assert.AreEqual(1, domain.GetContacts(a, c).Count);
              Assert.AreEqual(0, domain.GetContacts(a).Count());
              Assert.AreEqual(1, domain.GetContacts(c).Count());
              Assert.AreEqual(0, domain.ContactSets.Count);

              a.Enabled = false;
              b.Enabled = true;
              domain.Update(0.01f);
              Assert.AreEqual(false, domain.HaveContact(a, b));
              Assert.AreEqual(false, domain.HaveContact(a, c));
              Assert.AreEqual(false, domain.HasContact(a));
              Assert.AreEqual(false, domain.HasContact(b));
              Assert.AreEqual(true, domain.HasContact(c));
              Assert.AreEqual(null, domain.GetContacts(a, b));
              Assert.AreEqual(null, domain.GetContacts(a, c));
              Assert.AreEqual(0, domain.GetContacts(a).Count());
              Assert.AreEqual(1, domain.GetContacts(c).Count());
              Assert.AreEqual(0, domain.ContactSets.Count);

              c.Enabled = false;
              domain.Update(0.01f);
              Assert.AreEqual(false, domain.HaveContact(a, b));
              Assert.AreEqual(false, domain.HaveContact(a, c));
              Assert.AreEqual(false, domain.HasContact(a));
              Assert.AreEqual(false, domain.HasContact(b));
              Assert.AreEqual(false, domain.HasContact(c));
              Assert.AreEqual(null, domain.GetContacts(a, b));
              Assert.AreEqual(null, domain.GetContacts(a, c));
              Assert.AreEqual(0, domain.GetContacts(a).Count());
              Assert.AreEqual(0, domain.GetContacts(c).Count());
              Assert.AreEqual(0, domain.ContactSets.Count);

              a.Enabled = true;
              c.Enabled = true;
              ((CollisionFilter) domain.CollisionDetection.CollisionFilter).Set(a, b, false);
              domain.Update(0.01f);
              Assert.AreEqual(false, domain.HaveContact(a, b));
              Assert.AreEqual(true, domain.HaveContact(a, c));
              Assert.AreEqual(false, domain.HasContact(a));
              Assert.AreEqual(false, domain.HasContact(b));
              Assert.AreEqual(true, domain.HasContact(c));
              Assert.AreEqual(null, domain.GetContacts(a, b));
              Assert.AreEqual(1, domain.GetContacts(a, c).Count);
              Assert.AreEqual(0, domain.GetContacts(a).Count());
              Assert.AreEqual(2, domain.GetContacts(c).Count());
              Assert.AreEqual(0, domain.ContactSets.Count);

              ((CollisionFilter) domain.CollisionDetection.CollisionFilter).Set(a, b, true);
              domain.Update(0.01f);
              Assert.AreEqual(true, domain.HaveContact(a, b));
              Assert.AreEqual(true, domain.HaveContact(a, c));
              Assert.AreEqual(true, domain.HasContact(a));
              Assert.AreEqual(true, domain.HasContact(b));
              Assert.AreEqual(true, domain.HasContact(c));
              Assert.AreEqual(1, domain.GetContacts(a, b).Count);
              Assert.AreEqual(1, domain.GetContacts(a, c).Count);
              Assert.AreEqual(1, domain.GetContacts(a).Count());
              Assert.AreEqual(2, domain.GetContacts(c).Count());
              Assert.AreEqual(1, domain.ContactSets.Count);

              c.Enabled = false;
              domain.Update(0.01f);
              Assert.AreEqual(true, domain.HaveContact(a, b));
              Assert.AreEqual(false, domain.HaveContact(a, c));
              Assert.AreEqual(true, domain.HasContact(a));
              Assert.AreEqual(true, domain.HasContact(b));
              Assert.AreEqual(false, domain.HasContact(c));
              Assert.AreEqual(1, domain.GetContacts(a, b).Count);
              Assert.AreEqual(null, domain.GetContacts(a, c));
              Assert.AreEqual(1, domain.GetContacts(a).Count());
              Assert.AreEqual(0, domain.GetContacts(c).Count());
              Assert.AreEqual(1, domain.ContactSets.Count);
        }
        public FigurePickerObject(IGraphicsService graphicsService, Scene scene, CameraObject cameraObject, DebugRenderer debugRenderer)
        {
            _cameraObject  = cameraObject;
            _scene         = scene;
            _debugRenderer = debugRenderer;

            // Create a collision domain which manages all collision objects used for
            // picking: the picking object and the collision objects for figure nodes.
            _collisionDomain = new CollisionDomain(new CollisionDetection());

            // Create the picking object:
            // The picking object represents the mouse cursor or the reticle. Usually
            // a ray is used, but in this example we want to use a cylinder/cone. This
            // allows to check which objects within a certain radius of the reticle. A
            // picking cylinder/cone is helpful for touch devices where the picking is
            // done with an imprecise input method like the human finger.

            // We want to pick objects in 10 pixel radius around the reticle. To determine
            // the world space size of the required cylinder/cone, we can use the projection
            // and the viewport.
            const float pickingRadius = 10;
            var         projection    = _cameraObject.CameraNode.Camera.Projection;
            var         viewport      = graphicsService.GraphicsDevice.Viewport;

            Shape pickingShape;

            if (projection is OrthographicProjection)
            {
                // Use cylinder for orthographic projections:
                // The cylinder is centered at the camera position and reaches from the
                // camera position to the camera far plane. A TransformedShape is used
                // to rotate and translate the cylinder.
                float radius = projection.Width / viewport.Width * pickingRadius;
                pickingShape = new TransformedShape(
                    new GeometricObject(
                        new CylinderShape(radius, projection.Far),
                        new Pose(new Vector3F(0, 0, -projection.Far / 2), Matrix33F.CreateRotationX(ConstantsF.PiOver2))));
            }
            else
            {
                // Use cone for perspective projections:
                // The cone tip is at the camera position and the cone base is at the
                // camera far plane.

                // Compute the radius at the far plane that projects to 10 pixels in screen space.
                float radius = viewport.Unproject(
                    new Vector3(viewport.Width / 2.0f + pickingRadius, viewport.Height / 2.0f, 1),
                    (Matrix)_cameraObject.CameraNode.Camera.Projection.ToMatrix44F(),
                    Matrix.Identity,
                    Matrix.Identity).X;

                // A transformed shape is used to rotate and translate the cone.
                pickingShape = new TransformedShape(
                    new GeometricObject(
                        new ConeShape(radius, projection.Far),
                        new Pose(new Vector3F(0, 0, -projection.Far), Matrix33F.CreateRotationX(ConstantsF.PiOver2))));
            }

            // Create collision object with the picking shape.
            _pickingObject = new CollisionObject(new GeometricObject(pickingShape, _cameraObject.CameraNode.PoseWorld));
        }
Example #56
0
        public void ValidateNewObjectWithInvalidShape()
        {
            GlobalSettings.ValidationLevel = 0xff;

              CollisionDomain cd = new CollisionDomain(new CollisionDetection());
              var shape = new SphereShape(1);
              var geometricObject = new GeometricObject(shape, Pose.Identity);
              var co = new CollisionObject(geometricObject);

              shape.Radius = float.NaN;
              Assert.Throws<GeometryException>(() => cd.CollisionObjects.Add(co));
        }
        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 top-down camera.
            GraphicsScreen.CameraNode = _topDownCameraNode;

            // 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.");
        }
Example #58
0
    //--------------------------------------------------------------
    #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);
    }
Example #59
0
        public void TestEnabledDisabledStochastic()
        {
            // Test random Enabled and Pose values.

              int numberOfObjects = 20;
              int numberOfSteps = 1000;

              Shape shape = new SphereShape(1);
              //var meshShape = new TriangleMeshShape(shape.GetMesh(0.01f, 4));
              //meshShape.Partition = new AabbTree<int>();
              //shape = meshShape;

              var geometricObjects = new GeometricObject[numberOfObjects];
              var collisionObjects = new CollisionObject[numberOfObjects];

              var domain = new CollisionDomain(new CollisionDetection());

              for (int i = 0; i < numberOfObjects; i++)
              {
            geometricObjects[i] = new GeometricObject(shape);
            collisionObjects[i] = new CollisionObject(geometricObjects[i]);
            domain.CollisionObjects.Add(collisionObjects[i]);
              }

              for (int i = 0; i < numberOfSteps; i++)
              {
            for (int j = 0; j < numberOfObjects; j++)
            {
              collisionObjects[j].Enabled = RandomHelper.Random.NextBool();

              domain.Update(0);

              if (RandomHelper.Random.NextFloat(0, 1) > 0.5f)
            geometricObjects[j].Pose = new Pose(RandomHelper.Random.NextVector3F(-2, 2));

              domain.Update(0);
            }

            domain.Update(0);
            domain.Update(0);
            domain.Update(0);
            domain.Update(0);
            domain.Update(0);
            domain.Update(0);
            domain.Update(0);

            // Compare result with brute-force check.
            for (int j = 0; j < numberOfObjects; j++)
            {
              for (int k = j + 1; k < numberOfObjects; k++)
              {
            var haveContact = domain.CollisionDetection.HaveContact(collisionObjects[j], collisionObjects[k]);
            Assert.AreEqual(haveContact, domain.ContactSets.GetContacts(collisionObjects[j], collisionObjects[k]) != null);
              }
            }
              }
        }
Example #60
0
    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);
    }