This page follows NewTek’s description of LWO2. Chunk layouts are written, as there,
as an ID followed by its fields, with each field’s type in brackets; *
means repeated to the end of the chunk, and ? means optional.
Data types
Everything is big-endian (most significant byte first).
| Type | Size | Meaning |
|---|---|---|
ID4 | 4 | A tag of four 7-bit ASCII characters, such as FORM or POLS |
I1, I2, I4 | 1, 2, 4 | Signed integers, two’s complement |
U1, U2, U4 | 1, 2, 4 | Unsigned integers |
F4 | 4 | IEEE floating-point number |
S0 | Even | ASCII string ending in a zero byte, plus one more zero when needed to make the length even |
VX | 2 or 4 | Variable-length index: a U2 when the index is below 65,280 (0xFF00); otherwise a U4 with the top byte FF. A reader that sees a first byte of FF reads four bytes and masks off the top byte |
COL12 | 12 | A colour: red, green, blue as F4, nominally 0.0 to 1.0 |
VEC12 | 12 | A position or vector: x, y, z as F4 |
FP4 | 4 | A percentage as F4, 1.0 being 100% |
ANG4 | 4 | An angle as F4, in radians |
FNAM0 | Even | A file name as S0, in a neutral form: disk:path/file for an absolute path, path/subpath/file for a relative one |
Chunks and sub-chunks
| Kind | Layout |
|---|---|
| Chunk | tag[ID4], length[U4], data, and one pad byte when the length is odd (not counted in the length) |
| Sub-chunk | tag[ID4], length[U2], data, and a pad byte when the length is odd |
| File | FORM, length[U4] (file size − 8), LWO2, then chunks |
Sub-chunks appear inside ENVL, CLIP and SURF.
A sub-chunk’s meaning depends on where it is: CHAN in an envelope is not
CHAN in a surface block. Readers skip chunks they do not know by their
length.
LAYR – Layer
LAYR { number[U2], flags[U2], pivot[VEC12], name[S0], parent[U2] ? }
Starts a new layer; every chunk after it belongs to that layer until the next
LAYR. Data before any layer goes into an arbitrary layer. Bit 0 of
flags set means the layer is hidden. pivot is the layer’s
pivot point. parent is the number of the default parent layer, or −1
(or missing) for none.
PNTS – Points
PNTS { point-location[VEC12] * }
The points of the current layer, numbered from 0; their number is the chunk length ÷
12. A PNTS must come before the POLS, VMAP and
VMAD chunks that refer to it. LightWave’s coordinate system is
left-handed: +X right (east), +Y up, +Z forward (north). There are no explicit units;
by convention the unit is the metre. Positions are relative to the layer’s pivot.
VMAP – Vertex map
VMAP { type[ID4], dimension[U2], name[S0], ( vert[VX], value[F4] # dimension )* }
Gives some of the points of the latest PNTS a vector of
dimension values. A file may hold any number of vertex maps, each with a
different type or name.
| Type | Dimension | Meaning |
|---|---|---|
PICK | 0 | A selection set: marks points for quick selection; no effect on the geometry |
WGHT | 1 | A weight map, usually for the influence of deformers such as bones; may be negative; unmapped points weigh 0.0 |
MNVW | 1 | Subpatch weights, which change the shape of subdivided geometry |
TXUV | 2 | UV texture coordinates |
RGB (with a trailing space), RGBA | 3, 4 | Vertex colours |
MORF | 3 | A morph target as displacements from the base positions |
SPOT | 3 | A morph target as absolute positions |
MBAL | 1 | The radius of influence of each metaball point |
The description notes that other types will appear. As every ID is four bytes,
RGB is written RGB , with a space.
POLS – Polygons
POLS { type[ID4], ( numvert+flags[U2], vert[VX] # numvert )* }
The polygons of the current layer. Each starts with a U2 whose low 10
bits are the vertex count (up to 1023) and whose top 6 bits are flags; the vertices
follow as point numbers in the latest PNTS.
| Type | Meaning |
|---|---|
FACE | Ordinary polygons, the most common |
CURV | Catmull–Rom spline curves, used in modelling and ignored by the renderer |
PTCH | Subdivision patches: the polygons are the control cage, and LightWave subdivides them by a method that is not documented |
MBAL | Metaballs: single-point polygons, whose radius is in an MBAL vertex map |
BONE | Two-point line segments forming the object’s skeleton |
The meaning of the 6 flag bits depends on the type and is documented only for
CURV: the two lowest flag bits (bits 10 and 11) mark the first and last
points as continuity control points, and the four highest (bits 12 to 15) are extra
high bits of the vertex count, allowing curves of up to 16,383 points. A polygon’s
vertices start at a convex vertex and run clockwise as seen from its visible side;
the normal is the cross product of the first and last edges.
VMAD – Discontinuous vertex map
VMAD { type[ID4], dimension[U2], name[S0], ( vert[VX], poly[VX], value[F4] # dimension )* }
Introduced with LightWave 6.5. Like VMAP, but each value belongs to a
point as used by one particular polygon, so a point can have different values in
different polygons. This solves UV seams: where a VMAD has the same name
as a VMAP, its values replace the map’s for the polygons it lists. The
types TXUV, RGB , RGBA and WGHT
are supported; others, such as MORF and SPOT, are kept but
never used.
VMPA – Vertex map parameters
VMPA { UV-subdivision-type[I4], sketch-colour[I4] }
Special properties of a vertex map, from later versions of LightWave. The UV subdivision types are 0 linear, 1 subpatch, 2 subpatch with linear corners, 3 subpatch with linear edges, 4 subpatch with discontinuous edges.
Other chunks
| Chunk | Layout | Meaning |
|---|---|---|
BBOX | min[VEC12], max[VEC12] | Optional bounding box of the layer’s points |
DESC | description-line[S0] | Optional short description of the object, without control characters |
TEXT | comment[S0] | Optional comments, which may contain line breaks |
ICON | encoding[U2], width[U2], data[U1] * | Optional thumbnail. The only encoding is 0, uncompressed RGB byte triples; the height is (chunk length − 4) ÷ (width × 3) rows |
ENVL | index[VX], sub-chunks | An envelope; see Envelopes and clips |
CLIP | index[U4], sub-chunks | An image or image sequence; see Envelopes and clips |
SURF | name[S0], source[S0], sub-chunks | A surface; see Surface parameters |
The description gives the icon’s height as (chunk length − 4) ÷ width, which counts bytes rather than pixels; with three bytes per pixel the row count is a third of that.