PcoWSkbVqDnWTu_dm2ix
We use cookies on this site to enhance your user experience

Roblox Mesh Format

Roblox Mesh Format

Jul 19 2018, 1:49 PM PST 5 min

When a mesh is uploaded to Roblox, it is converted into an in-house format that the game engine can read. Roblox’s mesh format isn’t a format you can export to, but you can download meshes off of their servers, which you can use to view files like these. This article will cover the file specification for this mesh format, so that you might be able to write code externally that can read Roblox mesh files.

This format is always subject to change, so keep an eye out for changes to this article if anything breaks!

Version Header

Every mesh in Roblox starts with a header that is 12 characters in length, followed by a newline (\n) character. The header is represented in ASCII, and it is used to indicate what version of the mesh format is being used.

Currently, there are 3 versions that exist:

  • version 1.00
  • version 1.01
  • version 2.00

Each version has it’s own specific rules and quirks that may need to be addressed while reading the file.

version 1.00

This is the original version of Roblox’s mesh format, which is stored purely in ASCII and can be read by humans. These files are stored as 3 lines of text:

version 1.00
num_faces
(data...)

The num_faces line represents the number of polygons to expect in the data line.

The (data…) line represents a series of concatenated DataType/Vector3 pairs, stored in-between brackets with the XYZ coordinates separated by commas as such: [1.00,1.00,1.00]

Data Specification

For every polygon defined in the mesh, there are 3 vertex points that make up the face. Each vertex point contains 3 Vector3 pairs, representing the Position, Normal, and UV respectively.

Thus, you should expect to read num_faces * 9 concatenated Vector3 pairs in the (data…) line!

Each vertex is tokenized like so:
[pos_X,pos_Y,pos_Z][norm_X,norm_Y,norm_Z][tex_U,tex_V,tex_W]

Position

The 1st Vector3, [pos_X,pos_Y,pos_Z] is the position of the vertex point.

Meshes that use version 1.00 are 2x bigger than they should be, so you should scale this Vector3 down by 0.5 once you convert the XYZ coordinates into floats.

If the mesh is specified to be using version 1.01, then you can safely assume the mesh is using the correct scale.

Normal

The 2nd Vector3, [norm_X,norm_Y,norm_Z] is the normal vector of the vertex point, which is used to smooth out the shading of the mesh.

This Vector3 is expected to be a unit vector, so its Magnitude should be exactly 1. The mesh might have unexpected behavior if this isn’t the case!

UV

The 3rd Vector3, [tex_U,tex_V,tex_W] is the UV texture coordinate of the vertex point, which is used to determine how the mesh’s texture is applied to the mesh. The tex_W coordinate is unused, so you can expect its value to be 0.

version 2.00

The version 2.00 format is stored in a binary format, and files may differ in structure depending on factors that aren’t based on the version number. You will need a good understanding of C++ headers in order to understand this next section!

Data Specification

Once you have read past the version 2.00\n text at the beginning of the file, the binary data begins!

There will be three struct types used to read the file:

  • MeshHeader
  • MeshVertex
  • MeshFace

The variables in each of these structs are defined in a specific order, and the type of each variable specifies how many bytes should be sequentially read and copied into the variable.

MeshHeader

The first chunk of data is the MeshHeader, represented by the following struct definition:

struct MeshHeader
{
	uint16_t sizeofMeshHeader;
	// ^ The sizeof(MeshHeader) used to represent this file.

	uint8_t sizeofMeshVertex; 
	// ^ The sizeof(MeshVertex) used to represent this file.

	uint8_t sizeofMeshFace; 
	// ^ The sizeof(MeshFace) used to represent this file.

	uint32_t num_vertices; 
	// ^ The number of vertices in this mesh.

	uint32_t num_faces; 
	// ^ The number of faces in this mesh.
}

If you read MeshHeader.sizeofMeshHeader and it does not share the same sizeof(MeshHeader) as the one in your code, then it is unlikely that you’ll be able to read it correctly!

MeshVertex

Once you have read the MeshHeader, you should expect to read an array, MeshVertex[num_vertices] vertices; using the following struct:

struct MeshVertex
{
	float px, py, pz; // XYZ position of the vertex's position
	float nx, ny, nz; // XYZ unit vector of the vertex's normal vector.
	float tu, tv, tw; // UV coordinate of the vertex (tw is reserved)

	uint8_t r, g, b, a; // RGBA color of the vertex
}

This array represents all of the vertices in the mesh, which can be linked together into faces.

MeshFace

Finally, you should expect to read an array, MeshFace[num_faces] faces; using the following struct:

struct MeshFace
{
	int32_t a; // 1st Vertex Index
	int32_t b; // 2nd Vertex Index
	int32_t c; // 3rd Vertex Index
}

This array represents indexes in the MeshVertex array that was noted earlier. The 3 MeshVertex structs that are indexed using the MeshFace are used to form a polygon in the mesh!


Wrapping up

Congratulations! You should now hopefully have a basic understanding of how Roblox’s mesh format works!

Tags:
  • model