From CloudModding OoT Wiki
A diagram showing how different parts of a CMB model file are connected.
The CMB format (CTR Model Binary?) is a 3D model format used in Ocarina of Time 3D. It's also used in Majora's Mask 3D with a few differences.

Note: Nearly all this information was gathered from the source code of N3DSCmbViewer, which warns that it is "unfinished, experimental code."

CMB chunk

The CMB chunk is first chunk encountered in the file. It encompasses the entire file and contains other chunks.

Offset Type Description
0000 char[4] magic "cmb " ("CTR Model Binary")
0004 u32 FileSize
0008 u32 Version 0x6 = OoT3D
000C u32 Unused. Always 0
0010 char[16] Model Name
0020 u32 # of vertex indices (# is always in size of u16 Even when bytes)
0024 u32 SKL chunk pointer (absolute)
0028 u32 MATS chunk pointer (absolute)
002C u32 TEX chunk pointer (absolute)
0030 u32 SKLM chunk pointer (absolute)
0034 u32 LUTS chunk pointer (absolute)
0038 u32 VATR chunk pointer (absolute)
003C u32 Vertex indices' data pointer
0040 u32 Texture data pointer

SKL chunk

SKL chunk
The SKL chunk contains bones ordered in a hierarchy.
Offset Type Description
0000 char[4] magic "skl " ("Skeleton")
0004 u32 size of chunk
0008 u32 # of bones
000C u32 unknown (Values seen: 0-2 Maybe Flags?)
0010 Bone[# of bones] array of bones

Bone

Each Bone is:

Offset Type Description
0000 u8 bone ID
0001 u8 unknown
0002 s16 parent bone's ID, or -1 for no parent
0004 vector3 scale
0010 vector3 rotation
001C vector3 translation

Each bone's scale, rotation, and translation are relative to those of the parent bone. That is, to position the bones correctly, one must start with the root bone and work their way down through the child bones, adding each child bone's orientation to that of the parent bone.

QTRS chunk (Majora's Mask 3D only)

The QTRS chunk was added in CMB Version 10, and it's currently used for BoundingBox information. Also see the note under CMB chunk about Majora's Mask 3D models.

Offset Type Description
0000 char[4] magic "qtrs"
0004 u32 size of chunk (minus 4?)
0008 u32 #BoundingBox always 1
000C u32 unknown, always 0
0010 u32 unknown, always 0
0014 f32 MinX
0018 f32 MinY
001C f32 MinZ
0020 f32 MaxX
0024 f32 MaxY
0028 f32 MaxZ
002C s32 unknown, always -1
0030 s32 unknown, always -1
0034 u32 unknown, always 0

MATS chunk

MATS chunk
The MATS chunk contains materials and texture environment settings.
Offset Type Description
0000 char[4] magic "mats" ("Materials")
0004 u32 size of chunk (size not accurate probably an oversight)
0008 u32 # of materials
000C Material[# of materials] array of materials

Material

Each Material is:

Offset Type Description
0000 bool IsFragmentLightingEnabled
0001 bool IsVertexLightingEnabled
0002 bool IsHemiSphereLightingEnabled
0003 bool IsHemiSphereOcclusionEnabled
0004 bool Face Culling
0005 bool IsPolygonOffsetEnabled
0006 u16 PolygonOffset
0008 u32 TextureMappersUsed
000C u32 TextureCoordsUsed
0010 MatTexture[3] array of 3 textures
0058 TextureCoords[3] array of 3 textures
00A0 RGBA Emission Color
00A4 RGBA Ambient Color
00A8 RGBA Diffuse Color
00AC RGBA Specular0 Color
00B0 RGBA Specular1 Color
00B4 RGBA Constant0 Color
00B8 RGBA Constant1 Color
00BC RGBA Constant2 Color
00C0 RGBA Constant3 Color
00C4 RGBA Constant4 Color
00C8 RGBA Constant5 Color
00CC vector4 Buffer Color
00DC u16 Bump Texture
00DE u16 Bump Mode
00E0 u16 IsBumpRenormalize
00E2 u16 Padding
00E4 u16 Layer Config
00E6 u16 Padding
00E8 u16 Fresnel Selector
00EA bool IsClampHighLight
00EB bool IsDistribution0Enabled
00EC bool IsDistribution1Enabled
00ED bool IsGeometricFactor0Enabled
00EE bool IsGeometricFactor1Enabled
00EF bool IsReflectionEnabled
00F0 bool ReflectanceRSamplerIsAbs
00F1 byte ReflectanceRSamplerIndex
00F2 ushort ReflectanceRSamplerInput
00F4 float ReflectanceRSamplerScale
00F8 bool ReflectanceGSamplerIsAbs
00F9 byte ReflectanceGSamplerIndex
00FA ushort ReflectanceGSamplerInput
00FC float ReflectanceGSamplerScale
0100 bool ReflectanceBSamplerIsAbs
0101 byte ReflectanceBSamplerIndex
0102 ushort ReflectanceBSamplerInput
0104 float ReflectanceBSamplerScale
0108 bool Distibution0SamplerIsAbs
0109 byte Distibution0SamplerIndex
010A ushort Distibution0SamplerInput
010C float Distibution0SamplerScale
0110 bool Distibution1SamplerIsAbs
0111 byte Distibution1SamplerIndex
0112 ushort Distibution1SamplerInput
0114 float Distibution1SamplerScale
0118 bool Fresnel1SamplerIsAbs
0119 byte Fresnel1SamplerIndex
011A ushort Fresnel1SamplerInput
011C float Fresnel1SamplerScale
0120 u32 UsedTexEnvStages (Combiner Stages)
0124 u16[6] TexEnvStages Indices (-1 if unused)
0130 bool Alpha Test Enabled
0131 u8 Alpha Reference Value
0132 u16 (AlphaFunction) Alpha Function
0134 bool DepthTestEnabled
0135 bool DepthWriteEnabled
0136 u16 (DepthFunction) Depth Test Function
0138 u32 BlendMode
013C u16 (BlendingFactorSrc) Alpha Source Function
013E u16 (BlendingFactorDest) Alpha Destination Function
0140 u32 Alpha Equation
0144 u16 Color Source Function
0146 u16 Color Destination Function
0148 u32 Color Equation
0158 Vector4 Blend Color

At the end of each Material, Majora's Mask 3D models have more values:

Offset Type Description
015C bool Stencil Enabled
015D s8 Stencil Reference Value
015E u8 Buffer Mask
015F u8 Buffer
0160 StencilFunction Stencil Function
0162 u16 FailOP
0164 u16 ZFailOP
0166 u16 ZPassOP
0168 u32 Unknown (crc32?)

MatTexture

Each MatTexture is:

Offset Type Description
0000 s16 index of the Texture to use (from the TEX chunk) or -1 for none
0002 s16 Padding
0004 u16 (TextureMinFilter) texture minification filter
0006 u16 (TextureMagFilter) texture magnification filter
0008 u16 (TextureWrapMode) texture wrap mode S
000A u16 (TextureWrapMode) texture wrap mode T
000C f32 MinLODBias (Minimum Level Of Detail Bias)
0010 f32 LODBias (Level Of Detail Bias)
0014 RGBA Border Color

TextureCoords

Each TextureCoords is:

Offset Type Description
0000 u8 Matrix Mode
0001 u8 Reference Camera
0002 u8 Mapping Method
0003 u8 Coordinate Index (cmb supports 3 UV layers)
0004 Vector2 Scale
000C f32 Rotation
0010 Vector2 Translation

TextureEnvSetting

Each TextureEnvSetting is:

Offset Type Description
0000 u16 (PicaTextureEnvModeCombine) combine RGB
0002 u16 (PicaTextureEnvModeCombine) combine alpha
0004 u16[2] unknown
0008 u16[2] unknown GL constant
000C u16[3] (PicaTextureEnvModeSource) source RGB
0012 u16[3] (PicaTextureEnvModeOperandRgb) operand RGB
0018 u16[3] (PicaTextureEnvModeSource) source alpha
001E u16[3] (PicaTextureEnvModeOperandAlpha) operand alpha
0024 u16[2] unknown

TEX chunk

TEX chunk
The TEX chunk contains textures.
Offset Type Description
0000 char[4] magic "tex " ("Textures?")
0004 u32 size of chunk
0008 u32 # of textures
000C Texture[# of textures] array of textures

Texture

Each Texture is:

Offset Type Description
0000 u32 Length of texture data in bytes
0004 u16 Mipmap Count
0006 u8 IsETC1 (if TextureFormat is ETC1RGB8NativeDMP or ETC1AlphaRGB8A4NativeDMP)
0007 u8 IsCubemap (see CubemapData)
0008 u16 Width
000A u16 Height
000C u16 (PicaTextureFormat) Texture color format
000E u16 (PicaDataType) Texture data type (If 0, just use the texture color format by itself. Also see PicaTextureFormat)
0010 u32 Texture data offset, relative to the Texture data pointer from the CMB chunk
0014 char[16] Texture name

CubemapData

Note: Cubemap entries come after all texture entries

Each Cubemap entry is:

Offset Type Description Coordinate
0000 u32 Right DataOffset (+X)
0004 u32 Left DataOffset (-X)
0008 u32 Bottom DataOffset (-Y)
000C u32 Top DataOffset (+Y)
0010 u32 Front DataOffset (-Z)
0014 u32 Back DataOffset (+Z)

SKLM chunk

SKLM chunk
The SKLM chunk contains mesh-related data.
Offset Type Description
0000 char[4] magic "sklm" ("Skeletal Meshes?")
0004 u32 size of chunk
0008 u32 MSHS chunk pointer, relative to the beginning of the SKLM chunk
000C u32 SHP chunk pointer, relative to the beginning of the SKLM chunk
After that, the SKLM chunk contains the MSHS chunk and SHP chunk.

MSHS chunk

MSHS chunk
The MSHS chunk contains meshes, which are a shape combined with a material.
Offset Type Description
0000 char[4] magic "mshs" ("Meshes?")
0004 u32 size of chunk
0008 u32 # of meshes
000C u16 unknown Count
000E u16 ID Count (used for visibility animations)
0010 Mesh[# of meshes] array of meshes

Mesh

Each Mesh is:

Offset Type Description
0000 u16 index of the SEPD chunk to use (from the SHP chunk)
0002 u8 index of the Material to use (from the MATS chunk)
0003 u8 ID

At the end of each Mesh, Majora's Mask 3D models also have:

Offset Type Description
0004 u32 unknown
0008 u32 unknown

SHP chunk

SHP chunk
The SHP chunk is a collection of multiple shapes, each of which can be used by a mesh.
Offset Type Description
0000 char[4] magic "shp " ("Shapes?")
0004 u32 size of chunk
0008 u32 # of SEPD chunks
000C u32 flags (only ever used for link in OoT3D. set to 0x58)
0010 u16[# of SEPD chunks] SEPD chunk pointers, relative to the beginning of the SHP chunk. Values are aligned on a 4-byte boundary.

After that, the SHP chunk contains the SEPD chunks.

SEPD chunk

SEPD chunk
Each SEPD chunk is a shape made of multiple primitives and the lists of vertex attributes used by those primitives.
Offset Type Description
0000 char[4] magic "sepd"
0004 u32 size of chunk
0008 u16 # of PRMS chunks
000A u16 Bit Flags
HasPosition : 00000001
HasNormals  : 00000010
MM3D or later HasTangents was added
HasTangents : 00000100
HasColors   : 00000100
HasUV0      : 00001000
HasUV1      : 00010000
HasUV2      : 00100000
HasIndices  : 01000000
HasWeights  : 10000000 
000C Vector3 Mesh Center
0018 Vector3 Position Offset
0024 VertexList Positions
0040 VertexList Normals
Tangents added in MM3D
005C VertexList Vertex colors
0078 VertexList TextureCoords0
0094 VertexList TextureCoords1
00B0 VertexList TextureCoords2
00CC VertexList BoneIndices (Only used on rigid and smooth skinning)
00E8 VertexList BoneWeights (Only used for smooth skinning)
0104 u16 Bone dimension
0106 u16 (flags) flags for automatic generation of vertex data. If a bit's value is 1, the game will automatically generate:
Bit Vertex data to automatically generate
0x01 Position
0x02 Normals
0x04 vertex colors
0x08 TextureCoords Layer0
0x10 TextureCoords Layer1
0x20 TextureCoords Layer2
0x40 Bone Indices
0x80 Bone Weights

If a vertex data type is automatically generated, then that data is not read from a VertexList; the VertexList and its values are completely ignored, even though it may contain values.

0108 u16[# of PRMS chunks] array of PRMS chunks offsets, relative to the beginning of the SEPD chunk. The values are aligned on a 4-byte boundary.

* Majora's Mask 3D models have another VertexList of unknown values at offset 005C, pushing down the vertex colors and everything after it by 0x1C bytes.

After that, the SEPD chunk contains the PRMS chunks.

VertexList
Offset Type Description
0000 u32 offset from which to start reading list elements, relative to offset to data in the matching VertexListData.
(For example, if this VertexList is for normals and you want to read the normals: the beginning of the VATR chunk + offset to data in the normals' VertexListData + this offset = the absolute offset from which to start reading normals.)
0004 f32 scale. All list elements are multiplied by this value. For example, bone weights range from 0 to 100, and multiplying by scale will result in a value between 0.0 and 1.0.
0008 u16 (PicaDataType) data type of the list elements
000A u16 Mode (Array or Constant)
000C Vector4 Constant
PRMS chunk
PRMS chunk
Each PRMS chunk contains a PRM chunk (primitive) and binds it to one or more bones.
Offset Type Description
0000 char[4] magic "prms" ("Primitives?" "Primitive Skinned?")
0004 u32 size of chunk
0008 u32 Prm Count
000C u16 skinning mode, with regard to Bones from the SKL chunk:
Skinning mode Description
0 All vertices in the PRMS chunk will be bound to a single bone, the first (and only) bone index in the array of bone indices below.
  • In addition, all vertices in the PRMS chunk must be repositioned, or else model parts like faces and held objects will appear by the character's feet. To do this, transform them by the bone's matrix (i.e. the orientation of the bone after taking the parent bones into account).
1 The vertices in the PRMS chunk will be weighed between multiple bones (see Notes on Skinning).
  • In addition, all vertices in the PRMS chunk must be repositioned like in skinning mode 0.
2 The vertices in the PRMS chunk will be weighed between multiple bones (see Notes on Skinning).
000E u16 # of bone indices
0010 u32 bone indices offset, relative to the beginning of the PRMS chunk
0014 u32 PRM chunk offset, relative to the beginning of the PRMS chunk
0018 u16[# bone indices] array of bone indices. Values are aligned on a 4 byte boundary.

After that, the PRMS chunk contains a PRM chunk.

PRM chunk
PRM chunk
Each PRM chunk contains a single primitive, in this case a set of triangles created from a list of vertex indices.
Offset Type Description
0000 char[4] magic "prm " ("Primitive?")
0004 u32 size of chunk
0008 u32 IsVisible
000C u32 Primitive Mode
0010 u16 (PicaDataType) data type
0012 u16 unknown
0014 u16 # of vertex indices to read
0016 u16 The first vertex index to read, relative to the CMB chunk's Vertex indices' data pointer.
(For example, a value of 0 starts right at that pointer. A value of 1 starts starts 2 bytes later if data type is s16, or 4 bytes later if data type is u32.)

The vertex indices read this way refer to the vertices in each VertexList of the SEPD chunk. Every three vertex indices creates a single triangle.

For example: Consider the SEPD chunk containing the PRMS chunk that contains this PRM chunk. If the vertices indices read in this PRM chunk are [0,1,2], those numbers refer to the first 3 vertex positions, normals, texcoords, etc. in each of the VertexLists of that SEPD chunk.
Notes on Skinning

Under normal circumstances, each vertex index uses to values in the SEPD chunk's VertexLists for vertex positions, normals, texcoords, and so on. If the PRMS chunk's skinning mode is 1 or 2, then it will also use VertexLists of bone index lookups and bone weights.

A bone index lookup is an index that points to a bone index in the PRMS chunk's array of bone indices, each of which in turn points to a Bone in the SKL chunk.
(PRM vertex index → SEPD bone index lookups → PRMS bone indices → SKL bone ID)

The SEPD chunk's bones per vertex determines how many bone index lookups and bone weights each vertex index points to. For example, if bones per vertex is 3, then every vertex index points to the next 3 values in the VertexLists of bone index lookups and bone weights.

A special case: when bones per vertex is 1, each vertex is weighed between two bone index lookups. However, in this case each vertex only uses one bone index lookup from the list, and it adds 1 to its value to obtain the other bone index lookup (wrapping back around to 0 if it would go past the end of the array of bone indices). Also, in this case the list of bone weights is ignored entirely, and the game uses the values [1, 0] (weighted completely to the first bone in each pair).

An even more special case: when the SEPD chunk's flags for automatic generation of vertex data has bit 0x40 set, the game automatically generates bone index lookups instead of using the values in the VertexList. The same goes for 0x80 and bone weights.

  • Bone index lookups start at 0 for each vertex index and increase by 1 for the rest of the bones. For example, if the SEPD chunk's bones per vertex is 4, the bone index lookups are [0, 1, 2, 3] for each vertex index.
  • Bones weights are probably weighted evenly between each bone (i.e. 1.0 / bones per vertex), but this isn't completely certain.

LUTS chunk

LookUpTables chunk

Offset Type Description
0000 char[4] magic "luts"
0004 u32 size of chunk
0008 u32 #LutSet
000C u32 unknown, always 0?

VATR chunk

VATR chunk
The VATR chunk contains the raw data for vertices.
Offset Type Description
0000 char[4] magic "vatr" ("Vertex Attributes?")
0004 u32 size of chunk
0008 u32 "max vertex index or something"
000C VertexListData Positions' data
0014 VertexListData Normals' data
001C VertexListData Vertex Colors' data
0024 VertexListData Texture Coordinates0' data
002C VertexListData Texture Coordinates1' data
0034 VertexListData Texture Coordinates2' data
003C VertexListData Bone Indices' data
0044 VertexListData Bone Weights' data

* Majora's Mask 3D models added Tangents, pushing down the vertex colors and everything after it by 8 bytes.

Constants

AlphaFunction and StencilFunction

AlphaFunction and StencilFunction

Value Description
0x0200 Never
0x0201 Less
0x0202 Equal
0x0203 Less than or equal
0x0204 Greater
0x0205 Not equal
0x0206 Greater than or equal
0x0207 Always

BlendingFactorSrc

BlendingFactorSrc

Value Description
0 Zero
0x0302 SrcAlpha
0x0303 OneMinusSrcAlpha
0x0304 DstAlpha
0x0305 OneMinusDstAlpha
0x0306 DstColor
0x0307 OneMinusDstColor
0x0308 SrcAlphaSaturate
0x8001 ConstantColor
0x8002 OneMinusConstantColor
0x8003 ConstantAlpha
0x8003 ConstantAlphaExt
0x8004 OneMinusConstantAlpha
0x8589 Src1Alpha
0x88F9 Src1Color
0x88FA OneMinusSrc1Color
0x88FB OneMinusSrc1Alpha
1 One

BlendingFactorDest

BlendingFactorDest

Value Description
0 Zero
0x0300 SourceColor
0x0301 OneMinusSourceColor
0x0302 SourceAlpha
0x0303 OneMinusSourceAlpha
0x0304 DestinationAlpha
0x0305 OneMinusDestinationAlpha
0x8001 ConstantColor
0x8002 OneMinusConstantColor
0x8003 ConstantAlpha
0x8004 OneMinusConstantAlpha
1 One

TextureMinFilter

TextureMinFilter

Value Description
0x2600 Nearest
0x2601 Linear
0x2700 NearestMipmapNearest
0x2701 LinearMipmapNearest
0x2702 NearestMipmapLinear
0x2703 LinearMipmapLinear

TextureMagFilter

TextureMagFilter

Value Description
0x2600 Nearest
0x2601 Linear

TextureWrapMode

TextureWrapMode

Value Description
0x2900 Clamp
0x2901 Repeat
0x812D ClampToBorder
0x812F ClampToEdge
0x8370 MirroredRepeat

PicaTextureEnvModeCombine

PicaTextureEnvModeCombine can be:

Value Description
0x00 Replace
0x01 Modulate
0x02 Add
0x03 AddSigned
0x04 Interpolate
0x05 Subtract
0x06 Dot3Rgb
0x07 Dot3Rgba
0x08 MultAdd (multiply add? same as 0x6401 in OpenGL)
0x09 AddMult (add multiply? same as 0x6402 in OpenGL)

PicaTextureEnvModeSource

PicaTextureEnvModeSource can be:

Value Description
0x00 PrimaryColor
0x01 FragmentPrimaryColorDMP (same as 0x6210 in OpenGL)
0x02 FragmentSecondaryColorDMP (same as 0x6211 in OpenGL)
0x03 Texture0
0x04 Texture1
0x05 Texture2
0x06 Texture3
0x07 PreviousBufferDMP (same as 0x8579 in OpenGL)
0x08 Constant
0x09 Previous

PicaTextureEnvModeOperandRgb

PicaTextureEnvModeOperandRgb can be:

Value Description
0x00 SrcColor
0x01 OneMinusSrcColor
0x02 SrcAlpha
0x03 OneMinusSrcAlpha
0x04 SrcRDMP (same as 0x8580 in OpenGL)
0x05 OneMinusSrcRDMP (same as 0x8583 in OpenGL)
0x06 SrcGDMP (same as 0x8581 in OpenGL)
0x07 OneMinusSrcGDMP (same as 0x8584 in OpenGL)
0x08 SrcBDMP (same as 0x8582 in OpenGL)
0x09 OneMinusSrcBDMP (same as 0x8585 in OpenGL)

PicaTextureEnvModeOperandAlpha

PicaTextureEnvModeOperandAlpha can be:

Value Description
0x00 SourceAlpha
0x01 OneMinusSourceAlpha
0x02 SrcRDMP (same as 0x8580 in OpenGL)
0x03 OneMinusSrcRDMP (same as 0x8583 in OpenGL)
0x04 SrcGDMP (same as 0x8581 in OpenGL)
0x05 OneMinusSrcGDMP (same as 0x8584 in OpenGL)
0x06 SrcBDMP (same as 0x8582 in OpenGL)
0x07 OneMinusSrcBDMP (same as 0x8585 in OpenGL)

PicaTextureFormat

PicaTextureFormat can be:

Value Description
0x6752 RGBANativeDMP
0x6754 RGBNativeDMP
0x6756 AlphaNativeDMP
0x6757 LuminanceNativeDMP
0x6758 LuminanceAlphaNativeDMP
0x675A ETC1RGB8NativeDMP
0x675B ETC1AlphaRGB8A4NativeDMP

PicaTextureFormat interacts with PicaDataType as follows:

PicaTextureFormat PicaDataType Resulting texture data format
ETC1RGB8NativeDMP 0 ETC1
ETC1AlphaRGB8A4NativeDMP 0 ETC1A4
RGBANativeDMP u8 (unsigned byte) RGBA8
RGBNativeDMP u8 (unsigned byte) RGB8
RGBANativeDMP UnsignedShort4444 RGBA4
RGBANativeDMP UnsignedShort5551 RGBA5551
RGBNativeDMP UnsignedShort565 RGB565
LuminanceAlphaNativeDMP UnsignedByte44DMP LA4
LuminanceAlphaNativeDMP u8 (unsigned byte) LA8
AlphaNativeDMP u8 (unsigned byte) A8
LuminanceNativeDMP u8 (unsigned byte) L8
LuminanceNativeDMP Unsigned4BitsDMP L4

PicaDataType

PicaDataType can be:

Value Description
0x1400 s8 (byte)
0x1401 u8 (unsigned byte)
0x1402 s16 (short)
0x1403 u16 unsigned short
0x1404 s32 (int)
0x1405 u32 (unsigned int)
0x1406 f32 (float)
0x6760 UnsignedByte44DMP
0x6761 Unsigned4BitsDMP
0x8033 UnsignedShort4444
0x8034 UnsignedShort5551
0x8363 UnsignedShort565

RGBA

Each RGBA is:

Value Type
R u8
G u8
B u8
A u8