3D model format: Difference between revisions
No edit summary |
|||
(42 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
Stores 3D models, more investigation needed. | |||
If "signed" was not added assume unsigned value | |||
Current analysis: https://docs.google.com/spreadsheets/d/1Hk_EIYk2E6hVd747JJmC9pqqqh_dVafM3dqOkeRp3No/edit?usp=sharing | |||
Thanks to Martin for initial format reversing. | Thanks to Martin for initial format reversing. | ||
* Magic - <code>PMD V1.83</code> | * Magic - <code>PMD V1.83</code> | ||
** some files use version 1.82 instead, but they aren't used by the game, the engine won't recognise anything other than 1.83 | ** some files use version <code>1.82</code> instead, but they aren't used by the game, the engine in PC version won't recognise anything other than <code>1.83</code> | ||
** There | ** There are mentions of unused versions <code>1.63</code> & <code>PMD V1.71</code> in the game binary | ||
** Prototype version features PMD files in versions <code>1.6</code>, <code>1.61</code>, <code>1.62</code>, <code>1.7</code> | |||
* <code>block_count</code> is equal to <code>32</code> for versions <code>1.6</code>, <code>1.61</code>, <code>1.62</code>; for <code>1.7</code> and later <code>block_count</code> is set to <code>37</code> | |||
{| class="wikitable" | {| class="wikitable" | ||
Line 16: | Line 23: | ||
|0x0 | |0x0 | ||
|0x18? | |0x18? | ||
|Magic - | |Magic - <code>PMD V1.83</code> | ||
|- | |- | ||
|0x18 | |0x18 | ||
Line 27: | Line 34: | ||
|- | |- | ||
|0x20 | |0x20 | ||
| | |4*block_count | ||
|offsetsTable | |[[3D model format#offsetsTable|offsetsTable]] | ||
|- | |- | ||
|0xB4 | |0xB4 | ||
| | |4*block_count | ||
| | |[[3D model format#offsetsTable|offsetsTable]] sizes | ||
|} | |} | ||
== | == Offsets table == | ||
You have to add '''0x148''' to each value to get proper pointers | |||
'''Bold''' IDs are in all files, rest of them are specific for tracks | |||
All blocks | Some of these are either unused or possibly repurposed | ||
{| class="wikitable" | |||
! | All blocks seems to be 32-bit aligned. | ||
If the offset/size address is empty it's always set to zero. | |||
{| class="wikitable mw-collapsible" | |||
!ID | |||
!offset | !offset | ||
!size offset | |||
!Description | !Description | ||
|- | |- | ||
|0 | |'''0''' | ||
|0x20 | |'''0x20''' | ||
| | |'''0xb4''' | ||
|Martin think it might be some sort of collider, a tiny ball of vertices, quite large number of points | |||
|- | |- | ||
|1 | |'''1''' | ||
|0x24 | |'''0x24''' | ||
| | |'''0xb8''' | ||
|[[3D model format#Polygon|polygons]] data? | |||
|- | |- | ||
|2 | |'''2''' | ||
|0x28 | |'''0x28''' | ||
| | |'''0xbc''' | ||
|[[3D model format#UV mapping|UV texture]] data? | |||
|- | |- | ||
|3 | |'''3''' | ||
|0x2c | |'''0x2c''' | ||
| | |'''0xc0''' | ||
|[[3D model format#Vertex|vertex]] data? | |||
|- | |- | ||
|4 | |'''4''' | ||
|0x30 | |'''0x30''' | ||
| | |'''0xc4''' | ||
|[[3D model format#Face|faces]] data? | |||
|- | |- | ||
|5 | |'''5''' | ||
|0x34 | |'''0x34''' | ||
|'''0xc8''' | |||
|Textures names | |Textures names | ||
|- | |- | ||
|6 | |'''6''' | ||
|0x38 | |'''0x38''' | ||
|Offsets to texture names, absolute addresses in file | |'''0xcc''' | ||
|Offsets to texture names, absolute addresses in file, add 0x148 | |||
|- | |- | ||
|7 | |'''7''' | ||
|0x3c | |'''0x3c''' | ||
| | |'''0xd0''' | ||
|Vertices data somehow connected to meshes, needs to be transformed | |||
|- | |- | ||
|8 | |'''8''' | ||
|0x40 | |'''0x40''' | ||
|'''0xd4''' | |||
|Holds IDs of elements in 7 | |Holds IDs of elements in 7 | ||
|- | |- | ||
|9 | |'''9''' | ||
|0x44 | |'''0x44''' | ||
| | |'''0xd8''' | ||
|[[3D model format#Transform|surface transforms]] data? | |||
|- | |- | ||
|10 | |'''10''' | ||
|0x48 | |'''0x48''' | ||
| | |'''0xdc''' | ||
|[[3D model format#Mesh|meshes]] data | |||
|- | |- | ||
|11 | |'''11''' | ||
|0x4c | |'''0x4c''' | ||
| | |'''0xe0''' | ||
|[[3D model format#LOD metadata|LOD metadata]], maybe something more | |||
|- | |- | ||
|12 | |'''12''' | ||
| | | | ||
| | |'''0xe4''' | ||
|for non-tracks it's size of 1 divided by 16, unknown for tracks | |||
|- | |- | ||
|13 | |''13'' | ||
| | | | ||
| | |||
| | | | ||
|- | |- | ||
|14 | |''14'' | ||
|0x58 | |''0x58'' | ||
| | | | ||
|''offset marks end of file'' | |||
|- | |- | ||
|15 | |15 | ||
|0x5c | |0x5c | ||
|0xf0 | |||
| | | | ||
|- | |- | ||
|16 | |16 | ||
|0x60 | |0x60 | ||
|0xf4 | |||
| | | | ||
|- | |- | ||
|17 | |17 | ||
|0x64 | |0x64 | ||
|0xf8 | |||
| | | | ||
|- | |- | ||
|18 | |18 | ||
| | | | ||
|0xfc | |||
|stores size of 20 divided by 0x90 | |||
|- | |- | ||
|19 | |19 | ||
| | | | ||
|0x100 | |||
| | | | ||
|- | |- | ||
|20 | |20 | ||
|0x70 | |0x70 | ||
|0x104 | |||
| | | | ||
|- | |- | ||
|21 | |21 | ||
|0x74 | |0x74 | ||
| | |0x108 | ||
|AI track points (same as vertex) | |||
|- | |- | ||
|22 | |22 | ||
|0x78 | |0x78 | ||
| | |0x10c | ||
|AI track meta | |||
|- | |- | ||
|23 | |23 | ||
|0x7c | |0x7c | ||
|0x110 | |||
| | | | ||
|- | |- | ||
|24 | |24 | ||
|0x80 | |0x80 | ||
|0x114 | |||
| | | | ||
|- | |- | ||
|25 | |25 | ||
|0x84 | |0x84 | ||
|0x118 | |||
| | | | ||
|- | |- | ||
|26 | |26 | ||
|0x88 | |0x88 | ||
|0x11c | |||
| | | | ||
|- | |- | ||
|27 | |27 | ||
|0x8c | |0x8c | ||
|0x120 | |||
| | | | ||
|- | |- | ||
|28 | |28 | ||
|0x90 | |0x90 | ||
|0x124 | |||
| | | | ||
|- | |- | ||
|29 | |29 | ||
|0x94 | |0x94 | ||
|0x128 | |||
| | | | ||
|- | |- | ||
|30 | |30 | ||
|0x98 | |0x98 | ||
|0x12c | |||
| | | | ||
|- | |- | ||
|31 | |31 | ||
|0x9c | |0x9c | ||
|0x130 | |||
| | | | ||
|- | |- | ||
|32 | |32 | ||
|0xa0 | |0xa0 | ||
|0x134 | |||
|Exists only in PMD V1.7 and later: track metadata | |||
|- | |||
|''33'' | |||
| | | | ||
| | |||
|Unused | |||
|- | |||
|''34'' | |||
| | |||
| | |||
|Unused | |||
|- | |||
|''35'' | |||
| | |||
| | |||
|Unused | |||
|- | |||
|''36'' | |||
| | |||
| | |||
|Unused | |||
|} | |||
== Basic elements == | |||
Each model contains these elements | |||
=== LOD metadata === | |||
I'm skipping most of this block, as it's unused or used directly by the engine to store some of the calculated addresses | |||
If the number of LODs is set to less than 3, later ones just copy id from previous ones | |||
{| class="wikitable mw-collapsible mw-collapsed" | |||
!Offset | |||
!Type | |||
!Description | |||
|- | |||
|0x0 | |||
|short | |||
|Same as file type at 0x18 | |||
|- | |||
|0x2 | |||
|short | |||
|Unknown, always set to 1 for normal files, 2 for tracks and 4 for cars | |||
|- | |||
|0x1C | |||
|float | |||
|Always 1.0 | |||
|- | |||
|0x20 | |||
|byte | |||
|unknown | |||
|- | |||
|0x21 | |||
|byte | |||
|unknown | |||
|- | |||
|0x22 | |||
|short | |||
|unknown | |||
|- | |||
|0x24 | |||
|int | |||
|number of meshes (surfaces) for each LOD | |||
|- | |||
|0x48 | |||
|int | |||
|ID of first mesh for LOD 0 | |||
|- | |||
|0x4c | |||
|int | |||
|ID of first mesh for LOD 1 | |||
|- | |||
|0x50 | |||
|int | |||
|ID of first mesh for LOD 2 | |||
|- | |||
|0x54 | |||
|int | |||
|ID of first mesh for LOD 3 | |||
|- | |||
|0x58 | |||
|int | |||
|Number of additional LODs, can be 0-3 | |||
|} | |||
=== Vertex === | |||
{| class="wikitable mw-collapsible mw-collapsed" | |||
!Offset | |||
!Type | |||
!Description | |||
|- | |||
|0x0 | |||
|float | |||
|X | |||
|- | |||
|0x4 | |||
|float | |||
|Y | |||
|- | |||
|0x8 | |||
|float | |||
|Z | |||
|- | |||
|0xC | |||
|float | |||
|unknown, might be weight | |||
|} | |||
=== Polygon === | |||
{| class="wikitable mw-collapsible mw-collapsed" | |||
!Offset | |||
!Type | |||
!Description | |||
|- | |||
|0x0 | |||
|byte | |||
|vertex count | |||
|- | |||
|0x1 | |||
|byte | |||
|material ID | |||
|- | |||
|0x2 | |||
|byte | |||
|unknown, might be material power effect | |||
|- | |||
|0x3 | |||
|byte | |||
|unknown, might be material binary mask, no alpha, with alpha, blend, multiply and other effect, power regulated in 0x2 | |||
|- | |||
|0x4 | |||
|short | |||
|vertices index? | |||
|- | |||
|0x6 | |||
|short | |||
|face table start index | |||
|} | |||
=== UV mapping === | |||
{| class="wikitable mw-collapsible mw-collapsed" | |||
!Offset | |||
!Type | |||
!Description | |||
|- | |||
|0x0 | |||
|float | |||
|X | |||
|- | |||
|0x4 | |||
|float | |||
|Y | |||
|- | |||
|0x8 | |||
|short | |||
|vertex index | |||
|- | |||
|0xA | |||
|short | |||
|unknown, might be texture index | |||
|- | |||
|0xC | |||
|int | |||
|normal vector? | |||
|} | |||
=== Face === | |||
{| class="wikitable mw-collapsible mw-collapsed" | |||
!Offset | |||
!Type | |||
!Description | |||
|- | |||
|0x0 | |||
|short | |||
|index ? | |||
|} | |||
=== Seven === | |||
Some kind of vertices data, bound to mesh somehow | |||
=== Transform === | |||
{| class="wikitable mw-collapsible mw-collapsed" | |||
!Offset | |||
!Type | |||
!Description | |||
|- | |||
|0x0 | |||
|float[4][4] | |||
|some kind of matrix | |||
|- | |||
|0x40 | |||
|int[4] ? | |||
|unknown four ints, set to 0 in all models, might be parent transform? | |||
|} | |||
=== Mesh === | |||
{| class="wikitable mw-collapsible mw-collapsed" | |||
!Offset | |||
!Type | |||
!Description | |||
|- | |- | ||
| | |0x0 | ||
| | |short[4] | ||
|unknown | |||
|- | |||
|0x8 | |||
|short | |||
|transform index? | |||
|- | |||
|0xA | |||
|short[3] | |||
|zeros? | |||
|- | |||
|0x10 | |||
|int[3] | |||
|zeros? | |||
|- | |||
|0x1C | |||
|float | |||
|weight? | |||
|- | |||
|0x20 | |||
|short | |||
|unknown (index?) | |||
|- | |||
|0x22 | |||
|short | |||
|unknown (index?) | |||
|- | |||
|0x24 | |||
|short | |||
|polys count | |||
|- | |||
|0x26 | |||
|short | |||
|UVs count | |||
|- | |||
|0x28 | |||
|int | |||
|vertices count | |||
|- | |||
|0x2C | |||
|int | |||
|UVs start index | |||
|- | |||
|0x30 | |||
|int | |||
|vertices start index | |||
|- | |||
|0x34 | |||
|int | |||
|polys start index | |||
|- | |||
|0x38 | |||
|int[2] | |||
|zeros? | |||
|} | |||
== Track data == | |||
=== Block 15 === | |||
{| class="wikitable mw-collapsible mw-collapsed" | |||
!Offset | |||
!Type | |||
!Description | |||
|- | |||
|0x0 | |||
|signed int | |||
|If there is any data it's set to 1, last one is always set to -1 | |||
|- | |||
|0x4 | |||
| | |||
| | | | ||
|- | |- | ||
| | |0x8 | ||
| | | | ||
| | | | ||
|- | |- | ||
| | |0xC | ||
| | |float | ||
|unknown | |||
|- | |||
|0x10 | |||
|float | |||
|unknown | |||
|} | |||
=== Block 16 === | |||
12 floats and 4 ints, seems similar to 3 points (each 4th float is always 1.0) | |||
=== Block 17 === | |||
0x28 bytes, seems like there are 4 floats (perhaps intensity/R/G/B values?), rest unused? | |||
=== Block 20 === | |||
Long, each element 0x90 bytes long, OR might have varying size dependent on type? | |||
{| class="wikitable" | |||
|+ | |||
!type | |||
!size | |||
|- | |||
|1 | |||
|0x50 | |||
|- | |||
|2 | |||
|0x90 | |||
|- | |||
|3 | |||
|0x40 | |||
|} | |||
=== Block 21 / 22 === | |||
Block 21 holds list of vertices, possibly defining track for AI. | |||
There are 5 curves in this block, 255 points each. | |||
Curve 0, 2-4 are track curves, curve 1 is for the charging station. | |||
Chall1 only has one curve. | |||
=== Block 22 === | |||
Holds the same number of elements as is the number of curves. | |||
Each element is 0x1C long | |||
WIP, so far hardcoded data from one track | |||
{| class="wikitable mw-collapsible mw-collapsed" | |||
!Offset | |||
!Type | |||
!Description | |||
|- | |||
|0x0 | |||
|int | |||
|id | |||
|- | |||
|0x4 | |||
|int | |||
|starting vertex offset | |||
|- | |||
|0x8 | |||
|int | |||
|length? | |||
|- | |||
|0xC | |||
|int | |||
|0x1 | |||
|- | |||
|0x10 | |||
|int | |||
|0x2 | |||
|- | |||
|0x14 | |||
|int | |||
|0xa | |||
|- | |||
|0x18 | |||
|float? | |||
| | | | ||
|} | |||
=== Block 23 === | |||
List of vertices | |||
=== Block 24 === | |||
list of faces? Each element 0x2 bytes long | |||
=== Block 25 === | |||
list of faces? Each element 0x2 bytes long | |||
=== Block 26 === | |||
Each element 0x40 long. | |||
=== Block 27 === | |||
list of faces? Each element 0x2 bytes long | |||
=== Block 28 === | |||
list of faces? Each element 0x2 bytes long | |||
=== Block 29 === | |||
Each element 0x4 long. | |||
=== Block 30 === | |||
Each element 0x8 long. | |||
=== Block 31 === | |||
Each element 0x30 long. | |||
4 floats (last one set to 1.0), and 16 shorts. | |||
=== Block 32 === | |||
0x38 bytes, mostly zeros | |||
{| class="wikitable mw-collapsible mw-collapsed" | |||
!Offset | |||
!Type | |||
!Description | |||
|- | |||
|0x18 | |||
|float | |||
|Always 50.0 | |||
|- | |||
|0x20 | |||
|float | |||
|Always 100.0 | |||
|- | |- | ||
| | |0x24 | ||
| | |int | ||
| | | | ||
|} | |} |
Latest revision as of 21:16, 16 November 2022
Stores 3D models, more investigation needed.
If "signed" was not added assume unsigned value
Current analysis: https://docs.google.com/spreadsheets/d/1Hk_EIYk2E6hVd747JJmC9pqqqh_dVafM3dqOkeRp3No/edit?usp=sharing
Thanks to Martin for initial format reversing.
- Magic -
PMD V1.83
- some files use version
1.82
instead, but they aren't used by the game, the engine in PC version won't recognise anything other than1.83
- There are mentions of unused versions
1.63
&PMD V1.71
in the game binary - Prototype version features PMD files in versions
1.6
,1.61
,1.62
,1.7
- some files use version
block_count
is equal to32
for versions1.6
,1.61
,1.62
; for1.7
and laterblock_count
is set to37
Offset | Size | Description |
---|---|---|
0x0 | 0x18? | Magic - PMD V1.83
|
0x18 | 0x4 | Type - 0 = shadow & skybox; 1 = track; 2 = car |
0x1C | 0x4 | Zeroes? |
0x20 | 4*block_count | offsetsTable |
0xB4 | 4*block_count | offsetsTable sizes |
Offsets table
You have to add 0x148 to each value to get proper pointers
Bold IDs are in all files, rest of them are specific for tracks
Some of these are either unused or possibly repurposed
All blocks seems to be 32-bit aligned.
If the offset/size address is empty it's always set to zero.
ID | offset | size offset | Description |
---|---|---|---|
0 | 0x20 | 0xb4 | Martin think it might be some sort of collider, a tiny ball of vertices, quite large number of points |
1 | 0x24 | 0xb8 | polygons data? |
2 | 0x28 | 0xbc | UV texture data? |
3 | 0x2c | 0xc0 | vertex data? |
4 | 0x30 | 0xc4 | faces data? |
5 | 0x34 | 0xc8 | Textures names |
6 | 0x38 | 0xcc | Offsets to texture names, absolute addresses in file, add 0x148 |
7 | 0x3c | 0xd0 | Vertices data somehow connected to meshes, needs to be transformed |
8 | 0x40 | 0xd4 | Holds IDs of elements in 7 |
9 | 0x44 | 0xd8 | surface transforms data? |
10 | 0x48 | 0xdc | meshes data |
11 | 0x4c | 0xe0 | LOD metadata, maybe something more |
12 | 0xe4 | for non-tracks it's size of 1 divided by 16, unknown for tracks | |
13 | |||
14 | 0x58 | offset marks end of file | |
15 | 0x5c | 0xf0 | |
16 | 0x60 | 0xf4 | |
17 | 0x64 | 0xf8 | |
18 | 0xfc | stores size of 20 divided by 0x90 | |
19 | 0x100 | ||
20 | 0x70 | 0x104 | |
21 | 0x74 | 0x108 | AI track points (same as vertex) |
22 | 0x78 | 0x10c | AI track meta |
23 | 0x7c | 0x110 | |
24 | 0x80 | 0x114 | |
25 | 0x84 | 0x118 | |
26 | 0x88 | 0x11c | |
27 | 0x8c | 0x120 | |
28 | 0x90 | 0x124 | |
29 | 0x94 | 0x128 | |
30 | 0x98 | 0x12c | |
31 | 0x9c | 0x130 | |
32 | 0xa0 | 0x134 | Exists only in PMD V1.7 and later: track metadata |
33 | Unused | ||
34 | Unused | ||
35 | Unused | ||
36 | Unused |
Basic elements
Each model contains these elements
LOD metadata
I'm skipping most of this block, as it's unused or used directly by the engine to store some of the calculated addresses
If the number of LODs is set to less than 3, later ones just copy id from previous ones
Offset | Type | Description |
---|---|---|
0x0 | short | Same as file type at 0x18 |
0x2 | short | Unknown, always set to 1 for normal files, 2 for tracks and 4 for cars |
0x1C | float | Always 1.0 |
0x20 | byte | unknown |
0x21 | byte | unknown |
0x22 | short | unknown |
0x24 | int | number of meshes (surfaces) for each LOD |
0x48 | int | ID of first mesh for LOD 0 |
0x4c | int | ID of first mesh for LOD 1 |
0x50 | int | ID of first mesh for LOD 2 |
0x54 | int | ID of first mesh for LOD 3 |
0x58 | int | Number of additional LODs, can be 0-3 |
Vertex
Offset | Type | Description |
---|---|---|
0x0 | float | X |
0x4 | float | Y |
0x8 | float | Z |
0xC | float | unknown, might be weight |
Polygon
Offset | Type | Description |
---|---|---|
0x0 | byte | vertex count |
0x1 | byte | material ID |
0x2 | byte | unknown, might be material power effect |
0x3 | byte | unknown, might be material binary mask, no alpha, with alpha, blend, multiply and other effect, power regulated in 0x2 |
0x4 | short | vertices index? |
0x6 | short | face table start index |
UV mapping
Offset | Type | Description |
---|---|---|
0x0 | float | X |
0x4 | float | Y |
0x8 | short | vertex index |
0xA | short | unknown, might be texture index |
0xC | int | normal vector? |
Face
Offset | Type | Description |
---|---|---|
0x0 | short | index ? |
Seven
Some kind of vertices data, bound to mesh somehow
Transform
Offset | Type | Description |
---|---|---|
0x0 | float[4][4] | some kind of matrix |
0x40 | int[4] ? | unknown four ints, set to 0 in all models, might be parent transform? |
Mesh
Offset | Type | Description |
---|---|---|
0x0 | short[4] | unknown |
0x8 | short | transform index? |
0xA | short[3] | zeros? |
0x10 | int[3] | zeros? |
0x1C | float | weight? |
0x20 | short | unknown (index?) |
0x22 | short | unknown (index?) |
0x24 | short | polys count |
0x26 | short | UVs count |
0x28 | int | vertices count |
0x2C | int | UVs start index |
0x30 | int | vertices start index |
0x34 | int | polys start index |
0x38 | int[2] | zeros? |
Track data
Block 15
Offset | Type | Description |
---|---|---|
0x0 | signed int | If there is any data it's set to 1, last one is always set to -1 |
0x4 | ||
0x8 | ||
0xC | float | unknown |
0x10 | float | unknown |
Block 16
12 floats and 4 ints, seems similar to 3 points (each 4th float is always 1.0)
Block 17
0x28 bytes, seems like there are 4 floats (perhaps intensity/R/G/B values?), rest unused?
Block 20
Long, each element 0x90 bytes long, OR might have varying size dependent on type?
type | size |
---|---|
1 | 0x50 |
2 | 0x90 |
3 | 0x40 |
Block 21 / 22
Block 21 holds list of vertices, possibly defining track for AI.
There are 5 curves in this block, 255 points each.
Curve 0, 2-4 are track curves, curve 1 is for the charging station.
Chall1 only has one curve.
Block 22
Holds the same number of elements as is the number of curves.
Each element is 0x1C long
WIP, so far hardcoded data from one track
Offset | Type | Description |
---|---|---|
0x0 | int | id |
0x4 | int | starting vertex offset |
0x8 | int | length? |
0xC | int | 0x1 |
0x10 | int | 0x2 |
0x14 | int | 0xa |
0x18 | float? |
Block 23
List of vertices
Block 24
list of faces? Each element 0x2 bytes long
Block 25
list of faces? Each element 0x2 bytes long
Block 26
Each element 0x40 long.
Block 27
list of faces? Each element 0x2 bytes long
Block 28
list of faces? Each element 0x2 bytes long
Block 29
Each element 0x4 long.
Block 30
Each element 0x8 long.
Block 31
Each element 0x30 long.
4 floats (last one set to 1.0), and 16 shorts.
Block 32
0x38 bytes, mostly zeros
Offset | Type | Description |
---|---|---|
0x18 | float | Always 50.0 |
0x20 | float | Always 100.0 |
0x24 | int |