Mesh/Mesh Asset Format
Overview
This document is a specification of the mesh asset format used by Second Life. At its highest level, a mesh asset is a collection of data blocks spread across a file. The sizes, locations, and types of the data elements are described in the header at the beginning of the file. This document will describe the format of the header and each of the data block types it may reference.
Header
The header is an uncompressed, binary encoded LLSD map containing the following elements:
Versioning and Creator Information
- "version" -- integer -- A version number for the entire asset, filled in by simulator post-import.
- "creator" -- UUID -- agent id of the agent that uploaded the asset, filled in by simulator
- "date" -- LLDate (as LLSD, seconds since epoch UTC) of upload, filled in by simulator
Level of Detail
Up to four level of detail blocks may be specified. Level of detail block names are:
- "high_lod" -- Highest level of detail mesh for this asset, MUST be provided
- "medium_lod" -- Optional, medium level of detail
- "low_lod" -- Optional, low level of detail, must NOT be present if "medium_lod" is absent
- "lowest_lod" -- Optional, lowest level of detail, must NOT be present if "low_lod" is absent
Each level of detail entry must contain the following elements:
- "offset" -- integer -- the offset (in bytes) of the level of detail block in the asset starting from the end of the header
- "size" -- integer -- the size (in bytes) of the level of detail block
Physics
Each physics entry must contain a "hash" for validation purposes. The hash is filled in by the simulator at the time of upload and used for every subsequent load to verify that the asset is valid. Each of these entries must also contain an "offset" and "size" as described by the "Level of Detail" section above. There are four physics data blocks:
- "physics_mesh" -- Optional, a mesh representing the physical shape of this asset
- "physics_convex" -- Required, a single convex hull encompassing the entire mesh asset plus an (optional) set of convex hulls (known as a convex decomposition) for more detailed collisions. If the "physics_convex" data block contains such a decomposition, "physics_mesh" MUST be absent, as it will never be used.
- "physics_havok" -- Filled in by simulator at upload time, contains some cached data specific to Havok to improve load time performance on the simulator.
- "physics_cost_data" -- Data needed to determine the physics cost of this asset for any given scale -- contains a single LLMatrix3 ("mesh") in LLSD format defining mesh physics cost constants if a mesh is used.
Skin
A "skin" block may be present and must contain an "offset" and "size" as described in the Level of Detail section above. See below for details.
Mesh Level of Detail Block
Each level of detail block is a gzip'd binary encoded LLSD list of submeshes. Each submesh will map to a "face" in Second Life, and each level of detail MUST have the same number of submeshes. Each level of detail must have a lower triangle count than any higher level of detail. Each submesh contains the following fields:
- "NoGeometry" -- optional, boolean, must be true -- If present, there is no geometry for this submesh. This submesh is just a placeholder to let the simulator/viewer know that there is a texture entry for this submesh with no geometry at this LoD. No additional fields may be specified if "NoGeometry" is present.
- "Position" -- required, LLSD byte array containing 16-bit unsigned position values (6 bytes per position).
- "PositionDomain" "Min"/"Max" -- optional, LLSD vector3 pair specifying domain of position values (domain is presumed to be [-0.5, 0.5] if "PositionDomain" is not specified). Domain must be within [-0.501, 0.501].
- "Normal" -- optional, LLSD byte array containing 16-bit unsigned normal values ([-1.0, 1.0] domain, not necessarily unit normals). Must be the same length as "Position" array.
- "TexCoord0" -- optional, LLSD byte array containing 16-bit unsigned texture coordinate values (2 dimensional, 4 bytes per texture coordinate). Must have the same number of texture coordinates as there are position values.
- "TexCoord0Domain" "Min"/"Max" -- required if "TexCoord0" is present, vector2 pair denoting domain to unpack 16-bit texture coordinate values into.
- "TriangleList" -- required, LLSD byte array containing 16-bit unsigned vertex indices. Must contain at least one reference to every vertex position and must NOT contain indices larger than the number of vertex positions. No single triangle in the list may reference the same vertex twice (no degenerate triangles).
- "Weights" - required if "skin" block is present in header. LLSD byte array containing joint influences.
Vertex Weight Encoding
Each weight entry corresponds to a position in the Position array. Each entry may contain up to 4 influences. Each influence is defined as a 16-bit unsigned joint index followed by a 16-bit unsigned weight value. A joint index of “0xFF” indicates there are no more influences for this entry. Other than 0xFF, no joint index may have a value >31. If 4 influences have been read for the current entry, it is assumed there are no more influences for this entry.
For example, an entry denoting weights to joints 2 and 3 would contain the values:
0x02 0xWW 0x03 0xWW 0xFF
Where 0xWW represents some arbitrary weight value. An entry denoting weights to joints 1, 2, 3, and 5 would contain the values:
0x01 0xWW 0x02 0xWW 0x03 0xWW 0x05 0xWW
No terminating joint index is needed when 4 values are specified. The number of joint influence entries must match the number of positions from the "Position" array above.
Skin Block
Physics Mesh Block
A physics mesh block is the same as a Level of Detail block above, but with the additional constraint that it must not contain any degenerate triangles at 0.5x0.5x0.5 scale as defined by the function ll_is_degenerate in llfloatermodelpreview.cpp.