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 |
Maximum amount of bones per surface | 128 |
Maximum number of active morph targets per mesh | 7 |
Compression of Normals#
Compression of normalized floating-point normals into unsigned short format is performed in the following way:
x = (unsigned short)(clamp((int)((normal.x * 0.5f + 0.5f) * 65535.0f),0,65535));
y = (unsigned short)(clamp((int)((normal.y * 0.5f + 0.5f) * 65535.0f),0,65535));
z = (unsigned short)(clamp((int)((normal.z * 0.5f + 0.5f) * 65535.0f),0,65535));
Here:
- normal is a normalized float normal.
- x, y and z are unsigned short compressed normals.
Decompression of Animation Frames#
Frames' translations and scales that are compressed into the unsigned short format, can be decompressed as follows:
-
Decompression of the frame translations:
x = xyz_min.x + xyz_size.x * (compressed_position.x / 65535.0f); y = xyz_min.y + xyz_size.y * (compressed_position.y / 65535.0f); z = xyz_min.z + xyz_size.z * (compressed_position.z / 65535.0f);
Here:
- xyz_min is a bounding box minimum along X, Y and Z axes.
- xyz_size is a bounding box size.
- x, y and z are unsigned short compressed translations of the frame.
-
Decompression of the frame scales:
x = scale_min.x + scale_size.x * (compressed_scale.x / 65535.0f); y = scale_min.y + scale_size.y * (compressed_scale.y / 65535.0f); z = scale_min.z + scale_size.z * (compressed_scale.z / 65535.0f);
Here:
- scale_min is a bounding box minimum along X, Y and Z axes.
- scale_size is a bounding box size.
- x, y and z are unsigned short compressed scales of the frame.
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 "ms11" ('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 mesh animations (int)
Header information for each animation:
Name of the animation. It is a null-terminated string that contains:
- The number of characters in the string including the null character (int).
- Animation name of the specified length (char[length])
- 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])
- 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 "ms11" ('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])
For each animation:
- Number of bones taking part in the animation (int)
- Indices of the bones taking part in the animation (short[length])
- Flag (unsigned char), each 8 bits of which determine if the mesh animations should store translation, scale or rotation components for bones taking part in the animations.
- Number of animation frames (int)
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 X (float)
- Translation of the bone along Y (float)
- Translation of the bone along Z (float)
- Rotation quaternion (short[4])
- X component of the bone scale (float)
- Y component of the bone scale (float)
- Z component of the bone scale (float)
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 "ms11" ('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 "an10" ('a' | ('n' << 8) | ('1' << 16) | ('0' << 24)))
Bounding volume of the whole animation:
- Bounding box minimum (float[3])
- Bounding box maximum (float[3])
- Bounding sphere center (float[3])
- Bounding sphere radius (float)
- 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)
- Number of animations (int)
Header information for each animation:
Name of the animation. It is a null-terminated string that contains:
- The number of characters in the string including the null character (int).
- Animation name of the specified length (char[length])
- File format identifier (int32 "an10" ('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])
For each animation:
- Number of animation bones (int)
- Indices of the bones taking part in the animation (short[length])
Bounding box within which animation takes place:
Bounding box within which the translation of animation bones is performed:
- Bounding box minimum along X, Y and Z axes (float[3])
- Bounding box size (float[3]).
Bounding box within which the scaling of animation bones is performed:
- Bounding box minimum along X, Y and Z axes (float[3])
- Bounding box size (float[3]).
- 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.
- Number of animation frames (int)
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 X (unsigned short)
- Translation of the bone along Y (unsigned short)
- Translation of the bone along Z (unsigned short)
- Rotation quaternion (short[4])
- X component of the bone scale (unsigned short)
- Y component of the bone scale (unsigned short)
- Z component of the bone scale (unsigned short)
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 "an10" ('a' | ('n' << 8) | ('1' << 16) | ('0' << 24)))