Created: 2008/08/26 23:08:46 EDT

Updated: 2009/12/11 16:46:51 EST

Mesh File Format

 

Introduction

A tool set to work with .msh files in Titan Quest was never released. However, I have taken some time to investigate the format for some of my own modifications. Please note that this is a very incomplete work. I do not know all the details of the file format, but will share what I do know.

Tools

Here are some self-written programs that I use for working with meshes (source code is included -- do whatever you want with it). This method is just barely more friendly than hex editing, so don't expect much.

Mesh2CSV - This program will take a .msh file and convert it to a human readable .csv file. It can also optionally create a .tga file of the 2D texture mapping points. This can be overlayed onto an actual texture in order to visualize the actual triangles used in game.

CSV2Mesh - This program will take a .csv file (or multiple .csv files split by section) and construct a .msh file from them.

Warning: Do not re-save the .csv with a program like Microsoft Excel that expects every row to have the same number of columns or you will corrupt the file and be unable to translate back to a .msh.

These programs are command line only. They are NOT resilient and are probably quite prone to breaking. In particular, if a bad .csv file is used to create a mesh, it is quite likely that the program will simply go into an infinite loop and create a bigger and bigger file. If the CSV2Mesh does not complete within a few seconds, just hit CRTL+C or CTRL+BREAK to stop it.

The usage is as follows:

Mesh2CSV input.msh output.csv
Will read "input.msh" and create "output.csv".
Mesh2CSV input.msh output.csv output.tga 512 1024
Will read "input.msh" and create "output.csv" along with "output.tga" with width 512 and height 1024.
CSV2Mesh output.msh input.csv
Will read "input.csv" and create "output.msh".
CSV2Mesh output.msh input1.csv input2.csv [etc]
Will read each input specified in order to create "output.msh". Each file must start and end on an exact section break.
 

Header

The file header is a single integer value 0x0B48534D (the letters "MSH" followed by a vertical tab).

After the header there are a number of sections denoted by a single integer, followed by the total byte size of the section. These sections appear to be optional and probably do not have to occur in any order; the game will read them if they are present. Information about the data inside each section follows

 

Section 0 - MIF location (Material Information File)

Breakdown
  • First four bytes: total size of string
  • Remaining bytes: ASCII string
Example
0x0000: 00 00 00 00 26 00 00 00 22 00 00 00             ; Integers 0, 38, 34
0x000C: 43 72 65 61 74 75 72 65 73 5C 50 43 5C 46 65 6D ; String "Creatures\PC\Fem
0x001C: 61 6C 65 5C 46 65 6D 61 6C 65 50 43 30 31 2E 6D ; String "ale\FemalePC01.m
0x002C: 69 66                                           ; String "if 
Explanation

FYI, this appears to be useless without the original tools used to create meshes.

In the example, the integers 0, 38 denote Section 0 of 38 total bytes. The integer 34 indicates a string of 34 characters ("Creatures\PC\Female\FemalePC01.mif").

 

Section 3 - Plain text data

Example
0x0000: 03 00 00 00 3B 70 00 00                         ; Integers 3, 28731
0x0008: 41 74 74 61 63 68 50 6F 69 6E 74 0D 0A 7B 0D 0A ; String "AttachPoint\r\n{\r\n
0x0018: 20 20 20 20 6E 61 6D 65 20 20 20 3D 20 22 4C 20 ; String "    name   = "L
0x0028: [...] Lots more... 
Explanation

The data in this block is ASCII and easily readable. Possibly just documentation.

In the example, the integers 3, 28731 denote Section 3 of 28731 total bytes.

 

Section 4 - Vertices

Section Breakdown
  • First four bytes: Number of integer values preceding the vertex data
  • Second four bytes: Size of a single vertex data entry in bytes
  • Third four bytes: Total number of vertices
  • Remaining bytes: Vertex data
Vertex Breakdown
  • Three floats for the 3D X, Y, and Z position
  • Two floats for the 2D X and Y texture position, expressed as a percentage.
  • Three more floats (unknown usage)
  • Four bytes (unknown usage; not the right format for a float)
  • Four more floats (unknown usage)
  • Six more floats (unknown usage)
Example
0x0000: 04 00 00 00 34 CE 03 00                         ; Integers 4, 249396
0x0008: 07 00 00 00 4C 00 00 00 D1 0C 00 00             ; Integers 7, 76, 3281
0x0014: 00 00 00 00 04 00 00 00 01 00 00 00 06 00 00 00 ; Integers 0, 4, 1, 6
0x0024: 05 00 00 00 02 00 00 00 03 00 00 00             ; Integers 5, 2, 3 
0x0030: DE 86 31 BE 12 89 B3 3F 5C 82 1C BE             ; Floats -0.17,  1.40, -0.15
0x003C: 2E AA 55 3F 8A E1 F0 3E                         ; Floats  0.83,  0.47
0x0044: C4 D3 2F BF BC 1B CD 3E B8 40 1B BF             ; Floats -0.69,  0.40, -0.61
0x0050: 00 01 02 FF                                     ; Bytes 0, 1, 2, 255
0x0054: CD CC CC 3E CD CC CC 3E CD CC 4C 3E 00 00 00 00 ; Floats  0.40,  0.40,  0.20,  0.00
0x0064: 4F 4E 34 3F D6 AD 24 3E 54 01 31 BF             ; Floats  0.70,  0.16, -0.69
0x0070: 1D 15 8F 3E 28 72 6A 3F 35 B0 93 3E             ; Floats  0.28,  0.92,  0.29 
Explanation

I do not know what the values marked "unknown usage" represent, though I suspect they are material and lighting information. I have broken them out into the groups listed above due to certain similarities. For example, the "four more floats" tends to be nice round values like 0, 0.25, and 0.5, while none of the others are ever particularly nice.

In the example, the integers 4, 249396 denote Section 4 of 249396 total bytes. There are 7 integers before the actual vertex data, each vertex data is 76 bytes, and there are 3281 total vertices. The 7 integers 0, 4, 1, 6, 5, 2, 3 come next, though I do not know what they represent.

In the example vertex, the point is located at -0.17 x 1.40 x -0.15 in 3D space. It is mapped to the 2D texture point located 83% from left to right and 47% from top to bottom. For example, given a 512x512 texture, this would be the point located at 425x241. What the rest of the data represents, I do not know.

Section 5 - Triangles

Section Breakdown
  • First four bytes: The total number of triangles
  • Second four bytes: The number of draw calls
  • Remaining bytes: Triangle definitions followed by draw call definitions
Triangle Breakdown
  • First two bytes: First vertex index
  • Second two bytes: Second vertex index
  • Third two bytes: Third vertex index
Draw Call Breakdown
  • First four bytes: Unknown usage
  • Second four bytes: First triangle to draw
  • Third four bytes: Total number of triangles to draw
  • Fourth four bytes: Unknown usage
  • Next 24 bytes: Six floating point values (unknown usage)
  • Next four bytes: The number of integer values before the next draw call (or end of data)
  • Remaining bytes: Integer values (unknown usage)
Example
0x0000: 05 00 00 00 AC 2E 00 00                         ; Integers 5, 11948
0x0008: A2 07 00 00 02 00 00 00                         ; Integers 1954, 2 
0x0010: 02 00 01 00 00 00 05 00 04 00 03 00             ; Short Ints 2, 1, 0, 5, 4, 3
0x001D: [...] More... 
0x2DDC: 00 00 00 00 00 00 00 00 2C 07 00 00 00 00 00 00 ; Integers 0, 0, 1836, 0
0x2DEC: D0 F2 F7 BD E7 DA 98 3F E0 E6 CC BB             ; Floats -0.12,  1.19, -0.01
0x2DF8: DA 94 7A 3F AD 38 99 3F DF 65 59 3E             ; Floats  0.98,  1.20,  0.21
0x2E04: 1A 00 00 00                                     ; Integer  26
0x2E08: 03 00 00 00 05 00 00 00 04 00 00 00 0E 00 00 00 ; Integers (26 in total)
0x2E18: [...] More... 
Explanation

In the example, the integers 5, 11948 denote Section 5 of 11948 total bytes. There are 1954 total triangles and 2 total draw calls.

In the triangle example, the first two triangles are shown. The first one connects vertices 2, 1, and 0, and the second connects 5, 4, and 3.

In the draw call example, the call will draw 1836 triangles starting at 0. Since there are 1954 total triangles and only 2 draw calls, it is likely that the next draw call will start with the 1837th triangle and draw the remaining 118 triangles. I do not know what the rest of the data is used for.

Section 6 - Bones

This section describes the bones, which are viewable using "Viewer.exe" supplied with TQ. I have not attempted to decipher this section at this time.

Section 8 - Attributes

This section contains various name/value pairs including default texture information, shaders and parameters, and the like. I have not attempted to decipher this section at this time.

Section 10 - 3D Extents

Breakdown
Consists of 6 float values indicating X, Y, and Z minimums followed by X, Y, and Z maximums.
Example
0x0000: 0A 00 00 00 18 00 00 00                         ; Integers 10, 24
0x0008: 9A C9 8C BF 07 8E 3B BB 99 96 24 BF             ; Floats -1.099902, -0.002862, -0.642923
0x0014: 99 C9 8C 3F CF D5 1A 40 79 1A 5D 3E             ; Floats  1.099902,  2.419300,  0.215921 
Explanation

The size of this section should always be 24.

In the example, the integers 10, 28731 denote Section 10 of 24 total bytes. The values state that X coordinates will range between -1.1 and 1.1, the Y will range between 0 and 2.4, and the Z will range between -0.6 and 0.2.

All Other Sections

Unknown at this time.

 

 

Post your comment

Please be aware that comments are subject to moderation and will not appear immediately.

Comments

  • The Skeleon Emitter given in section 3 does not appear to be used at all.

    Some scenery meshes have a long Section 2 instead of Section 3 after the shader section. They don't use a MIF, and so have no need of Section 3. Section 2 contains a mix of integers and floats (probably vectors - they seem to be in multiples of 3.) No idea yet what info is in here - it doesn't seem critical to a simple import of the mesh and textures. HOWEVER, the texture coords for these verts don't seem to be normalized like creature meshes are. Some info for that may be hidden in here, or it may not matter if the textures are tiled. Haven't looked closely at this yet.

    Also note: parsing Attach Points out of the MIF data is needed for some of the CallBacks in the .ANM files for creatures. Some of those (spawns and transformations mainly) are CreateEntity calls for attached FX, so if you want to use those in some way, you'll have to parse the AP's eventually.

    I have Gmax scripts that do all this so far for importing into Dungeon Siege. They result in a completely boned and weighted mesh. I am currently testing the animation script, but import works (in most cases.) If you can script enough it would be simple to change to keep it more generic for possible import back into TQ. Dunno if we'll ever have enough info for that to be seamless, but I can send the script if you have a place to host it and are interested. Let me know (anybody!) at bjsmith72032 at hotmail dot com.

    I'll keep updating here as I figure out more info. I want the meshes as intact as possible, but my final destination is Dungeon Siege 2, so that influences the final form of my tools, but most of the code is general if somebody is technical enough to modify it for their purposes.

    Posted by Graagh, 2010/10/23 19:13:45 EDT (1 year ago)

  • Section 8 contains the Hit Box info, though I haven't deciphered it yet beyond the basics:
    Integer: number of boxes
    32-byte String: box name
    15 floats: there's bound to be a position and rotation in there, but I can't figure out why you'd need the extra 3, unless instead of position it's a min/max. Haven't looked very closely at this one yet.
    Integer: unknown

    Posted by Graagh, 2010/10/18 11:00:43 EDT (1 year ago)

  • Section 3, the plain text data, is the contents of the MIF file given in Section 0. It contains definitions of all the Attach Points and attached Entities, Rigid Bodies, Joints, and sometimes a Skeleton Emitter. If you save the contents into the file name given in Section 0 in your data path, the Viewer (and I assume other TQ apps) will recognize all this data.

    Posted by Graagh, 2010/10/18 10:38:15 EDT (1 year ago)

  • Section 7:
    Integer: number of textures
    Integer: length of shader name
    ASCII String: shader name
    Integer: number of parameters for this shader

    all parameters in this format:
    Integer: length of parameter name
    ASCII String: parameter name
    Integer: data type of parameter value - 7=string, 9=color, 10=float, possibly others I haven't seen
    Type: parameter value - strings are integer length followed by string, colors are 3 floats (RGB), and floats are (obviously) a 4-byte float.

    Posted by Graagh, 2010/10/18 10:35:10 EDT (1 year ago)

  • Additionally, since the first 4 bytes of the drawcall are the texture index, then for each vert that forms a corner of one of the triangles of this drawcall, its texture coordinates from Section 4 map into the referenced texture from Section 7 - the whole shader is referenced, but I just map to the filename given in the shader's "baseTexture" parameter. I guess I should explain section 7 next... :-)

    Posted by Graagh, 2010/10/18 10:24:40 EDT (1 year ago)

  • More info on vert weighting:
    In the drawcalls, the first 4 bytes are the index of the texture to use for this drawcall. The textures are given in Section 7 as a shader call and its associated parameters.

    After the triangle data, all the drawcall data is given, and THEN the "Fourth 4 bytes unknown usage". It's not really the 4th word unless, as in this case, there's only one drawcall. There will be as many of these sections as there are drawcalls. If this initial word is 0, then it is followed by the 6 floats, otherwise the count and list of integers follows immediately. This is the number of bones, and the order of their indexes, for this drawcall. So in your example, there are 26 bones for the first drawcall, bone 0 is bone 3 from Section 6, bone 1 is bone 5 from Section 6, bone 2 is bone 4 from Section 6, etc. These indexes (NOT the ones from Section 6) correspond to the bone indexes given in the verts. So for each vert that makes a corner of one of the tris from this drawcall, if its bone indexes in Section 4 are 01 00 02 03, then the actual bones you would weight to from Section 6 are: 05 03 04 0E. Repeat for each draw call. Still no idea what the 6 floats are used for.

    Posted by Graagh, 2010/10/18 10:18:28 EDT (1 year ago)

  • More research: The 8th component of the vert in the empusa mesh is not component number 7, but number 14. It appears to be a 4-byte vertex color stored as unsigned byte R, G, B, A values.

    Posted by Graagh, 2010/09/19 23:00:51 EDT (1 year ago)

  • The problem you're having with verts is that they're not always in that format.

    The "integer values preceding the data" are the components of the vert - generally non-boned meshes have 5 and boned have 7 (adding the bones and weights), and the empusa from IT has 8! The integers themselves give the layout of the vert data.

    Component 0 = position
    Component 1 = normal
    Component 2,3 = unknown, but appear to be 3 floats each
    Component 4 = tex coords
    Component 5 = bone weights
    Component 6 = bone indexes
    Component 7 = unknown, haven't looked at this one yet

    These components can be given in any order and appear in that order in the vert data - so it's not a fixed format...

    I'm working on decoding the format as completely as I can. Reach me with any questions at bjsmith72032 at hotmail dot com

    Posted by Graagh, 2010/09/19 22:24:00 EDT (1 year ago)

  • additional info about the vertices:
    - the next 3 floats (after the 3 for position and 2 for tex coords) are the vertex normal - it is normalized: nx*nx + ny*ny + nz*nz = 1).
    - the next 4 bytes are indexes of up-to 4 bones to which the vertex is attached and the following 3 floats are the corresponding attachment weights. Their sum is 1.
    Note: bone index of 255 and/or attachment weight of 0 means no bone attachment; the format supports maximum 4 attachments per vertex, but can be less than that for each individual vertex.

    Posted by shade, 2010/02/12 17:21:45 EST (2 years ago)

  • Section Bones

    4 byte for number of bones.

    A bone consists of:

    32 byte for name
    4 byte (integer) for index of child bone
    4 byte (integer) for number of childs
    3 * 3 floats for axis of the bone
    3 floats for position of bone

    I think that should work.

    Posted by Nobsta, 2009/07/27 15:19:59 EDT (3 years ago)