Mesh File Formats
UNIGINE supports the following mesh file formats for common and skinned meshes:
- *.mesh, which is used for static geometry and animated characters.
- *.anim, which contains animation for a skinned mesh (*.mesh file).
Here are some general notes that are valid for any mesh format.
- All data is in the little-endian notation.
- float is a 32-bit IEEE754 floating-point type. It has a range of 3.4 e-38 to 3.4 e+38.
- int here is a compact signed integer.To read / write compact integer values use readInt2() / writeInt2() methods respectively.
- int32 is a signed 32-bit two's complement integer. It has a range of –2,147,483,648 to 2,147,483,647.
- unsigned short is an unsigned 16-bit integer. It has a range of 0 to 65,535.
- char is a signed 8-bit two's complement integer. It has a range of -128 to 127.
- unsigned char is a 8-bit unsigned integer. It has a range of 0 to 255.
- string must be null terminated. The string size should include this terminating null character.
- All formats allow multiple surfaces.
The mesh limitations set in UNIGINE:
Maximum number of vertices per mesh | 4,294,967,295 |
Maximum number of surfaces per mesh | 32,768 |
Maximum amount of weights per vertex | 4 |
Compression and Decompression of Tangents#
Compression of normalized floating-point tangents into unsigned short format is performed in the following way:
x = (unsigned short)(clamp((int)((tangent.x * 32767.0f), -32767, 32767)));
y = (unsigned short)(clamp((int)((tangent.y * 32767.0f), -32767, 32767)));
z = (unsigned short)(clamp((int)((tangent.z * 32767.0f), -32767, 32767)));
w = (unsigned short)(clamp((int)((tangent.w * 32767.0f), -32767, 32767)));
Here:
- tangent is a normalized float tangent.
- x, y, z and w are unsigned short compressed tangent values.
Decompression of tangents that are compressed into the unsigned short format can be performed as follows:
tangent.x = (compressed_tangent.x / 65535.0f);
tangent.y = (compressed_tangent.y / 65535.0f);
tangent.z = (compressed_tangent.z / 65535.0f);
tangent.w = (compressed_tangent.w / 65535.0f);
Here:
- compressed_tangent is an unsigned short compressed tangent.
- tangent is a normalized float tangent.
Compression and Decompression of Weights#
Compression of normalized floating-point weights into unsigned short format is performed in the following way:
w = (unsigned short)clamp((int)((weight * 65535.0f), 0, 65535));
Here:
- weight is a normalized float weight.
- w is unsigned short compressed weight.
Decompression of weights that are compressed into the unsigned short format can be performed as follows:
weight = compression_weight / 65535.0f;
Here:
- compression_weight is an unsigned short compressed weight.
- weight is a normalized float weight.
Storing Meshes#
MESH is a universal file format for static and skinned geometry.
The skinned meshes can be stored as follows:
- Containing both mesh data (vertices and their weights) and animation (bones and their transformations). This variant of storing mesh together with animation data in one file is less flexible and more memory consuming. Use it only for small animation sequences.
- Containing only mesh data, i.e. the bind pose. This approach is useful, if you prefer to put additional animation out to separate files.
MESH File Format#
- File format identifier (int32 "ms13" ('m' | ('s' << 8) | ('1' << 16) | ('1' << 24)))
-
Bounding volume of the whole mesh:
- Mesh bounding box minimum (float[3])
- Mesh bounding box maximum (float[3])
- Mesh bounding sphere center (float[3])
- Mesh bounding sphere radius (float)
- Number of bones (int)
Header information for each bone:
Name of the bone. It is a null-terminated string that contains:
- The number of characters in the string including the null character (int).
- Bone name of the specified length (char[length]).
- Parent of the bone. If case of the root bone without a parent, -1 is used. (short)
- Number of surfaces (int)
Header information for each surface:
Name of the surface. It is a null-terminated string that contains:
- The number of characters in the string including the null character (int).
- Surface name of the specified length (char[length])
- UV channel used for the surface lightmap (unsigned char)
- Surface lightmap resolution (unsigned char)
- Surface bounding box minimum (float[3])
- Surface bounding box maximum (float[3])
- Surface bounding sphere center (float[3])
- Surface bounding sphere radius (float)
- Number of the surface morph targets (int)
Header information for each morph target:
- Name of the morph target. It is a null-terminated string that contains:
- The number of characters in the string including the null character (int).
- Morph target name of the specified length (char[length])
- Name of the morph target. It is a null-terminated string that contains:
- File format identifier (int32 "ms13" ('m' | ('s' << 8) | ('1' << 16) | ('1' << 24)))
For each bone:
- Bone position along X, Y, Z axes (float[3])
- Bone rotation quaternion (float[4])
- Bone scale in all directions(float[3])
Data on each surface geometry:
Data on each morph target of the surface:
- Number of surface weights (int)
For each surface weight:
- Number of bones that affect the vertex (the maximum value is 4) (unsigned char)
For each bone that affects the vertex:
- Bone index (short)
- Bone weight (unsigned short)
- Number of texture coordinates in the 1st UV set (int)
For each of texture coordinates:
- 1st UV texture coordinates(float[2])
- Number of texture coordinates in the 2nd UV set (int)
For each of texture coordinates:
- 2nd UV texture coordinates (float[2])
- Number of 8-bit vertex colors (int).
For each color:
- Color value (unsigned char[4])
- Number of coordinate indices (int)
Сoordinate indices for each vertex of the surface:
- If the zero morph target contains less than 256 coordinate vertices, all the indices are unsigned char[length]
- If the zero morph target contains less than 65536 coordinate vertices, all the indices are unsigned short[length]
- Otherwise, all the indices are int32[length]
- Number of triangle indices (int)
Triangle indices for each vertex of the surface:
- If the zero morph target contains less than 256 triangle vertices, all the indices are unsigned char[length]
- If the zero morph target contains less than 65536 triangle vertices, all the indices are unsigned short[length]
- Otherwise, all the indices are int32[length]
- File format identifier (int32 "ms13" ('m' | ('s' << 8) | ('1' << 16) | ('1' << 24)))
Storing Skinned Mesh Animation#
Skinned mesh animation format contains only animation for skinned mesh *.mesh files. They are useless without a "base" skinned mesh in its bind pose that contains vertices and their weights.
*.anim files store animation data more efficiently than one skinned mesh *.mesh file containing both a mesh and bones transformations. That is the reason why *.anim files are ideal for long animations.
If you need to load such a file in a script or save it, treat it like a *.mesh animation file.
ANIM File Format#
- File format identifier (int32 "an11" ('a' | ('n' << 8) | ('1' << 16) | ('0' << 24)))
- Number of bones in skinned animation (int)
Header information for each bone:
Name of the bone. It is a null-terminated string that contains:
- The number of characters in the string including the null character (int).
- Bone name of the specified length (char[length])
- Parent of the bone (short)
- File format identifier (int32 "an11" ('a' | ('n' << 8) | ('1' << 16) | ('0' << 24)))
For each bone:
- Bone position along X, Y, Z axes (float[3])
- Bone rotation quaternion (float[4])
- Bone scale in all directions(float[3])
- Number of animation bones (int)
- Indices of the bones taking part in the animation (short[length])
- Number of animation frames (int)
- Flag (unsigned char), each 8 bits of which determine if the animations should store translation, scale or rotation components for bones taking part in the animations.
Transformation data for each bone in each frame:
- Flag (unsigned char), each 8 bits of which determine if the current frame should store new translation, scale or rotation components for the bone. If these components have not changed since the previous frame, new data is not stored. Instead, data from the previous frame is used, which maximizes the efficiency of memory usage.
If the data is flagged as changed, for each component of the bone:
- Translation of the bone along axes X, Y, Z (float[3])
- Rotation quaternion (float[4])
- Bone scaling along axes X, Y, Z (float[3])
These position and rotation values are specified inside of the calculated bounding box: as a coordinate between its minimum and its maximum (a value in range from 0 to 65535).
- File format identifier (int32 "an11" ('a' | ('n' << 8) | ('1' << 16) | ('0' << 24)))