LightWave 3D Object File Format 2

June 16, 1999


Contents


Introduction

LightWave 3D objects are stored on disk as 3D meshes consistsing of points, polygons (which can be faces, curves or patches), and surfaces. Files can contain multiple layers (or parts) and each part can be a single connected mesh or several disjoint meshes. An object file may also contain one or more surface definitions with no mesh.

This document describes the high-level format of the file, and describes in detail all the elements of the file. There is a sample file at the end displayed as an annotated dump.


Types and Structures

LightWave 3D object files are binary files composed of a series of bytes in the range of 0 to 255. The format conforms to the IFF ("Interchange File Format") specification with a FORM-type of LWO2. The full IFF format specification can be found in "EA IFF 85 Standard for Interchange Format Files," but a simplified description is included here.

The atomic (or lowest-level) types in the file are listed below along with their type name (I2, F4, etc.). These are used interpret sequences of bytes in the file.

ID Tag
ID4

An ID tag is a sequence of 4 bytes interpreted as 7-bit ASCII values, usually upper-case. These tags are used to identify the type of data which follows. FORM, SURF, POLS, and LWO2 are all examples of ID tags.

Signed Integer
I1, I2, I4
Unsigned Integer
U1, U2, U4

Integers can have 1, 2 or 4 bytes and can be signed or unsigned. The most significant byte comes first in the file, so bytes read into memory should be reversed before being interpreted on Intel and compatible CPUs.

Float
F4

Floats are written as 4 byte IEEE floating-point values. The bytes should generally be reversed before being interpreted on Intel and compatible CPUs.

String
S0

Names or other character strings are written as a series of ASCII character values followed by a zero (or null) byte. If the length of the string plus the null terminating byte is odd, an extra null is added to make the total length even.
The basic structural element in an IFF file is the Chunk. This is given by the structure:

CHUNK ::= tag[ID4], length[U4], data[...], pad[U1] ?
Each chunk starts with an ID tag which indicates the type of chunk, and an unsigned four-byte integer which indicates the length of the data. After that follows length bytes of data and an optional pad byte if length is odd. The pad byte, if included, should have a value of zero.

LightWave objects also have the Sub-chunk (or mini-chunk) structural element which is just like a chunk except that the length is given by a two-byte unsigned integer. Sub-chunks are specific to LightWave objects, not general IFF files.

SUB-CHUNK ::= tag[ID4], length[U2], data[...], pad[U1] ?
For the purposes of this document, chunks and sub-chunks are written as "id-tag { data }". The entire file can be an example of this notation, since it is itself a FORM chunk containing the ID tag LWO2 and a series of data chunks.

FORM { 'LWO2'[ID4], data[CHUNK] * }
Very roughly, object files start with the four bytes "FORM" followed by a four-byte integer giving the length of the file (not including the first 8 bytes) and the four bytes of the FORM-type, "LWO2". The remainder of the data is a series of chunks, each given by a four-character type and a four-byte length for the data which follows. The contents of each chunk is determined by its type.

The chunks can occur in any order except when the data in a chunk depends on knowing the values in previous chunks, in which case the dependant chunk must occur after the chunk it depends upon. Different applications may write their chunks in slightly different orders, so it is important for parsers to support order-independence.

The LightWave format has some composite datatypes that it uses consistently which are built from the fundamental types.

Variable-length Index
VX ::= index[U2] | (index + 0xFF000000)[U4]

A vertex or polygon index is written as a variable length two or four byte element. If the index value is less than 65,280 (0xFF00), then the index is written as an unsigned two-byte integer. Otherwise the index is written as an unsigned four byte integer with bits 24-31 set. When reading, if the first byte in the number is 255 (0xFF), then the four-byte form is being used.

Color
COL12 ::= red[F4], green[F4], blue[F4]

A color is written as an RGB triple, with each color component being a floating point value in the range of 0.0 to 1.0. 0.0,0.0,0.0 is full black and 1.0,1.0,1.0 is full white. Values may also be out of range, although the behavior of such colors will depend on their context.

Coordinate
VEC12 ::= X[F4], Y[F4], Z[F4]

3D coordinates are written as an XYZ vector in floating point format. The values are distances along the X, Y, and Z axes.

Percentage
FP4 ::= fractional-value[F4]

Percentages are written as a floating point value, where 0.0 is equal to 0% and 1.0 is equal to 100%.

Angle
ANG4 ::= degrees[F4]

Angles are specified as floating point values expressed in radians.

Filename
FNAM0 ::= name[S0]

Filenames (such as the names of images) are written as strings in a platform-neutral format. This format is aaa:bbb/ccc for absolute filenames and aaa/bbb/ccc for relative filenames. The PC filename A:\images\monalisa.tga would be stored as A:images/monalisa.tga; the Mac file :Images:Mona Lisa would be stored as Images/Mona Lisa; and the Unix file /usr/images/monaLisa.t would be stored as usr:images/monaLisa.t.


Object File Chunks

The following section describes all the chunks that can be found in a LightWave object file. Their order here is not important, except that chunks which define values in other chunks are listed first.

Start Layer

LAYR { number[U2], flags[U2], pivot[VEC12], name[S0], parent[U2] }

This chunk signals the start of a new layer. All the data chunks which follow will be included in this layer until another layer chunk is encountered. If data is encountered before a layer chunk, it goes into an arbitrary layer. The parent index indicates the default parent for this layer and can be -1 or missing to indicate no parent.

Point List

PNTS { point-location[VEC12] * }

This chunk contains a list of the X, Y, and Z coordinates for a set of points. Since each coordinate has three components, and each component is stored as a four byte floating point number, the number of points in an object can be determined by dividing the size in bytes of the PNTS chunk by 12.

By convention, the +X direction is to the right or east, the +Y direction is upward, and the +Z direction is forward or north. For models of real-world objects, the unit size is usually considered to be one meter. The coordinates are specified relative to an object's pivot point. See the LightWave Modeler manual for more information about LightWave 3D's geometric conventions.

Points in a PNTS chunk are numbered in the order they occur, starting with zero. This index is then used by polygons to define their vertices. The PNTS chunk must be before the POLS or VMAP chunks that refer to it.

Vertex Mapping

VMAP { type[ID4], dimension[U2], name[S0],
( vert[VX], value[F4] # dimension )* }

This chunk contains a set of floating point vectors associated with a set of vertices. Each one has a type which is a four-character ID code, a dimension and a name string. After that follows a list of vertex / vector pairs, with the vertex given by a vertex index in VX format and an array of "dimension" floating-point values. There can be any number of these chunks, although they should all have different types or names.

Some possible type codes are TXUV for UV mapping coordinates, MNVW for MetaNURBS vertex weights, MORF for vector offsets defining an alternate object shape, SPOT for alternate vertex positions, RGBA for coloring, etc.

Polygon List

POLS { type[ID4], ( numvert+flags[U2], vert[VX] # numvert )* }

This chunk contains a list of polygons for the current layer. The 'type' code indicates the polygon type and can be FACE, CURV, PACH, or possibly other values. Each entry starts with a short integer specifying the number of vertices in the polygon. The 6 high-order bits of the number of vertices are flags bits with different meaning for each polygon type, so there are a maximum of 1023 vertices per polygon. The vertex list is the specified number of two or four byte VX vertex indices (relative to the most recent points list). The vertex list for each polygon should begin at a convex vertex and proceed clockwise as seen from the visible side of the polygon (LightWave 3D polygons are single-sided, except for those whose surfaces have the double-sided flag set). Polygons should be read from the file until as many bytes as the chunk size specifies have been read.

Tag Strings

TAGS { tag-string[S0] * }

This chunk lists the tags strings that can be associated with polygons by the PTAG chunk. Strings should be read until as many bytes as the chunk size specifies have been read, and each string is assigned an index starting from zero.

Polygon Tag Mapping

PTAG { type[ID4], ( poly[VX], tag[U2] )* }

This chunk contains the all the tags of a given type for some subset of the polygons defined in the preceding POLS chunk. The type of the tag association is given by the first element of the chunk and is an normal 4-character ID code. The rest of the chunk is a list of polygon/tag associations. The polygon is identified by its index into the previous POLS chunk, and the tag is given by its index into the previous TAGS chunk. Any number of polygons may be mapped with this type of tag, and mappings should be read from the file until as many bytes as the chunk size specifies have been read.

Polygon tags types and their values are extensible, but there are some pre-defined types. The SURF type tags each polygon with the name of its surface. In LightWave 3D terminology, a "surface" is defined as a named set of shading attributes and may be described in the object file in SURF chunks. Another pre-defined type is PART which describes what aspect of the mesh each polygon belongs to, and SMGP which names the smoothing group for each polygon. Not all polygons have a value for every tag type, and the behavior for polygon which lack a certain tag depends on the type.

Envelope Definition

ENVL { index[U4], attributes[SUB-CHUNK] * }

Each ENVL chunk defines the time-varying curve for a single parameter channel. The index is used to identify this envelope uniquely, and can have any non-zero value less than 0x1000000. Following the index is a series of sub-chunks, which are like normal IFF chunks except that their sizes are specified by short integers instead of longs. The number of sub-chunks may vary depending on the complexity of the envelope, so sub-chunks should be read from the file until as many bytes as the chunk size specifies have been read. New types of sub-chunks may be introduced as the program capabilities increase, but any unknown sub-chunks may be skipped over by using their size.

Image or Sequence Definition

CLIP { index[U4], attributes[SUB-CHUNK] * }

Each CLIP chunk defines a image which can be used for applying as a texture map in surfaces. The term 'clip' is used to describe these since they may be time-varying sequences or animations rather than just stills. The index identifies this clip uniquely and may be any non-zero value less than 0x1000000. The attributes which define the source imagery and modifiers follow as a variable list of sub-chunks.

Surface Definition

SURF { name[S0], source[S0], attributes[SUB-CHUNK] * }

Each SURF chunk describes the shading attributes of a particular surface. These chunks begin with the name of the surface being described plus the name of the source surface. If the source name is non-null, then this surface is derived from the source surface. The base attributes of the source surface can be overridden by this surface, and texture blocks can be added to the source surface. The material attributes follow as a variable list of sub-chunks.

Bounding Box

BBOX { min[VEC12], max[VEC12] }

This is an optional chunk which can be included to store the bounding box for the vertex data in a layer. The min and max vectors are the lower and upper corners of the bounding box.

Description Line

DESC { description-line[S0] }

This is an optional chunk which can be used to hold an object description. This should be a simple line of upper and lowercase characters, punctuation and spaces which describes the contents of the object file. There should be no control characters in this text string and it should generally be kept short.

Commentary Text

TEXT { comment[S0] }

This is another optional chunk which can be used to hold comments about the object. The text is just like the DESC chunk, but it can be about any subject, it may contain newline characters and it does not need to be particularly short.

Thumbnail Icon Image

ICON { encoding[U2], width[U2], data[U1] * }

This optional chunk contains an iconic or thumbnail image for the object which can be used when viewing the file in a browser. The encoding is a code for the data format which can only be zero for now meaning uncompressed, unsigned bytes as RGB triples. The width specifies the number of pixels contained in each row of the image. The data consists of rows of pixels (RGB triples for now), and the height of the image is determined by the length of the data.


Envelope Sub-chunks

The ENVL chunk contains a series of sub-chunks describing the keyframes, intervals and global attributes of a single envelope.

Envelopes are referenced by clips and surfaces by their index. The index value is given in the preamble of the ENVL chunk, and index values of zero indicate no envelope for a parameter.

Pre-Behavior

PRE { type[U2] }

The pre-behavior for an envelope defines the signal value for times before the first key. The integer code selects one of several predefined behaviors, starting from zero: Reset, Constant, Repeat, Ocsillate, Offset Repeat, Linear.

Post-Behavior

POST { type[U2] }

The post-behavior determines the signal value for times after the last key. The type codes are the same as for pre-behaviors.

Keyframe Time and Value

KEY { time[F4], value[F4] }

This chunk defines the time and value for an envelope keyframe. The signal value for the envelope is exactly the value of the key when the signal is evaluated at the time of the key. Values between keyframes are interpolations of adjacent keyframe values.

Interval Interpolation

SPAN { type[ID4], value[F4] * }

This sub-chunk defines the interpolation between the most recently specified KEY chunk and the keyframe immediately before it in time. The type ID code defines the interpolation algorithm and can be STEP, LINE, TCB, HERM or BEZI. The variable number of parameters values that follow define the particulars of the interpolation.

Plug-in Channel Operators

CHAN { server-name[S0], flags[U2], data[...] }

Channel filters can be layered on top of a basic keyframed envelope to provide some more elaborate effects. Each channel chunk contains the name of the plug-in server and some flags bits. Only the first flag bit is defined, which if set indicates that the filter is disabled. The plug-in data follows as raw bytes.

Channel Name

NAME { channel-name[S0] }

This is an optional envelope sub-chunk which is not used by LightWave in any way. It is only provided to allow external programs to browse through the envelopes available in an object fille.


Image Sub-chunks

The CLIP chunk contains a series of sub-chunks which serve to describe a single time-varying image. The first sub-chunk has to be one of the source chunks: STIL, ISEQ, ANIM, XREF or STCC. The chunks after that serve as modifiers for the source chunk and are applied as filters layered on top of the source image.

Still Image

STIL { name[FNAM0] }

This source chunk describes a single still image. The image is referenced by a filename in neutral path format.

Image Sequence

ISEQ { num-digits[U1], flags[U1], offset[I2], loop-length[I2], prefix[FNAM0], suffix[S0] }

This source chuck describes an image sequence, which is basically a filename with a number in the middle. The number of digits is the number of zeros used to encode the sequence number in the filename. The flags has bits for looping and interlace. Offset and loop-length define the frames in the sequence. The prefix and suffix are stuck before and after the frame number to make the filename for each frame, which is in neutral path format.

Plug-in Animation

ANIM { server-name[S0], data[...] }

This chunk indicates that the source imagery comes from a plug-in animation loader. The loader is defined by the server name and its data which just follows as binary bytes.

Reference

XREF { clip-index[VX] }

The source for a clip can also be a different clip, which is identified by its index value, stored in variable-length format.

Color-cycling Still

STCC { lo[I2], hi[I2], name[FNAM0] }

A still image with color-cycling is a source defined by a neutral-format name and cycling parameters. If lo is less than hi, the colors cycle forward, and if hi is less than lo, they go backwards.

Contrast

CONT { contrast-delta[FP4], envelope[VX] }

This modifier alters the contrast of the image up or down by the given percentage.

Brightness

BRIT { brightness-delta[FP4], envelope[VX] }

This modifier alters the brightness of the image up or down by the given percentage.

Saturation

SATR { saturation-delta[FP4], envelope[VX] }

This modifier alters the saturation of the image up or down by the given percentage.

Hue

HUE { hue-rotation[FP4], envelope[VX] }

This modifier rotates the hue of the image 360 degrees for 100% of hue rotation.

Gamma Correction

GAMM { gamma[F4], envelope[VX] }

This modifier applies the given gamma to the image, where a value of 1.0 is no change.

Negative

NEGA { enable[U2] }

If the value is true, this modifier performs a negation of the image.

Image Cropping

CROP { x[FP4], y[FP4], w[FP4], h[FP4] }

This operator crops the image by a window specified as fractions of the total. After the operator is applied, the value of the image at (x,y) is now found at (0.0,0.0) and the value at (x+w,y+h) is found at (1.0,1.0).

Override Alpha

ALPH { clip-index[VX] }

This modifier takes a different clip (referenced by index) and uses its grayscale value as the alpha for this image.

Composite

COMP { clip-index[VX], blend[FP4], envelope[VX] }

This modifier takes a different clip (referenced by index) and composites it on top of the current image. The alpha for the other image is multiplied by the blend percentage before it is composited with this image.

Plug-in Image Filters

IFLT { server-name[S0], flags[U2], data[...] }

Plug-in image filters can be used to pre-filter an image before rendering. The filter has to be able to exist outside of the special environment of rendering in order to work here. Filters are given by a server name, an enable flag, and plug-in server data as raw bytes.

Plug-in Pixel Filters

PFLT { server-name[S0], flags[U2], data[...] }

Pixel filters may also be used as clip modifiers, and they are stored and used in a way that is exactly like image filters above.


Surface Sub-chunks

The sub-chunks found in a SURF surface chunk will consists of one of two types. They may be "basic" surface parameters with some simple data, or they may be surface blocks which contain nested parameters specific to the block type.

BLOK { type[ID4], ordinal[ID4], attributes[SUB-CHUNK] * }

Blocks are identified by a type, which is a four-character ID code, plus an ordinal string which is used to order the block with respect to other blocks. After that the type-specific block parameters follow as nested sub-chunks. The ordinal strings are never read by the user, so they can contain any characters from 1 to 255 and tend to be very short. The only rule is that an ordinal string must not end with a 1 byte, since that prevents arbitrary insertion.

The shading parameters for a polygon are the result of composing the surface parameters of the SURF chunk with the parameters from any source surface (which may itself be a composite). If the same basic surface parameter is found in both this surface and its source, then the values in this surface take precedence. All the blocks in both this surface and in the source surface are composed together, sorting on the ordinal string.

Basic Surface Parameters

The following surface sub-chunks define the base characteristics of a surface. These are values that are independent of texturing and correspond roughly to the options on the main window of the Surface Editor. Even if the effects of textures and shaders override these settings completely in final rendering, as many of these should still be specified as possible since they are also used for previewing and real-time rendering. Most of these values contain a reference to an optional envelope and may therefore change over time.

Base Color

COLR { base-color[COL12], envelope[VX] }

This defines the base color of the surface, which is the color that lies under all the other texturing attributes.

Base Shading Values

DIFF, LUMI, SPEC, REFL, TRAN, TRNL { intensity[FP4], envelope[VX] }

These sub-chunks specify the base level of the surface's diffuse, luminosity, specular, reflection, transparency, or tranlucency settings. If any of these sub-chunks are absent for a surface, a value of zero is assumed.

Specular Glossiness

GLOS { glossiness[FP4], envelope[VX] }

Glossiness is encoded as a floating point percentage and is only needed if the specular value of a surface is non-zero. This glossiness percentage is converted to a specular exponent by the formula 2(10 * glossiness + 2). Thus a glossiness of 20% (0.2) gives a specular exponent of 24, or 16 which is equivalent to the old "Low" glossiness preset. Likewise 40% is 64 or "Medium," 60% is 256 or "High," and 80% is 1024 or "Maximum." If this chunk is missing a value of 40% is assumed.

Diffuse Sharpness

SHRP { sharpness[FP4], envelope[VX] }

Diffuse sharpness replaces the old "Sharp Terminator" flag with a smoothly varying percentage value. The default value of zero results in normal shading, and a 50% value is the same as the old sharp terminator setting.

Bump Intensity

BUMP { strength[FP4], envelope[VX] }

This encodes the basic bump map intensity. I'm not totally sure how this is used in the shading equation.

Polygon Sidedness

SIDE { sidedness[U2] }

The sidedness of a polygon can be 1 for front-only, or 3 for front and back. This replaces the old "Double Sided" flag bit. If missing, single-sided polygons are assumed.

Max Smoothing Angle

SMAN { max-smoothing-angle[ANG4] }

This specifies the maximum angle between two adjacent polygons that can be smooth shaded. Polygons with a greater angle between them will appear to meet at a sharp seam. If this chunk is missing, or if the value is zero or less, then the polygons are not smoothed.

Reflection Options

RFOP { reflection-options[U2] }

Reflection options is a numeric code that describes how reflections are handled for this surface and is only meaningful if the reflectivity of the surface is non-zero. If the mode is 0, then only the backdrop colors in the scene are reflected. If the mode is 1, it is the same as 0 except that raytracing is used for objects in the scene when it is enabled. If the mode is 2 and an image is provided by the RIMG sub-chunk, then the image wrapped spherically around the scene is reflected. If the mode is 3, it is the same as 2 except that raytracing is used when enabled. If there is no RFOP sub-chunk, a value of 3 is assumed.

Reflection Map Image

RIMG { image[VX] }

The reflection image is wrapped around the scene and is used for reflection mapping if the RFOP mode is set to use an image and the reflectivity of the surface is non-zero. If the RFOP mode setting expects an image and there is no RIMG chunk, then the backdrop colors are reflected. The image is the index of a CLIP chunk, or zero to indicate no image.

Reflection Map Image Seam Angle

RSAN { seam-angle[ANG4], envelope[VX] }

This angle is the heading angle of the reflection map seam. If missing, a value of zero is assumed.

Refractive Index

RIND { refractive-index[F4], envelope[VX] }

The surface's refractive index determines how much light rays bend when passing into or out of this material, and is defined as the ratio of the speed of light in a vacuum to the speed of light in the material. Since light is fastest in a vacuum, this value should therefore be greater than or equal to 1.0.

Color Highlights

CLRH { color-highlights[F4], envelope[VX] }

The color highlight percentage determines how much the reflections on a surface, including specular highlights, are tinted by the color of the surface. This replaces the old discrete "Color Highlights" flag.

Transparency Options

TROP { transparency-options[U2] }

Transparency options are just the same as reflection options except that they describe how refraction is handled. Refraction can be any combination of background color, image or raytracing.

Refraction Map Image

TIMG { image[VX] }

The refraction image is wrapped around the scene and is used for refraction mapping if the TROP mode is set to use an image and the transparency of the surface is non-zero. This setting is the refractive analogue of RIMG.

Color Filter

CLRF { color-filter[F4], envelope[VX] }

The color filter percentage determines how much rays passing through a transparent surface are tinted by the color of the surface. This replaces the old discrete "Color Filter" flag.

Additive Transparency

ADTR { additive[F4], envelope[VX] }

This percentage selects how "additive" transparency effect are. The default value of zero indicates that transparent surfaces fully attenuate the background color while a value of 100% indicates that that the background color is full strength under the transparent surface.

Glow Effect

GLOW { type[U2], intensity[F4], intensity-envelope[VX], size[F4], size-envelope[VX] }

The glow effect causes a surface to spread and effect neighboring areas of the image. The type can be 0 for Hastings glow, and 1 for image convolution. The size and intensity modulate how large and how strong the effect is, but the exact units are unclear.

Render Outlines

LINE { flags[U2], size[F4], size-envelope[VX], color[COL12], color-envelope[VX] }

The line effect draws illustrations-like outlines around the borders of objects and surfaces. The lines are drawn with the given thickness and the given color, but how thickness is reckoned is unclear.

Alpha Mode

ALPH { mode[U2], value[U2] }

This chunk defines the alpha channel output options for the surface. If mode is 0, this surface does not affect the Alpha channel at all when rendered. If mode is 1, the alpha channel will have a fixed value which is the second parameter in the chunk and should have a value from 0 to 255. If mode is 2, the alpha value is derived from surface opacity, which is the default if the ALPH chunk is missing. If mode is 3, the alpha value comes from shadow density.

Texture Layers

Surface textures in LightWave are BLOK sub-chunks of type IMAP, PROC or GRAD corresponding to image-based, procedural or gradient-based modulations of one of the shading parameters. Any number of these texture layers may be present in a surface and their effect is cumulative.

While each type of texture layer has sub-chunks that are specific to that block type, there are some common sub-chunks that may be present in some or all of the different texture types.

Channel Type

TYPE { texture-type[ID4] }

This sub-chunk is required in all texture blocks and can have a value of COLR, DIFF, LUMI, SPEC, REFL, TRAN, TRNL, or BUMP, corresponding to a modulation of the color, diffuse, luminosity, specular, reflection, transparency, translucency, or bump attribute.

Algorithm

NAME { algorithm-name[S0] }

This is a character string identifying the name of the algorithm used for this texturing layer. For image maps this is the name of the projection used; for gradients it is the name of the input parameter; and for procedurals it is the name of the texture algorithm.

Enable State

ENAB { enable[U2] }

This flag is either 1 for an enabled texture layer, or 0 for a texture layer that should be ignored. If the chunk is missing, the texture is assumed to be enabled.

Opacity

OPAC { type[U2], opacity[FP4], envelope[VX] }

This specifies how opaque this texture is with respect to the textures before it. The types can be 0 for additive opacity, 1 for subtractive opacity, 2 for difference, 3 for multiply, 4 for divide, 5 for alpha and 6 for texture displacement opacity mode. If no opacity parameters are specified, 100% additive opacity is assumed.

Flags

FLAG { texture-flags[U2] }

This short integer has bits which specify various options for the current texture. Currently only a few least significant bits are used. The options that set bits indicate are (starting with the least significant bit): World Coords, Negative Image, Pixel Blending, and Antialiasing. Some obviously apply only to image maps.

Texture Mapping

Image map and procedural texture blocks employ some of the same sub-chunks to define the mapping from object or world coordinate space to texture space.

Major Axis

AXIS { texture-axis[U2] }

This short integer can be 0, 1 or 2 indicating that the major axis of the texture is given by the X, Y or Z axis, respectively.

Position, Orientation and Size

CNTR, SIZE, ROTA { vector[VEC12], envelope[VX] }

These sub-chunks each consist of a vector for the texture's size, center and rotation. The size and center are normal positional vectors in meters, and the rotation is a vector of heading, pitch and bank in radians. If missing, the center and rotation are assumed to be zero. The size should always be specified if it to be used for any given mapping.

Reference Object

OREF { object-name[S0] }

This subchuck specifies a reference object for the texture. The reference object is given by name, and the position, rotation and scale of the object are used to compute the texture mapping at any given time. Does this override the previous chunks or just modify them? -- I don't know.

Falloff

FALL { type[U2], vector[VEC12], envelope[VX] }

Texture effects may fall off from the texture center if this sub-chunk is present. The type can be 0 to indicate that the falloff is independent in each axis, or it can be 1 to indicate that the falloff is based on distance from the center. How the vector is interpreted in distance-based falloff is also unclear.

Image Maps

Texture blocks of type IMAP are image maps, and use an image to modulate one of the shading parameters.

Image Map

IMAG { texture-image[VX] }

This specifies an image to be used for image texture mapping as an index of a CLIP chunk.

Image Wrap Options

WRAP { width-wrap[U2], height-wrap[U2] }

This specifies how image-based textures will interpret the color of areas outside the image. If the mode is 0, then outside the image is considered to be black. If the mode is 1, areas outside the image are clamped to the closest image edge value. If the mode is 2, then the image repeats outside the image area resulting in a uniform tiling. If the mode is 3, then the image repeats but with mirroring, so that each each adjacent repetition is reversed. If no wrap options are specified, 2 is assumed.

Image Wrap Ammount

WRPW, WRPH { cycles[FP4], envelope[VX] }

For mapping modes that wrap around in the width or height directions, like "Cylindrical" or "Spherical," these parameters control how many times the image repeats over each full interval.

UV Vertex Map

VMAP { txuv-map-name[S0] }

For mapping modes that depend on texture coordinates at each vertex, this selects the name of the TXUV vertex map that contains those coordinates.

Antialiasing Strength

AAST { antialising-strength[FP4] }

This specifies the strength of antialiasing used for the texture. If the Antialiasing bit is set in the TFLG sub-chunk and this sub-chunk is missing, 100% is assumed. This setting currently only affects image-based textures.

Procedural Textures

Texture blocks of type PROC are procedural textures that modulate their shading parameter with an algorithmic effect.

Texture Color

COLR { texture-color[COL12], envelope[VX] }

If the texture is set to modify the COLR shading channel, then this is the alternate color value to use.

Texture Value

VALU { texture-value[FP4], envelope[VX] }

Textures that modify anything other than the COLR channel are scalar values, and this is the alternate value.

Algorithmic Texture Parameters

FTPS { float-parameter[F4] * }
ITPS { integer-parameter[I2] * }
ETPS { envelope-parameter[VX] * }

The FTPS sub-chunk contains a sequence of floating point numbers that specify texture-type specific parameters (such as Contrast, Turbulence, Wavelength, etc). The ETPS sub-chunk contains a sequence of envelopes that correspond to each floating point parameter. The ITPS sub-chunk is similar but is used for integer parameters (such as number of Frequencies, Wave Sources, etc). In general, these parameters are stored in the sequence they are found on the interface panel, and the number of each type of parameter can be computed from the sub-chunk length.

Gradient Textures

Texture blocks of type GRAD are gradient textures that modulate their shading parameter by mapping some input parameter through an arbitrary transfer function.

Gradient Range

GRST, GREN { input-range[FP4] }

These two sub-chunks store the start and end of the input range. These values do not affect rendering at all and are stored only for the user-interface.

Gradient Keys

FTPS { ( input[FP4], output[FP4] # 4 )* }

The transfer function is defined as a series of keys, each with an input value and a vector of RGBA output values. Given an input value, the gradient can be evaluated by selecting the keys whose positions bracket the value and linearly interpolating between their outputs. If the input value is lower than the first key or higher than the last key, the gradient value is the value of the closest key. There is always at least one key, so every FTPS sub-chunk will have at least five values or there is no gradient.

Plug-in Shaders

Plug-in shaders are BLOK sub-chunks of type SHDR. They are applied to a surface after all built-in textures, and in the order specified by the block sequence. In addition to the sub-chunks listed below, shaders can also contain the standard ENAB sub-chunk.

Server Name

NAME { name[S0] }

Plug-in shaders are identified by their server name, which is stored in this sub-chunk.

Shader Data

DATA { shader-data[...] }

A shader can store up to 65,535 bytes of data to describe its settings, and these are stored directly in this sub-chunk without modification. The length and contents of this chunk will depend completely on the shader specified by the previous NAME chunk.


Object File Example

The file starts with the standard simple form IFF header. It is just a chunk of type FORM which identifies this file as an IFF. The first four bytes in the main outer chunk are the ID LWO2 which specifies this is a LightWave Object File IFF.

NOTE: This example is a bit out of date. It was created before the surface atom reformation and the polygon tag revolution.

464f524d 000003c2            FORM {		   IFF file header; FORM chunk
						     file length is 962 + 8 bytes
4c574f32                       LWO2		     FORM type ID for LW OBjects

53524653 00000016              SRFS {		   Surface name list
42 6c 75 65 20 50 6c 61 73 74 65 72 00 00
                                 "Blue Plaster"	     name 0
43 68 72 6f 6d 65 00 00          "Chrome"	     name 1
                               }

4c415952 0000001a              LAYR {		   Start New layer
0000 0000                        0, 0		     layer number, flags
00000000 00000000 00000000       0.0, 0.0, 0.0	     pivot point
57 61 6c 6c 20 42 6f 78 00 00    "Wall Box"	     layer name
                               }

504e5453 00000060              PNTS {		   Points (96 / 12 = 8 points)
3f800000 3f800000 3f800000        1.0,  1.0,  1.0    point 0
3f800000 bf800000 3f800000        1.0, -1.0,  1.0    point 1
bf800000 bf800000 3f800000       -1.0, -1.0,  1.0    point 2
bf800000 3f800000 3f800000       -1.0,  1.0,  1.0    point 3
3f800000 3f800000 bf800000        1.0,  1.0, -1.0    point 4
3f800000 bf800000 bf800000        1.0, -1.0, -1.0    point 5
bf800000 bf800000 bf800000       -1.0, -1.0, -1.0    point 6
bf800000 3f800000 bf800000       -1.0,  1.0, -1.0    point 7
                               }

42424f58 00000018              BBOX {		   Bounding Box (optional)
bf800000 bf800000 bf800000       -1.0, -1.0, -1.0    low corner
3f800000 3f800000 3f800000        1.0,  1.0,  1.0    high corner
                               }

564d4150 00000060              VMAP {		   Vertex Map
55564d50 0002                    UVMP, 2	     type code, dimension
49 6d 61 67 65 20 55 56 00 00    "Image UV"	     map name

  0000                           0		     point 0 mapped to:
    3f800000 3f800000             1.0,  1.0	      these 2 float values
  0001                           1		     point 1
    3f800000 00000000             1.0,  0.0
  0002                           2		     point 2
    00000000 00000000             0.0,  0.0
  0003                           3		     point 3
    00000000 3f800000             0.0,  1.0
  0004                           4		     point 4
    3f800000 3f800000             1.0,  1.0
  0005                           5		     point 5
    3f800000 00000000             1.0,  0.0
  0006                           6		     point 6
    00000000 00000000             0.0,  0.0
  0007                           7		     point 7
    00000000 3f800000             0.0,  1.0
                               }

504f4c53 0000004c              POLS {		   Polygons
46414345                         FACE		     type (facets)

  0004 0000                      4, 0		     4 vertices, surface 0 ("Blue Plaster")
    0000 0001 0002 0003          0, 1, 2, 3	     point indices for vertices
  0004 0000                      4, 0
    0004 0005 0006 0007          4, 5, 6, 7
  0004 0000                      4, 0
    0000 0001 0005 0004          0, 1, 5, 4
  0004 0000                      4, 0
    0001 0002 0006 0005          1, 2, 6, 5
  0004 0000                      4, 0
    0002 0003 0007 0006          2, 3, 7, 6
  0004 0000                      4, 0
    0003 0000 0004 0007          3, 0, 4, 7
                               }

4c415952 00000012              LAYR {		   Start New Layer
0001 0000                        1, 0		     layer number, flags
00000000 00000000 00000000       0.0, 0.0, 0.0	     pivot point
0000                             ""		     name (none)
                               }

504e5453 00000048              PNTS {		   Points (72 / 12 = 6 points)
00000000 3fb4fdf4 00000000        0.0,   1.414, 0.0    point 0
3fb4fdf4 00000000 00000000        1.414, 0.0,   0.0    point 1
00000000 00000000 3fb4fdf4        0.0,   0.0,   1.414  point 2
bfb4fdf4 00000000 00000000       -1.414, 0.0,   0.0    point 3
00000000 00000000 bfb4fdf4        0.0,   0.0,  -1.414  point 4
00000000 bfb4fdf4 00000000        0.0,  -1.414, 0.0    point 5
                               }

42424f58 00000018              BBOX {		   Bounding Box (optional)
bfb4fdf4 bfb4fdf4 bfb4fdf4       -1.414, -1.414, -1.414
3fb4fdf4 3fb4fdf4 3fb4fdf4        1.414,  1.414,  1.414
                               }

564d4150 0000004c              VMAP {		   Vertex Map
55564d50 0002                    UVMP, 2	     type, dimension
49 6d 61 67 65 20 55 56 00 00    "Image UV"	     map name

  0000                           0
    3f000000 3f000000            1.0, 1.0
  0001                           1
    3f800000 3f800000            0.5, 0.5
  0002                           2
    3f800000 00000000            0.5, 0.0
  0003                           3
    00000000 00000000            0.0, 0.0
  0004                           4
    00000000 3f800000            0.0, 0.5
  0005                           5
    3f000000 3f000000            1.0, 1.0
                               }

564d4150 00000018              VMAP {		   Vertex Map
5049434b 0000                    PICK, 0	     type, dimension
50 69 63 6b 20 53 65 74 00 00    "Pick Set"	     map name

  0001                           1
  0002                           2
  0003                           3
  0004                           4
                               }

504f4c53 00000054              POLS {
46414345                         FACE

  0003 0001                      3, 1
    0000 0001 0002               0, 1, 2
  0003 0001                      3, 1
    0000 0002 0003               0, 2, 3
  0003 0001                      3, 1
    0000 0003 0004               0, 3, 4
  0003 0001                      3, 1
    0000 0004 0001               0, 4, 1
  0003 0001                      3, 1
    0005 0001 0004               5, 1, 4
  0003 0001                      3, 1
    0005 0004 0003               5, 4, 3
  0003 0001                      3, 1
    0005 0003 0002               5, 3, 2
  0003 0001                      3, 1
    0005 0002 0001               5, 2, 1
                               }

53555246 00000020              SURF {
42 6c 75 65 20 50 6c 61 73 74 65 72 00 00
                                 "Blue Plaster"
50 6c 61 73 74 65 72 00          "Plaster"

    434f4c52 0003                COLR {
    a0 a0 c8 00                    160, 160, 200
                                 }
                               }

53555246 00000040              SURF {
43 68 72 6f 6d 65 00 00          "Chrome"
44 65 66 61 75 6c 74 00          "Default"

    434f4c52 0003                COLR {
    c8c8dc00                       200, 200, 220
                                 }
    44494646 0004                DIFF {
    3e99999a                       0.3
                                 }
    474c4f53 0002                GLOS {
    0040                           64
                                 }
    5245464c 0004                REFL {
    3f400000                       0.75
                                 }
    53504543 0004                SPEC {
    3eb33333                       0.35
                                 }
                               }

53555246 00000068              SURF {
50 6c 61 73 74 65 72 00          "Plaster"
44 65 66 61 75 6c 74 00          "Default"

    474c4f53 0002                GLOS {
    0018
                                 }
    53504543 0004                SPEC {
    3e4ccccd
                                 }

    424c4f4b 0040                BLOK {
      41544558                     ATEX
      80 00                        128

      4e414d45 000e                NAME {
      46 72 61 63 74 61 6c 20
      4e 6f 69 73 65 00              "Fractal Noise"
                                   }
      53495a45 000c                SIZE {
      3f000000 3f000000 3f000000     0.5, 0.5, 0.5
                                   }
      54595045 0004                TYPE {
      44494646                       DIFF
                                   }
      56414c55 0004                VALU {
      3f400000                       0.75
                                   }
                                 }
                               }


Index

NOTE: The index is just plain wrong. It's written by hand so I'm not going to update it until everything else is right.