StarCraft II M3 Model Format
M3 is the binary 3D model format used by StarCraft II (and Heroes of the Storm). OpenWarcraft3 includes an M3 loader so that StarCraft II assets can be rendered alongside Warcraft III content.
Overview
Unlike the chunked MDX format, an M3 file is structured as a reference table of typed data blocks. Every complex field in an M3 struct is a Reference — a (nEntries, offset, flags) triple that points into the reference table rather than embedding data inline. This makes the format highly self-describing and supports forward-compatibility through versioned structures.
File Header
DWORD magic // 'MD34' or '43DM' (little-endian)
DWORD refOffset // byte offset of the reference table
DWORD refCount // number of Reference entries
Reference modelRef // root model reference (always the first entry)
The file is divided into two regions:
1. Data region — packed binary data for all structs.
2. Reference table — array of { DWORD offset; DWORD nEntries; DWORD flags; } records immediately after the data region.
Core Types
typedef struct {
DWORD offset; // byte offset into data region
DWORD nEntries; // number of elements
DWORD flags; // usually 0
} Reference;
Primitive aliases used throughout the format:
| Alias | C type |
|---|---|
m3Float32_t |
float |
m3Vector2_t |
VECTOR2 |
m3Vector3_t |
VECTOR3 |
m3Vector4_t |
VECTOR4 |
m3Matrix4_t |
MATRIX4 |
m3Pixel_t |
COLOR32 |
m3Face_t |
USHORT |
Animation References
Animated scalar and vector values are represented by AnimRef structs. Each AnimRef embeds the initial/null value directly and carries an animation ID referencing an animation sequence data block:
typedef struct {
USHORT interpolationType; // 0=constant, 1=linear, 2=hermite, 3=bezier
USHORT animFlags;
DWORD animId; // index into ANIM table, or 0xFFFFFFFF
<type> initValue;
<type> nullValue;
DWORD unknown;
} m3<Type>AnimRef_t;
Typed variants are declared for Pixel, Uint16, Uint32, Float32, Vector2, Vector3, and Vector4.
Geometry
The geometry section contains:
- Vertices — position, normal, tangent, UV coordinates, and up to 4 bone weights/indices per vertex.
- Faces — triangle index list (
m3Face_t=USHORT). - Bone lookup table — maps per-vertex bone indices to the skeleton's actual bone indices.
The renderer (renderer/m3/r_m3_load.c) reads these arrays and builds a VBO with the following per-vertex layout:
// From the GLSL vertex shader embedded in r_m3_load.c:
in vec3 i_position;
in vec4 i_color;
in vec2 i_texcoord;
in vec3 i_normal;
in vec4 i_skin1; // bone indices (4 × uint8, packed in float4)
in vec4 i_boneWeight1; // bone weights (4 × float)
Up to 64 bones are uploaded to the shader as a mat4 uBones[64] uniform array for GPU skinning.
Materials
M3 materials reference textures through a Reference to an array of m3Layer_t structs. Each layer includes:
- a texture
Reference(points to aReferenceof path strings) - an
AnimReffor UV offset and scale animation - flags controlling blending, UV wrapping, and normal-map usage
Bones and Animation
The skeleton is stored as an array of m3Bone_t structs, each containing:
- parent bone index
- initial transform (
m3Matrix4_t) AnimRefs for translation, rotation, scale- a bounding sphere used for culling
Animation sequences are stored as m3Sequence_t entries. Each sequence specifies:
- start and end frame numbers
- movement speed
- bounding sphere for the whole sequence
- a Reference to per-sequence data blocks (containing the actual keyframe arrays for every AnimRef in the model that changes in that sequence)
Bounding Volumes
Every node and sequence carries a BoundingSphere struct:
Collision shapes are defined separately as BoundingShape structs with a shape type (sphere / capsule / box), a reference bone, and a transform matrix.
Versioning
M3 structs carry an embedded version number. The reader uses a versioned macro M3_READ(buffer, var, version) that only reads a field if the buffer's struct version exceeds the given threshold:
#define M3_READ(BUFFER, VAR, VERSION) \
if ((BUFFER)->ent.version > VERSION || VERSION == 0) \
M3_Read(BUFFER, &VAR, sizeof(VAR));
This allows the same reader code to handle multiple revisions of the format.
Related Source Files
| Source | Purpose |
|---|---|
renderer/m3/r_m3.h |
All M3 struct definitions |
renderer/m3/r_m3_load.c |
Reference-table reader, model loader, and GLSL shader |