From MultimediaWiki
Jump to navigation Jump to search

This page attempts to document the LucasArts MODL mesh format, file extension ".3do". Work is ongoing, so no guarantees are made regarding any information on this page.


The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.

This document is concerned with the binary flavour of the mesh files.

TODO -- add more games that use MODL, if there are any; upload samples.


This document employs several terms and conventions. Most of these are concerned with data types, of course.

  • float - IEEE floating point value
  • vectorN - an N-dimensional array that consists of N floats
  • geoset - a collection of meshes
  • string - character array padded with zeros (one or more) at the end
  • All values are little-endian unless otherwise specified
  • Fields marked with "(?)" have not been verified. this should not be confused with an ordinary question mark "?", which is a valid part of a field's description.


The MODL format, at the highest level, has the following layout:


That is, mesh primitives with no relational information are specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.


The header is formatted as follows:

"MODL" FOURCC           |4 bytes
number of materials used|4 bytes

This is followed by material name fields, one per material:

material name|32 bytes, string

Followed the rest of the header:

3d model name|32 bytes, string


The geoset header is formatted as follows:

unknown          |4 bytes
number of geosets|4 bytes

This is followed by (not very interesting) geoset structures, one per geoset:

number of meshes|4 bytes


A mesh is formatted as follows:

mesh name                            |32 bytes, string
unknown                              |4 bytes
geometry mode                        |4 bytes
lighting mode                        |4 bytes
texture mode                         |4 bytes
number of mesh vertices              |4 bytes
number of texture vertices           |4 bytes
number of faces                      |4 bytes
mesh vertex data                     |vector3 * number of mesh vertices
texture vertex data                  |vector2 * number of texture vertices
extra light data (see notes)         |float * number of mesh vertices
unknown                              |4 bytes * number of mesh vertices
face data (see below)                |...
mesh vertex normal data              |vector3 * number of mesh vertices
has shadow                           |4 bytes
unknown                              |4 bytes
mesh radius                          |4 bytes
unknown                              |vector3
unknown                              |vector3
face id (?)                           |4 bytes
face type                             |4 bytes
geometry mode                         |4 bytes
lighting mode                         |4 bytes
texture mode                          |4 bytes
number of vertices                    |4 bytes
unknown                               |4 bytes
has texture?                          |4 bytes
has material?                         |4 bytes
unknown                               |vector3
extra light                           |4 bytes, float
unknown                               |vector3
normal vector                         |vector3
mesh vertex indices                   |4 bytes, one per vertex
if has texture, texture vertex indices|4 bytes, one per texture vertex
if has material, material index       |4 bytes


The nodes header looks like this:

unknown        |4 bytes
number of nodes|4 bytes

Followed by node structures, one per node:

name                      |64 bytes, string
flags                     |4 bytes
unknown                   |4 bytes
type                      |4 bytes
mesh id                   |4 bytes
depth                     |4 bytes
has parent?               |4 bytes
number of children        |4 bytes
has children?             |4 bytes
has sibling?              |4 bytes
pivot                     |vector3
position                  |vector3
pitch                     |4 bytes, float
yaw                       |4 bytes, float
roll                      |4 bytes, float
unknown                   |48 bytes (whoa!)
if has parent, parent id  |4 bytes
if has child, child id    |4 bytes
if has sibling, sibling id|4 bytes


The final piece is the footer, which contains some more information about the model:

model radius                |4 bytes, float
insertion offset (see notes)|vector3


  1. Extra-light values are used to as additional brightness values that are added to their corresponding vertex brightness value. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.
  2. In order to conserve space, faces only refer to vertices in their enclosing mesh. Therefore a "vertex index" is simply the vertex's position in the vertex array, starting at 0.
  3. A "node id" refers to the node's position in the breadth-first traversal of the node tree.