示例#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);
        }
示例#2
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));
    }
示例#3
0
        /// <summary>
        /// Initializes a new instance of <see cref="Ray"/> from a <see cref="RayShape"/>.
        /// </summary>
        /// <param name="rayShape">
        /// The <see cref="RayShape"/> from which origin and direction are copied.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="rayShape"/> is <see langword="null"/>.
        /// </exception>
        public Ray(RayShape rayShape)
        {
            if (rayShape == null)
            {
                throw new ArgumentNullException("rayShape");
            }

            Origin    = rayShape.Origin;
            Direction = rayShape.Direction;
            Length    = rayShape.Length;
        }
示例#4
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.
        }
      }
    }
示例#5
0
    // Creates a lot of random objects.
    private void CreateRandomObjects()
    {
      var random = new Random();

      var isFirstHeightField = true;

      int currentShape = 0;
      int numberOfObjects = 0;
      while (true)
      {
        numberOfObjects++;
        if (numberOfObjects > ObjectsPerType)
        {
          currentShape++;
          numberOfObjects = 0;
        }

        Shape shape;
        switch (currentShape)
        {
          case 0:
            // Box
            shape = new BoxShape(ObjectSize, ObjectSize * 2, ObjectSize * 3);
            break;
          case 1:
            // Capsule
            shape = new CapsuleShape(0.3f * ObjectSize, 2 * ObjectSize);
            break;
          case 2:
            // Cone
            shape = new ConeShape(1 * ObjectSize, 2 * ObjectSize);
            break;
          case 3:
            // Cylinder
            shape = new CylinderShape(0.4f * ObjectSize, 2 * ObjectSize);
            break;
          case 4:
            // Sphere
            shape = new SphereShape(ObjectSize);
            break;
          case 5:
            // Convex hull of several points.
            ConvexHullOfPoints hull = new ConvexHullOfPoints();
            hull.Points.Add(new Vector3F(-1 * ObjectSize, -2 * ObjectSize, -1 * ObjectSize));
            hull.Points.Add(new Vector3F(2 * ObjectSize, -1 * ObjectSize, -0.5f * ObjectSize));
            hull.Points.Add(new Vector3F(1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize));
            hull.Points.Add(new Vector3F(-1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize));
            hull.Points.Add(new Vector3F(-1 * ObjectSize, 0.7f * ObjectSize, -0.6f * ObjectSize));
            shape = hull;
            break;
          case 6:
            // A composite shape: two boxes that form a "T" shape.
            var composite = new CompositeShape();
            composite.Children.Add(
              new GeometricObject(
                new BoxShape(ObjectSize, 3 * ObjectSize, ObjectSize),
                new Pose(new Vector3F(0, 0, 0))));
            composite.Children.Add(
              new GeometricObject(
                new BoxShape(2 * ObjectSize, ObjectSize, ObjectSize),
                new Pose(new Vector3F(0, 2 * ObjectSize, 0))));
            shape = composite;
            break;
          case 7:
            shape = new CircleShape(ObjectSize);
            break;
          case 8:
            {
              var compBvh = new CompositeShape();
              compBvh.Children.Add(new GeometricObject(new BoxShape(0.5f, 1, 0.5f), new Pose(new Vector3F(0, 0.5f, 0), Matrix33F.Identity)));
              compBvh.Children.Add(new GeometricObject(new BoxShape(0.8f, 0.5f, 0.5f), new Pose(new Vector3F(0.5f, 0.7f, 0), Matrix33F.CreateRotationZ(-MathHelper.ToRadians(15)))));
              compBvh.Children.Add(new GeometricObject(new SphereShape(0.3f), new Pose(new Vector3F(0, 1.15f, 0), Matrix33F.Identity)));
              compBvh.Children.Add(new GeometricObject(new CapsuleShape(0.2f, 1), new Pose(new Vector3F(0.6f, 1.15f, 0), Matrix33F.CreateRotationX(0.3f))));
              compBvh.Partition = new AabbTree<int>();
              shape = compBvh;
              break;
            }
          case 9:
            CompositeShape comp = new CompositeShape();
            comp.Children.Add(new GeometricObject(new BoxShape(0.5f * ObjectSize, 1 * ObjectSize, 0.5f * ObjectSize), new Pose(new Vector3F(0, 0.5f * ObjectSize, 0), QuaternionF.Identity)));
            comp.Children.Add(new GeometricObject(new BoxShape(0.8f * ObjectSize, 0.5f * ObjectSize, 0.5f * ObjectSize), new Pose(new Vector3F(0.3f * ObjectSize, 0.7f * ObjectSize, 0), QuaternionF.CreateRotationZ(-MathHelper.ToRadians(45)))));
            comp.Children.Add(new GeometricObject(new SphereShape(0.3f * ObjectSize), new Pose(new Vector3F(0, 1.15f * ObjectSize, 0), QuaternionF.Identity)));
            shape = comp;
            break;
          case 10:
            shape = new ConvexHullOfPoints(new[]
            {
              new Vector3F(-1 * ObjectSize, -2 * ObjectSize, -1 * ObjectSize),
              new Vector3F(2 * ObjectSize, -1 * ObjectSize, -0.5f * ObjectSize),
              new Vector3F(1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize),
              new Vector3F(-1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize),
              new Vector3F(-1 * ObjectSize, 0.7f * ObjectSize, -0.6f * ObjectSize)
            });
            break;
          case 11:
            ConvexHullOfShapes shapeHull = new ConvexHullOfShapes();
            shapeHull.Children.Add(new GeometricObject(new SphereShape(0.3f * ObjectSize), new Pose(new Vector3F(0, 2 * ObjectSize, 0), Matrix33F.Identity)));
            shapeHull.Children.Add(new GeometricObject(new BoxShape(1 * ObjectSize, 2 * ObjectSize, 3 * ObjectSize), Pose.Identity));
            shape = shapeHull;
            break;
          case 12:
            shape = Shape.Empty;
            break;
          case 13:
            var numberOfSamplesX = 10;
            var numberOfSamplesZ = 10;
            var samples = new float[numberOfSamplesX * numberOfSamplesZ];
            for (int z = 0; z < numberOfSamplesZ; z++)
              for (int x = 0; x < numberOfSamplesX; x++)
                samples[z * numberOfSamplesX + x] = (float)(Math.Cos(z / 3f) * Math.Sin(x / 2f) * BoxSize / 6);
            HeightField heightField = new HeightField(0, 0, 2 * BoxSize, 2 * BoxSize, samples, numberOfSamplesX, numberOfSamplesZ);
            shape = heightField;
            break;
          //case 14:
          //shape = new LineShape(new Vector3F(0.1f, 0.2f, 0.3f), new Vector3F(0.1f, 0.2f, -0.3f).Normalized);
          //break;            
          case 15:
            shape = new LineSegmentShape(
              new Vector3F(0.1f, 0.2f, 0.3f), new Vector3F(0.1f, 0.2f, 0.3f) + 3 * ObjectSize * new Vector3F(0.1f, 0.2f, -0.3f));
            break;
          case 16:
            shape = new MinkowskiDifferenceShape
            {
              ObjectA = new GeometricObject(new SphereShape(0.1f * ObjectSize)),
              ObjectB = new GeometricObject(new BoxShape(1 * ObjectSize, 2 * ObjectSize, 3 * ObjectSize))
            };
            break;
          case 17:
            shape = new MinkowskiSumShape
            {
              ObjectA = new GeometricObject(new SphereShape(0.1f * ObjectSize)),
              ObjectB = new GeometricObject(new BoxShape(1 * ObjectSize, 2 * ObjectSize, 3 * ObjectSize)),
            };
            break;
          case 18:
            shape = new OrthographicViewVolume(0, ObjectSize, 0, ObjectSize, ObjectSize / 2, ObjectSize * 2);
            break;
          case 19:
            shape = new PerspectiveViewVolume(MathHelper.ToRadians(60f), 16f / 10, ObjectSize / 2, ObjectSize * 3);
            break;
          case 20:
            shape = new PointShape(0.1f, 0.3f, 0.2f);
            break;
          case 21:
            shape = new RayShape(new Vector3F(0.2f, 0, -0.12f), new Vector3F(1, 2, 3).Normalized, ObjectSize * 2);
            break;
          case 22:
            shape = new RayShape(new Vector3F(0.2f, 0, -0.12f), new Vector3F(1, 2, 3).Normalized, ObjectSize * 2)
            {
              StopsAtFirstHit = true
            };
            break;
          case 23:
            shape = new RectangleShape(ObjectSize, ObjectSize * 2);
            break;
          case 24:
            shape = new TransformedShape(
              new GeometricObject(
                new BoxShape(1 * ObjectSize, 2 * ObjectSize, 3 * ObjectSize),
                new Pose(new Vector3F(0.1f, 1, -0.2f))));
            break;
          case 25:
            shape = new TriangleShape(
              new Vector3F(ObjectSize, 0, 0), new Vector3F(0, ObjectSize, 0), new Vector3F(ObjectSize, ObjectSize, ObjectSize));
            break;
          //case 26:
          //  {
          //    // Create a composite object from which we get the mesh.
          //    CompositeShape compBvh = new CompositeShape();
          //    compBvh.Children.Add(new GeometricObject(new BoxShape(0.5f, 1, 0.5f), new Pose(new Vector3F(0, 0.5f, 0), Matrix33F.Identity)));
          //    compBvh.Children.Add(
          //      new GeometricObject(
          //        new BoxShape(0.8f, 0.5f, 0.5f),
          //        new Pose(new Vector3F(0.5f, 0.7f, 0), Matrix33F.CreateRotationZ(-(float)MathHelper.ToRadians(15)))));
          //    compBvh.Children.Add(new GeometricObject(new SphereShape(0.3f), new Pose(new Vector3F(0, 1.15f, 0), Matrix33F.Identity)));
          //    compBvh.Children.Add(
          //      new GeometricObject(new CapsuleShape(0.2f, 1), new Pose(new Vector3F(0.6f, 1.15f, 0), Matrix33F.CreateRotationX(0.3f))));

          //    TriangleMeshShape meshBvhShape = new TriangleMeshShape { Mesh = compBvh.GetMesh(0.01f, 3) };
          //    meshBvhShape.Partition = new AabbTree<int>();
          //    shape = meshBvhShape;
          //    break;
          //  }
          //case 27:
          //  {
          //    // Create a composite object from which we get the mesh.
          //    CompositeShape compBvh = new CompositeShape();
          //    compBvh.Children.Add(new GeometricObject(new BoxShape(0.5f, 1, 0.5f), new Pose(new Vector3F(0, 0.5f, 0), QuaternionF.Identity)));
          //    compBvh.Children.Add(
          //      new GeometricObject(
          //        new BoxShape(0.8f, 0.5f, 0.5f),
          //        new Pose(new Vector3F(0.5f, 0.7f, 0), QuaternionF.CreateRotationZ(-(float)MathHelper.ToRadians(15)))));
          //    compBvh.Children.Add(new GeometricObject(new SphereShape(0.3f), new Pose(new Vector3F(0, 1.15f, 0), QuaternionF.Identity)));
          //    compBvh.Children.Add(
          //      new GeometricObject(new CapsuleShape(0.2f, 1), new Pose(new Vector3F(0.6f, 1.15f, 0), QuaternionF.CreateRotationX(0.3f))));

          //    TriangleMeshShape meshBvhShape = new TriangleMeshShape { Mesh = compBvh.GetMesh(0.01f, 3) };
          //    meshBvhShape.Partition = new AabbTree<int>();
          //    shape = meshBvhShape;
          //    break;
          //  }
          case 28:
            shape = new ConvexPolyhedron(new[]
            {
              new Vector3F(-1 * ObjectSize, -2 * ObjectSize, -1 * ObjectSize),
              new Vector3F(2 * ObjectSize, -1 * ObjectSize, -0.5f * ObjectSize),
              new Vector3F(1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize),
              new Vector3F(-1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize),
              new Vector3F(-1 * ObjectSize, 0.7f * ObjectSize, -0.6f * ObjectSize)
            });
            break;
          case 29:
            return;
          default:
            currentShape++;
            continue;
        }

        // Create an object with the random shape, pose, color and velocity.
        Pose randomPose = new Pose(
          random.NextVector3F(-BoxSize + ObjectSize * 2, BoxSize - ObjectSize * 2),
          random.NextQuaternionF());
        var newObject = new MovingGeometricObject
        {
          Pose = randomPose,
          Shape = shape,
          LinearVelocity = random.NextQuaternionF().Rotate(new Vector3F(MaxLinearVelocity, 0, 0)),
          AngularVelocity = random.NextQuaternionF().Rotate(Vector3F.Forward)
                            * RandomHelper.Random.NextFloat(0, MaxAngularVelocity),
        };

        if (RandomHelper.Random.NextBool())
          newObject.LinearVelocity = Vector3F.Zero;
        if (RandomHelper.Random.NextBool())
          newObject.AngularVelocity = Vector3F.Zero;

        if (shape is LineShape || shape is HeightField)
        {
          // Do not move lines or the height field.
          newObject.LinearVelocity = Vector3F.Zero;
          newObject.AngularVelocity = Vector3F.Zero;
        }

        // Create only 1 heightField!
        if (shape is HeightField)
        {
          if (isFirstHeightField)
          {
            isFirstHeightField = true;
            newObject.Pose = new Pose(new Vector3F(-BoxSize, -BoxSize, -BoxSize));
          }
          else
          {
            currentShape++;
            numberOfObjects = 0;
            continue;
          }
        }

        // Add collision object to collision domain.
        _domain.CollisionObjects.Add(new CollisionObject(newObject));

        //co.Type = CollisionObjectType.Trigger;
        //co.Name = "Object" + shape.GetType().Name + "_" + i;
      }
    }
示例#6
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);
      }
    }
示例#7
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;
          }
        }
      }
    }
示例#8
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.
    }
示例#9
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);
    }
示例#10
0
        public override void Update(GameTime gameTime)
        {
            if (_spring != null && !_inputService.IsDown(MouseButtons.Left) && !_inputService.IsDown(Buttons.LeftTrigger, PlayerIndex.One))
              {
            // The user has released the object.
            _spring.Simulation.Constraints.Remove(_spring);
            _spring = null;
              }

              if (_inputService.IsPressed(MouseButtons.Left, false) || _inputService.IsPressed(Buttons.LeftTrigger, false, PlayerIndex.One))
              {
            // The user has pressed the grab button.

            // Remove the old joint, in case anything is grabbed.
            if (_spring != null && _spring.Simulation != null)
              _spring.Simulation.Constraints.Remove(_spring);

            // The spring is attached 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).
            Camera camera = Game.Components.OfType<Camera>().First();
            Vector3F cameraPosition = camera.Pose.Position;
            Vector3F cameraDirection = camera.Pose.ToWorldDirection(-Vector3F.UnitZ);

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

            // Assign the collision object to collision group 2. (In PhysicsGame.cs a collision filter
            // based on collision groups was set.)
            rayCollisionObject.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 the rigid body.
              // Get the first contact in the contact set. (A ray hit usually contains exactly 1 contact.)
              Contact contact = contactSet[0];

              // The contact set contains the object pair of the collision. One object is the ray.
              // The other is the object we want to grab.
              CollisionObject hitCollisionObject = (contactSet.ObjectA == rayCollisionObject) ? contactSet.ObjectB : contactSet.ObjectA;

              // Check whether a dynamic rigid body was hit.
              RigidBody hitBody = hitCollisionObject.GeometricObject as RigidBody;
              if (hitBody != null && hitBody.MotionType == MotionType.Dynamic)
              {
            // Attach the rigid body at the cursor position using a ball-socket joint.
            // (Note: We could also use a FixedJoint, if we don't want any rotations.)

            // The penetration depth tells us the distance from the ray origin to the rigid body.
            _springAttachmentDistanceFromObserver = 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;

            _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 is set below.

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

              if (_spring != null)
              {
            // User has grabbed something.

            // Update the position of the object by updating the anchor position of the ball-socket
            // joint.
            Camera camera = Game.Components.OfType<Camera>().First();
            Vector3F cameraPosition = camera.Pose.Position;
            Vector3F cameraDirection = camera.Pose.ToWorldDirection(-Vector3F.UnitZ);

            _spring.AnchorPositionBLocal = cameraPosition + cameraDirection * _springAttachmentDistanceFromObserver;

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

              base.Update(gameTime);
        }
示例#11
0
        /// <summary>
        /// Determines whether the specified world space position is underwater.
        /// </summary>
        /// <param name="position">The position in world space.</param>
        /// <returns>
        /// <see langword="true"/> if the position is underwater; otherwise, <see langword="false"/>
        /// </returns>
        /// <remarks>
        /// A position is underwater if it is inside the <see cref="Shape"/> of this node.
        /// </remarks>
        public bool IsUnderwater(Vector3F position)
        {
            //if (!EnableUnderwaterEffect)
              //  return false;

              // Oceans are treated like a horizontal plane through the node origin.
              if (Volume == null)
            return position.Y < PoseWorld.Position.Y;

              // Thread-safety: We lock this operation because all tests use the same cache
              // and test objects.
              lock (_underwaterTestLock)
              {
            // Return cached result if the point and the water pose/shape are still the same.
            if (!IsDirty)
            {
              if (Vector3F.AreNumericallyEqual(position, _lastTestPosition))
            return _lastTestResult;
            }
            else
            {
              // Clear flag. We will cache a new result.
              IsDirty = false;
            }

            _lastTestPosition = position;
            _lastTestResult = false;

            // Use a shared collision detection instance.
            var collisionDetection = SceneHelper.CollisionDetection;

            if (_sphereShape == null)
            {
              // First time initializations.
              _sphereShape = new SphereShape(0);
              _rayShape = new RayShape();
              _testCollisionObject = new CollisionObject(TestGeometricObject.Create());
              _waterCollisionObject = new CollisionObject(TestGeometricObject.Create());
            }

            var testGeometricObject = (TestGeometricObject)_testCollisionObject.GeometricObject;
            var waterGeometricObject = (TestGeometricObject)_waterCollisionObject.GeometricObject;
            try
            {
              // Initialize water collision object.
              waterGeometricObject.Shape = Volume;
              waterGeometricObject.Scale = ScaleWorld;
              waterGeometricObject.Pose = PoseWorld;

              // Test if point touches underwater volume. (Skip this test for triangle mesh shapes.)
              if (!(Shape is TriangleMeshShape))
              {
            testGeometricObject.Pose = new Pose(position);
            testGeometricObject.Shape = _sphereShape;
            if (collisionDetection.HaveContact(_testCollisionObject, _waterCollisionObject))
            {
              _lastTestResult = true;
              return true;
            }

            // For convex shapes, the above test is sufficient.
            if (Shape is ConvexShape)
              return false;
              }

              // For triangle meshes - which are hollow - we have to make a more complex test.
              // We shoot vertical rays and check if we hit the underwater volume surface.

              // Make explicit point vs. AABB test first.
              if (!collisionDetection.HaveAabbContact(_testCollisionObject, _waterCollisionObject))
            return false;

              // Switch to ray shape.
              testGeometricObject.Shape = _rayShape;

              // Shoot down. Start 1 unit above the surface.
              Vector3F origin = position;
              origin.Y = Math.Max(Aabb.Maximum.Y, origin.Y) + 1;
              _rayShape.Origin = origin;
              _rayShape.Length = (origin - position).Length;
              _rayShape.Direction = Vector3F.Down;
              if (!collisionDetection.HaveContact(_testCollisionObject, _waterCollisionObject))
            return false; // Camera is above water.

              // Shoot up. Start 1 m under the water volume.
              origin = position;
              origin.Y = Math.Min(Aabb.Minimum.Y, origin.Y) - 1;
              _rayShape.Origin = origin;
              _rayShape.Length = (origin - position).Length;
              _rayShape.Direction = Vector3F.Up;

              _lastTestResult = collisionDetection.HaveContact(_testCollisionObject, _waterCollisionObject);
              return _lastTestResult;
            }
            finally
            {
              // Remove references to avoid "memory leaks".
              waterGeometricObject.Shape = Volume;
            }
              }
        }
        private float _slopeLimit = ConstantsF.PiOver4; // = 45°

        #endregion Fields

        #region Constructors

        //--------------------------------------------------------------
        /// <summary>
        /// Initializes a new instance of the <see cref="KinematicCharacterController"/> class.
        /// </summary>
        /// <param name="simulation">The simulation.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="simulation" /> is <see langword="null"/>.
        /// </exception>
        public DynamicCharacterController(Simulation simulation)
        {
            if (simulation == null)
            throw new ArgumentNullException("simulation");

              Simulation = simulation;

              CapsuleShape shape = new CapsuleShape(0.4f, 1.8f);
              MassFrame mass = new MassFrame { Mass = 80 };  // Push strength is proportional to the mass!
              UniformMaterial material = new UniformMaterial
              {
            // The body should be frictionless, so that it can be easily pushed by the simulation to
            // valid positions. And it does not slow down when sliding along walls.
            StaticFriction = 0.0f,
            DynamicFriction = 0.0f,

            // The body should not bounce when being hit or pushed.
            Restitution = 0
              };

              Body = new RigidBody(shape, mass, material)
              {
            // We set the mass explicitly and it should not automatically change when the
            // shape is changed; e.g. a ducked character has a smaller shape, but still the same mass.
            AutoUpdateMass = false,

            // This body is under our control and should never be deactivated by the simulation.
            CanSleep = false,
            CcdEnabled = true,

            // The capsule does not rotate in any direction.
            LockRotationX = true,
            LockRotationY = true,
            LockRotationZ = true,

            Name = "CharacterController",

            Pose = new Pose(new Vector3F(0, shape.Height / 2, 0)),
              };

              // Create a ray that senses the space below the capsule. The ray starts in the capsule
              // center (to detect penetrations) and extends 0.4 units below the capsule bottom.
              RayShape rayShape = new RayShape(Vector3F.Zero, -Vector3F.UnitY, shape.Height / 2 + 0.4f)
              {
            StopsAtFirstHit = true,
              };
              GeometricObject rayGeometry = new GeometricObject(rayShape, Body.Pose);
              _ray = new CollisionObject(rayGeometry);

              // Whenever the Body moves, the ray moves with it.
              Body.PoseChanged += (s, e) => rayGeometry.Pose = Body.Pose;

              // Enable the character controller. (Adds body to simulation.)
              Enabled = true;
        }