[ASSETS] [OPEN SOURCE] Tanks, tracks and N-wheeled vehicles

This isn’t difficult technically but it requires a lot of manual tuning and fiddling with spline coordinates and tangents manually.
There are three arrays that you need to modify: SplineCoordinatesR, SplineCoordinatesL and SplineTangents. To make things easier for me I usually add a dummy box into blueprint, place it where I think spline point should be and then copy/paste it’s coordinates into array. With tangents you just have to manually find some values which work, I haven’t found a good way to make it easier.

Then look at overloaded AnimateTreadsSpline() function. Here you need to add extra nodes (function calls) and change indexes of spline points. There should be one node (function call) per one suspension.

I don’t mind manual tuning and fiddling, I’m really good at that :smiley:
I thought you where able to add control point in the editor, but the way you describe it I have to manually add them in the array? Am I correct?

One thing about handling while driving with the M113 I noticed… How can you increase the responsiveness when steering.
When your speed increases it’s starting to feel really sluggish , while tracked vehicles are able to do pretty aggressive turns even at higher speeds.

Or a simple Blueprint you can drop in your scene so that you can create the spline visually and then store the coordinates in a variable that you can use to fill the Spline coordinate array

something like the content example

you can drop a reference model with wheels in the origin of your scene to draw the spline and then store the coordinates.

It’s a bit weird (and tedious) that you cannot edit a spline in a blueprint in UE4… or maybe I’m missing something.

BTW : I can insert extra spline coordinates manually now, but where can I find the tangent for a coordinate? Or edit the tangent?

I manually inserted the points and edited their location.
Also added and hooked them up in the AnimateThreadSpline function.
They move fine, also with the suspension.

As you can see… I just need to edit a couple of tangents… but I have no clue where to do that.
Also need to increase the number of Threads along the spline… also have no clue where to do that :smiley:

---------------snip-----------------

Wait… I found the Spline Tangents array :smiley:

Here goes.

Everything working :slight_smile:

This time with working tracks!

I love how well structured your blueprint is!

----snip----

I noticed a small error. wheels 6 and 7 do not make the track respond… I forgot to hook them up in the splineanimation function… fixed

Sorry couldn’t reply earlier. I’m glad you found the way how to fix splines! Yes SplineTangents arrays is where it’s stored.

Regarding controls, one reason for that can be the power output of engine. Turning of the tank is done by reversing torque on one of the tracks. If engine RPM is in a red zone then there is no power and tracks are just rolling, so you can’t really turn as you need power for that. In this case you ether upshift or break to loose some speed.
If you experience this when engine is not in the red zone than most likely there is simply not enough grip of the track with the ground. Perhaps it should be higher, I didn’t really found any reliable friction coefficients for tracks, maybe it’s just too low.

Looks good! There are few thing which I’ve noticed. Maybe it makes sense to have a bit thicker treads so they don’t clip the landscape so easily. For that you need to tweak two parameters: TreadHalfThickness and CollisionRadius in suspension. CollisionRadius is a radius of the road wheel + thickness on the track element.
Another thing is that dust particles should appear only on sand. Did you changed physx materials? Maybe it’s a bug with collision query channels.

To change amount of the treads look for variable TreadsOnSide. It’s the same variable for both sides, in case of M113 it actually should be different :smiley:

I saw the threadhalf thickness etc, but did not have time to play with them.

I see I made an error, suspension for wheel 6 and 7 is not hooked up to the spline… that also causes the track not to follow the wheel there, and also go through the floor.
Fixed it.

I changed the physx material on the floor yes :wink: … that’s not a bug… I like the dust. When I have time I will create a test map.
I plan to use Worldbuilder for that… now is a good time to test that workflow.

Next is to replace the thread with my thread… and I think I will continue detailing the model now.

I found torque curves for the engine.
CV90 has a Scania DSI 14 or 16 V8.
I implemented the 720Hp version and increased the weight of the hull to 24 ton.

Btw, the Weight value (for the hull) is that for the complete vehicle? I assume that is only for the lower section (hull, wheels etc) and that the weight of the turret is seperate.

The handling is much better with the new Torque curve and weight.

If turret will be attached on top, as a physical object that transfers it’s weight to the base of the tank then exclude it from chassis weight. Tracks can be included as technically suspension needs to carry at least half of the track weight (the other half is on the ground).

Make sure that your engine curve has a “red zone”, small range of RPMs at the end of the curve where engine torque is 0. For coloring of the RPM numbers in GUI I use a second curve with a color gradient.

The more suspension blocks you have, the less pressure on the ground in contact points (under road wheels) will be, if the supported weight is the same. When you increase weight, you get a better grip of the tracks with the ground.

Update:

  1. Added ability to flip wheel, sprocket and idler animation by 180 degrees.
  2. Refactored wheel animation function. It makes it little bit faster to customize and avoids annoying bug where functions in child blueprints got corrupted when their definition is changed in parent. This is how it looks in M113 example now:
    f76c4f119ebcee779c5942275308a17f629e81e3.jpeg
  3. Finally added proper friction coefficient calculation. Now MuX and MuY are used as radius for ellipse which defines what specific value of Mu (friction coefficient) should be used depending on the direction of the relative wheel (track under wheel) velocity. Now tank behave correctly and won’t spin like crazy if you try to turn it on spot for a while. They are harder too turn now so I’ve set MuY to 0.6 - half of MuX 1.2, which means it much easier for it to slide sideways then is to slip in place. Ideally Mu should be per-calculated in constructor and stored in an array to later be sampled in real-time.
    19ad11c764eafa69b8c0e02232c215f64771893a.jpeg
    Thank you Olento for this link: Friction Circle (The Basic Theory) it describes friction circle rather well and from there I got idea to use parametric ellipse equation to find a proper friction coefficient out of two (MuX and MuY) provided by user.

Btw, to turn faster you need to let go of gas pedal. The reason for that is when both forward and left/right controls are pressed than half of the torque from one track is directed to another, but when you press only left/right without pressing forward than one of the tracks get a complete torque in negative direction. I’m not sure how it works in real tanks.

Next step is to add automatic suspension and make turning easier. Not sure how exactly should be done.
Another thing is updating the whole thing to 4.10, do we want that? I don’t know if I should make it as a separate branch because most likely all assets will be marked as out of sync for you guys. How should I handle this from source control point of view?

Regarding friction circle, just in case someone needs it outside of the code. The math is following:
if we take a parametric ellipse equation
x = a * cos(t)
y = b * sin(t)
[where t=0…2Pi]
then our muX and muY (friction coefficients in X and Y axis of the wheel) can be used as radius of ellipse
x = muX * cos(t)
y = muY * sin(t)
we can find t from a dot product of relative velocity vector of the wheel and forward vector of the wheel
t = arccos( dot(V, Fvector))
substituting we get
x = muX * dot(V, Fvector)
y = muY * sqrt(1 - dot(V, Fvector)^2 )
then final friction coefficient mu is just length of the vector (x,y), which is a point on the ellipse in the direction of velocity
mu = length(x,y)

Nice!

Regarding source control, I’m looking into how this actually works inside UE4.
There should be a way to link your blueprint code from git directly in my UE4 project.
But I don’t know how this works yet… have to dig into that.
Also I have no idea what happens when I

As for upgrading to 4.10
If possible I would do that… I do plan on moving (and already moved for other projects) to 4.10 because there are some good vr optimisation things in the new version.
I can confirm that your scripts all work without any problems already in 4.10

I’m currently working on a more detailed hull for the cv90, and wanted to wait until you updated the script before moving on.
I’m also going to start moving my low res tiger into this, then I have both a modern IFV with automatic transmission, and a WW2 era tank with manual gearbox.
And I have a worldmachine license now, so will make a landscape to drive around on :slight_smile:

I think you just need to install GitHub client on your machine and sync using it. Then you open project in Unreal and enable source control. Perhaps I should try it myself and see how it works.

New update is out. If you are using previous version (0.41) I strongly advice to update, because I broke friction calculation in it. It might look like it works, but it isn’t working properly.

To test friction circle and component based approach I’ve added prototype of Aerosled. If you don’t know what it is: Aerosani - Wikipedia
I’ve re-used one of the tank meshes and added ski:

What you see on the left side is 4 static meshes for ski and 4 custom scene components which are responsible for suspension and friction. On the right side you can see their settings, which are very similar to the suspension settings of the tank.
Important part of this prototype is that ski are proper rigid bodies and can collide with environment. They are connected to chassis using constraint, which are not adjusted completely but they already very stable, especially taking into account that they need to slide over the surface and not roll as wheels.
Ski need to have anisotropic friction (like tank tracks or car wheels) which isn’t available out of the box. As friction have to be simulated manual, ski physics material is set to no friction (which adds to stability of constraint). To simulate friction we need to know “load on the wheel” which in our case is equal to suspension force. It’s possible to simulate suspension spring using constraint’s linear motor, unfortunately we can’t read suspension force of PhysX constraint due to the bug (or intentional implementation) in implementation of this function in PhysX’s code [more about it here: Linear Position Drive and Constraint Forces - Content Creation - Unreal Engine Forums]
For this reason spring is simulated separately and for now pushes only on chassis of the vehicle, it doesn’t effect ski itself.

Long term plan is to switch from monolithic design of the vehicles, as tanks made right now, to more modular. Based either on scene components or maybe some custom C++ components. The point is to have small building blocks out of which variety of vehicle can be constructed. For example, if I add a track component which would simulate several road wheels/sprocket and a single track, then combine it with ski of the aerosled - we get snowmobile. Perhaps it’s an overkill to simulate it like that as track of typical snowmobile is rather hidden but what if it’s a half-track with ski? :smiley:

Update compiled version of the project as well. Enjoy!
[I should probably add some brakes to aerosled]

thanks share

nice!
Like the aerosled :smiley:

Thank you!
Another good reason to get such setup of rigibody collision + physics constraint + manual spring + manual friction is that I can finally simulate this kind of suspension:
EkCtB0h.jpg
The bogie could be made as an actual animated object, constraint to a single point on chassis, wheel would be constraint to the sides of the bogie, each wheel would have a separate spring and their combined force would be pushing chassis at the top point of the bogie. I wouldn’t need to try it out to be sure. But first automatic suspension should be added to make current tanks more useable. Perhaps I should rebuild ripsaw to use skinned mesh for tracks instead of spline. Later both setups could be combined for the purpose of switching LODs.

yes indeed, I was also thinking about the sherman suspension.

One other thing I came across while testing.

And I had the same problem with the physics tank script in Unity.

Whenever you are on a slight slope sideways for example. The vehicle keeps sliding… is there any way to make sure it does not slip while standing still. Makes it really hard to aim at a target :slight_smile:

Also you need to add some sort of handbrake :D, so whenever you stand still on a slope you can put on the handbrake.

In the physics tank in unity he added an optional automatic handbrake that gets activated whenever you stand still and don’t give any drive inputs.

I see now that indeed it is handy to move some components into C++ in the future. Since you reall don’t need to acces what happens under the hood in the blueprints anymore.

Automatic handbrake should be easy, something like if you are not pressing gas or trying to turn and your speed is less than N then enable breaks. Makes sense to add it.

For sliding sideways it’s a bit trickier issue. I’m not exactly sure why exactly it happens, but theoretically there are multiple reasons for that:

  1. Overestimation of the friction force over the frame’s delta time. On one frame it applies too much friction and next frame it’s too little, so vehicle keeps being pushed very little one and another way. This could be solved by moving to C++ and calculating and applying forces in physics substeps. Which need to be done anyway for the whole thing to work properly when framerate changes rapidly.
  2. Estimation of the friction force on the basis of previous frame velocity. Right now I’m reading velocity calculated on previous frame, instead I should calculate it on a basis of what velocity will be at the end of current frame - before the next physics update is calculated. Because AddForce and AddForceAtLocation() will be triggered at the next physics update. So in the current setup friction force is resisting movement which already happened, instead it should resist movement which will happen.
  3. The other potential solution is to force physics object into sleep if you are not providing any inputs. Unfortunately I don’t know how to make this, because suspension force keeps it awake all the time as AddForce() awakes physics object. I need to somehow track if any inputs (not user inputs by physics inputs, like collision and etc) have changed since previous update and put whole physics to sleep if nothing changed. But this should be implemented anyway for performance reasons and LODs.
  4. More precise friction force can be calculated using constrains, which should stop movement of the object completely. I’m not sure how exactly this can be implemented. Logically it should be something like spawn constraint, limit all object movement and rotation, query force of the constraint, remove constraint and calculate how much of that force can be actually applied in regards to current limit of the friction force. The problem here is that I don’t know if constraints calculate their force as soon as they are added or they need to wait for physics update, if they need to wait then it would kind of ruin the whole idea as vehicle will be grounded in place for a time of the frame.
  5. I’m not completely sure that my suspension force is precise enough, depending on the settings it can fluctuate creating less or more friction from frame to frame. This would lead static vehicle to start sliding.

As you see I’m not sure which of them is exact problem, maybe all of them :smiley:
But I agree that this have to be solved to reach some basic degree of maturity for such setup to be actually used in real game. Funnily enough, while Arma3 uses physics, the vehicle were not capable of standing still on slopes, I’m curious what is going on there.

I have to check what chobi did for me in unity.

I know it was some sort of hack.

I believe indeed he disabled the wheels or something… or the body itself as a physics object when you did not give any movement inputs… and that worked like a charm.
And that is also how the auto handbrake was implemented from keeping the tank from sliding.
You cannot disable everything as you do need the suspensions to work when you fire the main gun for the recoil effect.

I have to see if I can fire up unity to look at the code.

Recoil from main gun will most likely call AddForceAtLocation() which should wake up physics body. Movement of the turret will do that too if it made as a physical object, which it better be for collisions. But this it still very useful for cases when some tanks are just parked or when you are looking out of the hatch and etc.

Please take a look at that code if you have some time, it would be very helpful!