Beispiel #1
0
        //--------------------------------------------------------------
        /// <summary>
        /// Initializes a new instance of the <see cref="Wheel"/> class.
        /// </summary>
        public Wheel()
        {
            Radius = 0.4f;
              SuspensionRestLength = 0.6f;
              MinSuspensionLength = float.NegativeInfinity;
              SuspensionLength = SuspensionRestLength;
              PreviousSuspensionLength = SuspensionRestLength;
              SuspensionStiffness = 20;
              SuspensionCompressionDamping = 4f;
              SuspensionRelaxationDamping = 3f;
              MaxSuspensionForce = 6000;
              RollingFrictionForce = 500;
              Friction = 0.9f;
              RollReduction = 0.3f;

              Vector3F rayOrigin = Vector3F.Zero;
              Vector3F rayDirection = -Vector3F.UnitY;
              float rayLength = Radius + SuspensionRestLength;
              Ray = new RayShape(rayOrigin, rayDirection, rayLength)
              {
            StopsAtFirstHit = true,
              };
              GeometricObject = new GeometricObject(Ray);
              CollisionObject = new CollisionObject(GeometricObject);
        }
Beispiel #2
0
    protected override void OnLoad()
    {
      var contentManager = _services.GetInstance<ContentManager>();

      // ----- Graphics
      // Load a graphics model and add it to the scene for rendering.
      _modelNode = contentManager.Load<ModelNode>("Ship/Ship").Clone();
      _modelNode.PoseWorld = new Pose(Vector3F.Zero, Matrix33F.CreateRotationY(-ConstantsF.PiOver2));

      var scene = _services.GetInstance<IScene>();
      scene.Children.Add(_modelNode);

      // ----- Collision Detection
      // Create a collision object and add it to the collision domain.

      // Load collision shape from a separate model (created using the CollisionShapeProcessor).
      var shape = contentManager.Load<Shape>("Ship/Ship_CollisionModel");

      // Create a GeometricObject (= Shape + Pose + Scale).
      _geometricObject = new GeometricObject(shape, _modelNode.PoseWorld);

      // Create a collision object and add it to the collision domain.
      _collisionObject = new CollisionObject(_geometricObject);

      // Important: We do not need detailed contact information when a collision
      // is detected. The information of whether we have contact or not is sufficient.
      // Therefore, we can set the type to "Trigger". This increases the performance 
      // dramatically.
      _collisionObject.Type = CollisionObjectType.Trigger;

      // Add the collision object to the collision domain of the game.
      var collisionDomain = _services.GetInstance<CollisionDomain>();
      collisionDomain.CollisionObjects.Add(_collisionObject);
    }
Beispiel #3
0
    protected override void OnLoad()
    {
      var contentManager = _services.GetInstance<ContentManager>();

      // ----- Graphics
      // Load graphics model (created using the ModelWithCollisionMeshProcessor).
      var sharedModelNode = contentManager.Load<ModelNode>("Saucer/saucer");

      // Let's create a clone because we do not want to change the shared Saucer 
      // instance stored in the content manager.
      _modelNode = sharedModelNode.Clone();

      _modelNode.PoseWorld = new Pose(Vector3F.Zero, Matrix33F.CreateRotationY(-ConstantsF.PiOver2));

      // The collision shape is stored in the UserData.
      var shape = (Shape)_modelNode.UserData;

      // Add model to the scene for rendering.
      var scene = _services.GetInstance<IScene>();
      scene.Children.Add(_modelNode);

      // ----- Collision Detection
      // Create a collision object and add it to the collision domain.
      _geometricObject = new GeometricObject(shape, _modelNode.PoseWorld);
      _collisionObject = new CollisionObject(_geometricObject);

      // Important: We do not need detailed contact information when a collision
      // is detected. The information of whether we have contact or not is sufficient.
      // Therefore, we can set the type to "Trigger". This increases the performance 
      // dramatically.
      _collisionObject.Type = CollisionObjectType.Trigger;

      var collisionDomain = _services.GetInstance<CollisionDomain>();
      collisionDomain.CollisionObjects.Add(_collisionObject);
    }
Beispiel #4
0
    public DumpContactSetSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      GraphicsScreen.ClearBackground = true;

      // Create two collision objects with triangle mesh shapes.
      var meshA = new SphereShape(1).GetMesh(0.01f, 4);
      var shapeA = new TriangleMeshShape(meshA, true) { Partition = new CompressedAabbTree() };
      var poseA = new Pose(new Vector3F(-1, 0, 0), RandomHelper.Random.NextQuaternionF());
      var collisionObjectA = new CollisionObject(new GeometricObject(shapeA, poseA));

      var meshB = new BoxShape(0.2f, 2, 1f).GetMesh(0.01f, 4);
      var shapeB = new TriangleMeshShape(meshB, true) { Partition = new CompressedAabbTree() };
      var poseB = new Pose(new Vector3F(0.1f, 0, 0), RandomHelper.Random.NextQuaternionF());
      var collisionObjectB = new CollisionObject(new GeometricObject(shapeB, poseB));

      // Explicitly create a contact set. (Normally you would get the contact set
      // from the collision domain...)
      var contactSet = ContactSet.Create(collisionObjectA, collisionObjectB);

      // Create a C# sample which visualizes the contact set.
      const string Filename = "DumpedContactSet001.cs";
      DumpContactSet(contactSet, Filename);

      GraphicsScreen.DebugRenderer2D.DrawText(
        "Contact set dumped into the file: " + Filename, 
        new Vector2F(300, 300), 
        Color.Black);
    }
Beispiel #5
0
        public static Contact CreateContact(CollisionObject objectA,
            CollisionObject objectB,
            Vector3F position,
            Vector3F normal,
            float penetrationDepth,
            bool isRayHit)
        {
            Debug.Assert(objectA != null);
              Debug.Assert(objectB != null);

              Contact contact = Contact.Create();
              contact.Position = position;
              contact.Normal = normal;
              contact.PenetrationDepth = penetrationDepth;
              contact.IsRayHit = isRayHit;

              if (isRayHit)
              {
            contact.PositionALocal = objectA.GeometricObject.Pose.ToLocalPosition(position);
            contact.PositionBLocal = objectB.GeometricObject.Pose.ToLocalPosition(position);
              }
              else
              {
            //Vector3F halfPenetration = normal * (penetrationDepth / 2);
            //contact.PositionALocal = objectA.GeometricObject.Pose.ToLocalPosition(position + halfPenetration);
            //contact.PositionBLocal = objectB.GeometricObject.Pose.ToLocalPosition(position - halfPenetration);

            // ----- Optimized version:
            float halfPenetration = penetrationDepth / 2;
            Vector3F halfPenetrationVector;
            halfPenetrationVector.X = normal.X * halfPenetration;
            halfPenetrationVector.Y = normal.Y * halfPenetration;
            halfPenetrationVector.Z = normal.Z * halfPenetration;

            var poseA = objectA.GeometricObject.Pose;
            Vector3F diffA;
            diffA.X = position.X + halfPenetrationVector.X - poseA.Position.X;
            diffA.Y = position.Y + halfPenetrationVector.Y - poseA.Position.Y;
            diffA.Z = position.Z + halfPenetrationVector.Z - poseA.Position.Z;
            Vector3F positionALocal;
            positionALocal.X = poseA.Orientation.M00 * diffA.X + poseA.Orientation.M10 * diffA.Y + poseA.Orientation.M20 * diffA.Z;
            positionALocal.Y = poseA.Orientation.M01 * diffA.X + poseA.Orientation.M11 * diffA.Y + poseA.Orientation.M21 * diffA.Z;
            positionALocal.Z = poseA.Orientation.M02 * diffA.X + poseA.Orientation.M12 * diffA.Y + poseA.Orientation.M22 * diffA.Z;
            contact.PositionALocal = positionALocal;

            var poseB = objectB.GeometricObject.Pose;
            Vector3F diffB;
            diffB.X = position.X - halfPenetrationVector.X - poseB.Position.X;
            diffB.Y = position.Y - halfPenetrationVector.Y - poseB.Position.Y;
            diffB.Z = position.Z - halfPenetrationVector.Z - poseB.Position.Z;
            Vector3F positionBLocal;
            positionBLocal.X = poseB.Orientation.M00 * diffB.X + poseB.Orientation.M10 * diffB.Y + poseB.Orientation.M20 * diffB.Z;
            positionBLocal.Y = poseB.Orientation.M01 * diffB.X + poseB.Orientation.M11 * diffB.Y + poseB.Orientation.M21 * diffB.Z;
            positionBLocal.Z = poseB.Orientation.M02 * diffB.X + poseB.Orientation.M12 * diffB.Y + poseB.Orientation.M22 * diffB.Z;
            contact.PositionBLocal = positionBLocal;
              }

              return contact;
        }
Beispiel #6
0
    public override void Update(GameTime gameTime)
    {
      if (InputService.IsPressed(MouseButtons.Left, true) || InputService.IsPressed(Buttons.RightTrigger, true, LogicalPlayerIndex.One))
      {
        var cameraPose = GraphicsScreen.CameraNode.PoseWorld;
        Vector3F cameraPosition = cameraPose.Position;
        Vector3F cameraDirection = cameraPose.ToWorldDirection(Vector3F.Forward);

        // Create a ray for picking.
        RayShape ray = new RayShape(cameraPosition, cameraDirection, 1000);

        // The ray should stop at the first hit. We only want the first object.
        ray.StopsAtFirstHit = true;

        // The collision detection requires a CollisionObject.
        CollisionObject rayCollisionObject = new CollisionObject(new GeometricObject(ray, Pose.Identity));

        // Get the first object that has contact with the ray.
        ContactSet contactSet = Simulation.CollisionDomain.GetContacts(rayCollisionObject).FirstOrDefault();
        if (contactSet != null && contactSet.Count > 0)
        {
          // The ray has hit something.

          // The contact set contains all detected contacts between the ray and the rigid body.
          // Get the first contact in the contact set. (A ray hit usually contains exactly 1 contact.)
          Contact contact = contactSet[0];
          var hitPosition = contact.Position;
          var normal = contact.Normal;
          if (contactSet.ObjectA == rayCollisionObject)
            normal = -normal;

          // The particle parameter arrays are circular buffers. Get the particle array index 
          // where the next particle is created:
          int particleIndex = (_decals.ParticleStartIndex + _decals.NumberOfActiveParticles) % _decals.MaxNumberOfParticles;

          // Add 1 particle.
          int numberOfCreatedParticles = _decals.AddParticles(1, null);
          if (numberOfCreatedParticles > 0)
          {
            // We initialize the particle parameters Position, Normal and Axis manually using
            // the results of the collision detection:
            var positionParameter = _decals.Parameters.Get<Vector3F>(ParticleParameterNames.Position);
            positionParameter.Values[particleIndex] = hitPosition + normal * 0.01f;  // We add a slight 1 cm offset to avoid z-fighting.

            var normalParameter = _decals.Parameters.Get<Vector3F>("Normal");
            normalParameter.Values[particleIndex] = normal;

            var axisParameter = _decals.Parameters.Get<Vector3F>("Axis");
            axisParameter.Values[particleIndex] = (normal == Vector3F.Up) ? Vector3F.Backward : Vector3F.Up;
          }
        }
      }

      // Synchronize particles <-> graphics.
      _particleSystemNode.Synchronize(GraphicsService);

      Profiler.AddValue("ParticleCount", ParticleHelper.CountNumberOfParticles(ParticleSystemService.ParticleSystems));
    }
Beispiel #7
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);
    }
Beispiel #8
0
    public GjkProblemTest(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      SampleFramework.IsMouseVisible = false;
      GraphicsScreen.ClearBackground = true;
      SetCamera(new Vector3F(0, 1, 10), 0, 0);

      var points1a = new List<Vector3F>
      {
                new Vector3F(0.0f, 0.0f, -0.1875f),
                new Vector3F(0.0f, 0.0f, 0.1875f),
                new Vector3F(10.0f, 0.0f, -0.1875f),
                new Vector3F(10.0f, 0.0f, 0.1875f),
                new Vector3F(10.0f, 5.0f, -0.1875f),
                new Vector3F(10.0f, 5.0f, 0.1875f),
                new Vector3F(0.0f, 5.0f, -0.1875f),
                new Vector3F(0.0f, 5.0f, 0.1875f)
            };

      var points1b = new List<Vector3F>
      {
                new Vector3F(0.0f, 0.0f, -0.1875f),
                new Vector3F(10.0f, 0.0f, -0.1875f),
                new Vector3F(10.0f, 5.0f, -0.1875f),
                new Vector3F(0.0f, 5.0f, -0.1875f),
                new Vector3F(0.0f, 0.0f, 0.1875f),
                new Vector3F(10.0f, 0.0f, 0.1875f),
                new Vector3F(10.0f, 5.0f, 0.1875f),
                new Vector3F(0.0f, 5.0f, 0.1875f)
            };

      var matrix1 = new Matrix44F(0.0f, 1.0f, 0.0f, 208.5f, -1.0f, 0.0f, 0.0f, 10.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);

      _part1A = new CollisionObject(new GeometricObject(new ConvexPolyhedron(points1a), Pose.FromMatrix(matrix1)));
      _part1B = new CollisionObject(new GeometricObject(new ConvexPolyhedron(points1b), Pose.FromMatrix(matrix1)));

      var points2 = new List<Vector3F>
      {
                new Vector3F(0.0f, 0.0f, -0.375f),
                new Vector3F(0.0f, 0.0f, 0.375f),
                new Vector3F(23.0f, 0.0f, -0.375f),
                new Vector3F(23.0f, 0.0f, 0.375f),
                new Vector3F(23.0f, 10.0f, -0.375f),
                new Vector3F(23.0f, 10.0f, 0.375f),
                new Vector3F(0.0f, 10.0f, -0.375f),
                new Vector3F(0.0f, 10.0f, 0.375f)
            };

      var matrix2 = new Matrix44F(0.0f, 0.0f, -1.0f, 208.125f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 5.0f, 0.0f, 0.0f, 0.0f, 1.0f);

      _part2 = new CollisionObject(new GeometricObject(new ConvexPolyhedron(points2), Pose.FromMatrix(matrix2)));

    }
Beispiel #9
0
    // OnUpdate() is called once per frame.
    protected override void OnUpdate(TimeSpan deltaTime)
    {
      if (_inputService.IsPressed(MouseButtons.Middle, true) || _inputService.IsPressed(Buttons.RightShoulder, true, LogicalPlayerIndex.One))
      {
        // The user has triggered an explosion.

        // The explosion is created at the position that is targeted with the cross-hair.
        // We can perform a ray hit-test to find the position. The ray starts at the camera
        // position and shoots forward (-z direction).
        var cameraGameObject = (CameraObject)_gameObjectService.Objects["Camera"];
        var cameraNode = cameraGameObject.CameraNode;
        Vector3F cameraPosition = cameraNode.PoseWorld.Position;
        Vector3F cameraDirection = cameraNode.PoseWorld.ToWorldDirection(Vector3F.Forward);

        // Create a ray for hit-testing.
        var ray = new RayShape(cameraPosition, cameraDirection, 1000);

        // The ray should stop at the first hit. We only want the first object.
        ray.StopsAtFirstHit = true;

        // The collision detection requires a CollisionObject.
        var rayCollisionObject = new CollisionObject(new GeometricObject(ray, Pose.Identity))
        {
          // In SampleGame.ResetPhysicsSimulation() a collision filter was set:
          //   CollisionGroup = 0 ... objects that support hit-testing
          //   CollisionGroup = 1 ... objects that are ignored during hit-testing
          //   CollisionGroup = 2 ... objects (rays) for hit-testing
          CollisionGroup = 2,
        };

        // Get the first object that has contact with the ray.
        ContactSet contactSet = _simulation.CollisionDomain.GetContacts(rayCollisionObject).FirstOrDefault();
        if (contactSet != null && contactSet.Count > 0)
        {
          // The ray has hit something.

          // The contact set contains all detected contacts between the ray and another object.
          // Get the first contact in the contact set. (A ray hit usually contains exactly 1 contact.)
          Contact contact = contactSet[0];

          // Create an explosion at the hit position.
          var explosion = new Explosion { Position = contact.Position };
          _simulation.ForceEffects.Add(explosion);

          // Note: The Explosion force effect removes itself automatically from the simulation once 
          // it has finished.
        }
      }
    }
Beispiel #10
0
    public ContinuousCollisionDetectionSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      GraphicsScreen.ClearBackground = true;
      SetCamera(new Vector3F(0, 1, 10), 0, 0);

      // ----- Initialize collision detection and create objects.

      // Create a geometric object with a capsule shape.
      // Position it on the top with an arbitrary rotation.
      _startPoseA = new Pose(new Vector3F(0, 2, 0), Matrix33F.CreateRotationZ(0.1f));
      var geometricObjectA = new GeometricObject(new CapsuleShape(0.2f, 1), _startPoseA);
      _collisionObjectA = new CollisionObject(geometricObjectA);

      // Object A moves to the bottom of the screen.
      _targetPoseA = new Pose(new Vector3F(0, -2, 0), Matrix33F.CreateRotationZ(0.63f));

      // Create a geometric object with a composite shape.
      // Position it on the left with an arbitrary rotation.
      _startPoseB = new Pose(new Vector3F(-3, -1, 0), Matrix33F.CreateRotationZ(0.2f));
      var composite = new CompositeShape();
      composite.Children.Add(new GeometricObject(new BoxShape(0.1f, 1, 0.1f), new Pose(new Vector3F(-0.75f, 0.5f, -0.5f))));
      composite.Children.Add(new GeometricObject(new BoxShape(0.1f, 1, 0.1f), new Pose(new Vector3F(0.75f, 0.5f, -0.5f))));
      composite.Children.Add(new GeometricObject(new BoxShape(0.1f, 1, 0.1f), new Pose(new Vector3F(-0.75f, 0.5f, 0.5f))));
      composite.Children.Add(new GeometricObject(new BoxShape(0.1f, 1, 0.1f), new Pose(new Vector3F(0.75f, 0.5f, 0.5f))));
      composite.Children.Add(new GeometricObject(new BoxShape(1.8f, 0.1f, 1.1f), new Pose(new Vector3F(0, 1f, 0))));
      var geometricObjectB = new GeometricObject(composite, _startPoseB);

      // Object B moves to the left of the screen.
      _targetPoseB = new Pose(new Vector3F(3, -1, 0), Matrix33F.CreateRotationZ(0.3f));

      // Create collision objects for the geometric objects. 
      // (A collision object is just a wrapper around the geometric object that stores additional 
      // information that is required by the collision detection.)
      _collisionObjectA = new CollisionObject(geometricObjectA);
      _collisionObjectB = new CollisionObject(geometricObjectB);

      // Create a collision detection.
      // (The CollisionDetection stores general parameters and it can be used to perform
      // closest-point and contact queries.)
      _collisionDetection = new CollisionDetection();
    }
Beispiel #11
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.
    }
Beispiel #12
0
    /// <summary>
    /// Allows the user to drag a rigid body by using touch.
    /// </summary>
    private void DragBodies()
    {
      // Here is how it works:
      // We first make a hit-test using a ray to check whether the user touches a rigid body.
      // If there is a hit we create a spring (using a ball-socket joint) and connect the rigid
      // body to the touch location. Every time the user moves her finger we update the position
      // of the spring and the spring pulls the rigid body towards the finger.

      // We use raw touch points to select and drag a rigid body.
      TouchCollection touches = InputService.TouchCollection;
      if (touches.Count == 0)
      {
        // No touches detected.
        if (_spring != null)
        {
          // There is an active spring, so the user is currently dragging a rigid body.
          // Release the body by removing the spring.
          _spring.Simulation.Constraints.Remove(_spring);
          _spring = null;
        }
      }
      else
      {
        // Touch detected.
        TouchLocation touchLocation = touches[0];

        // Convert the touch location from screen coordinates to world coordinates.
        var cameraNode = GraphicsScreen.CameraNode;
        Vector3 pScreen = new Vector3(touchLocation.Position.X, touchLocation.Position.Y, 0);
        Vector3 pWorld = GraphicsService.GraphicsDevice.Viewport.Unproject(
          pScreen, 
          cameraNode.Camera.Projection,
          (Matrix)cameraNode.View,
          Matrix.Identity);

        // pWorld is point on the near clip plane of the camera.
        // Set the origin and direction of the ray for hit-testing.
        Vector3F rayOrigin = _cameraPosition;
        Vector3F rayDirection = ((Vector3F)pWorld - _cameraPosition).Normalized;

        if (touchLocation.State == TouchLocationState.Pressed)
        {
          // Let's create a ray and see if we hit a rigid body.
          // (Create the ray shape and the required collision object only once.)
          if (_rayShape == null)
          {
            _rayShape = new RayShape { StopsAtFirstHit = true };
            _rayCollisionObject = new CollisionObject(new GeometricObject(_rayShape));
          }

          // Set the origin and direction of the ray.
          _rayShape.Origin = rayOrigin;
          _rayShape.Direction = rayDirection.Normalized;

          // Make a hit test using the collision detection and get the first contact found.
          var contactSet = Simulation.CollisionDomain
                                     .GetContacts(_rayCollisionObject)
                                     .FirstOrDefault();
          if (contactSet != null && contactSet.Count > 0)
          {
            // Get the point where the ray hits the rigid body.
            Contact contact = contactSet[0];

            // The contact sets contains two objects ("ObjectA" and "ObjectB"). 
            // One is the ray the other is the object that was hit by the ray.
            var hitCollisionObject = (contactSet.ObjectA == _rayCollisionObject)
                                       ? contactSet.ObjectB
                                       : contactSet.ObjectA;

            // Check whether the object is a dynamic rigid body.
            var hitBody = hitCollisionObject.GeometricObject as RigidBody;
            if (hitBody != null && hitBody.MotionType == MotionType.Dynamic)
            {
              // Remove the old joint, in case a rigid body is already grabbed.
              if (_spring != null && _spring.Simulation != null)
                _spring.Simulation.Constraints.Remove(_spring);

              // The penetration depth tells us the distance from the ray origin to the rigid body
              // in view direction.
              _springAnchorDistanceFromCamera = contact.PenetrationDepth;

              // Get the position where the ray hits the other object.
              // (The position is defined in the local space of the object.)
              Vector3F hitPositionLocal = (contactSet.ObjectA == _rayCollisionObject)
                                            ? contact.PositionBLocal
                                            : contact.PositionALocal;

              // Attach the rigid body at the touch location using a ball-socket joint.
              // (Note: We could also use a FixedJoint, if we don't want any rotations.)
              _spring = new BallJoint
              {
                BodyA = hitBody,
                AnchorPositionALocal = hitPositionLocal,

                // We need to attach the grabbed object to a second body. In this case we just want to 
                // anchor the object at a specific point in the world. To achieve this we can use the 
                // special rigid body "World", which is defined in the simulation.
                BodyB = Simulation.World,
                AnchorPositionBLocal = rayOrigin + rayDirection * _springAnchorDistanceFromCamera,

                // Some constraint adjustments.
                ErrorReduction = 0.3f,

                // We set a softness > 0. This makes the joint "soft" and it will act like 
                // damped spring. 
                Softness = 0.00001f,

                // We limit the maximal force. This reduces the ability of this joint to violate
                // other constraints. 
                MaxForce = 1e6f
              };

              // Add the spring to the simulation.
              Simulation.Constraints.Add(_spring);
            }
          }
        }
        else if (touchLocation.State == TouchLocationState.Moved)
        {
          if (_spring != null)
          {
            // User has grabbed something.

            // Update the position of the object by updating the anchor position of the ball-socket
            // joint.
            _spring.AnchorPositionBLocal = rayOrigin + rayDirection * _springAnchorDistanceFromCamera;

            // Reduce the angular velocity by a certain factor. (This acts like a damping because we
            // do not want the object to rotate like crazy.)
            _spring.BodyA.AngularVelocity *= 0.9f;
          }
        }
      }
    }
Beispiel #13
0
    //--------------------------------------------------------------
    #region Creation & Cleanup
    //--------------------------------------------------------------

    /// <summary>
    /// Initializes a new instance of the <see cref="ConstraintWheel"/> class.
    /// </summary>
    public ConstraintWheel()
    {
      _radius = 0.4f;
      _suspensionRestLength = 0.6f;
      MinSuspensionLength = float.NegativeInfinity;
      SuspensionLength = SuspensionRestLength;
      SuspensionStiffness = 100;
      SuspensionDamping = 10;
      MaxSuspensionForce = float.PositiveInfinity;
      RollingFrictionForce = 500;
      Friction = 1.1f;
      RollReduction = 0.3f;

      Vector3F rayOrigin = Vector3F.Zero;
      Vector3F rayDirection = -Vector3F.UnitY;
      float rayLength = Radius + SuspensionRestLength;
      _ray = new RayShape(rayOrigin, rayDirection, rayLength)
      {
        StopsAtFirstHit = true,
      };
      CollisionObject = new CollisionObject(this);

      Constraint = new WheelConstraint(this);
    }
Beispiel #14
0
        public void ComputeCapsuleWithRandomPoints()
        {
            float height;
              float radius;
              Pose pose;

              const int numberOfTests = 100;
              RandomHelper.Random = new Random(377);
              for (int test = 0; test < numberOfTests; test++)
              {
            // Fill list with a random number of random points.
            int numberOfPoints = RandomHelper.Random.NextInteger(2, 100);
            List<Vector3F> points = new List<Vector3F>();
            for (int i = 0; i < numberOfPoints; i++)
              points.Add(RandomHelper.Random.NextVector3F(-10, 100));

            GeometryHelper.ComputeBoundingCapsule(points, out radius, out height, out pose);

            // Check if sphere can be valid.
            Assert.IsTrue(radius >= 0);
            Assert.IsTrue(height >= 2 * radius);
            Assert.IsTrue(!float.IsNaN(pose.Position.Length));
            Assert.IsTrue(pose.Orientation.IsRotation);

            // Test if all points are in the shape.
            var cd = new CollisionDetection();

            GeometricObject geometry = new GeometricObject(new CapsuleShape(radius, height), pose);
            CollisionObject boundingObject = new CollisionObject(geometry);

            // Test if all points are in the bounding shape.
            for (int i = 0; i < numberOfPoints; i++)
            {
              var point = points[i];

              // Test against a sphere around the point. Some points are exactly on the surface
              // and are very sensitive to tiny numerical errors.
              var pointGeometry = new GeometricObject(new SphereShape(Numeric.EpsilonF * (height + 1)), new Pose(point));
              Assert.IsTrue(cd.HaveContact(new CollisionObject(pointGeometry), boundingObject));
            }
              }
        }
Beispiel #15
0
    private void CreateObjects()
    {
      // Create two collision objects with triangle mesh shapes.
      var meshA = new TriangleMesh();
      meshA.Add(new Triangle(new Vector3F(0, 1, 0), new Vector3F(0, 1, 0), new Vector3F(0, 1, 0)));
      meshA.Add(new Triangle(new Vector3F(0, 1, 0), new Vector3F(0, 1, 0), new Vector3F(0, 1, 0)));
      var shapeA = new TriangleMeshShape() { Partition = new CompressedAabbTree() }; 
      var poseA = new Pose(new Vector3F(-1, 0, 0));
      _objectA = new CollisionObject(new GeometricObject(shapeA, poseA));

      var meshB = new BoxShape(0.2f, 2, 1f).GetMesh(0.05f, 4);
      var shapeB = new TriangleMeshShape(meshB, true) { Partition = new CompressedAabbTree() };
      var poseB = new Pose(new Vector3F(0.1f, 0, 0));
      _objectB = new CollisionObject(new GeometricObject(shapeB, poseB)); 
    }
Beispiel #16
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;
 }
Beispiel #17
0
        /// <summary>
        /// Initializes a new instance of the <see cref="RigidBody"/> class.
        /// </summary>
        /// <param name="shape">
        /// The shape. Can be <see langword="null"/> to use the default <see cref="Shape"/>.
        /// </param>
        /// <param name="massFrame">
        /// The mass frame. Can be <see langword="null"/> in which case the mass properties for a
        /// density of 1000 are used.
        /// </param>
        /// <param name="material">
        /// The material. Can be <see langword="null"/> to use the default <see cref="Material"/>.
        /// </param>
        public RigidBody(Shape shape, MassFrame massFrame, IMaterial material)
        {
            AutoUpdateMass = true;
              IslandId = -1;
              Name = "Unnamed";

              _pose = Pose.Identity;
              _shape = shape ?? new BoxShape(1, 1, 1);
              _shape.Changed += OnShapeChanged;
              _scale = Vector3F.One;

              Material = material ?? new UniformMaterial();

              if (massFrame != null)
            MassFrame = massFrame;
              else
            UpdateMassFrame();

              CollisionResponseEnabled = true;
              MotionType = MotionType.Dynamic;

              CollisionObject = new CollisionObject(this);

              CanSleep = true;
              IsSleeping = false;

              TimeOfImpact = 1;
        }
Beispiel #18
0
    private static void Append(StringBuilder text, CollisionObject co, bool isFirstCollisionObject)
    {
      text.Append(@"
      {
        var mesh = new TriangleMesh();");

      var shape = co.GeometricObject.Shape as TriangleMeshShape;
      if (shape == null)
        throw new NotSupportedException("The shapes must be TriangleMeshShapes");

      var mesh = shape.Mesh;
      for (int i = 0; i < mesh.NumberOfTriangles; i++)
      {
        text.Append(@"
        mesh.Add(");
        Append(text, mesh.GetTriangle(i));
        text.Append(");");
      }

      text.Append(@"

        var pose = new Pose(");
      Append(text, co.GeometricObject.Pose.Position);
      text.Append(", ");
      Append(text, QuaternionF.CreateRotation(co.GeometricObject.Pose.Orientation));
      text.Append(@");
        var scale = ");
      Append(text, co.GeometricObject.Scale);
      text.Append(@";
        var shape = new TriangleMeshShape(mesh) { Partition = new CompressedAabbTree() };
        shape.IsTwoSided = ");
      Append(text, shape.IsTwoSided);
      text.Append(@";
        shape.EnableContactWelding = ");
      Append(text, shape.EnableContactWelding);
      text.Append(@";
        ");

      if (isFirstCollisionObject)
        text.Append("_objectA");
      else
        text.Append("_objectB");

      text.Append(@" = new CollisionObject(new GeometricObject(shape, scale, pose));
      }");
    }
Beispiel #19
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);
    }
Beispiel #20
0
    public BuoyancySample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      // Add basic force effects.
      Simulation.ForceEffects.Add(new Gravity());
      Simulation.ForceEffects.Add(new Damping());

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

        RigidBody cylinder = new RigidBody(cylinderShape, cylinderMass, null)
        {
          Pose = new Pose(position, orientation),
        };
        Simulation.RigidBodies.Add(cylinder);
      }
    }
Beispiel #21
0
    protected override void OnHandleInput(InputContext context)
    {
      if (_cameraObject.CameraNode == null)
        return;

      // The input context contains the mouse position that is used by the UI controls of this
      // screen. The mouse position is stored in the following properties:
      // - context.ScreenMousePosition
      // - context.ScreenMousePositionDelta
      // - context.MousePosition
      // - context.MousePositionDelta
      // 
      // Currently, these properties contain the mouse position relative to the game window.
      // But the mouse position of the in-game screen is determined by the reticle of the 
      // game camera. We need to make a ray-cast to see which part of the screen is hit and
      // override the properties.
      bool screenHit = false;

      // Get the camera position and the view direction in world space.
      Vector3F cameraPosition = _cameraObject.CameraNode.PoseWorld.Position;
      Vector3F cameraDirection = _cameraObject.CameraNode.PoseWorld.ToWorldDirection(Vector3F.Forward);

      // Create a ray (ideally this shape should be cached and reused).
      var ray = new RayShape(cameraPosition, cameraDirection, 1000);

      // We are only interested in the first object that is hit by the ray.
      ray.StopsAtFirstHit = true;

      // Create a collision object for this shape.
      var rayCollisionObject = new CollisionObject(new GeometricObject(ray, Pose.Identity));

      // Use the CollisionDomain of the physics simulation to perform a ray cast.
      ContactSet contactSet = _simulation.CollisionDomain.GetContacts(rayCollisionObject).FirstOrDefault();
      if (contactSet != null && contactSet.Count > 0)
      {
        // We have hit something :-)

        // Get the contact information of the ray hit.
        Contact contact = contactSet[0];

        // Get the hit object (one object in the contact set is the ray and the other object is the hit object).
        CollisionObject hitCollisionObject = (contactSet.ObjectA == rayCollisionObject) ? contactSet.ObjectB : contactSet.ObjectA;

        RigidBody hitBody = hitCollisionObject.GeometricObject as RigidBody;
        if (hitBody != null && hitBody.UserData is string && (string)hitBody.UserData == "TV")
        {
          // We have hit a dynamic rigid body of a TV object. 

          // Get the normal vector of the contact.
          var normal = (contactSet.ObjectA == rayCollisionObject) ? -contact.Normal : contact.Normal;

          // Convert the normal vector to the local space of the TV box.
          normal = hitBody.Pose.ToLocalDirection(normal);

          // The InGameUIScreen texture is only mapped onto the -Y sides of the boxes. If the user
          // looks onto another side, he cannot interact with the game screen.
          if (normal.Y < 0.5f)
          {
            // The user looks onto the TV's front side. Now, we have to map the ray hit position 
            // to the texture coordinate of the InGameUIScreen render target/texture.
            var localHitPosition = (contactSet.ObjectA == rayCollisionObject) ? contact.PositionBLocal : contact.PositionALocal;
            var normalizedPosition = GetTextureCoordinate(localHitPosition);

            // The texture coordinate is in the range [0, 0] to [1, 1]. If we multiply it with the
            // screen extent to the position in pixels.
            var inGameScreenMousePosition = normalizedPosition * new Vector2F(ActualWidth, ActualHeight);
            var inGameScreenMousePositionDelta = inGameScreenMousePosition - _lastMousePosition;

            // Finally, we can set the mouse positions that are relative to the InGame screen. Hurray!
            context.ScreenMousePosition = inGameScreenMousePosition;
            context.ScreenMousePositionDelta = inGameScreenMousePositionDelta;

            context.MousePosition = inGameScreenMousePosition;
            context.MousePositionDelta = inGameScreenMousePositionDelta;

            // Store the mouse position so that we can compute MousePositionDelta in the next frame.
            _lastMousePosition = context.MousePosition;
            screenHit = true;
          }
        }
      }

      if (screenHit)
      {
        // Call base class to call HandleInput for all child controls. The child controls will 
        // use the overridden mouse positions.
        base.OnHandleInput(context);
      }
    }
Beispiel #22
0
        /// <summary>
        /// Computes the closest points between two <see cref="CollisionObject"/>s.
        /// </summary>
        /// <param name="objectA">The first collision object.</param>
        /// <param name="objectB">The second collision object.</param>
        /// <returns>
        /// The <see cref="ContactSet"/> with the closest-point information. The 
        /// <see cref="ContactSet"/> will have exactly 1 <see cref="Contact"/> (describing the
        /// closest-point pair).
        /// </returns>
        /// <remarks>
        /// <para>
        /// Collision filtering (see <see cref="CollisionFilter"/>) is NOT applied.
        /// </para>
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="objectA"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="objectB"/> is <see langword="null"/>.
        /// </exception>
        public ContactSet GetClosestPoints(CollisionObject objectA, CollisionObject objectB)
        {
            if (objectA == null)
            throw new ArgumentNullException("objectA");
              if (objectB == null)
            throw new ArgumentNullException("objectB");

              return AlgorithmMatrix[objectA, objectB].GetClosestPoints(objectA, objectB);
        }
Beispiel #23
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);
    }
Beispiel #24
0
        /// <summary>
        /// Computes the contacts between two <see cref="CollisionObject"/>s.
        /// </summary>
        /// <param name="objectA">The first collision object.</param>
        /// <param name="objectB">The second collision object.</param>
        /// <returns>
        /// A <see cref="ContactSet"/> describing the contact information if <paramref name="objectA"/>
        /// and <paramref name="objectB"/> are intersecting; otherwise, <see langword="null"/> if the
        /// objects are separated.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="objectA"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="objectB"/> is <see langword="null"/>.
        /// </exception>
        public ContactSet GetContacts(CollisionObject objectA, CollisionObject objectB)
        {
            // Broad phase AABB check and collision filtering
              if (HaveAabbContact(objectA, objectB) == false)
            return null;

              // Narrow phase
              ContactSet contactSet = AlgorithmMatrix[objectA, objectB].GetContacts(objectA, objectB);

              Debug.Assert(contactSet != null, "CollisionAlgorithm.GetContacts should always return a ContactSet.");
              if (contactSet.HaveContact)
              {
            return contactSet;
              }
              else
              {
            contactSet.Recycle();
            return null;
              }
        }
Beispiel #25
0
        public void ComputeBoundingShapeCenteredSphere()
        {
            RandomHelper.Random = new Random(123);
              var radius = new Vector3F(3, 0, 0);
              var points = new List<Vector3F>
              {
            new Vector3F(3, 0, 0), new Vector3F(-3, 0, 0),
            new Vector3F(0, 3, 0), new Vector3F(0, -3, 0),
            new Vector3F(0, 0, 3), new Vector3F(0, 0, -3),
              };

              for (int i = 0; i < 40; i++)
            points.Add(RandomHelper.Random.NextQuaternionF().Rotate(radius));

              var shape = GeometryHelper.CreateBoundingShape(points);
              SphereShape s = (SphereShape)shape;
              Assert.IsTrue(Numeric.AreEqual(3, s.Radius));

              var cd = new CollisionDetection();

              GeometricObject geometry = new GeometricObject(shape);
              CollisionObject boundingObject = new CollisionObject(geometry);

              // Test if all points are in the bounding shape.
              for (int i = 0; i < points.Count; i++)
              {
            var point = points[i];

            // Test against a sphere around the point. Some points are exactly on the surface
            // and are very sensitive to tiny numerical errors.
            var pointGeometry = new GeometricObject(new SphereShape(Numeric.EpsilonF * 10), new Pose(point));

            Assert.IsTrue(cd.HaveContact(new CollisionObject(pointGeometry), boundingObject));
              }
        }
Beispiel #26
0
        /// <summary>
        /// Gets the time of impact between two moving objects.
        /// </summary>
        /// <param name="objectA">The object A.</param>
        /// <param name="targetPoseA">The target pose of A.</param>
        /// <param name="objectB">The object B.</param>
        /// <param name="targetPoseB">The target pose of B.</param>
        /// <param name="allowedPenetration">
        /// The allowed penetration. A positive allowed penetration value makes sure that the objects 
        /// have a measurable contact at the time of impact.
        /// </param>
        /// <returns>The time of impact in the range [0, 1].</returns>
        /// <remarks>
        /// <para>
        /// Both objects are moved from their current pose (time = 0) to the given target pose (time =
        /// 1). If they collide during this movement the first time of impact is returned. A time of
        /// impact of 1 can mean that the objects do not collide or they collide at their target
        /// positions.
        /// </para>
        /// <para>
        /// The result is undefined if the objects are already in contact at their start poses.
        /// </para>
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="objectA"/> or <paramref name="objectB"/> is <see langword="null"/>.
        /// </exception>
        public float GetTimeOfImpact(CollisionObject objectA, Pose targetPoseA, CollisionObject objectB, Pose targetPoseB, float allowedPenetration)
        {
            if (objectA == null)
            throw new ArgumentNullException("objectA");
              if (objectB == null)
            throw new ArgumentNullException("objectB");

              return AlgorithmMatrix[objectA, objectB].GetTimeOfImpact(objectA, targetPoseA, objectB, targetPoseB, allowedPenetration);
        }
Beispiel #27
0
        public void CreateBoundingShape()
        {
            int numberOfBoxes = 0;
              int numberOfSpheres = 0;
              const int numberOfTests = 100;
              RandomHelper.Random = new Random(727);
              for (int test = 0; test < numberOfTests; test++)
              {
            // Fill list with a random number of random points.
            int numberOfPoints = RandomHelper.Random.NextInteger(2, 100);
            List<Vector3F> points = new List<Vector3F>();
            for (int i = 0; i < numberOfPoints; i++)
              points.Add(RandomHelper.Random.NextVector3F(-10, 100));

            Shape shape = GeometryHelper.CreateBoundingShape(points);
            GeometricObject geometry = new GeometricObject(shape);
            CollisionObject boundingObject = new CollisionObject(geometry);

            if (shape is BoxShape)
              numberOfBoxes++;
            if (shape is SphereShape)
              numberOfSpheres++;
            if (((TransformedShape)shape).Child.Shape is BoxShape)
              numberOfBoxes++;
            else
              numberOfSpheres++;

            Assert.IsNotNull(shape);

            var cd = new CollisionDetection();

            // Test if all points are in the bounding shape.
            for (int i = 0; i < numberOfPoints; i++)
            {
              var point = points[i];

              // Test against a sphere around the point. Some points are exactly on the surface
              // and are very sensitive to tiny numerical errors.
              var pointGeometry = new GeometricObject(new SphereShape(Numeric.EpsilonF * 10), new Pose(point));

              Assert.IsTrue(cd.HaveContact(new CollisionObject(pointGeometry), boundingObject));
            }
              }

              Console.WriteLine("ShapeHelper.CreateBoundingShape: Number of Boxes : Number of Spheres = " + numberOfBoxes + " : " + numberOfSpheres);
        }
Beispiel #28
0
        public bool HaveAabbContact(CollisionObject objectA, CollisionObject objectB)
        {
            if (objectA == null)
            throw new ArgumentNullException("objectA");
              if (objectB == null)
            throw new ArgumentNullException("objectB");

              // Collision filtering
              if (objectA.Enabled == false || objectB.Enabled == false
              || (CollisionFilter != null && !CollisionFilter.Filter(new Pair<CollisionObject>(objectA, objectB))))
              {
            return false;
              }

              // AABB test
              return GeometryHelper.HaveContact(objectA.GeometricObject.Aabb, objectB.GeometricObject.Aabb);
        }
Beispiel #29
0
        public CollisionAlgorithm this[CollisionObject objectA, CollisionObject objectB]
        {
            get
              {
            if (objectA == null)
              throw new ArgumentNullException("objectA");
            if (objectB == null)
              throw new ArgumentNullException("objectB");

            Debug.Assert(objectA.GeometricObject != null, "CollisionObject needs to ensure that GeometricObject is not null.");
            Debug.Assert(objectB.GeometricObject != null, "CollisionObject needs to ensure that GeometricObject is not null.");
            Debug.Assert(objectA.GeometricObject.Shape != null, "IGeometricObject needs to ensure that Shape is not null.");
            Debug.Assert(objectB.GeometricObject.Shape != null, "IGeometricObject needs to ensure that Shape is not null.");

            return this[objectA.GeometricObject.Shape.GetType(), objectB.GeometricObject.Shape.GetType()];
              }
              set
              {
            if (objectA == null)
              throw new ArgumentNullException("objectA");
            if (objectB == null)
              throw new ArgumentNullException("objectB");

            Debug.Assert(objectA.GeometricObject != null, "CollisionObject needs to ensure that GeometricObject is not null.");
            Debug.Assert(objectB.GeometricObject != null, "CollisionObject needs to ensure that GeometricObject is not null.");
            Debug.Assert(objectA.GeometricObject.Shape != null, "IGeometricObject needs to ensure that Shape is not null.");
            Debug.Assert(objectB.GeometricObject.Shape != null, "IGeometricObject needs to ensure that Shape is not null.");

            this[objectA.GeometricObject.Shape.GetType(), objectB.GeometricObject.Shape.GetType()] = value;
              }
        }
Beispiel #30
0
        /// <summary>
        /// Returns <see langword="true"/> if two <see cref="CollisionObject"/>s are in contact.
        /// </summary>
        /// <param name="objectA">The first collision object.</param>
        /// <param name="objectB">The second collision object.</param>
        /// <returns>
        /// <see langword="true"/> if the object are touching or intersecting; otherwise 
        /// <see langword="false"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="objectA"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="objectB"/> is <see langword="null"/>.
        /// </exception>
        public bool HaveContact(CollisionObject objectA, CollisionObject objectB)
        {
            // Broad phase AABB check and collision filtering
              if (HaveAabbContact(objectA, objectB) == false)
            return false;

              // Narrow phase
              return AlgorithmMatrix[objectA, objectB].HaveContact(objectA, objectB);
        }