PLY format (.ply)
Overview
The .ply is a chunk-based format used to store meshes in engines of the GEM family.
Chunk loading must continue until the end of the file.
Because chunk size is not stored, it must be calculated by the parser based on the chunk data structure.
Each file may contain:
static meshes;
skinned meshes;
landscape meshes;
terrain grids;
adjacency data;
shadow data;
multiple UV channels;
tangent space;
skinning
materials and textures
File structure
The order of chunks inside the loop is not fixed, and some of them may not be present. The parser must determine the chunk type from its FourCC value and process the data accordingly.
File header
Each .ply file begins with one of the following identifiers:
EPLY
uint8[4]
4
Regular mesh with 16-bit indices
BPLY
uint8[4]
4
Landscape mesh with 32-bit indices.
PM01
uint8[4]
4
GEM3 mesh format
The starting FourCC is a file format identifier, it is not a regular chunk. After reading the starting FourCC, the parser reads the rest of the file as a sequence of chunks.
Chunk IDs
INDX
Mesh indices (16-bit)
IND4
Mesh indices (32-bit)
VERT
Vertex data
BAS2
Terrain grid basis
InfG
Terrain grid
BNDS
Bounding box
ADJA
Adjacency
SHDW
Shadow data
MROR
Mirrored mesh flag
MARK
Markup data
SKIN
Bone map
MESH
Legacy submesh
SBM1
GEM RTS 1.1+ submesh
SUBM (GEM RTS)
GEM3 / GEM RTS submesh
SUBM (AS2)
Assault Squad 2 submesh
There are two incompatible variants of the SUBM chunk. The chunk structure depends on the resource starting FourCC value. The parser must choose the appropriate SUBM variant according to the starting FourCC.
Chunk ID loading loop
Chunk INDX | IND4
Data structure
Chunk INDX
FourCC
uint8[4]
4
INDX
Mesh indices
index_count
int32
4
Number of indices
indices
uint16[index_count]
2
Index array. Index size is determined by the starting chunk ID
Chunk IND4
FourCC
uint8[4]
4
IND4
Mesh indices
index_count
int32
4
Number of indices
indices
uint32[index_count]
4
Index array. Index size is determined by the starting chunk ID
Chunk VERT
FourCC
uint8[4]
4
VERT
vertex_count
int32
4
Number of vertices
vertex_size
uint16
2
Size of a single vertex in bytes. The engine primarily relies on this value even if the size calculated from flags is smaller
vertex_flags
uint16
2
Vertex flag bit mask
vertices
struct[vertex_count]
Vertex array. Vertex structure depends on the submesh format
FVF
Vertex flags are combined using a bit mask.
0x0001
Full color. If the flag is absent, vertex colors are multiplied by 2 after loading
0x0002
Optimized vertex order. If the flag is absent, the engine may attempt to optimize the mesh automatically after loading
0x0004
Color verified. *) Not used in GEM RTS
Vertices struct[vertex_count]
position
float[3]
12
Vertex position in local coordinates
normal
float[3]
12
Normal vector in local coordinates
tangent
float[3]
12
Tangent vector in local coordinates. Optional
uv
float[2]
8
Texture UV coordinates. Multiple UV sets are supported
bone_indices
uint8[4]
4
Indices into the local submesh bone remap
bone_weights
uint8[4]
4
Bone weights stored in UNORM8 format (0..1)
Chunk BAS2
Terrain grid basis.
FourCC
uint8[4]
4
BAS2
polygons.center
float[2]
8
Origin of the triangle generation coordinate system
polygons.axis_x
float[2]
8
X axis of the triangle generation coordinate system
polygons.axis_y
float[2]
8
Y axis of the triangle generation coordinate system
texture.center
float[2]
8
Origin of the UV coordinate system
texture.axis_x
float[2]
8
X axis of UV space
texture.axis_y
float[2]
8
Y axis of UV space
Chunk InfG
Terrain triangle grid.
FourCC
uint8[4]
4
InfG
Terrain grid
grid_start_xy
int32[2]
8
Grid starting coordinates
grid_end_xy
int32[2]
8
Grid ending coordinates
face_count
uint32
4
Number of triangles
faces
uint16[face_count]
Triangle data array
Bit layout of faces
0x7FFF
Submesh index submesh: 15
0x8000
Invalid triangle flag invalid: 1
Chunk BNDS
Axis-aligned mesh bounding box.
FourCC
uint8[4]
4
BNDS
Mesh bounding box
min
float[3]
12
Minimum XYZ coordinates
max
float[3]
12
Maximum XYZ coordinates
Chunk ADJA
Information about adjacent triangles.
*) Not used in GEM RTS.
FourCC
uint8[4]
4
ADJA
Adjacency information
face_count
int32
4
Number of triangles
adjacencies
struct[face_count]
Triangle neighbour information
Adjacencies (struct)
neighbours
uint16[3]
6
Indices of neighbouring triangles.
0xFFFF means no neighbour
Chunk SHDW
Shadow information.
*) Not used in GEM RTS.
FourCC
uint8[4]
4
SHDW
Shadow information
face_count
int32
4
Number of triangles
shadow_infos
uint8[face_count]
Shadow casting flags:
0: does not cast shadows
1: casts shadows
Chunk MROR
Mirrored mesh flag.
FourCC
uint8[4]
4
MROR
Indicates a mirrored mesh
Chunk MARK
Triangle markup.
*) Not used in GEM RTS.
FourCC
uint8[4]
4
MARK
mark_size
uint32
4
Size of markup data
marks
uint8[mark_size]
Binary markup data
Chunk SKIN
Bone map for a skinned mesh.
FourCC
uint8[4]
4
SKIN
bone_count
uint32
4
Number of bones
bone_names
string8[bone_count]
Bone names
Chunk SUBM (GEM RTS, GEM3)
Submesh description format used by GEM3 and GEM RTS models.
The file must start with the PM01 format identifier.
FourCC
uint8[4]
4
SUBM
vertex_format
uint16
2
Vertex format bit mask
face_start
uint16
2
Index of the first triangle in the submesh
face_count
uint16
2
Number of triangles in the submesh
vertex_start
uint16
2
Index of the first vertex in the submesh. Not used in GEM RTS
vertex_count
uint16
2
Number of vertices in the submesh. Not used in GEM RTS
mesh_flags
uint16
2
Bit flags describing mesh properties
material_name
string8/24
1+
Material name
Bit field vertex_format
0x0001
float[3]
Position
0x0002
float[3]
Normal
0x0004
uint8[4]
Color 0, RGBA
0x0008
uint8[4]
Color 1, RGBA
0x0010
float[2]
Texture coordinates 0
0x0020
float[2]
Texture coordinates 1
0x0040
float[2]
Texture coordinates 2
0x0080
float[2]
Texture coordinates 3
0x0100
float[4]
Tangent
0x0200
uint8
Skinning with 2 bones
0x0400
uint8[2]
Skinning with 3 bones
0x0600
uint8[3]
Skinning with 4 bones. Both 0x0200 and 0x0400 bits are set simultaneously
0x0800
float
Wind amplitude
Bit mask for mesh_flags
0x0001
Double-sided mesh
0x0002
Skin
Skin data
Present only if the 0x0002 (skin) flag is set in mesh_flags.
bone_count
uint8
1
Number of bones used by the skin
bone_map
uint8[bone_count]
bone_count
Bone indices in the bone map
Values of bone_map
0
Use the mesh's global transform matrix
N > 0
Use SKIN.bones[N - 1]
Chunk SBM1
GEM RTS 1.1+ submesh format used for map meshes.
FourCC
uint8[4]
4
SBM1
vertex_elements
struct[]
Vertex element descriptors
tags
struct[]
List of custom vertex tags
face_start
int32
4
Index of the first triangle in the submesh
face_count
int32
4
Number of triangles in the submesh
mesh_flags
uint32
4
Mesh bit flags
material_name
string8/24
1+
Material name
Vertex format elements
The vertex_elements[] array describes the vertex layout.
The list does not contain an element count and is read sequentially until a terminator element is encountered.
The type_usage field stores both the element type and its semantic:
(type_usage & 0x0F)specifies the element type.(type_usage & 0xF0) >> 4specifies the element usage.
The value 0xFF is used as the list terminator and ends vertex format parsing.
Element structure
type_usage
uint8
1
Element type and semantic
usage_index
uint8
1
Usage index
stream_index
uint8
1
Stream index
Element type
Determined by the lower four bits of type_usage.
0
FLOAT1
float
1
FLOAT2
float[2]
2
FLOAT3
float[3]
3
FLOAT4
float[4]
4
SHORT2
int16[2]
5
BYTE4
uint8[4]
6
COLOR
uint8[4]
RGBA
7
HALF4
float[4]
Half-precision
8
BYTE4N
uint8[4]
UNORM8
Element usage
Determined by the upper four bits of type_usage.
0
POSITION
1
NORMAL
2
COLOR
3
TEXCOORD
4
BLEND WEIGHT
5
BLEND INDICES
6
TANGENT
Vertex tags
The tags[] list contains additional user-defined tags for vertex elements.
The list does not contain an element count and is read sequentially until a terminator element is encountered.
The value 0xFF is used as the tag list terminator.
Tag structure
tag_index
uint8
1
Vertex element index
tag_chunk
uint32
4
Tag identifier
Bit mask for mesh_flags
0x0001
Two-sided mesh (render without back-face culling)
0x0002
Use alpha (compatibility mode)
0x0004
Use realtime scene lighting
0x0008
Use player color lighting
0x0010
Skinned mesh
0x0020
Shadow volume mesh
0x0040
Mirrored mesh (negative scaling)
0x0080
Blend by second texture alpha
0x0100
Bump mapping (compatibility mode)
0x0200
Specular color is stored
0x0400
Uses materials instead of textures
0x0800
Sub-skin feature
0x1000
Two textures share a single texture coordinate set
0x2000
Uses VD (compatibility mode)
0x4000
Contains a lightmap
Chunk MESH
Legacy submesh format used in Faces of War and Men of War.
FourCC
uint8[4]
4
MESH
Legacy submesh format
fvf
uint32
4
Vertex format bit mask
face_start
int32
4
Index of the first triangle
face_count
int32
4
Number of triangles
mesh_flags
uint32
4
Mesh bit flags
Vertex format flags (FVF)
Bit mask describing the vertex format.
The fvf field contains a uint32 bit mask. The values shown below represent vertex layouts encountered in the format. If a value not listed in the table is found in a file, it should be interpreted as a combination of the corresponding flags.
For example, the value 0x00000012 is stored in the file as the byte sequence 12 00 00 00 (Little-endian). If flags 0x00000002 and 0x00000010 correspond to position and normal, then 0x00000012 indicates that both fields are present in the vertex.
0x002
position float[3]
0x006
position float[3] blend_weight uint8 blend_indices uint8[4]
0x008
position float[3] blend_weight uint8[2] blend_indices uint8[4]
0x00A
position float[3] blend_weight uint8[3] blend_indices uint8[4]
0x010
normal float[3]
0x040
diffuse_color uint8[4]
0x080
specular_color uint8[4]
0xN00
texcoord_mask N × float[2]
0x8000E000
tangent float[4]
Bit mask for mesh_flags
0x0001
Two-sided mesh (render without back-face culling)
0x0002
Use alpha (compatibility mode)
0x0004
Use realtime scene lighting
0x0008
Use player color lighting
0x0010
Skinned mesh
0x0020
Shadow volume mesh
0x0040
Mirrored (negative scaling)
0x0080
Blend by second texture alpha
0x0100
Bump (compatibility mode)
0x0200
Specular
0x0400
Use material
0x0800
Sub-skin feature
0x1000
Two textures with one texcoord
0x2000
Using VD (compatibility mode)
0x4000
Has lightmap
Specular color
Present if mesh_flags contains 0x0200 (specular).
specular_color
uint8[4]
4
Specular color
Material name
Present if mesh_flags contains 0x0400 (use material).
material_name
string8/24
1+
Material name
Texture data
Texture data is loaded when mesh_flags does not contain 0x0400 (use material). The structure depends on the specular, bump, number of texture coordinate sets (UV), and the two textures with one texcoord flag.
Texture data for standard material
Used when mesh_flags contains specular or bump.
diffuse
string8/24
1+
Diffuse texture name
specular_texture
string8/24
1+
Specular texture name. Present if mesh_flags contains specular
bump_texture
string8/24
1+
Normal map texture name. Present if mesh_flags contains bump
Texture data for two textures
Used if the standard material path is not used and one of the following conditions is true:
uv == 2mesh_flagscontainstwo textures with one texcoord
diffuse_0
string8/24
1+
Diffuse texture 0 name
diffuse_1
string8/24
1+
Diffuse texture 1 name
Texture data for one texture
Used if the standard material path is not used and the conditions for using two textures are not met.
diffuse
string8/24
1+
Diffuse texture name
Skin data
Skin data is present if mesh_flags contains skinned mesh.
bone_map_size
uint8
1
Size of the local bone remapping table
bone_map
uint8[bone_map_size]
bone_map_size
Local bone remapping table
The bone_map table is used to map submesh bones to the global bone map stored in the SKIN chunk.
Each array element contains the index of a bone from SKIN, incremented by 1.
Vertex bone_index values reference entries in the bone_map array rather than directly indexing bones in SKIN.
This allows a submesh to use only the subset of bones required by its vertices.
Values of bone_map
0
Use the mesh's global transform matrix
N > 0
Use SKIN.bones[N - 1]
Chunk SUBM (Assault Squad 2)
Submesh description format used by map meshes from Assault Squad 2. This format is used when the starting chunk is not PM01.
FourCC
uint8[4]
4
SUBM
vertex_elements
struct[]
List of vertex format elements
face_start
uint32
4
Index of the first triangle in the submesh
face_count
uint32
4
Number of triangles in the submesh
unknown[2]
uint32[2]
8
Unknown data
mesh_flags
uint32
4
Mesh bit flags
material_name
string8
1+
Material name
Vertex elements info
The vertex_elements[] list describes the vertex layout.
The list does not contain an element count and is read sequentially until a terminator element is encountered.
The type_usage field stores both the element type and its semantic.
(type_usage & 0x0F)determines the element type.(type_usage & 0xF0) >> 4determines the element usage.
The value 0xFF is used as the list terminator and ends vertex format parsing.
type_usage
uint8
1
Element type and semantic
Element type
Determined by the lower four bits of the type_usage field.
0
FLOAT1
float
1
FLOAT2
float[2]
2
FLOAT3
float[3]
3
FLOAT4
float[4]
4
SHORT2
int16[2]
5
BYTE4
uint8[4]
6
COLOR
uint8[4]
RGBA
7
HALF4
float[4]
Half-precision
8
BYTE4N
uint8[4]
UNORM8
Element usage
Determined by the upper four bits of the type_usage field.
0
POSITION
1
NORMAL
2
COLOR
3
TEXCOORD
4
BLEND WEIGHT
5
BLEND INDICES
6
TANGENT
Bit mask for mesh_flags
0x0001
Two-sided mesh (render this mesh without culling)
0x0002
Use alpha (compatibility mode)
0x0004
Use realtime scene lighting
0x0008
Use player color lighting
0x0010
Skinned mesh
0x0020
Shadow volume mesh
0x0040
Mirrored (has negative scaling)
0x0080
Blend by second texture alpha
0x0100
Bump (compatibility mode)
0x0200
Specular color stored
0x0400
Format with material instead of textures
0x0800
Sub-skin feature
0x1000
Two textures with one texcoord
0x2000
Using VD (compatibility mode)
0x4000
Has lightmap
Last updated