OBD:TRAM/raw0x34: Difference between revisions

From OniGalore
Jump to navigation Jump to search
m (localized image)
 
(33 intermediate revisions by 6 users not shown)
Line 1: Line 1:
Here's the minimal structure of the body animation tracks for a TRAM file (address stored at 0x34 in the dat)
<CENTER>[[OBD:TRAM/raw0x30|position part]] &nbsp;<<&nbsp; '''[[OBD:TRAM|TRAM]] - bodyparts animation parts part''' &nbsp;>>&nbsp; [[OBD:TRAM/raw0x38|sound part]]</CENTER>


(The example below is for '''SHINZOMidle1''')


The global stucture is 19 bone tracks, preceded by a list of their offsets (the "header").
This part belongs to the 01865-KONCOMpunch_heavy.TRAM file.
 
 
[[Image:tram_r11.gif]]
 
 
{{Table}}
{{OBDth}}
{{OBDtr| 0x00 | uint16 |FFC8C8| 26 00 | 38  | start position of the pelvis animation (80 BD 00 + 26 <nowiki>=</nowiki> 80 BD 26) }}
{{OBDtr| ...  | ...  |FFC8C8| ...  | ...  | ... }}
{{OBDtr| 0x24 | uint16 |FFC8C8| 84 0E | 3716 | start position of the right fist animation (80 BD 00 + 0E 84 <nowiki>=</nowiki> 80 CB 84) }}
{{OBDtrBK|1=First element (black outline) - pelvis animation}}
{{OBDtr| 0x26 | int16 |FFFFC8| EE FA | 357  | x-start-position in degrees }}
{{OBDtr| 0x28 | int16 |FFFFC8| E2 25 | 54  | y-start-position in degrees }}
{{OBDtr| 0x2A | int16 |FFFFC8| 11 51 | 280  | z-start-position in degrees }}
{{OBDtr|&nbsp;| int8  |C8FFC8| &nbsp;|&nbsp;| number of frames, which the animation has to go from one position to the next }}
{{OBDtr|&nbsp;| int16 |C8FFFF| &nbsp;|&nbsp;| x-position in degrees }}
{{OBDtr|&nbsp;| int16 |C8FFFF| &nbsp;|&nbsp;| y-position in degrees }}
{{OBDtr|&nbsp;| int16 |C8FFFF| &nbsp;|&nbsp;| z-position in degrees }}
{{OBDtr| 0xC7 | int16 |FFC8FF| 82 F7 | 352  | x-end-position in degrees }}
{{OBDtr| 0xC9 | int16 |FFC8FF| BB 1B | 39  | y-end-position in degrees }}
{{OBDtr| 0xCB | int16 |FFC8FF| 23 42 | 94  | z-end-position in degrees }}
|}
 
 
'''<u>Detailed Information</u>'''
 
 
Here's the minimal structure of the body animation tracks for a TRAM file (address stored at 0x34 in the .dat). The example below is for '''SHINZOMidle1''': those bone tracks are found at 0x480020 in the original level18_Final.raw. The global structure is 19 bone tracks, preceded by a list of their offsets (the "header").


Information required to read this part :
Information required to read this part :
*number of body parts (0x16A in the dat)
*number of body parts (at 0x16A in the .dat, always 19 in Oni)
*"compression size" (0x160 in the dat)
*"compression size" (at 0x160 in the .dat, 6 for almost all anims, 16 for a few)
*frame count (0x16C in the dat)
*frame count (at 0x16C in the .dat)


The size of a bone track is not known in advance. See "General info" below.
The size of a bone track is not known in advance. See "General info" below.


http://geyser.oni2.net/obd/tram/raw0x34/SHINZOMidle1.png
 
[[Image:TRAM 0x34.png]]
 


==Header==
==Header==
Line 20: Line 49:
!Body part
!Body part
!Raw hex
!Raw hex
!Value (offset of orientation track)
!Value (offset of bone track)
|-
|-
|0x00
|0x00
|Pelvis
|Pelvis
|style="background:fuchsia"|2600
|style="background:fuchsia"|26 00
|0x26
|0x26
|-
|-
|0x02
|0x02
|Lt Thigh
|Lt Thigh
|style="background:lime"|3300
|style="background:lime"|33 00
|0x33
|0x33
|-
|-
|0x04
|0x04
|Lt Calf
|Lt Calf
|style="background:aqua"|4000
|style="background:aqua"|40 00
|0x40
|0x40
|-
|-
|0x06
|0x06
|Lt Foot
|Lt Foot
|style="background:yellow"|4D00
|style="background:yellow"|4D 00
|0x4D
|0x4D
|-
|-
|0x08
|0x08
|Rt Thigh
|Rt Thigh
|style="background:#888888"|5A00
|style="background:#888888"|5A 00
|0x5A
|0x5A
|-
|-
|0x0A
|0x0A
|Rt Calf
|Rt Calf
|style="background:fuchsia"|6700
|style="background:fuchsia"|67 00
|0x67  
|0x67  
|-
|-
|0x0C
|0x0C
|Rt Foot
|Rt Foot
|style="background:lime"|7400
|style="background:lime"|74 00
|0x74
|0x74
|-
|-
|0x0E
|0x0E
|Mid
|Mid
|style="background:aqua"|8100
|style="background:aqua"|81 00
|0x81
|0x81
|-
|-
|0x10
|0x10
|Chest
|Chest
|style="background:yellow"|8E00
|style="background:yellow"|8E 00
|0x8E
|0x8E
|-
|-
|0x12
|0x12
|Neck
|Neck
|style="background:#888888"|9B00
|style="background:#888888"|9B 00
|0x9B  
|0x9B  
|-
|-
|0x14
|0x14
|Head
|Head
|style="background:fuchsia"|A800
|style="background:fuchsia"|A8 00
|0xA8  
|0xA8  
|-
|-
|0x16
|0x16
|Lt Shoulder
|Lt Shoulder
|style="background:lime"|B500
|style="background:lime"|B5 00
|0xB5  
|0xB5  
|-
|-
|0x18
|0x18
|Lt Arm
|Lt Arm
|style="background:aqua"|C200
|style="background:aqua"|C2 00
|0xC2  
|0xC2  
|-
|-
|0x1A
|0x1A
|Lt Wrist
|Lt Wrist
|style="background:yellow"|CF00
|style="background:yellow"|CF 00
|0xCF  
|0xCF  
|-
|-
|0x1C
|0x1C
|Lt Fist
|Lt Fist
|style="background:#888888"|DC00
|style="background:#888888"|DC 00
|0xDC  
|0xDC  
|-
|-
|0x1E
|0x1E
|Rt Shoulder
|Rt Shoulder
|style="background:fuchsia"|E900
|style="background:fuchsia"|E9 00
|0xE9  
|0xE9  
|-
|-
|0x20
|0x20
|Rt Arm
|Rt Arm
|style="background:lime"|F600
|style="background:lime"|F6 00
|0xF6  
|0xF6  
|-
|-
|0x22
|0x22
|Rt Wrist
|Rt Wrist
|style="background:aqua"|0301
|style="background:aqua"|03 01
|0x103  
|0x103  
|-
|-
|0x24
|0x24
|Rt Fist
|Rt Fist
|style="background:yellow"|1001
|style="background:yellow"|10 01
|0x110  
|0x110  
|}
|}
Line 120: Line 149:
==Bone tracks==
==Bone tracks==
===General info===
===General info===
An orientation track is a succession of keyframe fields (either 6 or 16 bytes depending on the "compression size") defining the orientation of the bone at a key moment. Every pair of keyframes is separated by an interval field (one byte) defining the number of frames between the two key moments. Orientation is interpolated linearly between two keyframes over the interval between them. If the cumulated intervals reach the total frame count of the animation (minus 1) then the next keyframe is the final one.
An orientation track is a succession of keyframe fields (either 6 or 16 bytes depending on the "compression size") defining the orientation of a bone (with respect to its parent) at a key moment. Every pair of keyframes is separated by an interval field (one byte) defining the number of frames between the two key moments. Orientation is interpolated linearly between two keyframes over the interval between them. If the cumulated intervals reach the total frame count of the animation (minus 1) then the next keyframe is the final one.


Thus the length of the track is determined upon reading
Thus the length of the track is determined upon reading
===Compression size 6===
===Compression size 6===
{|border="1" cellspacing="0" align="right"
{|border="1" cellspacing="0" style="float:right"
|+correspondence
|+correspondence
!Angle
!Angle
!Short
!Short
!Raw hex
|-
|-
|0°
|0°
|0x0000
|0x0000
|0x0000
|-
|-
|45°
|24°
|0x2000
|0x1111
|0x0020
|-
|-
|90°
|48°
|0x4000
|0x2222
|0x0040
|-
|-
|180°
|72°
|0x8000
|0x3333
|0x0080
|-
|-
|270°
|96°
|0xC000
|0x4444
|0x00C0
|}
|}
An orientation consists of three angles, each of them a 2-byte integer (short).
An orientation consists of three angles, each of them stored in quantized form, as a 2-byte signed integer (short).
:*Oni converts from the stored integer to an angle through multiplication by 360°/65535 = '''0.00549324'''78828[...]
:*Thus, when quantizing angles from a new animation, multiply the angles by 65535/360° = '''182.041'''6667[...]
:*A quantized angle of 65535 never occurs in Oni, so apparently they consistently used only 0 through 65534.
 
Note that these angles cannot be used directly for interpolation, they must first be converted to quaternions.


The example here is the '''SHINZOMidle1''' animation (10 frames long)
The example here is the '''SHINZOMidle1''' animation (10 frames long)
Line 164: Line 193:
|Pelvis
|Pelvis
|style="background:fuchsia"|5F45 F93D B6FA '''09''' 5F45 F93D B6FA
|style="background:fuchsia"|5F45 F93D B6FA '''09''' 5F45 F93D B6FA
|(97°, 87°, 352°)
|(98°, 87°, 353°)
|9 frames
|9 frames
|(97°, 87°, 352°)
|(98°, 87°, 353°)
|-
|-
|0x33
|0x33
|Lt Thigh
|Lt Thigh
|style="background:lime"|1839 1B34 8877 '''09''' 1839 1B34 8877
|style="background:lime"|1839 1B34 8877 '''09''' 1839 1B34 8877
|(°, °, °)
|(80°, 73°, 168°)
|9 frames
|9 frames
|(°, °, °)
|(80°, 73°, 168°)
|-
|-
|0x40
|0x40
|Lt Calf
|Lt Calf
|style="background:aqua"|0000 0000 96AB '''09''' 0000 0000 96AB
|style="background:aqua"|0000 0000 96AB '''09''' 0000 0000 96AB
|(0°, 0°, °)
|(0°, 0°, 241°)
|9 frames
|9 frames
|(0°, 0°, °)
|(0°, 0°, 241°)
|-
|-
|0x4D
|0x4D
|Lt Foot
|Lt Foot
|style="background:yellow"|9436 DFFB 3E15 '''09''' 9436 DFFB 3E15
|style="background:yellow"|9436 DFFB 3E15 '''09''' 9436 DFFB 3E15
|(°, °, °)
|(77°, 354°, 30°)
|9 frames
|9 frames
|(°, °, °)
|(77°, 354°, 30°)
|-
|-
|0x5A
|0x5A
|Rt Thigh
|Rt Thigh
|style="background:#888888"|5351 3D13 DC9C '''09''' 5351 3D13 DC9C
|style="background:#888888"|5351 3D13 DC9C '''09''' 5351 3D13 DC9C
|(°, °, °)
|(114°, 27°, 221°)
|9 frames
|9 frames
|(°, °, °)
|(114°, 27°, 221°)
|-
|-
|0x67
|0x67
|Rt Calf
|Rt Calf
|style="background:fuchsia"|0000 0000 D5E7 '''09''' 0000 0000 D5E7
|style="background:fuchsia"|0000 0000 D5E7 '''09''' 0000 0000 D5E7
|(0°, 0°, °)
|(0°, 0°, 326°)
|9 frames
|9 frames
|(0°, 0°, °)
|(0°, 0°, 326°)
|-
|-
|0x74
|0x74
|Rt Foot
|Rt Foot
|style="background:lime"|5703 30FA ACF4 '''09''' 5703 30FA ACF4
|style="background:lime"|5703 30FA ACF4 '''09''' 5703 30FA ACF4
|(°, °, °)
|(, 352°, 344°)
|9 frames
|9 frames
|(°, °, °)
|(, 352°, 344°)
|-
|-
|0x81
|0x81
|Mid
|Mid
|style="background:aqua"|1302 6301 6DFE '''09''' 1302 6301 6DFE
|style="background:aqua"|1302 6301 6DFE '''09''' 1302 6301 6DFE
|(°, °, °)
|(, , 358°)
|9 frames
|9 frames
|(°, °, °)
|(, , 358°)
|-
|-
|0x8E
|0x8E
|Chest
|Chest
|style="background:yellow"|0402 9F06 7FF4 '''09''' 0402 9F06 7FF4
|style="background:yellow"|0402 9F06 7FF4 '''09''' 0402 9F06 7FF4
|(°, °, °)
|(, , 344°)
|9 frames
|9 frames
|(°, °, °)
|(, , 344°)
|-
|-
|0x9B
|0x9B
|Neck
|Neck
|style="background:#888888"|0000 FEFF 496F '''09''' 0000 FEFF 496F
|style="background:#888888"|0000 FEFF 496F '''09''' 0000 FEFF 496F
|(0°, °, °)
|(0°, 360°, 156°)
|9 frames
|9 frames
|(0°, °, °)
|(0°, 360°, 156°)
|-
|-
|0xA8
|0xA8
|Head
|Head
|style="background:fuchsia"|90FB 2504 639B '''09''' 90FB 2504 639B
|style="background:fuchsia"|90FB 2504 639B '''09''' 90FB 2504 639B
|(°, °, °)
|(354°, , 219°)
|9 frames
|9 frames
|(°, °, °)
|(354°, , 219°)
|-
|-
|0xB5
|0xB5
|Lt Shoulder
|Lt Shoulder
|style="background:lime"|6548 B4DF 1677 '''09''' 6548 B4DF 1677
|style="background:lime"|6548 B4DF 1677 '''09''' 6548 B4DF 1677
|(°, °, °)
|(102°, 315°, 167°)
|9 frames
|9 frames
|(°, °, °)
|(102°, 315°, 167°)
|-
|-
|0xC2
|0xC2
|Lt Arm
|Lt Arm
|style="background:aqua"|90E2 360D 48E5 '''09''' 90E2 360D 48E5
|style="background:aqua"|90E2 360D 48E5 '''09''' 90E2 360D 48E5
|(°, °, °)
|(319°, 19°, 322°)
|9 frames
|9 frames
|(°, °, °)
|(319°, 19°, 322°)
|-
|-
|0xCF
|0xCF
|Lt Wrist
|Lt Wrist
|style="background:yellow"|0000 0000 D7E4 '''09''' 0000 0000 D7E4
|style="background:yellow"|0000 0000 D7E4 '''09''' 0000 0000 D7E4
|(0°, 0°, °)
|(0°, 0°, 322°)
|9 frames
|9 frames
|(0°, 0°, °)
|(0°, 0°, 322°)
|-
|-
|0xDC
|0xDC
|Lt Fist
|Lt Fist
|style="background:#888888"|1ABD 51EB D718 '''09''' 1ABD 51EB D718
|style="background:#888888"|1ABD 51EB D718 '''09''' 1ABD 51EB D718
|(°, °, °)
|(266°, 331°, 35°)
|9 frames
|9 frames
|(°, °, °)
|(266°, 331°, 35°)
|-
|-
|0xE9
|0xE9
|Rt Shoulder
|Rt Shoulder
|style="background:fuchsia"|AD8B 592B 0D5E '''09''' AD8B 592B 0D5E
|style="background:fuchsia"|AD8B 592B 0D5E '''09''' AD8B 592B 0D5E
|(°, °, °)
|(196°, 61°, 132°)
|9 frames
|9 frames
|(°, °, °)
|(196°, 61°, 132°)
|-
|-
|0xF6
|0xF6
|Rt Arm
|Rt Arm
|style="background:lime"|2C1C 1116 40D7 '''09''' 2C1C 1116 40D7
|style="background:lime"|2C1C 1116 40D7 '''09''' 2C1C 1116 40D7
|(°, °, °)
|(40°, 31°, 303°)
|9 frames
|9 frames
|(°, °, °)
|(40°, 31°, 303°)
|-
|-
|0x103
|0x103
|Rt Wrist
|Rt Wrist
|style="background:aqua"|0000 0000 1734 '''09''' 0000 0000 1734
|style="background:aqua"|0000 0000 1734 '''09''' 0000 0000 1734
|(0°, 0°, °)
|(0°, 0°, 73°)
|9 frames
|9 frames
|(0°, 0°, °)
|(0°, 0°, 73°)
|-
|-
|0x110
|0x110
|Rt Fist
|Rt Fist
|style="background:yellow"|2341 5404 53EE '''09''' 2341 5404 53EE
|style="background:yellow"|2341 5404 53EE '''09''' 2341 5404 53EE
|(°, °, °)
|(92°, , 335°)
|9 frames
|9 frames
|(°, °, °)
|(92°, , 335°)
|}
|}
In this example, there are only two keyframes for every bone, and the orientation is identical for both keyframes : in fact, Shinatama remains completely frozen during the whole anim.
In this example, there are only two keyframes for every bone, and the orientation is identical for both keyframes : in fact, Shinatama's pose remains completely frozen during the whole anim (apart from a slight vertical jitter supplied by the height track).
 
'''N.B.''' An animation with frame count 10, like the above '''SHINZOMidle1''', also has a ''duration'' of 10 game ticks which extends 1 tick past the final rotation keyframe. If an intermediate pose needs to be calculated during the final tick (e.g., during slowmo), it will be interpolated between the final keyframe of the current animation and the first keyframe of the following animation. In the case of '''SHINZOMidle1''', the rotation pose is exactly the same throughout the animation, so the pose during the last tick of an idle loop will be constant as well (apart from the height shift).
 
====Origin and direction of the angles====
====Origin and direction of the angles====
If the (0°, 0°, 0°) orientation is set for every bone, then all the bones point along the x axis of the character (from right to left) and face upwards
If the (0°, 0°, 0°) orientation is set for every bone, then all the bones point along the x axis of the character (from right to left) and face upwards


Viewed from above (front is now up), you get something like this : "o" is a pivot (yeah, the shoulders are attached to the neck); ":)" is a smiley :)  
Viewed from above, you get something like this : "o" is a pivot (yeah, the shoulders are attached to the neck); ":)" is a smiley :)  
  15-o-14-o-13-o-12-o  4-o-3-o-2-o
  15-o-14-o-13-o-12-o  4-o-3-o-2-o       ^ z
                   |            |
                   |            |       ^
             :)11-o-10-o-9-o-8-o-1
             :)11-o-10-o-9-o-8-o-1 < < <^< < <
                   |            |
                   |            |   x  ^
  19-o-18-o-17-o-16-o  7-o-6-o-5-o
  19-o-18-o-17-o-16-o  7-o-6-o-5-o       ^
Every angle triplet defines the rotation of a bone with respect to its parent (the "parent" of the pelvis lies on its back with its head pointing left, as above...). The orientation of the parent defines an (x,y,z) axis set : assuming the parent is aligned as above, this is simply the normal coordinate system (x=left, y=up, z=front).
Every angle triplet defines the rotation of a bone with respect to its parent (the "parent" of the pelvis lies on its back with its head pointing left, as above...). The orientation of the parent defines an (x,y,z) axis set : assuming the parent is aligned as above, this is simply the normal coordinate system (x=left, y=up, z=front).


Line 310: Line 342:
Effectively, the first angle is the "twist" of the bone with respect to its parent (because the direction of the parent ''is'' the "x axis", i.e. the axis of the first rotation).
Effectively, the first angle is the "twist" of the bone with respect to its parent (because the direction of the parent ''is'' the "x axis", i.e. the axis of the first rotation).


A leg's orientation is quite intuitive : if you set everything to (0°, 0°, 0°) except the orientation of the thighs (both set to (0°, 0°, 180°)), you get "normal" legs. Arms are a bit more complicated.
A leg's orientation is quite intuitive : if you set everything to (0°, 0°, 0°) except the orientation of the thighs (both set to (0°, 180°, 0°) ), you get "normal" legs. Arms are a bit more complicated.
 
===Compression size 16===
In this case a quaternion (4 float values) is stored instead of 3 angles.
It applies to the following original anims :
{|style="margin-left:auto; margin-right:auto;"
|align=center|
{|border=1 cellspacing=0
|align=center|KONOKO/STRIKE
|align=center|KONOKO
|-
|align=center|<br>bullet_chest1<br>bullet_chest2
|align=center|<br>bullet_chest3<br>shot_small
|}
|align=center|
{|border=1 cellspacing=0
|align=center|KON/COM/NIN
|-
|align=center|PIS/RIF
|-
|align=center|<br>holster
|}
|align=center|
{|border=1 cellspacing=0
|align=center|KONOKO/COMGUY/NINJA<br>KONCOM/COMCOM/NINCOM
|-
|align=center|draw_
|-
|align=center|pis/rif
|}
|}
 
{| style="margin-left:auto; margin-right:auto;"
|align=center colspan=2|
{|border=1 cellspacing=0
|align=center colspan=2|KON/STR/NIN
|align=center width= 33%|COM
|-
|align=center colspan=3|PIS
|-
|align=center width= 33%|recoil_
|align=center colspan=2|reload_
|-
|align=center|<br><br>autopistol<br>p_stream<br>vandergraf<br>
|align=center|<br><br>autopis_o<br>stream_o<br>vdgf_o<br>
|align=center|autopis_o
|}
|align=center|
{|border=1 cellspacing=0
|align=center colspan=2|KON/STR/NIN
|align=center width= 33%|COM
|-
|align=center colspan=3|RIF
|-
|align=center width= 33%|recoil_
|align=center colspan=2|reload_
|-
|align=center|phase_rif<br>superball<br>scram<br>mercury<br>screamer
|align=center|rifle_o<br>super_o<br>scram_o<br>merc_o<br>scream_o
|align=center|scream_o
|}
|}
 
{| style="margin-left:auto; margin-right:auto;"
|colspan=2|
{|border=1 cellspacing=0
|align=center|KON/STR<br>COM/NIN
|align=center|KON/STR<br>NIN
|align=center colspan=2|STR
|align=center width= 14%|COM<br>NIN
|align=center width= 14%|KON/STR<br>NIN
|align=center width= 14%|STR<br>NIN
|-
|align=center colspan=4|PIS/RIF
|align=center|RIF
|align=center colspan=2|PIS
|-
|align=center width= 14%|stand<br>crouch
|align=center width= 14%|run
|align=center width= 14%|prone
|align=center colspan=2|crouch_r
|align=center|ss_lt<br>ss_rt
|align=center|run_bk
|-
|colspan=7 align=center|_fire_arc
|}
|align=center|
{|border=1 cellspacing=0
|align=center colspan=2|KONOKO<br>TANPIS
|align=center width=33%|KONCOM<br>STRIKE<br>REDCOM<br>MURCOM
|-
|align=center width=33%|crouch
|align=center colspan=2|stand
|-
|align=center colspan=3|_fire_arc
|}
|}
Those animations exactly coincide with the set of overlay animations, i.e. animations that do not animate/move the character as a whole, and merely apply variations (typically to the upper body) on top of the main animation.


More, later...


===Compression size 16===
<CENTER>[[OBD:TRAM/raw0x30|position part]] &nbsp;<<&nbsp; '''[[OBD:TRAM|TRAM]] - bodyparts animation parts part''' &nbsp;>>&nbsp; [[OBD:TRAM/raw0x38|sound part]]</CENTER>
 
{{OBD}}

Latest revision as of 23:56, 15 December 2022

position part  <<  TRAM - bodyparts animation parts part  >>  sound part


This part belongs to the 01865-KONCOMpunch_heavy.TRAM file.


Tram r11.gif


Offset Type Raw Hex Value Description
0x00 uint16 26 00 38 start position of the pelvis animation (80 BD 00 + 26 = 80 BD 26)
... ... ... ... ...
0x24 uint16 84 0E 3716 start position of the right fist animation (80 BD 00 + 0E 84 = 80 CB 84)
First element (black outline) - pelvis animation
0x26 int16 EE FA 357 x-start-position in degrees
0x28 int16 E2 25 54 y-start-position in degrees
0x2A int16 11 51 280 z-start-position in degrees
  int8     number of frames, which the animation has to go from one position to the next
  int16     x-position in degrees
  int16     y-position in degrees
  int16     z-position in degrees
0xC7 int16 82 F7 352 x-end-position in degrees
0xC9 int16 BB 1B 39 y-end-position in degrees
0xCB int16 23 42 94 z-end-position in degrees


Detailed Information


Here's the minimal structure of the body animation tracks for a TRAM file (address stored at 0x34 in the .dat). The example below is for SHINZOMidle1: those bone tracks are found at 0x480020 in the original level18_Final.raw. The global structure is 19 bone tracks, preceded by a list of their offsets (the "header").

Information required to read this part :

  • number of body parts (at 0x16A in the .dat, always 19 in Oni)
  • "compression size" (at 0x160 in the .dat, 6 for almost all anims, 16 for a few)
  • frame count (at 0x16C in the .dat)

The size of a bone track is not known in advance. See "General info" below.


TRAM 0x34.png


Header

0x00-0x25 : list of the offsets of the 19 bone tracks

Offset Body part Raw hex Value (offset of bone track)
0x00 Pelvis 26 00 0x26
0x02 Lt Thigh 33 00 0x33
0x04 Lt Calf 40 00 0x40
0x06 Lt Foot 4D 00 0x4D
0x08 Rt Thigh 5A 00 0x5A
0x0A Rt Calf 67 00 0x67
0x0C Rt Foot 74 00 0x74
0x0E Mid 81 00 0x81
0x10 Chest 8E 00 0x8E
0x12 Neck 9B 00 0x9B
0x14 Head A8 00 0xA8
0x16 Lt Shoulder B5 00 0xB5
0x18 Lt Arm C2 00 0xC2
0x1A Lt Wrist CF 00 0xCF
0x1C Lt Fist DC 00 0xDC
0x1E Rt Shoulder E9 00 0xE9
0x20 Rt Arm F6 00 0xF6
0x22 Rt Wrist 03 01 0x103
0x24 Rt Fist 10 01 0x110

Bone tracks

General info

An orientation track is a succession of keyframe fields (either 6 or 16 bytes depending on the "compression size") defining the orientation of a bone (with respect to its parent) at a key moment. Every pair of keyframes is separated by an interval field (one byte) defining the number of frames between the two key moments. Orientation is interpolated linearly between two keyframes over the interval between them. If the cumulated intervals reach the total frame count of the animation (minus 1) then the next keyframe is the final one.

Thus the length of the track is determined upon reading

Compression size 6

correspondence
Angle Short
0x0000
24° 0x1111
48° 0x2222
72° 0x3333
96° 0x4444

An orientation consists of three angles, each of them stored in quantized form, as a 2-byte signed integer (short).

  • Oni converts from the stored integer to an angle through multiplication by 360°/65535 = 0.0054932478828[...]
  • Thus, when quantizing angles from a new animation, multiply the angles by 65535/360° = 182.0416667[...]
  • A quantized angle of 65535 never occurs in Oni, so apparently they consistently used only 0 through 65534.

Note that these angles cannot be used directly for interpolation, they must first be converted to quaternions.

The example here is the SHINZOMidle1 animation (10 frames long)

Offset Body part Raw hex from over to
0x26 Pelvis 5F45 F93D B6FA 09 5F45 F93D B6FA (98°, 87°, 353°) 9 frames (98°, 87°, 353°)
0x33 Lt Thigh 1839 1B34 8877 09 1839 1B34 8877 (80°, 73°, 168°) 9 frames (80°, 73°, 168°)
0x40 Lt Calf 0000 0000 96AB 09 0000 0000 96AB (0°, 0°, 241°) 9 frames (0°, 0°, 241°)
0x4D Lt Foot 9436 DFFB 3E15 09 9436 DFFB 3E15 (77°, 354°, 30°) 9 frames (77°, 354°, 30°)
0x5A Rt Thigh 5351 3D13 DC9C 09 5351 3D13 DC9C (114°, 27°, 221°) 9 frames (114°, 27°, 221°)
0x67 Rt Calf 0000 0000 D5E7 09 0000 0000 D5E7 (0°, 0°, 326°) 9 frames (0°, 0°, 326°)
0x74 Rt Foot 5703 30FA ACF4 09 5703 30FA ACF4 (5°, 352°, 344°) 9 frames (5°, 352°, 344°)
0x81 Mid 1302 6301 6DFE 09 1302 6301 6DFE (3°, 2°, 358°) 9 frames (3°, 2°, 358°)
0x8E Chest 0402 9F06 7FF4 09 0402 9F06 7FF4 (3°, 9°, 344°) 9 frames (3°, 9°, 344°)
0x9B Neck 0000 FEFF 496F 09 0000 FEFF 496F (0°, 360°, 156°) 9 frames (0°, 360°, 156°)
0xA8 Head 90FB 2504 639B 09 90FB 2504 639B (354°, 6°, 219°) 9 frames (354°, 6°, 219°)
0xB5 Lt Shoulder 6548 B4DF 1677 09 6548 B4DF 1677 (102°, 315°, 167°) 9 frames (102°, 315°, 167°)
0xC2 Lt Arm 90E2 360D 48E5 09 90E2 360D 48E5 (319°, 19°, 322°) 9 frames (319°, 19°, 322°)
0xCF Lt Wrist 0000 0000 D7E4 09 0000 0000 D7E4 (0°, 0°, 322°) 9 frames (0°, 0°, 322°)
0xDC Lt Fist 1ABD 51EB D718 09 1ABD 51EB D718 (266°, 331°, 35°) 9 frames (266°, 331°, 35°)
0xE9 Rt Shoulder AD8B 592B 0D5E 09 AD8B 592B 0D5E (196°, 61°, 132°) 9 frames (196°, 61°, 132°)
0xF6 Rt Arm 2C1C 1116 40D7 09 2C1C 1116 40D7 (40°, 31°, 303°) 9 frames (40°, 31°, 303°)
0x103 Rt Wrist 0000 0000 1734 09 0000 0000 1734 (0°, 0°, 73°) 9 frames (0°, 0°, 73°)
0x110 Rt Fist 2341 5404 53EE 09 2341 5404 53EE (92°, 6°, 335°) 9 frames (92°, 6°, 335°)

In this example, there are only two keyframes for every bone, and the orientation is identical for both keyframes : in fact, Shinatama's pose remains completely frozen during the whole anim (apart from a slight vertical jitter supplied by the height track).

N.B. An animation with frame count 10, like the above SHINZOMidle1, also has a duration of 10 game ticks which extends 1 tick past the final rotation keyframe. If an intermediate pose needs to be calculated during the final tick (e.g., during slowmo), it will be interpolated between the final keyframe of the current animation and the first keyframe of the following animation. In the case of SHINZOMidle1, the rotation pose is exactly the same throughout the animation, so the pose during the last tick of an idle loop will be constant as well (apart from the height shift).

Origin and direction of the angles

If the (0°, 0°, 0°) orientation is set for every bone, then all the bones point along the x axis of the character (from right to left) and face upwards

Viewed from above, you get something like this : "o" is a pivot (yeah, the shoulders are attached to the neck); ":)" is a smiley :)

15-o-14-o-13-o-12-o  4-o-3-o-2-o       ^ z
                  |            |       ^
           :)11-o-10-o-9-o-8-o-1  < < <^< < <
                  |            |   x   ^
19-o-18-o-17-o-16-o  7-o-6-o-5-o       ^

Every angle triplet defines the rotation of a bone with respect to its parent (the "parent" of the pelvis lies on its back with its head pointing left, as above...). The orientation of the parent defines an (x,y,z) axis set : assuming the parent is aligned as above, this is simply the normal coordinate system (x=left, y=up, z=front).

The first rotation is about the x axis, the second one is about the new y axis, and the last one is about the newest z axis. All rotations are in the normal trigonometric direction (clockwise if looking in the direction of the axis).

Effectively, the first angle is the "twist" of the bone with respect to its parent (because the direction of the parent is the "x axis", i.e. the axis of the first rotation).

A leg's orientation is quite intuitive : if you set everything to (0°, 0°, 0°) except the orientation of the thighs (both set to (0°, 180°, 0°) ), you get "normal" legs. Arms are a bit more complicated.

Compression size 16

In this case a quaternion (4 float values) is stored instead of 3 angles. It applies to the following original anims :

KONOKO/STRIKE KONOKO

bullet_chest1
bullet_chest2

bullet_chest3
shot_small
KON/COM/NIN
PIS/RIF

holster
KONOKO/COMGUY/NINJA
KONCOM/COMCOM/NINCOM
draw_
pis/rif
KON/STR/NIN COM
PIS
recoil_ reload_


autopistol
p_stream
vandergraf


autopis_o
stream_o
vdgf_o
autopis_o
KON/STR/NIN COM
RIF
recoil_ reload_
phase_rif
superball
scram
mercury
screamer
rifle_o
super_o
scram_o
merc_o
scream_o
scream_o
KON/STR
COM/NIN
KON/STR
NIN
STR COM
NIN
KON/STR
NIN
STR
NIN
PIS/RIF RIF PIS
stand
crouch
run prone crouch_r ss_lt
ss_rt
run_bk
_fire_arc
KONOKO
TANPIS
KONCOM
STRIKE
REDCOM
MURCOM
crouch stand
_fire_arc

Those animations exactly coincide with the set of overlay animations, i.e. animations that do not animate/move the character as a whole, and merely apply variations (typically to the upper body) on top of the main animation.


position part  <<  TRAM - bodyparts animation parts part  >>  sound part