Difference between revisions of "Motion (.MOT) File Format"
(Created page with "'''''Note''': This page pertains to Reverse Engineering of Okami File Formats.''") |
m (→(Example):) |
||
(27 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
'''''Note''': This | {{File Format}} | ||
==Explanation== | |||
This file incorporates '''curves and/or properties''' for an given embbed model. Because of that, it's almost always certain that they are contained in a file container (dat). | |||
There's instances of mots that controlled properties instead of bones, so it's not always certain of what it animates. A further inspection have to be done. But since it animates bones most of the times, i will threat it as curves that animates bones. | |||
Every curve is computed using the '''Cubic Hermite interpolation formula.''' That means every curve is treated as a Hermite Curve. | |||
:[[File:Formula.png|Formula of the Cubic Hermite Interpolation, used in curves.]] | |||
'''Note:''' This formula's image was taken from the [https://en.wikipedia.org/wiki/Cubic_Hermite_spline ''Cubic Hermite spline Wiki''.] | |||
== Mot main header (8 bytes length) == | |||
{| class="wikitable" | |||
! Offset !! Type !! Size !! Description | |||
|- | |||
| 0x00 || <code>uint32_t</code> || 4 || File identifier (Magic number). | |||
|- | |||
| 0x04 || <code>uint16_t</code> || 2 || Animation's frame count. | |||
|- | |||
| 0x06 || <code>uint8_t</code> || 1 || Animation's curve count. | |||
|- | |||
| 0x07 || <code>uint8_t</code> || 1 || Loop flag, sets if the animation either loops or not (1/0). | |||
|} | |||
On offset 8, The File gives informations about the curves, i.e: what bone it animates, etc. | |||
== Curve Info (8 bytes length) == | |||
{| class="wikitable" | |||
! Offset !! Type !! Size !! Description | |||
|- | |||
| 0x00 || <code>int8_t</code> || 1 || Bone index (-1 means it animates the mode's root bone). | |||
|- | |||
| 0x01 || <code>int8_t</code> || 1 || Curve properties (See below). | |||
|- | |||
| 0x02 || <code>uint16_t</code> || 2 || Curve keyframe count. | |||
|- | |||
| 0x04 || <code>uint32_t / float32_t</code> || 4 || Keyframes offset / value | |||
|} | |||
the 4th offset of each curve info can be either a float, or uint32. it's only set as a float if the ''Property Family'' of the curve is a Single Pose. Otherwise, it's a offset. | |||
The curve property will define what property of the bone/object it is animating. There's some properties who could not be determined yet. See some already identified values bellow. | |||
== Curve Properties (Already identified) == | |||
{| class="wikitable" | |||
! Value !! Property Family !! Property | |||
|- | |||
| 0 || Single Pose || Position X | |||
|- | |||
| 1 || Single Pose || Position Y | |||
|- | |||
| 2 || Single Pose || Position Z | |||
|- | |||
| 3 || Single Pose || Rotation X | |||
|- | |||
| 4 || Single Pose || Rotation Y | |||
|- | |||
| 5 || Single Pose || Rotation Z | |||
|- | |||
| 6 || Single Pose || Scale X | |||
|- | |||
| 7 || Single Pose || Scale Y | |||
|- | |||
| 8 || Single Pose || Scale Z | |||
|- | |||
| 16 || Quantized Curve || Position X | |||
|- | |||
| 17 || Quantized Curve || Position Y | |||
|- | |||
| 18 || Quantized Curve || Position Z | |||
|- | |||
| 19 || Quantized Curve || Rotation X | |||
|- | |||
| 20 || Quantized Curve || Rotation Y | |||
|- | |||
| 21 || Quantized Curve || Rotation Z | |||
|- | |||
| 22 || Quantized Curve || Scale X | |||
|- | |||
| 23 || Quantized Curve || Scale Y | |||
|- | |||
| 24 || Quantized Curve || Scale Z | |||
|- | |||
| 50 || Quantized-Precision Curve || Position X | |||
|- | |||
| 51 || Quantized-Precision Curve || Position Y | |||
|- | |||
| 52 || Quantized-Precision Curve || Position Z | |||
|- | |||
| 53 || Quantized-Precision Curve || Rotation X | |||
|- | |||
| 54 || Quantized-Precision Curve || Rotation Y | |||
|- | |||
| 55 || Quantized-Precision Curve || Rotation Z | |||
|- | |||
| 56 || Quantized-Precision Curve || Scale X | |||
|- | |||
| 57 || Quantized-Precision Curve || Scale Y | |||
|- | |||
| 58 || Quantized-Precision Curve || Scale Z | |||
|- | |||
| 80 || Full-Precision Curve || Position X | |||
|- | |||
| 81 || Full-Precision Curve || Position Y | |||
|- | |||
| 82 || Full-Precision Curve || Position Z | |||
|- | |||
| 83 || Full-Precision Curve || Rotation X | |||
|- | |||
| 84 || Full-Precision Curve || Rotation Y | |||
|- | |||
| 85 || Full-Precision Curve || Rotation Z | |||
|- | |||
| 86 || Full-Precision Curve || Scale X | |||
|- | |||
| 87 || Full-Precision Curve || Scale Y | |||
|- | |||
| 88 || Full-Precision Curve || Scale Z | |||
|} | |||
The Property Family tells the game how the keyframes are handled ingame. Depending on the Family the property is set in, curves will be readen diferently. | |||
== Single Pose == | |||
This ''Property Family'' is the cheapest to compute. Because since it's a single pose, The there's only one keyframe, in which is given on the Curve Info. | |||
===(Example):=== | |||
{| class="wikitable" | |||
! Offset !! Value !! Description | |||
|- | |||
| 0x00 || -1 || This field is telling that '''the curve is animating the root bone of the model.''' | |||
|- | |||
| 0x01 || 5 || This field is telling that '''the curve animates the Z rotation of the root bone''', being set on a '''Single-Pose ''Property Family''.''' | |||
|- | |||
| 0x02 || 1 || This field is telling that '''there's only one keyframe on this curve, which makes sense, since this curve is set on a Single-Pose ''Property Family''.''' | |||
|- | |||
| 0x04 || 0.52 || This field is '''telling the value or the Z rotation right away''', no more computing needed. | |||
|} | |||
== Quantized Curve == | |||
This ''Property Family'' Is known for having Quantized values. It's the most eficient type of curve, regarding storage size. | |||
===(Example):=== | |||
{| class="wikitable" | |||
! Offset !! Value !! Description | |||
|- | |||
| 0x00 || 0 || This field is telling that '''the curve is animating the bone index 0 of the model.''' | |||
|- | |||
| 0x01 || 16 || This field is telling that '''the curve animates the X Position of the bone index 0''', being set on a '''Quantized Curve ''Property Family''.''' | |||
|- | |||
| 0x02 || 4 || This field is telling that '''there's 4 keyframes on this curve.''' | |||
|- | |||
| 0x04 || 512 || This field is '''telling in which offset of the file the keyframes header are located'''. | |||
|} | |||
=== Quantized Curve Keyframe Header (12 bytes length)=== | |||
'''Only Quantized property families contain a keyframe Header'''. That's because Every keyframe is dependent on the values given on the Header. | |||
{| class="wikitable" | |||
! Offset !! Type !! Size !! Description | |||
|- | |||
| 0x00 || <code>float16_t</code> || 2 || Minimum value of a keyframe. | |||
|- | |||
| 0x02 || <code>float16_t</code> || 2 || Maximum value of a keyframe. | |||
|- | |||
| 0x04 || <code>float16_t</code> || 2 || Minimum value of the start tangent (m0) | |||
|- | |||
| 0x06 || <code>float16_t</code> || 2 || Maximum value of the start tangent (m0) | |||
|- | |||
| 0x08 || <code>float16_t</code> || 2 || Minimum value of the end tangent (m1) | |||
|- | |||
| 0x0A || <code>float16_t</code> || 2 || Maximum value of the end tangent (m1) | |||
|} | |||
This is the only ''Property Family'' that uses the '''float16_t''' type. That's a special type of float that can be represented as two bytes. Especifically, this type of float is built with a 1 bit sign, 6 bit exponent, a 9 bit significand and a bias of 47. The bias favours smaller numbers. That means, the highest the number, the less precise it is. That's to compensate the small amount of data two bytes can pack. | |||
After reading the keyframes header, what follows up are the keyframes in which the actual keyframes are stored in. | |||
=== Quantized Keyframes (4 bytes length)=== | |||
{| class="wikitable" | |||
! Offset !! Type !! Size !! Description | |||
|- | |||
| 0x00 || <code>uint8_t</code> || 1 || Keyframe time '''(Relative to the time of the last keyframe).''' | |||
|- | |||
| 0x01 || <code>uint8_t</code> || 1 || Delta value of the Keyframe. | |||
|- | |||
| 0x02 || <code>uint8_t</code> || 1 || Delta value of the keyframe's start tangent. (m0) | |||
|- | |||
| 0x03 || <code>uint8_t</code> || 1 || Delta value of the keyframe's end tangent. (m1) | |||
|} | |||
The keyframe deltas are calculated as following: | |||
X = Y + Z * W | |||
Where X is the output value, Y is the minimum value, Z is the maximum value, and W is the delta value. | |||
Essentially, the formula is telling that the '''output value is blending from the minimum to the maximum value, based on the value of Delta.''' | |||
So, that would leave us with... | |||
* P_value = '''minimum_value + maximum_value * delta_value''' | |||
* M0_value = '''minimum_m0 + maximum_m0 * delta_m0''' | |||
* M1_value = '''minimum_m1 + maximum_m1 * delta_m1''' | |||
After computing the full values, The curve is to be computed using the Hermite Cubic Interpolation. | |||
== Quantized-Precision Curve == | |||
For this ''Property Family'', the process is almost the exact same. However, there are some changes. | |||
First of, This is a more precise version of the Quantized curves. Therefore, the values are doubled up. | |||
===(Example):=== | |||
{| class="wikitable" | |||
! Offset !! Value !! Description | |||
|- | |||
| 0x00 || 0 || This field is telling that '''the curve is animating the bone index 0 of the model.''' | |||
|- | |||
| 0x01 || 50 || This field is telling that '''the curve animates the X Position of the bone index 0''', being set on a '''Quantized-Precision Curve ''Property Family''.''' | |||
|- | |||
| 0x02 || 4 || This field is telling that '''there's 4 keyframes on this curve.''' | |||
|- | |||
| 0x04 || 512 || This field is '''telling in which offset of the file the keyframes header are located'''. | |||
|} | |||
===(Keyframes header):=== | |||
{| class="wikitable" | |||
! Offset !! Type !! Size !! Description | |||
|- | |||
| 0x00 || <code>float32_t</code> || 4 || Minimum value of a keyframe. | |||
|- | |||
| 0x02 || <code>float32_t</code> || 4 || Maximum value of a keyframe. | |||
|- | |||
| 0x04 || <code>float32_t</code> || 4 || Minimum value of the start tangent (m0) | |||
|- | |||
| 0x06 || <code>float32_t</code> || 4 || Maximum value of the start tangent (m0) | |||
|- | |||
| 0x08 || <code>float32_t</code> || 4 || Minimum value of the end tangent (m1) | |||
|- | |||
| 0x0A || <code>float32_t</code> || 4 || Maximum value of the end tangent (m1) | |||
|} | |||
You can notice that, since the values were doubled up, The use of the custom float16_t were completely removed, since now the file can use float32's instead, which are more precise and stable in comparision. This results on the size of the keyframe header to be extended to '''24 bytes each.''' | |||
===(Keyframe):=== | |||
{| class="wikitable" | |||
! Offset !! Type !! Size !! Description | |||
|- | |||
| 0x00 || <code>uint16_t</code> || 2 || Keyframe time '''(Absolute)'''. | |||
|- | |||
| 0x02 || <code>uint16_t</code> || 2 || Delta value of the Keyframe. | |||
|- | |||
| 0x04 || <code>uint16_t</code> || 2 || Delta value of the keyframe's start tangent. (m0) | |||
|- | |||
| 0x06 || <code>uint16_t</code> || 2 || Delta value of the keyframe's end tangent. (m1) | |||
|} | |||
Aside from the keyframe time being '''Aboslute''', the rest of the process remains the exact same. | |||
== Full-Precision Curve == | |||
This is the most straightforward ''Property Family''. However, the most expensive (in storaging terms). | |||
Different from the Quantized types, this one is not dependent of a ''Keyframe Header.'' | |||
Instead, it tells the values right away, Rendering this ''Property Family'' the easiest to compute (considering this is not a single pose), the one with the most accurate movements, but the most expensive to store in storage terms. | |||
===(Example):=== | |||
{| class="wikitable" | |||
! Offset !! Value !! Description | |||
|- | |||
| 0x00 || 0 || This field is telling that '''the curve is animating the bone index 0 of the model.''' | |||
|- | |||
| 0x01 || 80 || This field is telling that '''the curve animates the X Position of the root bone''', being set on a '''Full-Precision Curve ''Property Family''.''' | |||
|- | |||
| 0x02 || 4 || This field is telling that '''there's 4 keyframes on this curve.''' | |||
|- | |||
| 0x04 || 512 || This field is '''telling in which offset of the file the keyframes are located'''. | |||
|} | |||
===(Keyframes):=== | |||
{| class="wikitable" | |||
! Offset !! Type !! Size !! Description | |||
|- | |||
| 0x00 || <code>uint16_t</code> || 2 || Keyframe time '''(Absolute)'''. | |||
|- | |||
| 0x02 || <code>uint16_t</code> || 2 || Padding, used to align the file, It has no use. | |||
|- | |||
| 0x04 || <code>float32_t</code> || 4 || Keyframe Value | |||
|- | |||
| 0x06 || <code>float32_t</code> || 4 || Value of the keyframe's end tangent. (m0) | |||
|- | |||
| 0x06 || <code>float32_t</code> || 4 || Value of the keyframe's end tangent. (m1) | |||
|} | |||
After that, the values can be used straight into the cubic interpolation formula. | |||
===Final Notes:=== | |||
The space in which the movement of bones takes in also depends of the ''Property Family'' the curve is set in. For instance, if a bone's rest position's property (let's say it's 125.14 for X) is animated on a quantized curve, Since this is a big value, movement information will be lost due to the nature of the quantized ''Property Family'', especially when not used in a ''Quantized-Precision Curve''. Because of that, '''The bone's movements are relative to the bone's parent's pose on quantized types.''' For full precision however, since quantization is not needed, '''the property values are absolute.''' |
Latest revision as of 22:42, 7 September 2025
Note: This page pertains to Reverse Engineering of Okami File Formats.
Explanation
This file incorporates curves and/or properties for an given embbed model. Because of that, it's almost always certain that they are contained in a file container (dat). There's instances of mots that controlled properties instead of bones, so it's not always certain of what it animates. A further inspection have to be done. But since it animates bones most of the times, i will threat it as curves that animates bones.
Every curve is computed using the Cubic Hermite interpolation formula. That means every curve is treated as a Hermite Curve.
Note: This formula's image was taken from the Cubic Hermite spline Wiki.
Mot main header (8 bytes length)
Offset | Type | Size | Description |
---|---|---|---|
0x00 | uint32_t |
4 | File identifier (Magic number). |
0x04 | uint16_t |
2 | Animation's frame count. |
0x06 | uint8_t |
1 | Animation's curve count. |
0x07 | uint8_t |
1 | Loop flag, sets if the animation either loops or not (1/0). |
On offset 8, The File gives informations about the curves, i.e: what bone it animates, etc.
Curve Info (8 bytes length)
Offset | Type | Size | Description |
---|---|---|---|
0x00 | int8_t |
1 | Bone index (-1 means it animates the mode's root bone). |
0x01 | int8_t |
1 | Curve properties (See below). |
0x02 | uint16_t |
2 | Curve keyframe count. |
0x04 | uint32_t / float32_t |
4 | Keyframes offset / value |
the 4th offset of each curve info can be either a float, or uint32. it's only set as a float if the Property Family of the curve is a Single Pose. Otherwise, it's a offset. The curve property will define what property of the bone/object it is animating. There's some properties who could not be determined yet. See some already identified values bellow.
Curve Properties (Already identified)
Value | Property Family | Property |
---|---|---|
0 | Single Pose | Position X |
1 | Single Pose | Position Y |
2 | Single Pose | Position Z |
3 | Single Pose | Rotation X |
4 | Single Pose | Rotation Y |
5 | Single Pose | Rotation Z |
6 | Single Pose | Scale X |
7 | Single Pose | Scale Y |
8 | Single Pose | Scale Z |
16 | Quantized Curve | Position X |
17 | Quantized Curve | Position Y |
18 | Quantized Curve | Position Z |
19 | Quantized Curve | Rotation X |
20 | Quantized Curve | Rotation Y |
21 | Quantized Curve | Rotation Z |
22 | Quantized Curve | Scale X |
23 | Quantized Curve | Scale Y |
24 | Quantized Curve | Scale Z |
50 | Quantized-Precision Curve | Position X |
51 | Quantized-Precision Curve | Position Y |
52 | Quantized-Precision Curve | Position Z |
53 | Quantized-Precision Curve | Rotation X |
54 | Quantized-Precision Curve | Rotation Y |
55 | Quantized-Precision Curve | Rotation Z |
56 | Quantized-Precision Curve | Scale X |
57 | Quantized-Precision Curve | Scale Y |
58 | Quantized-Precision Curve | Scale Z |
80 | Full-Precision Curve | Position X |
81 | Full-Precision Curve | Position Y |
82 | Full-Precision Curve | Position Z |
83 | Full-Precision Curve | Rotation X |
84 | Full-Precision Curve | Rotation Y |
85 | Full-Precision Curve | Rotation Z |
86 | Full-Precision Curve | Scale X |
87 | Full-Precision Curve | Scale Y |
88 | Full-Precision Curve | Scale Z |
The Property Family tells the game how the keyframes are handled ingame. Depending on the Family the property is set in, curves will be readen diferently.
Single Pose
This Property Family is the cheapest to compute. Because since it's a single pose, The there's only one keyframe, in which is given on the Curve Info.
(Example):
Offset | Value | Description |
---|---|---|
0x00 | -1 | This field is telling that the curve is animating the root bone of the model. |
0x01 | 5 | This field is telling that the curve animates the Z rotation of the root bone, being set on a Single-Pose Property Family. |
0x02 | 1 | This field is telling that there's only one keyframe on this curve, which makes sense, since this curve is set on a Single-Pose Property Family. |
0x04 | 0.52 | This field is telling the value or the Z rotation right away, no more computing needed. |
Quantized Curve
This Property Family Is known for having Quantized values. It's the most eficient type of curve, regarding storage size.
(Example):
Offset | Value | Description |
---|---|---|
0x00 | 0 | This field is telling that the curve is animating the bone index 0 of the model. |
0x01 | 16 | This field is telling that the curve animates the X Position of the bone index 0, being set on a Quantized Curve Property Family. |
0x02 | 4 | This field is telling that there's 4 keyframes on this curve. |
0x04 | 512 | This field is telling in which offset of the file the keyframes header are located. |
Quantized Curve Keyframe Header (12 bytes length)
Only Quantized property families contain a keyframe Header. That's because Every keyframe is dependent on the values given on the Header.
Offset | Type | Size | Description |
---|---|---|---|
0x00 | float16_t |
2 | Minimum value of a keyframe. |
0x02 | float16_t |
2 | Maximum value of a keyframe. |
0x04 | float16_t |
2 | Minimum value of the start tangent (m0) |
0x06 | float16_t |
2 | Maximum value of the start tangent (m0) |
0x08 | float16_t |
2 | Minimum value of the end tangent (m1) |
0x0A | float16_t |
2 | Maximum value of the end tangent (m1) |
This is the only Property Family that uses the float16_t type. That's a special type of float that can be represented as two bytes. Especifically, this type of float is built with a 1 bit sign, 6 bit exponent, a 9 bit significand and a bias of 47. The bias favours smaller numbers. That means, the highest the number, the less precise it is. That's to compensate the small amount of data two bytes can pack.
After reading the keyframes header, what follows up are the keyframes in which the actual keyframes are stored in.
Quantized Keyframes (4 bytes length)
Offset | Type | Size | Description |
---|---|---|---|
0x00 | uint8_t |
1 | Keyframe time (Relative to the time of the last keyframe). |
0x01 | uint8_t |
1 | Delta value of the Keyframe. |
0x02 | uint8_t |
1 | Delta value of the keyframe's start tangent. (m0) |
0x03 | uint8_t |
1 | Delta value of the keyframe's end tangent. (m1) |
The keyframe deltas are calculated as following:
X = Y + Z * W
Where X is the output value, Y is the minimum value, Z is the maximum value, and W is the delta value.
Essentially, the formula is telling that the output value is blending from the minimum to the maximum value, based on the value of Delta.
So, that would leave us with...
- P_value = minimum_value + maximum_value * delta_value
- M0_value = minimum_m0 + maximum_m0 * delta_m0
- M1_value = minimum_m1 + maximum_m1 * delta_m1
After computing the full values, The curve is to be computed using the Hermite Cubic Interpolation.
Quantized-Precision Curve
For this Property Family, the process is almost the exact same. However, there are some changes. First of, This is a more precise version of the Quantized curves. Therefore, the values are doubled up.
(Example):
Offset | Value | Description |
---|---|---|
0x00 | 0 | This field is telling that the curve is animating the bone index 0 of the model. |
0x01 | 50 | This field is telling that the curve animates the X Position of the bone index 0, being set on a Quantized-Precision Curve Property Family. |
0x02 | 4 | This field is telling that there's 4 keyframes on this curve. |
0x04 | 512 | This field is telling in which offset of the file the keyframes header are located. |
(Keyframes header):
Offset | Type | Size | Description |
---|---|---|---|
0x00 | float32_t |
4 | Minimum value of a keyframe. |
0x02 | float32_t |
4 | Maximum value of a keyframe. |
0x04 | float32_t |
4 | Minimum value of the start tangent (m0) |
0x06 | float32_t |
4 | Maximum value of the start tangent (m0) |
0x08 | float32_t |
4 | Minimum value of the end tangent (m1) |
0x0A | float32_t |
4 | Maximum value of the end tangent (m1) |
You can notice that, since the values were doubled up, The use of the custom float16_t were completely removed, since now the file can use float32's instead, which are more precise and stable in comparision. This results on the size of the keyframe header to be extended to 24 bytes each.
(Keyframe):
Offset | Type | Size | Description |
---|---|---|---|
0x00 | uint16_t |
2 | Keyframe time (Absolute). |
0x02 | uint16_t |
2 | Delta value of the Keyframe. |
0x04 | uint16_t |
2 | Delta value of the keyframe's start tangent. (m0) |
0x06 | uint16_t |
2 | Delta value of the keyframe's end tangent. (m1) |
Aside from the keyframe time being Aboslute, the rest of the process remains the exact same.
Full-Precision Curve
This is the most straightforward Property Family. However, the most expensive (in storaging terms). Different from the Quantized types, this one is not dependent of a Keyframe Header. Instead, it tells the values right away, Rendering this Property Family the easiest to compute (considering this is not a single pose), the one with the most accurate movements, but the most expensive to store in storage terms.
(Example):
Offset | Value | Description |
---|---|---|
0x00 | 0 | This field is telling that the curve is animating the bone index 0 of the model. |
0x01 | 80 | This field is telling that the curve animates the X Position of the root bone, being set on a Full-Precision Curve Property Family. |
0x02 | 4 | This field is telling that there's 4 keyframes on this curve. |
0x04 | 512 | This field is telling in which offset of the file the keyframes are located. |
(Keyframes):
Offset | Type | Size | Description |
---|---|---|---|
0x00 | uint16_t |
2 | Keyframe time (Absolute). |
0x02 | uint16_t |
2 | Padding, used to align the file, It has no use. |
0x04 | float32_t |
4 | Keyframe Value |
0x06 | float32_t |
4 | Value of the keyframe's end tangent. (m0) |
0x06 | float32_t |
4 | Value of the keyframe's end tangent. (m1) |
After that, the values can be used straight into the cubic interpolation formula.
Final Notes:
The space in which the movement of bones takes in also depends of the Property Family the curve is set in. For instance, if a bone's rest position's property (let's say it's 125.14 for X) is animated on a quantized curve, Since this is a big value, movement information will be lost due to the nature of the quantized Property Family, especially when not used in a Quantized-Precision Curve. Because of that, The bone's movements are relative to the bone's parent's pose on quantized types. For full precision however, since quantization is not needed, the property values are absolute.