Difference between revisions of "MT5"
(5 intermediate revisions by 2 users not shown) | |||
Line 18: | Line 18: | ||
| 0x08 || 0x04 || uint || First node offset | | 0x08 || 0x04 || uint || First node offset | ||
|} | |} | ||
[[File:Hrcm format.png|400px|thumb|none|HRCM Format]] | |||
The image above shows the general format of the HRCM(.mt5) model format used in Shenmue. The file is broken down into three major sections, the header, model data and texture data. The header is given in the first 12 bytes of the file and provides three values and uint32_t. The first value is the magic number of 'HRCM' indicating the model format. The second value is the offset to the texture data (provided as a list of embedded .pvr images). The third value is the offset to the first node (bone) definition for the model data. | |||
<pre> | |||
typdef struct { | |||
uint32_t magic; | |||
uint32_t texd_ofs; | |||
uint32_t node_ofs; | |||
} Mt5_Header_t; | |||
</pre> | |||
===MT5 Node=== | ===MT5 Node=== | ||
Line 66: | Line 78: | ||
These instructions are state machine like. Each instruction changes the state of how to render the strip.<br> | These instructions are state machine like. Each instruction changes the state of how to render the strip.<br> | ||
Each instruction identifier is 2 bytes long. | Each instruction identifier is 2 bytes long. | ||
* Instructions can act as padding (2 bytes) | |||
* Instructions can be followed by a single 2 byte value (4 bytes) | |||
* Otherwise instructions can provide a list of values of (n) bytes in which the length of the chunk follows the instruction. | |||
=====Unused (0x0E00, 0x0F00)===== | =====Unused (0x0E00, 0x0F00)===== | ||
Ignored. Skip 10 bytes. | Ignored. Skip 10 bytes. | ||
0x0E00 is likely the material definition | |||
* [ 0x0e00 (2) ] [ 0x08 (2) ] [ 0xffffffff (4) ][ 0x000000ff (4) ] | |||
* The material definition is often given by the format above. | |||
* The instruction for 0x0e00 is provided | |||
* The length of the chunk is declared (static 8 value) | |||
* The value of 0xffffffff is likely diffuse color rgba(255, 255, 255, 1.0); | |||
* The value of 0x000000ff is likely ambient color rgba(0,0,0,1); | |||
Note:<br> | |||
Since the color is only ever white, this effectively means the texture is applied directly. This hypothesis can be tested by changing these values to see if it changes the tint of the characters in game. | |||
=====Unused (0x8000, 0xA000)===== | =====Unused (0x8000, 0xA000)===== | ||
Ignored. Skip 2 bytes. | Ignored. Skip 2 bytes. | ||
===== | =====UV Size (0x0B00)===== | ||
Size of the as UV which divides the raw UV value being read.<br> | |||
Only usable for non-UVH coordinates. | |||
[ 0x0B00 (2) ] [ UV Size 0x400 (2) ] | |||
=====Strip Attributes (0x0200 | =====Strip Attributes (0x0200 - 0x0700)===== | ||
First byte holds UV flag for how they are interpreted. | First byte holds UV flag for how they are interpreted. | ||
Holds information about the texture UV wrap modes. | Holds information about the texture UV wrap modes. | ||
Line 82: | Line 112: | ||
=====Texture (0x0900)===== | =====Texture (0x0900)===== | ||
Sets the texture to use for the next instructions. | Sets the texture to use for the next instructions. | ||
[ 0x0900 (2) ] [ Texture Id (2) ] | |||
=====Strip Group (0x1000 - 0x1400, 0x1800 - 0x1C00)===== | =====Strip Group (0x1000 - 0x1400, 0x1800 - 0x1C00)===== | ||
Line 103: | Line 135: | ||
| 0x1400, 0x1C00 || 2 Bytes (Index) + 4 Bytes (UV) + 4 Bytes (BGRA) || Vertex index, UV, Color | | 0x1400, 0x1C00 || 2 Bytes (Index) + 4 Bytes (UV) + 4 Bytes (BGRA) || Vertex index, UV, Color | ||
|} | |} | ||
* The index values in each strip group are defined locally to the weighted vertices being defined with the mesh group. | |||
* Negative index values are defined as relative to the end of the parent node's vertex list | |||
======Strip====== | ======Strip====== | ||
Line 112: | Line 147: | ||
|} | |} | ||
Sometimes the vertex count can be negativ, just abs() it.<br> | Sometimes the vertex count can be negativ, just abs() it.<br> | ||
The reason for this | The reason for this behavior is to indicate the wind direction of the first triangle when converting from strips to triangles. | ||
<pre> | |||
let clockwise = stripLen < 0; | |||
for (let i = 0; i < strip.length - 2; i++) { | |||
let a, b, c; | |||
if (clockwise && i % 2 === 0) { | |||
a = strip[i + 1]; | |||
b = strip[i + 0]; | |||
c = strip[i + 2]; | |||
} else { | |||
a = strip[i + 0]; | |||
b = strip[i + 1]; | |||
c = strip[i + 2]; | |||
} | |||
let face = new THREE.Face3(a.i, b.i, c.i); | |||
face.materialIndex = texId; | |||
this.faces.push(face); | |||
let auv = new THREE.Vector2(a.u, a.v); | |||
let buv = new THREE.Vector2(b.u, b.v); | |||
let cuv = new THREE.Vector2(c.u, c.v); | |||
this.faceVertexUvs.push([auv, buv, cuv]); | |||
} | |||
</pre> | |||
======Strip "Vertex"====== | ======Strip "Vertex"====== | ||
Line 158: | Line 220: | ||
===Texture Entry=== | ===Texture Entry=== | ||
The MT5 support external and embedded textures. | The MT5 format support external and embedded textures. | ||
====Texture ID==== | ====Texture ID==== |
Latest revision as of 04:41, 3 August 2020
MT5 is an model container format for Shenmue I.
The model format is based on an node based hierarchy tree.
For an C# implementation based on this documentation look here.
Header
Position | Length | Type | Description |
---|---|---|---|
0x00 | 0x04 | string | Identifier (HRCM) |
0x04 | 0x04 | uint | TEXD offset |
0x08 | 0x04 | uint | First node offset |
The image above shows the general format of the HRCM(.mt5) model format used in Shenmue. The file is broken down into three major sections, the header, model data and texture data. The header is given in the first 12 bytes of the file and provides three values and uint32_t. The first value is the magic number of 'HRCM' indicating the model format. The second value is the offset to the texture data (provided as a list of embedded .pvr images). The third value is the offset to the first node (bone) definition for the model data.
typdef struct { uint32_t magic; uint32_t texd_ofs; uint32_t node_ofs; } Mt5_Header_t;
MT5 Node
Position | Length | Type | Description |
---|---|---|---|
0x00 | 0x04 | uint | ID |
0x04 | 0x04 | uint | Mesh offset |
0x08 | 0x0C | short | Rotation (X, Y, Z) |
0x14 | 0x0C | float | Scale (X, Y, Z) |
0x20 | 0x0C | float | Position/Translate (X, Y, Z) |
0x2C | 0x04 | uint | Child offset |
0x30 | 0x04 | uint | Sibling offset |
0x34 | 0x04 | uint | Parent offset |
0x38 | 0x04 | string | Node name |
0x3C | 0x04 | ? | Reserved |
Mesh Data
Position | Length | Type | Description |
---|---|---|---|
0x00 | 0x04 | uint | Polytype? |
0x04 | 0x04 | uint | Vertices offset |
0x08 | 0x04 | uint | Vertex count |
0x0C | 0x04 | uint | Instructions offset |
0x10 | 0x0C | float | Mesh center (X, Y, Z) |
0x1C | 0x04 | float | Mesh radius |
Instructions
These instructions are state machine like. Each instruction changes the state of how to render the strip.
Each instruction identifier is 2 bytes long.
- Instructions can act as padding (2 bytes)
- Instructions can be followed by a single 2 byte value (4 bytes)
- Otherwise instructions can provide a list of values of (n) bytes in which the length of the chunk follows the instruction.
Unused (0x0E00, 0x0F00)
Ignored. Skip 10 bytes.
0x0E00 is likely the material definition
- [ 0x0e00 (2) ] [ 0x08 (2) ] [ 0xffffffff (4) ][ 0x000000ff (4) ]
- The material definition is often given by the format above.
- The instruction for 0x0e00 is provided
- The length of the chunk is declared (static 8 value)
- The value of 0xffffffff is likely diffuse color rgba(255, 255, 255, 1.0);
- The value of 0x000000ff is likely ambient color rgba(0,0,0,1);
Note:
Since the color is only ever white, this effectively means the texture is applied directly. This hypothesis can be tested by changing these values to see if it changes the tint of the characters in game.
Unused (0x8000, 0xA000)
Ignored. Skip 2 bytes.
UV Size (0x0B00)
Size of the as UV which divides the raw UV value being read.
Only usable for non-UVH coordinates.
[ 0x0B00 (2) ] [ UV Size 0x400 (2) ]
Strip Attributes (0x0200 - 0x0700)
First byte holds UV flag for how they are interpreted. Holds information about the texture UV wrap modes.
Texture (0x0900)
Sets the texture to use for the next instructions.
[ 0x0900 (2) ] [ Texture Id (2) ]
Strip Group (0x1000 - 0x1400, 0x1800 - 0x1C00)
Position | Length | Type | Description |
---|---|---|---|
0x00 | 0x02 | ushort | Strip count |
These strip groups have the following vertex structure based on the identifiers:
Identifier | Vertex Size | Description |
---|---|---|
0x1000, 0x1300, 0x1800, 0x1B00 | 2 Bytes (Index) | Vertex index |
0x1200, 0x1A00 | 2 Bytes (Index) + 4 Bytes (BGRA) | Vertex index, Color |
0x1100, 0x1900 | 2 Bytes (Index) + 4 Bytes (UV) | Vertex index, UV |
0x1400, 0x1C00 | 2 Bytes (Index) + 4 Bytes (UV) + 4 Bytes (BGRA) | Vertex index, UV, Color |
- The index values in each strip group are defined locally to the weighted vertices being defined with the mesh group.
- Negative index values are defined as relative to the end of the parent node's vertex list
Strip
Position | Length | Type | Description |
---|---|---|---|
0x00 | 0x02 | short | Strip vertex count |
Sometimes the vertex count can be negativ, just abs() it.
The reason for this behavior is to indicate the wind direction of the first triangle when converting from strips to triangles.
let clockwise = stripLen < 0; for (let i = 0; i < strip.length - 2; i++) { let a, b, c; if (clockwise && i % 2 === 0) { a = strip[i + 1]; b = strip[i + 0]; c = strip[i + 2]; } else { a = strip[i + 0]; b = strip[i + 1]; c = strip[i + 2]; } let face = new THREE.Face3(a.i, b.i, c.i); face.materialIndex = texId; this.faces.push(face); let auv = new THREE.Vector2(a.u, a.v); let buv = new THREE.Vector2(b.u, b.v); let cuv = new THREE.Vector2(c.u, c.v); this.faceVertexUvs.push([auv, buv, cuv]); }
Strip "Vertex"
Type | Size | Description |
---|---|---|
short | 0x02 | Vertex index |
short | 0x04 | (optional) Texture Coordinate (UV) |
byte | 0x04 | (optional) BGRA8888 Color |
The vertex structure is based on the strip group identifier.
Often the vertex index can be negativ, this is an optimization and is used to point to the parents vertices.
The UV coordinates are UVH (UV high-resolution) and need to be divided by 1024 to get normalized UV coordnates.
End (0x0080)
Defines the end of instructions.
Vertices
The vertices only hold the position and normal of an vertex.
Vertex
Position | Length | Type | Description |
---|---|---|---|
0x00 | 0x0C | float | Position (X, Y, Z) |
0x0C | 0x0C | float | Normals (X, Y, Z) |
TEXD (Texture Definition)
This sections holds texture count for the model.
Position | Length | Type | Description |
---|---|---|---|
0x00 | 0x04 | string | Identifier (TEXD) |
0x04 | 0x04 | uint | Size in bytes |
0x08 | 0x04 | uint | Texture count |
Texture Entry
The MT5 format support external and embedded textures.
Texture ID
Each texture entry has an texture ID which is 8 bytes long.
The actual data type of the ID is still unknown, sometimes it looks like ASCII strings, Shift-JIS or plain garbage.
Position | Length | Type | Description |
---|---|---|---|
0x00 | 0x08 | string | Texture ID |
TEXN (Texture Entry)
This entry defines an embedded PVRT texture.
Position | Length | Type | Description |
---|---|---|---|
0x00 | 0x08 | TextureID | Texture ID |
0x08 | 0x0? | PVRT | Texture |
NAME (Texture Names)
This entry defines external PVRT textures each using the texture id for reference.
Position | Length | Type | Description |
---|---|---|---|
0x00 | 0x04 | string | Identifier (NAME) |
0x04 | 0x04 | uint | Size in bytes |
0x08 | 0x0? | TextureID[] | Texture ID Array |
TEXL (Texture Library)
This sections holds offsets to the texture IDs.
Position | Length | Type | Description |
---|---|---|---|
0x00 | 0x04 | string | Identifier (TEXL) |
0x04 | 0x04 | uint | Size in bytes |
0x08 | 0x04 | uint | Texture count |
TEXL Entry
Position | Length | Type | Description |
---|---|---|---|
0x00 | 0x04 | uint | Offset to TextureID |
0x04 | 0x04 | uint | Unknown |
0x08 | 0x04 | uint | Unknown |
PTRL
This sections holds offsets to various parts of the model.
Its purpose is still unclear.
Position | Length | Type | Description |
---|---|---|---|
0x00 | 0x04 | string | Identifier (PTRL) |
0x04 | 0x04 | uint | Size in bytes |