private static void UpdateWheelVelocity(float deltaTime, ConstraintVehicle vehicle, ConstraintWheel wheel) { if (wheel.Tag == 1) { wheel.Tag = 0; if (Numeric.IsZero(wheel.BrakeForce)) { // We set the angular velocity, so that the wheel matches the moving underground. Vector3F relativeContactVelocity = vehicle.Chassis.GetVelocityOfWorldPoint(wheel.GroundPosition) - wheel.TouchedBody.GetVelocityOfWorldPoint(wheel.GroundPosition); float forwardVelocity = Vector3F.Dot(relativeContactVelocity, wheel.GroundForward); wheel.AngularVelocity = forwardVelocity / wheel.Radius; wheel.RotationAngle += wheel.AngularVelocity * deltaTime; } else { // Braking wheels do not rotate. wheel.AngularVelocity = 0; } } else { // To keep it simple: The wheel continues spinning in the same direction. // Damp angular velocity and update rotation angle. wheel.AngularVelocity *= 0.99f; wheel.RotationAngle += wheel.AngularVelocity * deltaTime; } }
// Creates or gets the ConstraintVehicleHandler instance and adds a vehicle. internal static void Add(ConstraintVehicle vehicle) { var simulation = vehicle.Simulation; var handler = GetHandler(simulation); if (handler == null) { // The first vehicle: Add a new instance of this class to the simulation. handler = new ConstraintVehicleHandler(); simulation.ForceEffects.Add(handler); simulation.SubTimeStepFinished += handler.OnSubTimeStepFinished; } handler._vehicles.Add(vehicle); }
// Removes a vehicle. When the last vehicle is removed, the ConstraintVehicleHandler // instance is removed too. internal static void Remove(ConstraintVehicle vehicle) { Simulation simulation = vehicle.Simulation; ConstraintVehicleHandler handler = GetHandler(simulation); if (handler != null) { handler._vehicles.Remove(vehicle); // The last vehicle was removed. if (handler._vehicles.Count == 0) { simulation.ForceEffects.Remove(handler); simulation.SubTimeStepFinished -= handler.OnSubTimeStepFinished; } } }
//-------------------------------------------------------------- #region Creation & Cleanup //-------------------------------------------------------------- public ConstraintVehicleObject(IServiceLocator services) { Name = "Vehicle"; _services = services; _inputService = services.GetInstance<IInputService>(); _simulation = services.GetInstance<Simulation>(); // Load models for rendering. var contentManager = services.GetInstance<ContentManager>(); _vehicleModelNode = contentManager.Load<ModelNode>("Car/Car").Clone(); _wheelModelNodes = new ModelNode[4]; _wheelModelNodes[0] = contentManager.Load<ModelNode>("Car/Wheel").Clone(); _wheelModelNodes[1] = _wheelModelNodes[0].Clone(); _wheelModelNodes[2] = _wheelModelNodes[0].Clone(); _wheelModelNodes[3] = _wheelModelNodes[0].Clone(); // Add wheels under the car model node. _vehicleModelNode.Children.Add(_wheelModelNodes[0]); _vehicleModelNode.Children.Add(_wheelModelNodes[1]); _vehicleModelNode.Children.Add(_wheelModelNodes[2]); _vehicleModelNode.Children.Add(_wheelModelNodes[3]); // ----- Create the chassis of the car. // The Vehicle needs a rigid body that represents the chassis. This can be any shape (e.g. // a simple BoxShape). In this example we will build a convex polyhedron from the car model. // 1. Extract the vertices from the car model. // The car model has ~10,000 vertices. It consists of a MeshNode for the glass // parts and a MeshNode "Car" for the chassis. var meshNode = _vehicleModelNode.GetDescendants() .OfType<MeshNode>() .First(mn => mn.Name == "Car"); var mesh = MeshHelper.ToTriangleMesh(meshNode.Mesh); // Apply the transformation of the mesh node. mesh.Transform(meshNode.PoseWorld * Matrix44F.CreateScale(meshNode.ScaleWorld)); // 2. (Optional) Create simplified convex hull from mesh. // We could also skip this step and directly create a convex polyhedron from the mesh using // var chassisShape = new ConvexPolyhedron(mesh.Vertices); // However, the convex polyhedron would still have 500-600 vertices. // We can reduce the number of vertices by using the GeometryHelper. // Create a convex hull for mesh with max. 64 vertices. Additional, shrink the hull by 4 cm. var convexHull = GeometryHelper.CreateConvexHull(mesh.Vertices, 64, -0.04f); // 3. Create convex polyhedron shape using the vertices of the convex hull. var chassisShape = new ConvexPolyhedron(convexHull.Vertices.Select(v => v.Position)); // (Note: Building convex hulls and convex polyhedra are time-consuming. To save loading time // we should build the shape in the XNA content pipeline. See other DigitalRune Physics // Samples.) // The mass properties of the car. We use a mass of 800 kg. var mass = MassFrame.FromShapeAndMass(chassisShape, Vector3F.One, 800, 0.1f, 1); // Trick: We artificially modify the center of mass of the rigid body. Lowering the center // of mass makes the car more stable against rolling in tight curves. // We could also modify mass.Inertia for other effects. var pose = mass.Pose; pose.Position.Y -= 0.5f; // Lower the center of mass. pose.Position.Z = -0.5f; // The center should be below the driver. // (Note: The car model is not exactly centered.) mass.Pose = pose; // Material for the chassis. var material = new UniformMaterial { Restitution = 0.1f, StaticFriction = 0.2f, DynamicFriction = 0.2f }; var chassis = new RigidBody(chassisShape, mass, material) { Pose = new Pose(new Vector3F(0, 2, 0)), // Start position UserData = "NoDraw", // (Remove this line to render the collision model.) }; // ----- Create the vehicle. Vehicle = new ConstraintVehicle(_simulation, chassis); // Add 4 wheels. Vehicle.Wheels.Add(new ConstraintWheel { Offset = new Vector3F(-0.9f, 0.6f, -2.0f), Radius = 0.36f, SuspensionRestLength = 0.55f, MinSuspensionLength = 0.25f, Friction = 2 }); // Front left Vehicle.Wheels.Add(new ConstraintWheel { Offset = new Vector3F(0.9f, 0.6f, -2.0f), Radius = 0.36f, SuspensionRestLength = 0.55f, MinSuspensionLength = 0.25f, Friction = 2 }); // Front right Vehicle.Wheels.Add(new ConstraintWheel { Offset = new Vector3F(-0.9f, 0.6f, 0.98f), Radius = 0.36f, SuspensionRestLength = 0.55f, MinSuspensionLength = 0.25f, Friction = 1.8f });// Back left Vehicle.Wheels.Add(new ConstraintWheel { Offset = new Vector3F(0.9f, 0.6f, 0.98f), Radius = 0.36f, SuspensionRestLength = 0.55f, MinSuspensionLength = 0.25f, Friction = 1.8f }); // Back right // Vehicles are disabled per default. This way we can create the vehicle and the simulation // objects are only added when needed. Vehicle.Enabled = false; }