Along with my changes to the suspension model where to refine the traction model for https://github.com/Murph9/RallyGame
The previous model uses a simplifed Pacejka Magic Formula as noted in a previous blog post. That only covers each direction individually, I found a good blog post (http://phors.locost7.info/phors25.htm) which basically describes the math behind how it all has to work. The summary is that you want each direction to contribute to the maximum slip irrelevent of whether what its maximum slip value is. This can result in a maximum which is actually ellipse shaped. This math mostly goes over my head, but the graphs below should help.
So trying to implement this I found that it was very hard to tell whether or not the combined values where actually combining successfuly - although running the game and seeing the car accelerate in a uncontrolled spin and roll was helpful it didn’t tell me what was going wrong.
Basically this comes down to how to normalise each of them based on their maximal value. The math goes like this:
float ratiofract = slipratio/maxLong; float anglefract = slipangle/maxLat; float p = FastMath.sqrt(ratiofract*ratiofract + anglefract*anglefract); fz = (ratiofract/p)*formula(p*maxLong) * susForce; fx = -(anglefract/p)*formula(p*maxLat) * susForce;
So to explain this:
*fract lines = fraction comparing the value to the maximal value
p = combined total maximal value, if equal to 1 the tyre has no more to give. More and we are more slipping than gripping.
f* = calculate the value for the normalised traction value
Which results in a graph like this:
With this change it feels like a ‘real’ car game, hopefully this helps someone else.
My source for this is at:
Custom Suspension Model 2018-12-02
This is in reference to my other post about wheel physics, last year. Related to the project: https://github.com/Murph9/RallyGame
The game engine (JMonkeyEngine3) has a built in VehicleControl which handles suspension forces and wheel translation which used a translation of bullet (C++) called jbullet (Java).
I moved to bullet (C++) as I thought jbullet isn’t as supported as it was before in jme 3.2 - but this broke how I was accessing the built in VehicleControl class as some internal fields became inaccessable (as I was extending the PhysicsVehicle class).
This meant that I needed to basically rewrite the jbullet class myself. Since then I have found that it should still work it was just my project setup that failed me but the underlying rigidbody was hidden in the way I was accessing it. Although updateing the suspension been a long time coming as the suspension model didn’t have sway bars (more on this soon). And so to spoiler this early I’ve ‘finished’ it, I decided it would be a good time to explain problems that I have had.
First I found the sources for all the classes involved, this is the jme3 VehicleControl class, the jbullet class and a source for the bullet class. So some copy/paste happened, I had a low level class which handled everything with at least 300 errors in the editor. Added all the references the solution had available but still I was getting a lot of errors.
After that came was translating raycasting using bullet library rather than jbullet, decided to add a source to the methods into the editor for quick reference at this point. Skipping over any details, the raycast returns a method in “world” space which is decidedly not. From what the source did it could only mean that it was backwards causing this line in the raycast class:
rd.hitNormalInWorld = result.getHitNormalLocal();
It is still right as of now, who knows, but it leads into the next problem.
The Vector3(f) classes weren’t compatible in the 2 reference files below (along with Quaternion and Matrix classes as well) - lets just say that a method translation reference notepad++ file was made to map them.
Methods that differred basically boiled down to order of arguments and whether or not it returned the value as well.
A few methods did very different things
.sub() being a good example, there is also heavy use of
Transform which the game library doesn’t use much.
And finally the translation seemed successful and I could at least continue.
Next main problem was that the class I had in my game
MyPhysicsVehicle was doing everything, from input control to traction curve calculations - this had to go and did.
I decided to split the files into
RayCar (suspension and traction),
RayCarPowered (engine torque and braking),
RayCarControl (jme3 integration i.e. visual model and input control).
Honestly an arbatory split.
The suspension itself caused the most problems as the world->local->world translation of the forces caused many
inf vector values due to either positive feedback loops or div by small or 0 numbers. The
body.impulse(force, pos) method in jme3 doesn’t explicitly say whether its in local or world space - although in bullet there is no concept of local space so this should have been obvious in retrospect.
Later I found the suspension force was being incorrectly converted to local space, which meant that driving on slopes caused you to slide up them unpowered, very small commit for the largest change that one.
The next and hopefully last large problem was deciphering what the constants being sent to the suspension model where, values like
maxSuspensionTravelCm which didn’t sit with how I wanted the suspension to work.
My new model works closer to values you can retrieve from the real world. My model a preload force, which defines the suspension force at maximum suspension travel (wheel furthest from the car body), and a force which is linear from that point up until the minimum suspension travel (closest to the car body).
And lastly I finally got to add a new feature, sway-bars (or anti-rol bars) which basically just try and keep the wheels and the same suspension travel with each other.
Current tests of this system work really well, but the last outstanding problem is that the spring constant seems off compared to real world values.Read more..
TODO aliteration 2018-03-15
Just an entry from my personal TODO list, a friend said it sounds like a free form poem:Read more..