News:

Herr Otto Partz says you're all nothing but pipsqueaks!

Main Menu

Physics investigations on Stunts

Started by Duplode, December 09, 2008, 01:05:09 AM

Previous topic - Next topic

Chulk

Quote from: Krys TOFF on December 10, 2008, 09:47:01 AM
Quote from: DuplodeBTW, just an useful observation on tile lengths. As mentioned, a tile is 205ft long. While giving the value in feet makes sense from a stressed user perspective, track designers may find another approximation more relevant: 205ft = 62.484m. Considering 62.5 = 1000/16, we can say that for all practical purposes 16 tiles = 1 kilometer...
Much more practical indeed, km means much more to me than feet. ;)
To most of us (just to avoid saying "to all of us")
Yes, it is me. No, I'm not back at racing (for now...)

Overdrijf

Quote from: Chulk on December 10, 2008, 04:30:06 PM
Quote from: Krys TOFF on December 10, 2008, 09:47:01 AM
Quote from: DuplodeBTW, just an useful observation on tile lengths. As mentioned, a tile is 205ft long. While giving the value in feet makes sense from a stressed user perspective, track designers may find another approximation more relevant: 205ft = 62.484m. Considering 62.5 = 1000/16, we can say that for all practical purposes 16 tiles = 1 kilometer...
Much more practical indeed, km means much more to me than feet. ;)
To most of us (just to avoid saying "to all of us")
On the other hand, stunts expresses speeds in miles/h...

P.S. When you were dropping from a hill, how fast where you going? I expect downforce is quite strong in stunts. :)

Duplode

Quote from: Overdrijf on February 17, 2009, 10:56:53 PM
On the other hand, stunts expresses speeds in miles/h...

Pertinent remark, and also graphic coordinates are in units of 0.2 feet - thus Stunts hackers are recommended to adapt to Imperial units...

Quote from: Overdrijf on February 17, 2009, 10:56:53 PM
P.S. When you were dropping from a hill, how fast where you going? I expect downforce is quite strong in stunts. :)

It was Countach on Default, so it must have been ~120mph. As far as I remember, though, the results were (barring the usual random bugs) independent of speed. I don't believe there is real downforce in Stunts, just some unreliable aerodynamic drag that sometimes disappears and gives way to Power Gear  :)

Overdrijf

Quote from: Duplode on February 18, 2009, 12:19:25 AM
Quote from: Overdrijf on February 17, 2009, 10:56:53 PM
On the other hand, stunts expresses speeds in miles/h...

Pertinent remark, and also graphic coordinates are in units of 0.2 feet - thus Stunts hackers are recommended to adapt to Imperial units...

Quote from: Overdrijf on February 17, 2009, 10:56:53 PM
P.S. When you were dropping from a hill, how fast where you going? I expect downforce is quite strong in stunts. :)

It was Countach on Default, so it must have been ~120mph. As far as I remember, though, the results were (barring the usual random bugs) independent of speed. I don't believe there is real downforce in Stunts, just some unreliable aerodynamic drag that sometimes disappears and gives way to Power Gear  :)

In that case there is either a strong centrifugal force or reverse gravity in loops and tubes... :)

Duplode

That's an interesting point: there must be a model for centripetal force for such situations. Worth investigating...

Friker

i think there is a normal vector of a road while youre stick to the road and a normal vector of 'the Earth' while youre flying (high :) ).

Overdrijf

Quote from: Friker on February 18, 2009, 10:38:56 AM
i think there is a normal vector of a road while youre stick to the road and a normal vector of 'the Earth' while youre flying (high :) ).
Something like that, it would explain why you can drive slow and straight upside down in a tube...

Duplode

After several months of very slow progress, it seems I finally managed to understand partly (about 40%) how the physical model of track elements is stored. Details to follow later...

dstien

Quote from: Duplode on April 11, 2009, 08:01:51 PM
Details to follow later...
Whoa, what a cliffhanger! I'm waiting in suspense. :o

Friker

Quote from: dstien on April 12, 2009, 02:07:21 PM
Quote from: Duplode on April 11, 2009, 08:01:51 PM
Details to follow later...
Whoa, what a cliffhanger! I'm waiting in suspense. :o

im glad to see results from his investigation too :)

Duplode: give us the knowledge :)

Duplode

#25
Okay, here we go. First of all I must say "40% of understanding" was an over-estimation by far (as you'll see by the loads of mysterious stuff I can't explain), but hopefully what little was found will be worth the suspense already ( :)/ :D).

The new findings are about stuff contained in GAME.PRE (unpacked to GAME.RES, of course). Alongside with some other random pieces of data (crack patterns for the windshield in F1 view and many familiar in-game messages) there is a very large heap of bytes split between two resources with the rather suggestive names of plan and wall. Now, jumping to the first of the final conclusions (I won't follow chronological order in the explanation or else this will get twice as long as it'll get), we can say Stunts employs two different kinds of surfaces for building track elements:


  • Drivable surfaces, to which I'll refer as simply surfaces, and which are defined by plan
  • Vertical walls, which are undrivable surfaces and are *supposed* to be defined by wall (the reason for the "supposed" will become clear later on)

The game then uses the definitions of surfaces and walls in GAME.RES to assemble the track elements, joining them in specific positions according to rules defined *somewhere else*.  Now, on to the nature of the resources themselves, starting with plan...

---

plan is composed of 536 structures of 34 bytes each. Each of these defines a plane in space (thus the name of the resource) which corresponds to one or more drivable surfaces in game. The structures can be described as (in this context WORD = 2-byte signed integer, as usual):


struct PLANE {
    WORD angleYZ;
    WORD angleXY;
    VECTOR origin;
    VECTOR normal;
    VECTOR[3] rotationMatrix;
};

struct VECTOR {
    WORD x;
    WORD y;
    WORD z;
};


The 'origin' vector is just a regular point coordinate that sets a point belonging to the plane. Usually the origins match vertexes employed on the actual track elements which employ the planes, thus allowing for relatively easy matching between planes and polygons in GAME1.3SH and GAME2.3SH (which contain the track elements 3D shapes). The 'normal' vector is a normal vector to the plane (good guess, Friker and Overdrijf!  ;)), whose length is 8192 (0x2000). A point and a normal through it are enough to define a plane unambiguously, thus 'origin' and 'normal' give full control over the plane attributes - by displacing the origin you can set the height and (to some extent) the position of the plane in the tile, while the normal sets the plane inclination in xy (banked road inclinations, etc.) and yz (ramp slopes, etc.) planes.

After the normal there is a set of three vectors whose length is 16384 (0x4000). Looked as a whole, they look very much like a 3D rotation matrix arranged by columns, though I'm not fully sure if they act strictly like one. Their role is to set the orientation of the car after it makes contact with the surface. The correct values should of course get the car lying on the plane of the surface. The values aren't hard to figure out once you know what the normal is. An interesting observation is to note this way of modelling the landing on a surface is very simple and quite unphysical (no forces, no torques, just a forced change of orientation) and may well be the source of several bugs we're so familiar with (think of this scenario: you are about to land from a jump, and the game is supposed to reorientate the car so it is parallel to the ground. Just as you land, however, the accumulation of rounding errors over the past few seconds makes engine think it still has to reorientate the car, even if it is horizontal already. Then the game over-corrects rotating the car further upwards, and *bam* - magic carpet! :) In fact, it is probably possible to make a bouncing track by messing up with the matrix in a consistent way).

Finally, there are the angles in xy and yz planes, which convey much of the same information given by the normal in a different format. These angles are given in fractions of 1/1024 of a circle, thus ranging from 0 to 1023. The thing is, modifying the angles has no visible effect over the surfaces, so I have no clue on what they're doing there (unless these angles interact with stuff contained in the other resource, 'wall', but that's another story).

---

Now, let's return to the macro-organization of 'plan'. After understanding the structure of the planes it becomes obvious that the 536 planes are arranged in blocks of four, planes within each block differing only in xz orientation (like ramps facing different directions). This reduces the actual number of surfaces to identify to 536/4 = 134. For instance, here is the set of ramp/slope surfaces...


0000516: 0000 4300 7800 0000 00fe 0000 4b1d 21f3 0040 0000 0000 0000 ab3a 6de6 0000 9319 ab3a
0000538: 4300 0000 0002 0000 7800 df0c 4b1d 0000 ab3a 6de6 0000 9319 ab3a 0000 0000 0000 0040 
000055a: 0000 bd03 88ff 0000 0002 0000 4b1d df0c 0040 0000 0000 0000 ab3a 9319 0000 6de6 ab3a
000057c: bd03 0000 00fe 0000 88ff 21f3 4b1d 0000 ab3a 9319 0000 6de6 ab3a 0000 0000 0000 0040 


and the values "translated" to decimal.


0 67 120 0 -512 0 7499 -3295 16384 0 0 0 15019 -6547 0 6547 15019
67 0 512 0 120 3295 7499 0 15019 -6547 0 6547 15019 0 0 0 16384
0 957 -120 0 512 0 7499 3295 16384 0 0 0 15019 6547 0 -6547 15019
957 0 -512 0 -120 -3295 7499 0 15019 6547 0 -6547 15019 0 0 0 16384


As you can see, axes permutations and sign inversions are the only changes involved. The order on each quartet is predictable: the first one is in S->N orientation (pointing to +z) and the others correspond to counter-clockwise rotations (for pieces of bridge corners and banked roads, the first plane of the quartet is from the corner going S->W, the second one E->S and so on).

By crossing data from GAME.RES and GAME1/2.3SH plus some in-game tests I could identify almost all of the quartets (only for 12 of them I have no clue). It was not a massive amount of work to do, as complex surfaces like corks u/d take a very large number of quartets and are easily recognizable. The identifications (as well as human-readable transcripts of both 'plan' and 'wall') are included in the .xls file attached.

One important point to stress before moving on: nowhere in plan there is any indication of how the surfaces are to be assembled. In fact, many of the surfaces are reused in several elements. For instance all ramps AND hill slopes share the same properties, so do all sorts of flat terrain both on and off hills. More remarkably, the surface of pipes and cork l/r use the exact same planes - the only difference is the walls of corks are shorter in the z direction and aligned properly so the final result looks looks like a spiral, and not like a tube. The differences between hill slopes and ramps, or corks l/r and pipes - namely, where each part of the surface starts and ends - are not in GAME.RES, so we're only looking at half the story here. Hopefully this data is not packed somewhere too hard to reach (the executables...), as we will need to find it in order to make more radical mods to the track elements.

---

Enough speaking of 'plan' already, let us move to 'wall'. 'wall' left me bewildered for the longest time, as I tried to find some correlation between the values there and 'plan', or GAME1/2. Anyway, here is how the vertical walls in game appear to be described:


struct WALL {
    WORD angleXZ;
    WORD x;
    WORD z;
};


'wall' has 3-integer structures which when combined describe of the xz projection of the wall path (that is, the wall path viewed from above). Each pair of 'x' and 'z' forms an endpoint for the wall segments, and angleXZ is the angle of said segment. Plotting 'x' and 'z' values reveal clearly most of the obstacle structures we know - block houses, bridge corner walls, slalom blocks... (I included some graphs in the .xls file which illustrate this point neatly). This looks clear enough, but there are a few unresolved issues with the description. First of all, trying to make simple changes to wall positions (like displacing slalom blocks from their positions) didn't work, at least for me - all changes to 'x' and 'z' ended up making the wall penetrable or otherwise buggy seemingly without changing the position as intended. Maybe the angles need to be adjusted properly prior to the adjustment to some specific value, or there is some additional info we're not aware of (the obvious possibility of having the physical walls linked to the graphical data in GAME1/2 is ruled out by a few simple tests, however). Furthermore, there is no obvious connection between 'wall' and 'plan' in terms of indices or list positions, so the resources must be called independently by a third entity in order to compose the objects. And the final issue, which I find the most annoying, is that there is no information at all about wall height, and yet we know a block house is much taller than a slalom block (and no, neither of them has a 'plan' surface associated to them). Thus, the 'wall' definitions are less complete than 'plan' ones, to the point of being confusing...

---

In conclusion, with these findings we elucidated quite a bit more of Stunts' data, but there is obviously a big piece of information still missing to complete the puzzle. As of now, we can make minor-to-moderate scale changes to elements, such as modifying bankings, slopes and heights of surfaces, but we cannot reassemble the planes which make an element at will, nor create new elements instead of overwriting them and not even decoupling the elements which share 'plan' surfaces (for instance, all changes made to one kind of ramp will be reflected on all ramps and on hill slopes too). I'm particularly interested in trying to reflect corks l/r and loops through the yz plane (thus changing their handedness), but I'm not very confident that will be possible.

Anyway, it's a beginning  :)

Friker


Overdrijf


zaqrack


Duplode

#29
Since further extensive testing of track surfaces will mean a hell lot of work, I have for the moment opted to resume testing of the unknown CAR*.RES / CarBlaster parameters instead. More specifically, I have been following a good hint left by Overdrijf about possible size-related parameters on the not-understood region of the file (between the torque curve and the steering wheel dot coordinates). I will present some of the results without the technical details on how to do it (that will go straight to the Wiki as soon as I get to write it down). First of all, it turned out that there are not one, but *two* sets of car size data there! The first one is a trio of values that loosely match the 3D shape dimensions (as half-length, half-width and height). For some reason (code efficiency, I guess), however, this set is only used for car-car collision detection, and not with regular trackside objects, and thus it is not so useful - but it can be used for something very cool...



...Trackmania-stlye racing vs. ghost cars. Too bad Skid is not smart enough to realize this and will keep swerving to avoid your car even if he can drive straight through it... this also explains why you can't crash at the scenario cars you can put with TrackBlaster - they have neither collision parameters nor a 'wall' definition in GAME.RES .

As mentioned, though, there is another dimension-related set of bytes, namely the 24 bytes just before the steering wheel coordinates. Each 6-byte sequence in it (two integers separated by 0000h) is a xz (width-length) coordinate set for one of the corners of the car, starting from front/left and then going clockwise. Although in principle you can position the corners to form any sort of four-sided polygon, in practice the polygon must be centred at zero x and zero z - failure to do so will introduce exotic bugs such as making the car move forward, backward, sideways, etc. on its own... By the way, the effect Overdrijf noticed after changing one of the parameters (the car rotates mid-air and lands on two wheels) is not a bug of this sort, but rather a reflection of the fact that one side of the car became longer than the other, so it tends to rotate as it leaves the ground.  In any case, if you plan to make reasonable cars you'll be most likely bound to make rectangles symmetric about the origin (or trapezes at the very most if you want the front to be narrower than the rear or something).

The question that arises by now is whether collision tests confirm such explanations. Such tests are rather elusive because (as you probably know by now) Stunts' collision model is not the most reliable or precise piece of code around, and sometimes it just doesn't do what it should. Anyway, by making symmetrical changes to the corners' positions, it was possible to make cars which were wider...



longer...



and shorter than the defaults.



(narrowing the car a lot is difficult to achieve, it seems that there is a hard-coded lower limit to the width of the car)

A more dramatic demonstration of the coordinates in action is below:



The car appears to be floating above the water, but in fact it is not - as it was made a couple times wider than the 3D shape, its right side wheels are still safely on the grass.

That is not the most interesting part of the story, however! During the tests it became obvious that the car length, as defined by the corner positions, influences the behaviour of the car. Shorter cars are more responsive to direction changes than longer cars, which has a number of important consequences:

  • They are more nimble to drive - even if the grip (as measured by the speed at which the car begins to skid) remains the same, the car responds faster to steering input, and thus the driver is able to steer less hard, lowering the chances of skidding and losing control.
  • They drop from jumps faster, as they take less time to rotate downwards (that indicates there is no real gravity anywhere in Stunts...)
  • They get more twitchy and sensitive to surface changes, raising the chances of unexpected behaviour like magic carpets.
Now, please have a look at the list of the positive z coordinates (that correspond to half-lengths) for a number of common cars (CDOR is Melange, the other abbreviations are more clear):


ANSX 1856
AUDI 1472
CDOR 1856
COUN 1984
FGTO 1984
GATE 1920
JAGU 1920
LANC 1472
LM02 1856
NSKY 1984
P962 1920
PC04 1792
PMIN 1984
RANG 1856
VETT 1984
ZGT3 1984


Notice how Audi and Lancia are indeed dramatically shorter than other cars. That finally provides a convincing explanation for their delightful handling, as well as their notorious bug-proneness. Maybe even more striking is to see that Melange, through inheriting the parameters from the LM-002, became shorter than the rest of the IMSA cars - and that may justify its magic carpet potential... :)