← Back to Blog

Unity3D - Vehicle physics

This article elaborates car physics and chassis deformation simulation implemented in Unity3D. The goal of this project is to implement a real-time simulation that imitates the real life behaviour of vehicles, including dynamics, various frictions and collision with softbody implementation. The key is to create a realistic environment considering performance as well.
Video games often offer the ability to control a vehicle, most commonly personal- or race cars. Both controlling and the possible deformations (e. g. damages from collision) are based on simplified physical models, which significantly reduce the computing complexity and also provide a real life like experience. A physical model, which decipts reality much better provides by far more realistic experience and can be used in a wider range as well (e. g. in the automobile industry). The goal of this experimental project is to create a simulation environment, which is able to run in real-time and provides as much realistic deformation as possible.

Driving simulation

The first task was to implement a driving experience. The engine uses NVidia's PhysX simulation, where general vehicle simulation can be accessed. This includes suspension, basic movement and basic tire friction, making it a good start. It does not include transmission, dynamic friction, aerodynamics, so this had to be extended.
As in real life, the motor's torque has to be transferred to the wheels of the car. The car has an Axle class (A pair of wheels) which can be set whether it is connected to the motor or not. This way we can easily parametrize FWD, RWD or even AWD vehicles. The Motor class has a Torque property and RPM property, and the connection of these can be described using a graph parameter. Here is an example for a 3.5L V6 engine:

RPM-torque graph


And finally, the Transmission class, that connects the motor and the axle(s). The efficiency of the torque throughput varies depending on the current speed. This is compensated by gears. The transmission can have N gears, where each has a min-max RPM and velocity, and it linearly interpolates the appropriate value and when reaching the limit value, it switches to the appropriate gear. Note that the velocity of the car can also change the RPM of the engine, typically after shifting gears.

Frictions

I have implemented these types of frictions:
  • Rolling friction
  • Dynamic tyre friction
  • Air-drag
  • Downforce

Rolling friction

The friction that is preventing the wheels from rolling. This is depending on the mass of the body and a friction constant that describes the materials.

Dynamic tyre friction

Tyre ubber has nature that the magnitude of friction may vary depending on the current state of the dynamics of the car and once it loses grip, it becomes lower. This typically happens at sudden velocity magnitude or direction steps (e. g. slipping in curves, sudden braking, burnout). This is called the extremum point, where the tyres fail to grip over a specific force and begin to slip sideways. The material of the tyre, the surface can also influence this. The following graph indicates the typical force-grip parameters:

Tyre friction graph


The tyre grips until the extremum point, and then it beginss to slip depending on the magnitude of the force applied to it. Once the asymptote point is reached, the friction becomes constant. The tangent is zero both at the extremum and asymptote points.

Air-drag

Depending on the shape, the velocity and the face area of the car, the air drag vector pulls the body to the opposite direction of the velocity vector. For simplicity, I declared a parameter within the [0,1] range that is used to calculate the requested air-drag force vector.

Downforce

Typically sports cars are designed with such aerodynamics. The idea is air-drag is used to push the car downwards, improving its handling and stability at higher speed.

Softbody simulation

Unlike rigidbodies, softbodies have a more intricate simulation. Rigidbodies retain their relative distances between any two points within the body volume, while these can vary over time for softbodies. However, it is also expected that the shape is retained at some level unlike for fluids. An important property for softbodies is permanency. Jelly and rubber like materials will try to move back to the original shape after deformation. On the other hand, materials like thin metal will conserve the deformation, like car chassis. This is the goal I wanted reach.

Warping chassis, the bodies interact with each other, and the environment.

Generating reference points

Using Unity3D's Editor scripting tools, I created a method that generates referance points within the car geometry's bounds. These reference points have an uniform distribution for the x, y, z coordinates. With a press of a button on my script, the program generates these reference points and also provides them all the components (e.g. Springs) it requires for simulation. Now I have my reverence points with the ability to simulate softbodies.

Rigging the meshes

Now that I have the reference points that simulate the behaviour of softbodies, I want them to influence the mesh of our geometries. The same rigging method used for character animations, to control the positure of the mesh using bones. This time, the result is similar, however, the geometry is now distorted using simulation points, not baked animations.

private void RigMesh()
{
var bones = _controlPoints.Select(x => x.transform).ToArray();
var skinMesh = !GetComponent<SkinnedMeshRenderer>() ?
gameObject.AddComponent<SkinnedMeshRenderer>() :
GetComponent<SkinnedMeshRenderer>();
if (skinMesh.sharedMesh == null) return;
var mesh = new Mesh
{
vertices = skinMesh.sharedMesh.vertices,
triangles = skinMesh.sharedMesh.triangles,
uv = skinMesh.sharedMesh.uv,
normals = skinMesh.sharedMesh.normals,
name = skinMesh.sharedMesh.name
};
var weights = new BoneWeight[mesh.vertexCount];
for (var i = 0; i < weights.Length; ++i)
{
var closest = GetClosest4(transform.TransformPoint(mesh.vertices[i]));
//Gaussian-like weight distribution, sum must be 1
weights[i].boneIndex0 = closest[0];
weights[i].weight0 = 0.4f;
weights[i].boneIndex1 = closest[1];
weights[i].weight1 = 0.2f;
weights[i].boneIndex2 = closest[2];
weights[i].weight2 = 0.2f;
weights[i].boneIndex3 = closest[3];
weights[i].weight3 = 0.2f;
}
mesh.boneWeights = weights;
var bindPoses = new Matrix4x4[bones.Length];
for (var i = 0; i < bones.Length; ++i)
{
bindPoses[i] = bones[i].worldToLocalMatrix * transform.localToWorldMatrix;
}
mesh.bindposes = bindPoses;
skinMesh.quality = SkinQuality.Bone4;
skinMesh.bones = bones;
skinMesh.sharedMesh = mesh;
}

Each vertex of the geometry gets a weight for the nearest four control point. Four is the highest bone that can be attached to each vertex for optimization purposes.