Friction is fractious. It’s a bear to work with, but you’ve gotta do it if you want physics to look right. I’ve had to do some annoying busybody work to deduce proper values, so I’m sharing those values and my process to arrive at them in the hopes of saving somebody else some time.
Note: Here we’re discussing the Bullet Physics Engine, not the physics of small gun projectiles.
Friction in Bullet Physics
Bullet defines friction with a coefficient value per object. Ranging from 0 to just over 1, this value defines how strongly friction applies to that object.
A value of 0 is no friction (wheeeee!) a value of 1 is high friction.
Note I said it gives a coefficient per object. By definition friction happens when two objects rub into each other. So the coefficient per object only ever matters when there are two objects and thus two coefficients. Bullet calculates the friction of a collision by multiplying the coefficients from the two colliding objects.
Find friction coefficient values for each game object that are accurate enough to real life to not break suspension of disbelief.
Bullet doesn’t model real life.
In real world physics, the coefficient of friction is not per object, it’s per combination of objects. For example, an iron sword has a different coefficient of friction when rubbing against a steel breastplate than against an iron one. This makes sense, but the difference isn’t entirely due to the different coefficients of steel and iron. To get real world values, Iron’s coefficient would need to change depending on what it was interacting with.Example:
Drawing on this list of measured friction coefficients, we get a few useful values but cleaning them up for game use is going to take some work. We’re going to have to make some assumptions.
Steel x Steel = 0.5-0.8 (let’s assume a middle value of 0.65),
Mild Steel x Cast Iron = 0.4 (not sure what mild steel is as compared to the steel tested against itself. Lets assume they’re close to the same.)
Cast Iron x Cast Iron = 1.1
In bullet, if you had a steel object rubbing against a steel object you could define each of their coefficients as square root of 0.65 or 0.806 and it would calculate the coefficient as 0.806*0.806 = 0.65, accurately producing the real world value.
For cast iron, using the same process, you’d have to define the object’s coefficient as a value of 1.048 to get two cast iron objects to interact with the real world value of 1.1.
But then when you rub the cast iron object with it’s value of 1.048 against the steel object with its value of 0.68 you get 1.048 * 0.68 = 0.712, not matching real world tests which measure that value as 0.4.
In other words, bullet’s solution of a single value per object doesn’t match reality.
We don’t want to rewrite bullet to check what kind of surfaces are interacting and look up a perfect value. That would be silly. We don’t need ‘perfect,’ we just need ‘believable.’
I decided to simplify the tables of measured real-life friction values, and then come up with a list of game values that calculate closely to the real-life values. The objective is to have the smallest possible margin of difference between the values bullet calculates on collision and the measured real-world values, bearing in mind that the way bullet does it will never yield perfect results.
|Hard Metal||Hard Metal||1.1|
|Hard Metal||Soft Metal||1.05|
|Soft Metal||Soft Metal||1|
Note: the values in yellow are my best guesses, necessary to fill out the table, but not based on actual tests.
These are the target values. We need to find “per surface” values so that bullet’s calculations arrive as close as possible to these marks.
I set up a spreadsheet to test an array of arbitrary values for each surface against these target values
I used two metrics to measure the accuracy of my results:
- The average variance from what bullet calculates to the real world values
- The number of bullet calculated values whose difference from real world is above 0.1.
This second metric is because it’s possible to have a large number of bad results cancel out to an average difference of 0.
Then I input arbitrary ranges for each of the selected surfaces and watched my metrics. I selected the set of values with the smallest possible average variance and number of bad results.
This is what I came up with:
Using these values will result in an average variance from real world values of 0.026, but the friction values between hard metal and soft metal will be too low (calculating to 0.58 instead of the observed 1.05. Hard metal on hard metal and soft metal on soft metal are also too low, but giving them higher values makes their interactions with other surfaces much worse.
Note that these values will change if you use a different set of common surfaces. We’re working in a dark ages type environment so this set covers most of our basic needs very well, but if you wanted to add say, ice, which we don’t have, you’d come up with different values for everything else.Also, the average variance inevitably goes up as you add more surfaces.
The takeaway here is that while bullet won’t ever reproduce reality exactly, it can get pretty close for a narrowly defined set of materials. I suppose you’re also welcome to take away the values I’ve generated, but unless your set is exactly the same as mine, these values may not be optimal.
I hope this is helpful to someone out there. Feel free to comment with any questions or suggestions. Always happy to talk shop.