FMDL (File Format)
The FMDL (caFe MoDeL) model format is a format for models which appears as a subfile of a BFRES file in the 0th file group. Typically a BFRES file has one FMDL but some have none and some have more than one.
- 1 Format
- 1.1 Header (FMDL)
- 1.2 FVTX
- 1.3 FMAT
- 1.4 FSKL
- 1.5 FSHP
An FMDL file begins with an FMDL header. This is then followed by a number of sections pointed to by the header, many of which can occur multiple times. The purpose of these sections is described in the table below. Unless otherwise noted, all offsets in BFRES files are relative to themselves, not the beginning of the file which is more common in other formats.
|FVTX||Describes an array of array of vertices which can have a number of attributes including position, normal, colour and texture coordinates.|
|FMAT||Describes the properties of a surface necessary to draw it including texture information.|
|FSKL||Describes a skeleton for the model which may be used in animations.|
|FSHP||Selects triples of vertices from one FVTX section to draw triangles between. Also specifies the FMAT material and the FSKL attachment of the triangles.|
Every FMDL begins with an 0x30 byte FMDL header.
|0x00||4||Char||"FMDL" file identifier, ASCII string.|
|0x04||4||Int32||File name offset (without file extension).|
|0x08||4||Int32||File path offset, the path of the file this data was originally created from. Stripped in Mario Kart 8 files, always pointing to an empty string at the end of the BFRES string table.|
|0x0C||4||Int32||FSKL offset. Offset to the FSKL Header.|
|0x10||4||Int32||FVTX array offset. Offset to the first element in an array of FVTX Headers.|
|0x14||4||Int32||FSHP index group offset. Offset to an index group which contains named pointers to FSHP Headers.|
|0x18||4||Int32||FMAT index group offset. Offset to an index group which contains named pointers to FMAT Headers.|
|0x1C||4||Int32||User Data index group offset. It is only used in a handful of Mario Kart 8 models to set the value of "ParticleLimit".|
|0x20||2||UInt16||FVTX count: number of FVTX sections in the FVTX array.|
|0x22||2||UInt16||FSHP count: number of FSHP sections in the the FSHP index group.|
|0x24||2||UInt16||FMAT count: number of FMAT sections in the the FMAT index group.|
|0x26||2||UInt16||User Data entry count.|
|0x28||4||UInt32||Total number of vertices to process.|
|0x2C||4||UInt32||User pointer, can be set at runtime, 0 in files.|
|0x30||End of FMDL header|
The model may have one or more FVTX (caFe VerTeX) sections which describe the vertices for one polygon (e.g. the road of a track). The section describes a series of buffers and attributes. Buffers are arrays of arbitrary elements which contain the actual values of the vertices and are passed directly to the graphics card. Attributes are properties of vertices (e.g. position, texture coordinate, vertex colours) and they describe the format and layout of the elements in the buffers.
Each FVTX section has a 0x20 byte header. These headers are stored sequentially in an array at the offset given in the FMDL header. The length of this array is also given in that header.
|0x00||4||Char||"FVTX" section identifier, ASCII string.|
|0x04||1||Byte||Attribute count: number of different attributes (position, normal, colour, etc) in the attribute array.|
|0x05||1||Byte||Buffer count: number of attribute buffers in the buffer array.|
|0x06||2||UInt16||Section index: index into FVTX array of this entry.|
|0x08||4||UInt32||Number of vertices. This is also the number of elements in each buffer.|
|0x0C||1||Byte|| Vertex skin count, the number of bones influencing a vertex. Depending on the value, vertex positions are stored in different coordinate systems:
|0x10||4||Int32||Attribute array offset. Offset to the first element in the Attribute array.|
|0x14||4||Int32||Attribute index group offset. Named pointers to the members of the Attribute array to allow named lookups.|
|0x18||4||Int32||Buffer array offset. Offset to the first element in the Buffer array.|
|0x1C||4||UInt32||User pointer, can be set at runtime, 0 in files.|
|0x20||End of FVTX header|
The attributes of each FVTX section are stored as a simple repeating 0xc byte structure. These are stored in an array with location and length specified by the FVTX header. They are also referenced by the attribute index group, presumably to allow both index and name based lookup of attributes.
|0x00||4||Int32||Attribute name offset (s. below).|
|0x04||1||Byte||Buffer index in the FVTX Buffer array of the buffer storing the data of this attribute (s. below).|
|0x05||2||UInt16||Buffer offset of the attribute in each element in the buffer (in bytes).|
|0x08||4||UInt32||Format of the attribute's data in the buffer, maps to GX2AttribFormat (s. below).|
|0x0C||End of attribute|
Based on some of the shader code in /vol/content/mapobj/PackunMusic/PackunMusic.bfres the following naming convention seems to be used for attributes.
|Attribute Name||Friendly Name||Description|
|_p0||position0||The position of the vertex.|
|_n0||normal0||The normal of the vertex used in lighting calculations.|
|_t0||tangent0||The tangent of the vertex used in advanced lighting calculations.|
|_b0||binormal0||The binormal of the vertex used in advanced lighting calculations.|
|_w0||blendweight0||Influence amount of the smooth skinning matrix at the index given in blendindex0.|
|_i0||blendindex0||Index of influencing smooth skinning matrix.|
|_u0||uv0||Texture coordinates used for texture mapping.|
|_c0||color0||Vertex colours used for simple shadow mapping.|
Original files typically store all attributes into one buffer or each attribute into a separate buffer. Rarely more than 1 attribute is stored in one and remaining attributes in another buffer. The condition determining which way is chosen seems arbitrary and does not follow specific rules.
The following formats are available in the GX2AttribFormat enum:
|0x0000||unorm_8||One u8||0f||1f||Represents one u8 that is converted to one float.|
|0x0004||unorm_8_8||Two u8s||0f||1f||Represents two u8 that is converted to two floats.|
|0x0007||unorm_16_16||Two u16s||0f||1f||Represents two u16 that is converted to two floats.|
|0x000A||unorm_8_8_8_8||Four u8||0f||1f||Represents four u8 that is converted to four floats.|
|0x0100||uint_8||One u8||0x00||0xFF||Represents one u8 that is converted to one u32.|
|0x0104||uint_8_8||Two u8||0x00||0xFF||Represents two u8 that is converted to two u32.|
|0x010A||uint_8_8_8_8||Four u8||0x00||0xFF||Represents four u8 that is converted to four u32.|
|0x0200||snorm_8||One s8||-1f||1f||Represents one s8 that is converted to one float.|
|0x0204||snorm_8_8||Two s8||-1f||1f||Represents two s8 that is converted to two floats.|
|0x0207||snorm_16_16||Two s16||-1f||1f||Represents two s16 that is converted to two floats.|
|0x020A||snorm_8_8_8_8||Four s8||-1f||1f||Represents four s8 that is converted to four floats.|
|0x020B||snorm_10_10_10_2||Three s10||-1f||1f||Represents three s10 that is converted to three floats. The top two bits are always 0b01.|
|0x0300||sint_8||One s8||—||—||Represents one s8.|
|0x0304||sint_8_8||Two s8||—||—||Represents two s8.|
|0x030A||sint_8_8_8_8||Four s8||—||—||Represents four s8.|
|0x0806||float_32||One float||—||—||Represents one 32 bit floating point number.|
|0x0808||float_16_16||Two halfs||—||—||Represents two 16 bit floating point numbers that is converted to two floats.|
|0x080D||float_32_32||Two floats||—||—||Represents two 32 bit floating point numbers.|
|0x080F||float_16_16_16_16||Four halfs||—||—||Represents four 16 bit floating point numbers that is converted to four floats.|
|0x0811||float_32_32_32||Three floats||—||—||Represents three 32 bit floating point numbers.|
|0x0813||float_32_32_32_32||Four floats||—||—||Represents four 32 bit floating point numbers.|
The buffers of each FVTX section are stored as a repeating 0x18 byte header structure which references the actual data stored later in the BFRES file. The headers are stored in an array with location and length specified by the FVTX header.
|0x00||4||UInt32||Data pointer filled at runtime, always 0 in files.|
|0x04||4||UInt32||Size of the buffer in bytes.|
|0x08||4||UInt32||Buffer handle, filled at runtime, always 0 in files.|
|0x0C||2||UInt16||Stride, the size of each element in the buffer (always 0 for index buffers).|
|0x0E||2||UInt16||Buffering count, always 1. Multiplicator for the number of bytes reserved as buffer data at runtime.|
|0x10||4||UInt32||Context pointer filled at runtime as a pointer to GX2StreamOutContext, always 0 in files.|
|0x18||End of buffer|
The model may have one or more FMAT (caFe MATerial) sections which describe surface properties of a polygon such as textures. Every polygon is rendered using a vertex shader and a fragment shader. A geometry shader is optional. These are pieces of code which run on the GPU. Like any code, these have parameters which is principally what the FMAT section controls. There are many different ways for the FMAT section to set variables in the shader code. All shader parameters are either uniforms or attributes. Attribute parameters vary per vertex or pixel, whereas uniform parameters are global. The FMAT must specify values for all uniform parameters, and specifies a mapping between vertex attributes in the corresponding FVTX sections and attribute parameters for both the fragment and vertex shader. In Mario Kart 8 the shader file is called Turbo_UBER. The name is the same for most files but the rendering code varies. All shaders are generic and has many parameters to configure. A GLSL shader for a shader file is available in /vol/content/mapobj/PackunMusic/PackunMusic.bfres.
Every FMAT begins with an 0x4C byte header structure. This references the other structures documented here to describe the material.
|0x00||4||Char||"FMAT" section identifier, ASCII string.|
|0x04||4||Int32||Material name offset.|
|0x08||4||UInt32||Material flags. Only bit 0 has a meaning, controlling the visibility of the material (visible if set).|
|0x0C||2||UInt16||Section index of this material.|
|0x0E||2||UInt16||Render info parameter count. Number of elements in the Render Info Parameter index group.|
|0x10||1||Byte||Texture Reference count. Number of elements in Texture Reference array.|
|0x11||1||Byte||Texture Sampler count. Number of elements in the Texture Sampler array. Always equal to the number of elements in the Texture Selector array.|
|0x12||2||UInt16||Material Parameter count. Number of elements in the Material Parameter array.|
|0x14||2||UInt16||Volatile Parameter count. Number of parameters handled as volatile, unknown purpose.|
|0x16||2||UInt16||Material Parameter data length. The size of the Material Parameter Data section in bytes.|
|0x18||2||UInt16||Raw Parameter data length, unknown purpose.|
|0x1A||2||UInt16||User Data entry count. User data in FMAT sections is apparently used to assign values to a shadow variable in the shader code. Shadow variables are always uniform variables.|
|0x1C||4||Int32||Render Info Parameter index group offset. Offset to the index group defining render info parameters.|
|0x20||4||Int32||Render State offset. Offset to the render state structure.|
|0x24||4||Int32||Shader Assign offset. Offset to the shader assign structure.|
|0x28||4||Int32||Texture Reference array offset. Each element points to FTEX file names and FTEX headers.|
|0x2C||4||Int32||Texture Sampler offset. Offset to the first element in the Texture Sampler array.|
|0x30||4||Int32||Texture Sampler index group offset. Offset to an index group which references the Texture Sampler array, to allow named value lookups.|
|0x34||4||Int32||Material Parameter array offset. Offset to the first element in the Material Parameter array.|
|0x38||4||Int32||Material Parameter index group offset. Offset to an index group which references the Material Parameter array, to allow named value lookups.|
|0x3C||4||Int32||Material Parameter data offset. Offset to the beginning of the values for Material Parameters. The Material Parameter array references this data.|
|0x40||4||Int32||User Data index group offset.|
|0x44||4||Int32||Volatile Flags data offset. Points to an array of Ceil((Material Parameter count) / 8) bytes, representing bits determining if a parameter is volatile. Unknown purpose.|
|0x48||4||Int32||User pointer, can be set at runtime, 0 in files.|
|0x4C||End of FMAT Header|
Render Info Parameter
A Render Info Parameter is a repeating structure of at least 0x08 bytes, each of which describes an array of values to assign to a render info variable in the shader code. Render info variables are always uniform variables and are used to set how the shader should render the graphics. The Render Info Parameter structures are referenced by the Render Info Parameter index group in the corresponding FMAT Header.
|0x00||2||UInt16||Array length, number of elements in the array. Always 0 or 1 in Mario Kart 8 files.|
|0x02||1||Byte|| Type of each array element.
|0x04||4||Int32||Variable name offset.|
|Varies||End of Render Info Parameter|
A Texture Sampler is a repeating 0x18 byte structure each of which is used to assign a texture to the shader. The length and position of the Texture Sampler array is specified by the corresponding FMAT Header.
|0x00||4||UInt32|| First value of GX2Sampler structure. Bits packed as xxxJJJxx IIHHHGGF FxEExDDC CCBBBAAA.
|0x04||4||UInt32|| Second value of GX2Sampler structure. Bits packed as CCCCCCCC CCCCBBBB BBBBBBAA AAAAAAAA.
10-bit values are stored unsigned. To get a float value, divide it by 64. 12-bit values are stored signed. To get the float value, divide the signed value by 64. 10-bit values have a range between 0 – 32 and 12-bit values have a range between -32 – 31.984375.
|0x08||4||UInt32|| Third value of GX2Sampler structure. Bits packed as xAxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx.
|0x0C||4||UInt32||Handle of the sampler, set at runtime.|
|0x10||4||Int32||Attribute name offset.|
|0x14||1||Byte||Index of this element.|
|0x18||End of Texture Sampler|
Based on the some of the shader code in /vol/content/mapobj/PackunMusic/PackunMusic.bfres the following naming convention seems to be used for texture attributes.
|Attribute Name||Friendly Name||Description|
|_a0||albedo0||Ordinary colour textures for surface albedo.|
|_n0||normal0||Normal map texture for altering surface normals.|
|_s0||specular0||Specular highlight texture.|
|_e0||emission0||Emissive lighting texture.|
A Material Parameter is a repeating 0x14 byte structure each of which describes the value to assign to a uniform variable in the shader code. The length and position of the Material Parameter array is controlled by the corresponding FMAT Header.
|0x00||1||Byte||Type of the variable (s. below).|
|0x01||1||Byte||Size of the value in bytes.|
|0x02||2||UInt16||Offset relative to the start of the Material Parameter Data section to the value.|
|0x04||4||Int32||Uniform variable offset, set at runtime, always -1 in files.|
|if BFRES version >= 22.214.171.124|
|0x08||4||UInt32||Conversion callback pointer, set at runtime, always 0 in files.|
|0x0C||2||UInt16||Parameter index into the Material Parameter array.|
|0x0E||2||UInt16||Same value as Parameter index again.|
|0x10||4||Int32||Variable name offset.|
|if BFRES version = 3.3.X.X|
|0x08||4||UInt32||Conversion callback pointer, set at runtime, always 0 in files.|
|0x0C||2||UInt16||Parameter index into the Material Parameter array.|
|0x0E||2||UInt16||Same value as Parameter index again.|
|0x14||4||Int32||Variable name offset.|
|if BFRES version < 126.96.36.199|
|0x08||4||Int32||Variable name offset.|
The Type field can be one of the following:
|0||4||1 boolean value.|
|1||8||2-component boolean vector.|
|2||12||3-component boolean vector.|
|3||16||4-component boolean vector.|
|4||4||1 signed integer value.|
|5||8||2-component signed integer vector.|
|6||12||3-component signed integer vector.|
|7||16||4-component signed integer vector.|
|8||4||1 unsigned integer value.|
|9||8||2-component unsigned integer vector.|
|10||12||3-component unsigned integer vector.|
|11||16||4-component unsigned integer vector.|
|12||4||1 floating point value.|
|13||8||2-component floating point vector.|
|14||12||3-component floating point vector.|
|15||16||4-component floating point vector.|
|17||16||2×2 floating point matrix.|
|18||24||2×3 floating point matrix.|
|19||32||2×4 floating point matrix.|
|21||24||3×2 floating point matrix.|
|22||36||3×3 floating point matrix.|
|23||48||3×4 floating point matrix.|
|25||32||4×2 floating point matrix.|
|26||48||4×3 floating point matrix.|
|27||64||4×4 floating point matrix.|
|28||20|| 2D SRT data.
|29||36|| 3D SRT data.
|30||24|| Texture SRT data.
|31||28|| Texture SRT data which is then multiplied by a 3x4 matrix referenced by the matrix pointer. The structure is the same as above, but with a field added to store the pointer to the matrix in at runtime:
Matrices are encoded down columns then along rows, so a 2×3 identity matrix would be encoded 1, 0, 0, 1, 0, 0.
A Render State structure is a 0x30 byte structure controlling if and how polygons are drawn. The structure is referenced by the corresponding FMAT Header.
|0x00||4||UInt32|| Flags. Controls how polygons are affecting the depth buffer and how they are blended / composed. A mode and blend value have to be combined to form valid flags.
|0x04||4||UInt32|| Polygon control, maps to GX2PolygonControlReg, a bitset packed as xxxxxxxx xxxxxxxx xxIHGFFF EEEDDCBA. Beyond other features, it most prominently controls culling and cull order of polygons.
|0x08||4||UInt32|| Depth control, maps to GX2DepthStencilControlReg, a bitset packed as MMMLLLKK KJJJIIIH HHGGGFFF EDDDxCBA. Controls depth and stencil buffer value comparison and action before writing new data to buffers.
|0x0C||8||UInt32 / Single|| Alpha test, maps to GX2AlphaTestReg, a structure of an unsigned integer and a floating point value. Controls how alpha colors are written to buffers. The unsigned integer is a bitset packed as xxxxxxxx xxxxxxxx xxxxxxxx xxxxBAAA.
Floating point reference value always less than 1.0f in Mario Kart 8 files.
|0x14||4||UInt32|| Color control, maps to GX2ColorControlReg, a bitset packed as xxxxxxxx DDDDDDDD CCCCCCCC xBBBxxxA. Controls how colors are written to buffers.
Defaults to Copy operation and nothing else enabled. Some files set a bitmask of 00000001.
|0x18||8||UInt32|| Blend control, maps to GX2BlendControlReg, a structure of two unsigned integers. Controls how and to which target blending is performed. The first unsigned integer describes the target index (always 0 in Mario Kart 8 files), the second is a bitset packed as xxGFFFFF EEEDDDDD xxxCCCCC BBBAAAAA.
Blend value always 0x20010101, 0x20010104, 0x20010501 or 0x20010504 in Mario Kart 8 files.
|0x20||16||Single|| Blend color, maps to GX2BlendConstantColorReg. Controls the blend color as 4 RGBA floating point values.
Defaults to (0f, 0f, 0f, 0f).
|0x30||End of Render State|
A Shader Assign structure is a 0x1C byte structure which describe the shader to be used by a material. A Shader Assign structure is referenced by the corresponding FMAT Header.
|0x00||4||Int32||Shader archive name offset.|
|0x04||4||Int32||Shading model name offset.|
|0x08||4||UInt32||Revision. Apparently unused, always 0 or 1.|
|0x0C||1||Byte||Vertex Shader Input count. Number of elements in the Vertex Shader Input index group.|
|0x0D||1||Byte||Fragment Shader Input count. Number of elements in the Fragment Shader Input index group.|
|0x0E||2||UInt16||Parameter count. Number of elements in the Parameter index group.|
|0x10||4||Int32||Vertex Shader Input index group offset. Offset to the index group which forms a mapping between strings, mapping an FVTX attribute to a vertex shader variable. Normally the names are always the same in Mario Kart 8, so this mapping is just ["_p0": "_p0", "_n0": "_n0", ...]?|
|0x14||4||Int32||Fragment Shader Input index group offset. Offset to the index group which forms a mapping between strings, mapping an FVTX attribute to a fragment shader variable. Normally the names are always the same in Mario Kart 8, so this mapping is just ["_p0": "_p0", "_n0": "_n0", ...]?|
|0x18||4||Int32||Parameter index group offset. Offset to the index group which forms a mapping between strings, mapping a uniform shader variable to a value. The values are always strings, even for numeric parameters. The values are used to specify the shader program used for rendering.|
|0x1C||End of Shader Assign|
Each model has one FSKL (caFe SKeLeton) section which describes one or more bones. The bones form a skeleton and give a transformation to apply to any attached polygon. Every FSHP polygon is attached to at least one bone. The FSKL format is somewhat different in BFRES files with values other than 0x03040004 after the FRES identifier, which may indicate an alternative version of the format. These are rare in Mario Kart 8 and not documented here.
The FSKL section always starts with an 0x24 byte header. The location of this header is given by the offset in the FMDL header.
|0x00||4||Char||"FSKL" section identifier, ASCII string.|
|0x04||4||UInt32|| Flags. Controls how scaling and rotation is performed. Encoded as xxxxxxxx xxxxxxxx xxxRxxSS xxxxxxxx bits.
Always 0x00001100 (standard scaling & euler XYZ rotation) or 0x00001200 (Maya scaling & euler XYZ rotation) in Mario Kart 8 files.
|0x08||2||UInt16||Bone array count. Number of elements in the Bone array.|
|0x0A||2||UInt16||Smooth Index array count. Number of elements in the Smooth Matrix array for smooth skinning (shape vertices are influenced by multiple bones).|
|0x0C||2||UInt16||Rigid Index array count. Number of elements in the Rigid Matrix array at the end of the Smooth Index array for rigid skinning (shape vertices are influenced by a single bone).|
|0x10||4||Int32||Bone index group offset. Named pointers to the members of the Bone array to allow named lookups.|
|0x14||4||Int32||Bone array offset. Offset to the first element in the Bone array.|
|0x18||4||Int32||Smooth Index array offset. Offset to the first element in the Smooth Index array. Always given even if the array is empty.|
|0x1C||4||Int32||Smooth Matrix array offset. Offset to the first element in the Smooth Matrix array. Always given even if the array is empty.|
|0x20||4||UInt32||User pointer, can be set at runtime, 0 in files.|
|0x24||End of FSKL header|
A Bone is a repeating 0x40 byte structure which descibes a transformation to apply to a polygon. Each bone has up to four parents, which form a tree called a skeleton. To compute the final transformation of a point, apply the transformation required by the bone it is attached to, then that bone's parent recursively up until no parents remain. The Bone tree is stored as an array with offset and length specified by the FSKL header.
|0x00||4||Int32||Name offset for this bone.|
|0x04||2||UInt16||Bone index of this bone into the bone array.|
|0x06||2||UInt16||Parent index of the parents to this bone. 0xFFFF for no parent.|
|0x08||2||Int16||Smooth Matrix index to reverse the transformation of this bone. -1 for no smooth matrix.|
|0x0A||2||Int16||Rigid Matrix index with unknown purpose. -1 for no rigid matrix.|
|0x0C||2||Int16||Billboard index to control how billboarded bones are affected in a hierarchy. -1 if no billboarded bones are affected.|
|0x0E||2||UInt16||User Data entry count.|
|0x10||4||UInt32|| Flags, encoded as CCCCTTTT TxxxxBBB xxxRxxxx xxxxxxxV bits.
Always 0x00001001 (visible & euler XYZ rotation) in Mario Kart 8 files.
|0x14||12||Single||Scale Vector 3 floats. The amount to scale the vertices by.|
|0x20||16||Single||Rotation Vector, either stored as euler rotation (X, Y, Z in radians) or a quaternion, depending on the bone Flags. Mario Kart 8 always uses euler XYZ rotation, so the last float is always set to 1f.|
|0x30||12||Single||Translation Vector 3 floats. The amount to translate the vertices by.|
|0x3C||4||Int32||User Data index group offset. Never used in Mario Kart 8 FSKL sections and thus 0.|
|0x40||End of Bone|
The FSKL may specify an Smooth Matrix for any Bone. It does this by creating an entry in the Inverse Index array which is the index of the bone, and in the corresponding place in the Smooth Matrix array it places a 4×3 transformation matrix which reverses the full transformation of the bone and all its parents. Smooth Matrices are optional, it is Unknown if they are ever referenced. The position of and number of elements in the Smooth Matrix array and the Smooth Index array are given in the FSKL Header.
At the end of the Smooth Index array are a number of indices for Rigid Matrices, which have Unknown purpose. The number of such Rigid Matrices is also present in the FSKL Header.
The model may have one or more FSHP (caFe SHaPe) sections which describe the one polygon (e.g. the road of a track). The FSHP section consists of an 0x40 byte header, which references an FVTX section and indices of the polygons to draw. A basic FSHP amounts to a list of indices into the corresponding FVTX indicating which points to draw triangles between. The FSHP also references an FMAT to describe the material of the triangles, and an FSKL to indicate the bone structure of the model used in animation.
The triangles in an FSHP are organised by two systems; LoD Models and Visibility Groups. No model in Mario Kart 8 uses both of these features non-trivially simultaneously. LoD stands for Level of Detail, which is a standard performance technique used across many 3d rendering systems. Each LoD model is a simpler version of the one before it, with extraneous triangles removed, and finer detail simplified. As the camera in the game moves away from a polygon, the simpler version of the model is rendered instead, which should look the same as the fine detailed version at a distance. A trivial polygon will only have one LoD model, which will be rendered no matter what distance the camera is. Separately, the Visibility Group system allows parts of the model to not be rendered if they are off-screen. This allows an polygon which is partially off-screen to be rendered faster, by skipping the off-screen components. A trivial polygon will only have one Visibility Group, which will always be rendered.
Every FSHP begins with an 0x40 byte header. This references other data structures which describe the polygon.
|0x00||4||Char||"FSHP" section identifier, ASCII string.|
|0x04||4||Int32||Polygon name offset.|
|0x08||4||UInt32|| Flags with only the following meaning:
Always set (thus 2) in Mario Kart 8 files.
|0x0E||2||UInt16||FMAT index. Index of the material for this polygon.|
|0x10||2||UInt16||FSKL index of the bone for this polygon.|
|0x12||2||UInt16||FVTX index of the vertex buffer this polygon uses.|
|0x14||2||UInt16||FSKL Bone skin index. Specifies the index of the bone to which local coordinate matrix vertices are relative in case of rigid bodies using no skinning.|
|0x16||1||Byte|| Vertex skin count, the number of bones influencing a vertex. Depending on the value, vertex positions are stored in different coordinate systems:
|0x17||1||Byte||LoD Model count. Number of elements in the array.|
|0x18||1||Byte||Key Shape count. This feature is not used in Mario Kart 8, thus always 0.|
|0x19||1||Byte||Target Attribute count. This feature is not used in Mario Kart 8, thus always 0.|
|0x1A||2||UInt16||Visibility Group Tree Node count.|
|0x1C||4||Single||Radius of spherical bounding box.|
|0x20||4||Int32||FVTX offset to the vertex buffer for this polygon.|
|0x24||4||Int32||LoD Model offset. Offset to the first element in the array.|
|0x28||4||Int32||FSKL Index array offset. Each element of this array is a 16 bit index.|
|0x2C||4||Int32||Key Shape index group offset. Never used in Mario Kart 8 and thus 0.|
|0x30||4||Int32||Visibility Group Tree Nodes offset.|
|0x34||4||Int32||Visibility Group Tree Ranges offset.|
|0x38||4||Int32||Visibility Group Tree Indices offset.|
|0x3C||4||UInt32||User pointer, can be set at runtime, 0 in files.|
|0x40||End of FSHP header|
A LoD Model is a repeating 0x1C byte structure which are stored in a sequential array with location and size specified by the FSHP Header. Their purpose is described at the beginning of this section.
|0x00||4||UInt32|| Primitive Type, maps to GX2PrimitiveType (line 527 here). Determines how index lists are interpreted to form triangles.
Always GX2_PRIMITIVE_TRIANGLES (thus 4) in Mario Kart 8 files.
|0x04||4||UInt32|| Index Format, maps to GX2IndexFormat (line 515 here). The data type of indices.
Always GX2_INDEX_FORMAT_U16 (thus 4) in Mario Kart 8 files.
|0x08||4||UInt32||Count of points drawn in all Visibility Groups, thus the maximum number of points drawn at this LoD.|
|0x0C||2||UInt16||Visibility Group count. The number of elements in the array.|
|0x10||4||Int32||Visibility Group offset to the first element in the array.|
|0x14||4||Int32||Index Buffer offset.|
|0x18||4||UInt32||Skip vertices, the number of elements to skip in the corresponding FVTX buffer.|
|0x1C||End of LoD Model|
A Visibility Group is a repeating 0x08 byte structure describing an offset and a count in the corresponding Index Buffer. Visibility Groups are stored in a sequential array with location and count indicated by the corresponding LoD Model. This allows multiple visibility groups to use the same Index Buffer. In many cases, a single group is used which simply draws the entire Index Buffer.
|0x00||4||UInt32||Offset into index buffer in bytes.|
|0x04||4||UInt32||Count of the points to draw.|
|0x08||End of Visibility Group|
An Index Buffer is an 0x18 byte structure which describes a list of values (of type as given in the header) which are used to index the FVTX section when drawing the polygon. Index Buffers are referenced by LoD Models. They are instances of the same structure as FVTX Buffers and thus have the same layout.
Visibility Group Tree
The Visibility Group Tree is some sort of tree structure that occurs in all FSHP sections. In all Mario Kart 8 files, when the FSHP has multiple LoD Models, the Visibility Group Tree is a trivial one node tree. The Visibility Group Tree is used to control which Visibility Groups need to be drawn as described at the beginning of this section. The workings of the structure are however unknown.
The Visibility Group Tree Node is a repeating 0x0C byte structure. The nodes form a binary tree. The FSHP header contains a pointer to node array, as well as specifying its length. The root node is the first node in this array. Each node specifies a range of Visibility Groups, with the root node always covering all nodes, and the children of each node always selecting disjoint subsets of that node's range.
|0x00||2||Left child index. The current node's index if it has no left child.|
|0x02||2||Right child index. The current node's index if it has no right child.|
|0x04||2||Unknown, always the same as Left child index.|
|0x06||2||Next sibling index. For left children, always the current node's parent's right child (the current node's index if it has no right child).|
|0x08||2||Visibility Group index selects a range of Visibility Groups along with the count.|
|0x0A||2||Visibility Group count selects a range of Visibility Groups along with the index.|
|0x0C||End of Node|
The Visibility Group Tree Range is a repeating 0x18 byte structure. There are exactly as many Ranges as Nodes. The range contains two 3D vectors defining a bounding box.
|0x00||12||Single||Center 3D position (X,Y,Z float).|
|0x0C||12||Single||Extent from the center position (X,Y,Z float).|
|0x18||End of Range|
Note that in older BFRES versions, the vectors specify minimum and maximum points of the bounding boxes rather than center and extent.
The Visibility Group Tree Index array is an array of 16 bit values which appear to be the index of the leaf node of the Visibility Group Tree which contains the corresponding Visibility Group. Therefore this array has length equal to the number of Visibility Groups in the FSHP section.