Vehicle crash damage and mesh deformation

Author: Finn Hoogerwerf

Table of contents:

  • Introduction
  • Goal
  • How I did it
  • Conclusion and known issues
  • Sources
  • Research methods

Introduction:

For my Research & Development assignment I was inspired by Grand Theft Auto V to work on a crash deformation system for vehicles in Unity Engine. In Grand Theft Auto V, vehicles may get damaged by crashing into other objects or by debris hitting the vehicle. If the vehicle’s armor hasn’t been upgraded much, this often results in deep dents and scratches on the surface. The vehicle will often lose all kinds of parts because they break off after impact. Those dents and parts that break off are what I will be focusing on in this article.

(Link to Rockstar Games’ official Grand Theft Auto V developer website: https://www.rockstargames.com/gta-v)

Goal:

My goal for this assignment is to make a vehicle get dented on impact with other objects. I will achieve this by writing a script that can be applied to any part of the vehicle that should be allowed to dent. These parts can be given unique values for minimal/maximal deformation, minimal damage to create a dent, if a part should be allowed to break off and after how much damage, if a part with a hinge (door, hood, trunk, etc.) should be able to break open and after how much damage.

How I did it:

I first decided to take a look at how deformation behaves in Grand Theft Auto V, because I wanted to base my goal and results on how it works in that game.

I tried crashing a random car 5 times in the same area and see how the damage would progress. In the image below you can see the result. In the first image the car is still in perfect condition.

After the first crash, some windows already broke and scratches were visible on the front of the car. The front bumper was hanging loose and the headlights broke. You can see the hood has been wrinkled by the impact. This has likely been done using normal mapping, but I decided making that would be outside my scope (still interesting to note, though). I won’t be making a scratch texture effect either for the same reason. Window shattering I will make using a simple particle system.

After the second crash, the hood was getting loose and the front wheel at the side of impact was bent inwards slightly. The third crash didn’t really bring anything new, except that the dent got deeper. At the fourth crash the hood popped off and the wheel was now bent inwards so much that the car wouldn’t drive straight anymore. In the fifth and last crash the front bumper finally broke off. The car still drives, but the engine occasionally cuts out.

After doing some more crashing, I found that the doors and trunk would also open on their own sometimes after hitting them with enough force or getting damaged too much. The front and rear bumpers could break off when getting hit too often or with too much force, too. All this combined with the results from the previous screenshots are what I want to create for this project.

Here’s a picture of one of my extremely beautiful modified cars (‘Maibatsu Penumbra’ (a relatively cheap sports car), model based off the Mitsubishi Eclipse SE in real life):

I marked all the parts that should be able to break in red (front/rear bumper, lights, windows), and all the ones that also work with hinges in yellow (doors, hood, trunk). This may differ per vehicle. These parts are the same ones I want to be able to break off in my project. On top of that, I would also like to allow the wheels and spoiler to detach, just for the sake of adding a little more realism.

Now it’s pretty much clear what I want to happen to specific parts of the vehicle. All parts should be able to deform, and certain parts can break or move using hinges, too. I just need to find a way to track how much each part has been damaged. This is a nice bridge to the next topic: programming deformation.

I need to find a way to change the shape of the vehicle’s parts when they get hit by other objects with a strong enough force. To change the shape of an object while the program is running, we need to modify the object’s mesh.

“What is a mesh?” you might say. Well, I’m glad you asked! A mesh is a collection of ‘vertices’, ‘edges’ and ‘faces’ that describe the shape of an object. A vertex is a singular point in space, an edge is a straight line segment between 2 vertices and a face is a flat surface enclosed by edges. As you’ll see in the example below, the more vertices a mesh has, the higher its resolution will be (meaning the shape will be more detailed). Meshes with a higher resolution are heavier to process, though.

To create a dent, we’ll need to move one or more vertices of the object’s mesh on collision. Before I get to programming the actual physics calculations, it might be handy to download a vehicle asset and decide what core variables we’ll play around with.

I decided to pick a car asset that resembles the Volkswagen Golf MK4. The black lines represent the mesh edges. All vehicle parts are separate objects (windows, wheels, hood, spoiler, etc.). As you can see, the mesh is relatively low resolution. I chose a low resolution model to save some performance.

Before I start with the programming, I’d like to credit the following video that helped me lay the groundwork of my deformation system: https://www.youtube.com/watch?v=-dsRIyzAcqg

These are my core variables. I’ll explain what they’re for.

deformRadius: when a specific point on the vehicle is hit, I don’t necessarily want to move just 1 vertex. To smooth it out, it’d be nice to move a few more vertices around it. Every vertex within the deformRadius from the point of collision, may be moved.

maxDeformDistance: in case a vertex is placed really far after a collision. It will be used to clamp the deformation distance.

hardness: in real life, different materials have a different hardness. A diamond for instance, has a lot more hardness than aluminum. I can give different parts of my vehicle a different hardness, to allow them to get damaged harder or easier. It’ll act as a minimum damage number. The damage taken has to be more than the object’s hardness, or no damage will be applied. If it is more than the hardness, the number of damage that is more than the hardness will be applied as final damage. Example: hardness is ’11’, damage is ’18’, the final applied damage is ‘7’.

damageDistribution: this one is important for the first variable (deformRadius). Vertices closer to the edges of this radius should probably be moved less far than the ones closer to the center. Making damageDistribution’s value ‘0’, will mean all vertices inside the deformRadius will be affected equally (not so smooth). Value ‘1’ means there will be a linear drop-off between the point of collision and a given vertex.

damageMultiplier: pretty self-explanatory. Changing this value lets me easily adjust how strong the total damage will be applied to the mesh.

Now that I’ve explained the core variables to get the deformation physics to work, we’ll need to write some code to do the calculations for us. First up, we need to have access to the vehicle part’s mesh and collider. Luckily for us, it’s not difficult:

To determine if something hit our vehicle object hard enough to cause a dent, we can measure the force which the vehicle was hit with. We can do this by taking the magnitude (meaning, the ‘length’) of the hitting object’s impulse vector. The hardness will be subtracted from the collision force if that force is higher than the hardness. This results in the total damage that will be applied to the car. Otherwise, no damage is applied.

Hold on tight, here’s where things start to get a little more complicated!

The first thing I do is getting the first contact point. There might be more, but they are irrelevant. I then go through every vertex of the vehicle part’s mesh to check if their position is within my deformation radius. I can’t do that without transforming the contact point’s position from world space to local space (InverseTransformPoint). This is important, because all vertex positions are stored in local space. After that I can simply calculate the distances between the collision point and the vertex position. Now I can finally complete the check to see if the vertex distance from the collision point is within the deform radius. If this check returns true, deformation will be calculated and applied.

How do we calculate the deformation? The first thing we do is calculate the distribution (a number between 0 and 1). After that we grab our vertex’s position and take it out of local space, into world space. This way I can make it manually ‘interact’ accurately with forces. I calculate the new position of the vertex based on the relative velocity between both objects, and multiply that by the distribution value we just calculated, by damageMultiplier and by addedDamage (the new amount of damage caused by this collision). Then we add this whole value onto a copy of our current vertex position (deform). We put this back into local space and apply it to the vertex’s real position value. Now we can update the mesh to show the changes:

Now that we made the first few steps in code, it’s time to do some work in the Unity editor. I added this script to every single part of the car and gave all of them a rigidbody and mesh collider. Every worked as it should when making the rigidbodies kinematic, but making it this way didn’t allow my car to move. It was forced to stay frozen in place. That’s a problem, because that wouldn’t make it possible to have working hinges for doors. That’s why I decided to use fixed joints. I need rigidbodies to allow per object collisions, this way I can make them non-kinematic, but they won’t just fall to the ground. The funny thing about fixed joints is that for some reason, they are a bit jiggly by default. In my opinion, this unintentionally added some more realism to my project.

Here’s an example. This is the front bumper of the car. It has a rigidbody, mesh collider, fixed joint and deform script. I set the connected body as the car’s main frame. There’s also a small sneak peak in the deform script about how I made the hinges work.

This is the trunk. It uses a hinge joint instead, as the trunk is essentially just a door. If I want it to work properly, I need to make use of limits of how far the door should be able to open and close. As you can see here, I left them at 0. Why? Because I don’t want the doors to move until they’re damaged enough, and just enabling/disabling ‘Use Limits’ at runtime would for some reason cause the door to bug out. That’s why I just moved those values to the deform script.

This is the updated UpdateMesh function. It now also checks the object has a hinge, and if it does, if it should pop open or not. You can also see I have a Detach function at the bottom to have them break off entirely. This of course also works for non-hinge joint objects, like the bumpers and wheels.

It checks if the object is allowed to be detached. If yes, it destroys the joint component and detaches the object from its parent. It does the same for any child objects it has. After that, it removes this script from the object. At the start you can see I’m enabling collisions, and at the end you can see I’m doing something with glass. I’ll explain the colliders first.

Because all parts would damage each other simply by constantly touching each other, I needed to disable the collisions between them. I did that by writing a script and applying it to the root object.

It simply looks for all the colliders in the car, and saves them in one list that can be accessed from anywhere. I also made it so that I can give the car an initial drive force to make them crash into something if I wanted to. Then in every instance of my deform script, I access this list in the Start function to disable collisions:

Now I’ll explain the glass. Obviously, the windows and lights should shatter when they get hit. After all, glass doesn’t deform, it just breaks. That’s why I made a boolean to select glass objects and a function to make them shatter using particles:

This was quite easy. I just reused the car’s window model as glass particle, and spawn a whole bunch of them and make them fall in a random direction. Just a matter of doing some tweaking until it looks nice.

Putting everything together, this is my final end result:

The player can move around using W, A, S, D + Space, Left Shift. The player can also shoot projectiles by pressing Left Mouse.

Conclusion and known issues:

Congratulations! We now have a working deformation script for vehicles! Several settings may be adjusted by developers, like how hardness, damage multiplier, maximum deformation distance, damage radius and damage distribution. You can also specify if an object is made of glass or if it should be able to break off. You can also make objects with hinges open on their own after a certain amount of damage.

Sadly, the project is not bug-free. The biggest issue I have right now likely has to do with the fact I use fixed joints. Sometimes after a hard enough impact the mesh will be deformed in a strange way (like spikes sticking out really far) (*), or a car will launch into space. It likely has to do with rigidbodies interfering with fixed joints. Luckily, both are difficult to reproduce without manual interference from within the scene editor. Here’s an example, but I’ve seen worse:

(*) After deadline: The spike issue appears to be somewhat fixed now. I made a mistake in the code. I thought ‘Vector3.ClampMagnitude(deformedPositionChange, maxDeformDistance);’ would set the ‘deformedPositionChange’ vector to the clamped vector, but in reality this method simply returns the clamped vector. Changing to ‘deformedPositionChange = Vector3.ClampMagnitude(deformedPositionChange, maxDeformDistance);’ made the maximum deform distance function properly. Still, this doesn’t take away sometimes dents are made in directions they’re probably not supposed to…

I’m very satisfied with my result for this project. At first, I was overwhelmed and afraid to add more functionalities and realism to the project as I thought I’d lose myself in enormous tasks that would add very little to the result. I’m happy that what I decided to add was really doable, but still challenging enough to keep me busy.

Sources:

Research methods:

  • Library: Available product analysis: Grand Theft Auto V game
  • Library: Available product analysis: Tutorial video by PolySync Productions
  • Library: Community research: Official Unity Discord server
  • Library: Literature study: Studying physics on the internet
  • Showroom: Peer review: Weekly guild meetings
  • Workshop: Code review: Official Unity Discord server

Leave a Reply

Your email address will not be published. Required fields are marked *