Page 1 of 3

Suspension script

Posted: 12 Jun 2007, 14:03
by Zpock
http://www.youtube.com/watch?v=cN1vt01mmcU

Here is a demonstration model + script, you will need to write an fbi and stuff to make it work if you want to test it.

Image

Image

The idea is that every wheel has a spring that pushes against the hull of the vehicle, so it bumps around. The spring force is normally proportional to it's displacement. First off we need these objects and variables:

Code: Select all

#define TA			// This is a TA script

#include "sfxtype.h"
#include "exptype.h"

piece  ground, hull, turret, gun, flare, wheel1, wheel2, wheel3, wheel4, wheel5, wheel6, susp1, susp2, susp3, susp4, susp5, susp6, gs1, gs2, gs3, gs4, gs5, gs6;

static-var  moving, xtilt, xtiltv, xtilta, ztilt, ztilta, ztiltv, ya, yv, yp, s1, s2, s3, s4, s5, s6, damp;

// Signal definitions
#define SIG_AIM				2

#define   ANIM_VARIABLE   Moving 
#undef   ANIM_VARIABLE 
As you can see I have added empty objects in the model, gs1, gs2 etc, those are the "ground sensors" that check the height at the locations of the wheels. This was a quick hack so it's certainly possible to reduce the nunmber of separate objects in different ways. The variables s1, s2, s3 etc is the displacement of each wheel/spring, wich I will show how to compute shortly. xtilt, xtiltv, xtilta etc are the current value, speed, and acceleration of the different axes that the hull can turn, and move. Notice that the body can rotate around both the zaxis, xaxis, and move up/down. Next is the suspension function itself:


Code: Select all

Suspension() 
{
	while(1)
	{
		
		s1 = get GROUND_HEIGHT(get PIECE_XZ(gs1)) - get PIECE_Y(gs1);
		if(s1 < [-2])
		{
			s1 = [-2];
		}

		s2 = get GROUND_HEIGHT(get PIECE_XZ(gs2)) - get PIECE_Y(gs2);
		if(s2 < [-2])
		{
			s2 = [-2];
		}

		s3 = get GROUND_HEIGHT(get PIECE_XZ(gs3)) - get PIECE_Y(gs3);
		if(s3 < [-2])
		{
			s3 = [-2];
		}

		s4 = get GROUND_HEIGHT(get PIECE_XZ(gs4)) - get PIECE_Y(gs4);
		if(s4 < [-2])
		{
			s4 = [-2];
		}

		s5 = get GROUND_HEIGHT(get PIECE_XZ(gs5)) - get PIECE_Y(gs5);
		if(s5 < [-2])
		{
			s5 = [-2];
		}

		s6 = get GROUND_HEIGHT(get PIECE_XZ(gs6)) - get PIECE_Y(gs6);
		if(s6 < [-2])
		{
			s6 = [-2];
		}
Here we compute the different values for s1, s2... etc. Pretty straightforward, but notice that the if:s put a lower bound on how far down the wheels can go, this is important. The result is that sometimes, the wheel is in the air. One thing that can be improved is to add similar code here for the upper bound, this is when the suspension is overloaded and it should make a nasty bump...

Anyway, now we need to take into consideration the different spring displacements. The force from the spring is proportional to this displacement. The force can act in different ways, either giving a linear acceleration, or rotational acceleration on the body, depending on how it's distributed among the wheels/springs. This is just a quick hack to get something that looks like real physics, so I have opted to simply guess some values until i found some that works:

Code: Select all

		xtilta = 0 - (get ATAN(s1, [14]) - get ATAN(s3, [14]) + get ATAN(s4, [14]) - get ATAN(s6, [14]))/300 + xtiltv/7;
		xtiltv = xtiltv + xtilta;
		xtilt = xtilt + xtiltv*4;
The ATANs where mostly to get angles instead of displacement, not much tought went into those. Notice that s1 and s4 are the front wheels, s3 and s6 are the backmost wheels. The force from the front wheels act in the opposite direction as that from the back, hence the difference in signs here. The last term "xtiltv/7" is the dampening. Depending on how much this is, you get different effects, called subcritical, critical and supercritical dampening. In short, subcritical (too weak) will continue to oscillate for a while, critical will quickly return to a balanced state, while supercritical will again slowly return to the balanced state but withouth oscillating at all.

Computing the speed from the acceleration is straightforward, so is the actual tilt. Notice the *4 there, I found that experimenting with different values here will change the amplitude/frequency in a different way then changing the constant in the acceleration formula itself (/300 here). Then we compute the other tilts, and the displacement, in a similar fashion:

Code: Select all

		ztilta = 0 - (get ATAN(s1, [14]) + get ATAN(s2, [14]) + get ATAN(s3, [14]) - get ATAN(s4, [14]) - get ATAN(s5, [14]) - get ATAN(s6, [14]))/300 + ztiltv/7;
		ztiltv = ztiltv + ztilta;
		ztilt = ztilt + ztiltv*4;
		
		ya = (s1 + s2 + s3 + s4 + s5 + s6)/100 - yv/25;
		yv = yv + ya;
		yp = yp + yv/10;
		
		move ground to y-axis yp now;
		turn ground to x-axis xtilt now;
		turn ground to z-axis ztilt now;
Notice that for the displacement we don't need any ATANS or stuff, it's pretty straightforwardly just an average. Different combinations of spring forces could probably be used to get interesting effects, like weighing or such. Then the actual transformations are put into action. The x rotation followed by z rotation is imprecise and can lead to problems with very steep slopes, a more sophisticated way would be to use vector/matrix math to get the rotations done straight, but interestingly, the system is suprisingly good at overcoming these problems and self-correcting itself in a way!

The spring displacements are then recalculated and the wheels repositioned:

Code: Select all

		s1 = get GROUND_HEIGHT(get PIECE_XZ(gs1)) - get PIECE_Y(gs1);
		if(s1 < [-2])
		{
			s1 = [-2];
		}
		s2 = get GROUND_HEIGHT(get PIECE_XZ(gs2)) - get PIECE_Y(gs2);
		if(s2 < [-2])
		{
			s2 = [-2];
		}
		s3 = get GROUND_HEIGHT(get PIECE_XZ(gs3)) - get PIECE_Y(gs3);
		if(s3 < [-2])
		{
			s3 = [-2];
		}
		s4 = get GROUND_HEIGHT(get PIECE_XZ(gs4)) - get PIECE_Y(gs4);
		if(s4 < [-2])
		{
			s4 = [-2];
		}
		s5 = get GROUND_HEIGHT(get PIECE_XZ(gs5)) - get PIECE_Y(gs5);
		if(s5 < [-2])
		{
			s5 = [-2];
		}
		s6 = get GROUND_HEIGHT(get PIECE_XZ(gs6)) - get PIECE_Y(gs6);
		if(s6 < [-2])
		{
			s6 = [-2];
		}
		
		move wheel1 to y-axis s1 now;
		move wheel2 to y-axis s2 now;
		move wheel3 to y-axis s3 now;
		move wheel4 to y-axis s4 now;
		move wheel5 to y-axis s5 now;
		move wheel6 to y-axis s6 now;
		sleep 10;
I'm not sure if the recalculation here is necessary, this is just a quick hack as said, I havn't tried removing it yet. The short sleep ensures that this is computed pretty much every frame. I think this is necessary and that It dosn't really take that much performance, but I havn't done any testing on this. I tries putting in 100 units at the same time or so and noticed no more lag then usual. The rest of the script is the usual stuff, just making sure to start this script on creation. It could probably be stopped from running when idle, but with some time to let any remaining oscillations run for a while.

So there is a lot of improvement that could be made. I'm pretty sure this can be used for a great deal of stuff, including different wheel configuration and even tank tracks. I also think these ideas could be used for a truely awesome walking script for legged things as well, combined with the work on "true walkscripts". Also, the unit recoiling when fireing weapons, when hit, and when starting/stopping movement can surely be added in for great effect.

Posted: 12 Jun 2007, 14:13
by SwiftSpear
This looks pretty much liquid cool. Please post a youtube demo!

Posted: 12 Jun 2007, 14:58
by Lippy
Hehe, that is awesome! Going down a hill at insane speed it seems to leave the ground on bumps and grab some air!

Posted: 12 Jun 2007, 15:33
by rattle
Now make the wheels turn accordingly!

This thing reminds me strongly of zwzsg's armduck.

Posted: 12 Jun 2007, 17:50
by Zpock
Youtube video up:

http://www.youtube.com/watch?v=cN1vt01mmcU

Yes, it can even make jumps, shown at the end of the video. I was shocked when I first saw it do that, hadn't thought about that.

Posted: 12 Jun 2007, 18:38
by pintle
that is awesome, very nice work :)

Posted: 12 Jun 2007, 18:47
by Argh
Neat :-)

However, the serious designer side of me has to ask:

A. What happens when 100 of these are spawned?

B. Is there a simpler way to fake this, that will look reasonably good most of the time?

Because I suspect that the answer to A is, "you see large CPU usage for scripts, which is inherently bad", and that the answer to B is, "definitely yes".

Posted: 12 Jun 2007, 19:08
by Zoombie
Holy crap that is one of the coolest things I've ever seen. Can it work with tanks?

Posted: 12 Jun 2007, 19:20
by Zpock
Argh wrote:A. What happens when 100 of these are spawned?

B. Is there a simpler way to fake this, that will look reasonably good most of the time?
I did a quick test, spawning 100 guys running around on victoria crater in the middle (no pathing issues) and scripts shows 15% CPU usage. I definitly think that it can be optimized a lot:

1: the math can probably be cut down a bit without downgrading it, for example get rid of the trigonometry.

2: i recalculated the springs after moving the body before moving the wheels, I think this can be cut without much trouble (I kinda made things up as I went, this was to try and stabilize it when i started, but I'm not sure it even does anything now.

3: the sleep could maybe be extended, to recaluclate fewer times withtout being noticable.

4: stop the script running when it's not needed... this needs a few checks tough.

Posted: 12 Jun 2007, 19:20
by Dragon45
Argh-> For point A:
I tries putting in 100 units at the same time or so and noticed no more lag then usual. The rest of the script is the usual stuff, just making sure to start this script on creation. It could probably be stopped from running when idle, but with some time to let any remaining oscillations run for a while.

Posted: 12 Jun 2007, 19:21
by 1v0ry_k1ng
finally wezels can have pro wheelz

Posted: 12 Jun 2007, 21:32
by Neddie
1v0ry_k1ng wrote:finally wezels can have pro wheelz
Fo sho.

Posted: 12 Jun 2007, 22:12
by Dragon45
dude - weezels, jeffies, trucks..

OP could really use this
incorporate in all units NOW! :O

Posted: 12 Jun 2007, 23:57
by 1v0ry_k1ng
can someone see what it looks like when applied to tank treads? be sweet for 1944

Posted: 13 Jun 2007, 00:16
by VonGratz
Congrats!
VERY well done!
VonGratz :wink:

Posted: 13 Jun 2007, 01:18
by SwiftSpear
1v0ry_k1ng wrote:can someone see what it looks like when applied to tank treads? be sweet for 1944
Most tank treads don't animate in spring, and it's gonna take some magic to make the links flow naturally between the wheel components when they vary in height. Not saying it's impossible, but it's not a cut and paste job.

Posted: 13 Jun 2007, 01:37
by Zpock
Yes, what to do with the threads themselves are the big question here. Might try and cut them in segments between the wheels. Might be costly with one ATAN evaluation for each segment, to put it in place, then it can get ugly if you want to do show/hide style animation as well, tough could perhaps just move the segments around a little to create the track animation too. Another option is to simply leave the threads flat and just move the wheels, this can look decent too and they even do it in CoH on the smaller tanks. They seem to be used a bones system for stuff like the tiger tough.

Anyway I can try scripting one of the s44 tanks if you want. Perhaps on the T-34 model? It has a nice simple wheel layout.

Image

Posted: 13 Jun 2007, 01:45
by imbaczek
Cool.

BTW, Spring could use some engine-sanctioned IK... ::dreams::

Posted: 13 Jun 2007, 02:02
by trepan
shaders? ;-)

Posted: 13 Jun 2007, 02:08
by Nemo
You're welcome to try applying it to a 44 tank, but I don't think we can afford the CPU cost of putting it on all our tanks, so I doubt it'll be used in a release.


The script is unquestionably awesome, however.