This page follows two of Valve’s own programs: the model compiler
studiomdl in the Half-Life SDK, which reads SMD files, and the 3ds Max SMD
exporter smdlexp in the Source SDK 2013, which writes them. SMD is plain
text read one line at a time, so unlike most text formats the line breaks matter. Values
on a line are separated by spaces or tabs.
Sections
The file is a version line followed by sections. Each section starts with a keyword
alone on its line and ends with a line end.
| Line | Meaning |
|---|---|
version 1 | The format version. 1 is the only version; Half-Life’s compiler stops on any other |
nodes | Starts the list of bones |
skeleton | Starts the bone poses, one block per frame |
triangles | Starts the mesh; present in reference (mesh) files, absent in animation files |
end | Ends the current section |
A reference file has one skeleton frame, the rest pose, and a triangles section. An
animation file has one skeleton frame per frame of the animation and no triangles.
Source-era files used for facial animation (.vta) add a
vertexanimation section; its layout could not be checked against a public
Valve source and is not described here.
Nodes
One line per bone:
index "name" parent
| Value | Type | Meaning |
|---|---|---|
| index | integer | Bone number, counted from 0 and listed in order |
| name | quoted text | Bone name, such as "Bip01 Pelvis"; it may contain spaces but not double quotes |
| parent | integer | Number of the parent bone, or −1 for a root |
Skeleton
Each frame starts with a line time and the frame number, counted from 0,
followed by one line per bone:
bone px py pz rx ry rz
| Value | Type | Meaning |
|---|---|---|
| bone | integer | Bone number from the nodes section |
| px, py, pz | 3 floats | Position relative to the parent bone (relative to the model’s origin for a root) |
| rx, ry, rz | 3 floats | Rotation relative to the parent, as Euler angles in radians about x, y and z; Valve’s exporter writes them within −2π to 2π |
Triangles
Each triangle takes four lines: the material, then three vertices.
material
bone x y z nx ny nz u v [links bone1 weight1 bone2 weight2 …]
bone x y z nx ny nz u v [links …]
bone x y z nx ny nz u v [links …]
The material line is the texture or material name, such as body.bmp
for Half-Life, where it names a bitmap. Trailing white space is ignored.
| Value | Type | Meaning |
|---|---|---|
| bone | integer | Bone the vertex is attached to; Half-Life’s compiler refuses a number outside the nodes list |
| x, y, z | 3 floats | Position in model space, in the rest pose |
| nx, ny, nz | 3 floats | Normal in model space |
| u, v | 2 floats | Texture coordinates, 0 to 1, with v measured up from the bottom of the image |
| links | integer, optional | Source engine files only: how many bone weights follow |
| bonen weightn | integer and float, optional | A bone and its share of the vertex, from 0 to 1 |
Half-Life reads only the first nine values, so each vertex there belongs wholly to one
bone. Valve’s Source exporter writes the weights largest first, at most 8 per vertex,
and a rigidly attached vertex as 1 bone 1.000.
Worked example
version 1
nodes
0 "root" -1
1 "arm" 0
end
skeleton
time 0
0 0 0 0 0 0 0
1 0 0 10 0 0 1.570796
end
triangles
skin.bmp
1 0 0 10 0 1 0 0 0 2 1 0.75 0 0.25
1 5 0 10 0 1 0 1 0 1 1 1.000
1 0 0 15 0 1 0 0 1 1 1 1.000
end