3D model format: Difference between revisions

From Trickstart wiki
 
(34 intermediate revisions by the same user not shown)
Line 1: Line 1:


Stores 3D models, more investigation needed.
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 in PC version 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 is one unused mention of <code>PMD V1.71</code> in the game binary
** 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 26: Line 34:
|-
|-
|0x20
|0x20
|0x94?
|4*block_count
|[[3D model format#offsetsTable|offsetsTable]]
|[[3D model format#offsetsTable|offsetsTable]]
|-
|-
|0xB4
|0xB4
|0x94?
|4*block_count
|[[3D model format#offsetsTable|offsetsTable]] sizes
|[[3D model format#offsetsTable|offsetsTable]] sizes
|}
|}


== offsetsTable ==
== Offsets table ==


You have to add '''0x148''' to each value to get proper pointers
You have to add '''0x148''' to each value to get proper pointers


Some of these are either unused or possibly repurpesed
'''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.


All blocks seem to be 32-bit aligned
If the offset/size address is empty it's always set to zero.
{| class="wikitable"
{| class="wikitable mw-collapsible"
!ID
!ID
!offset
!offset
Line 50: Line 62:
|'''0x20'''
|'''0x20'''
|'''0xb4'''
|'''0xb4'''
|Martin think it might be some sort of colider
|Martin think it might be some sort of collider, a tiny ball of vertices, quite large number of points
|-
|-
|'''1'''
|'''1'''
|'''0x24'''
|'''0x24'''
|'''0xb8'''
|'''0xb8'''
|polygons data?
|[[3D model format#Polygon|polygons]] data?
|-
|-
|'''2'''
|'''2'''
|'''0x28'''
|'''0x28'''
|'''0xbc'''
|'''0xbc'''
|UV texture data?
|[[3D model format#UV mapping|UV texture]] data?
|-
|-
|'''3'''
|'''3'''
|'''0x2c'''
|'''0x2c'''
|'''0xc0'''
|'''0xc0'''
|vertex data?
|[[3D model format#Vertex|vertex]] data?
|-
|-
|'''4'''
|'''4'''
|'''0x30'''
|'''0x30'''
|'''0xc4'''
|'''0xc4'''
|faces data?
|[[3D model format#Face|faces]] data?
|-
|-
|'''5'''
|'''5'''
Line 80: Line 92:
|'''0x38'''
|'''0x38'''
|'''0xcc'''
|'''0xcc'''
|Offsets to texture names, absolute addresses in file
|Offsets to texture names, absolute addresses in file, add 0x148
|-
|-
|'''7'''
|'''7'''
|'''0x3c'''
|'''0x3c'''
|'''0xd0'''
|'''0xd0'''
|Each element is 16B long, ?, ?, float, float
|Vertices data somehow connected to meshes, needs to be transformed
|-
|-
|'''8'''
|'''8'''
Line 95: Line 107:
|'''0x44'''
|'''0x44'''
|'''0xd8'''
|'''0xd8'''
|surface transforms data?
|[[3D model format#Transform|surface transforms]] data?
|-
|-
|'''10'''
|'''10'''
|'''0x48'''
|'''0x48'''
|'''0xdc'''
|'''0xdc'''
|surfaces data?
|[[3D model format#Mesh|meshes]] data
|-
|-
|'''11'''
|'''11'''
|'''0x4c'''
|'''0x4c'''
|'''0xe0'''
|'''0xe0'''
|[[3D model format#LOD metadata|LOD metadata]], maybe something more
|-
|'''12'''
|
|
|-
|'''0xe4'''
|12
|for non-tracks it's size of 1 divided by 16, unknown for tracks
|''0x50''
|0xe4
|Offset is 0x0; the size is non-zero, for shadow it's 1, with one <code>00</code> byte, size is checked for tracks
|-
|-
|''13''
|''13''
|''0x54''
|
|''0xe8''
|
|''unused''
|
|-
|-
|''14''
|''14''
|''0x58''
|''0x58''
|''0xec''
|
|''unused, for tracks offset marks enf of file''
|''offset marks end of file''
|-
|-
|15
|15
|0x5c
|0x5c
|0xf0
|0xf0
|track stuff
|
|-
|-
|16
|16
|0x60
|0x60
|0xf4
|0xf4
|track stuff
|
|-
|-
|17
|17
Line 138: Line 150:
|-
|-
|18
|18
|''0x68''
|
|0xfc
|0xfc
|size if 18 stores size of 20 divided by 0x90
|stores size of 20 divided by 0x90
|-
|-
|19
|19
|''0x6c''
|
|0x100
|0x100
|
|
Line 155: Line 167:
|0x74
|0x74
|0x108
|0x108
|track stuff
|AI track points (same as vertex)
|-
|-
|22
|22
|0x78
|0x78
|0x10c
|0x10c
|track stuff
|AI track meta
|-
|-
|23
|23
|0x7c
|0x7c
|0x110
|0x110
|track stuff
|
|-
|-
|24
|24
|0x80
|0x80
|0x114
|0x114
|track stuff
|
|-
|-
|25
|25
|0x84
|0x84
|0x118
|0x118
|track stuff
|
|-
|-
|26
|26
|0x88
|0x88
|0x11c
|0x11c
|track stuff
|
|-
|-
|27
|27
|0x8c
|0x8c
|0x120
|0x120
|track stuff
|
|-
|-
|28
|28
|0x90
|0x90
|0x124
|0x124
|track stuff
|
|-
|-
|29
|29
|0x94
|0x94
|0x128
|0x128
|track stuff
|
|-
|-
|30
|30
|0x98
|0x98
|0x12c
|0x12c
|track stuff
|
|-
|-
|31
|31
|0x9c
|0x9c
|0x130
|0x130
|track stuff
|
|-
|-
|32
|32
|0xa0
|0xa0
|0x134
|0x134
|track stuff
|Exists only in PMD V1.7 and later: track metadata
|-
|-
|''33''
|''33''
|''0xa4''
|
|''0x138''
|
|''unused''
|Unused
|-
|-
|''34''
|''34''
|''0xa8''
|
|''0x13c''
|
|''unused''
|Unused
|-
|-
|''35''
|''35''
|''0xac''
|
|''0x140''
|
|''unused''
|Unused
|-
|-
|''36''
|''36''
|''0xb0''
|
|''0x144''
|
|''unused''
|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 than 1.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
  • block_count is equal to 32 for versions 1.6, 1.61, 1.62; for 1.7 and later block_count is set to 37
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