Skip to main content
filamesh converts mesh files into Filament’s optimized binary format for fast loading and rendering.
Caution! filamesh was designed to operate on trusted inputs. To minimize the risk of triggering memory corruption vulnerabilities, please make sure that the files passed to filamesh come from a trusted source, or run filamesh in a sandboxed environment.

Usage

filamesh [options] <source_mesh> <destination_file>

Supported Input Formats

Any mesh format supported by Assimp, including:
  • FBX
  • OBJ
  • GLTF/GLB
  • And many others

Requirements

Input meshes must have at least one set of UV coordinates (texture coordinates).

Options

  • --help, -h - Print help message
  • --license - Print copyright and license information
  • --interleaved, -i - Interleave mesh attributes
    • Stores vertex data in an interleaved format for better cache coherency
  • --compress, -c - Enable compression
    • Uses meshoptimizer compression for smaller file sizes
  • --ignore-uv1, -g - Ignore the second set of UV coordinates
    • Use when secondary UVs are present but not needed

Output Format

The .filamesh binary format contains:

Vertex Attributes

  • Positions: half4 (XYZ + W=1.0)
  • Tangents: short4 quaternion (encodes tangent, bitangent, and normal)
  • Colors: ubyte4 (RGBA, 0-255)
  • UV0: half2 or short2 (primary texture coordinates)
  • UV1: half2 or short2 (optional secondary texture coordinates)

Storage Modes

Non-Interleaved (default)

Attributes stored in separate arrays:
[all positions][all tangents][all colors][all UV0][all UV1]

Interleaved (with -i flag)

Attributes stored per-vertex:
[pos, tangent, color, UV0][pos, tangent, color, UV0]...
UV1 attribute cannot be used in interleaved mode.

Mesh Parts

Each mesh can have multiple parts (sub-meshes), with each part:
  • Using a contiguous range of indices
  • Having its own material ID
  • Including a bounding box (AABB)

Examples

Basic conversion

filamesh model.obj model.filamesh

Interleaved with compression

filamesh --interleaved --compress character.fbx character.filamesh

Ignore secondary UVs

filamesh --ignore-uv1 mesh.obj mesh.filamesh

Compressed output

filamesh -c building.fbx building.filamesh

File Format Details

Header Structure

char[8]   magic;              // "FILAMESH"
uint32    version;
uint32    parts;              // Number of sub-meshes
float3    aabbCenter;         // Bounding box center
float3    aabbHalfExtent;     // Bounding box half extent
uint32    flags;              // Feature flags
uint32    offsetPosition;     // Byte offset for positions
uint32    stridePosition;     // Byte stride for positions
uint32    offsetTangents;     // Byte offset for tangents
uint32    strideTangents;     // Byte stride for tangents
uint32    offsetColor;        // Byte offset for colors
uint32    strideColor;        // Byte stride for colors
uint32    offsetUV0;          // Byte offset for UV0
uint32    strideUV0;          // Byte stride for UV0
uint32    offsetUV1;          // Byte offset for UV1 (0xFFFFFFFF if not present)
uint32    strideUV1;          // Byte stride for UV1 (0xFFFFFFFF if not present)
uint32    vertexCount;
uint32    vertexSize;         // Size in bytes (possibly compressed)
uint32    indexType;          // 0=uint32, 1=uint16
uint32    indexCount;
uint32    indexSize;          // Size in bytes (possibly compressed)

Flags

  • Bit 0: Vertex attributes are interleaved
  • Bit 1: UVs are 16-bit signed normalized integers (snorm16) instead of half-floats
  • Bit 2: Vertex and index data are compressed using meshoptimizer

Part Structure

uint32  offset;          // First index in index buffer
uint32  indexCount;      // Number of indices
uint32  minIndex;        // Minimum index value
uint32  maxIndex;        // Maximum index value  
uint32  materialID;      // Index in materials array
float3  aabbCenter;      // Part bounding box center
float3  aabbHalfExtent;  // Part bounding box half extent

Materials

uint32  materialCount;
// For each material:
  uint32  nameLength;    // Length of name string (not including \0)
  char[]  name;          // Null-terminated material name

Processing Pipeline

filamesh automatically:
  1. Triangulates all geometry
  2. Generates smooth normals if not present
  3. Calculates tangent space for normal mapping
  4. Optimizes topology:
    • Joins identical vertices
    • Optimizes mesh order
    • Improves cache locality
  5. Pre-transforms vertices (bakes transformations)
  6. Encodes tangent frames as quaternions
  7. Converts UV coordinates to half-float or snorm16
  8. Computes bounding boxes for culling

UV Coordinate Encoding

filamesh automatically chooses the best UV encoding:
  • Half-float (half2): Used when UVs are outside [-1, 1] range
    • Higher precision, larger file size
    • Suitable for atlases or tiled textures
  • Signed normalized 16-bit (short2): Used when UVs are within [-1, 1]
    • Lower precision, smaller file size
    • Suitable for standard 0-1 UV mapping

Loading in Filament

See the README for complete loading examples. Basic loading pattern:
// Read file
char* data = readFile("model.filamesh");

// Parse header
Header* header = parseHeader(data);

// Create buffers
VertexBuffer* vb = createVertexBuffer(header);
IndexBuffer* ib = createIndexBuffer(header);

// Build renderable
RenderableManager::Builder builder(header->parts);
for (size_t i = 0; i < header->parts; i++) {
    builder.geometry(i, PrimitiveType::TRIANGLES, 
                     vb, ib, parts[i].offset, 
                     parts[i].indexCount);
}

Best Practices

  1. Use compression (-c) for production to reduce file size
  2. Use interleaved (-i) for better cache performance (if not using UV1)
  3. Validate UVs - Ensure your source mesh has proper UV unwrapping
  4. Material names - Use meaningful material names in source files
  5. Triangulate - While filamesh does this automatically, pre-triangulating in your DCC tool gives you more control

Troubleshooting

”mesh does not have texture coordinates”

Ensure your 3D model has UV coordinates. In Blender/Maya/Max, check that the model is properly UV unwrapped.

”mismatch in # of verts and # of secondary texcoords”

Either fix the secondary UVs in your source file, or use --ignore-uv1 to skip them.

”mesh doesn’t have any parts”

The mesh file is empty or couldn’t be parsed. Verify the file format is supported.

Build docs developers (and LLMs) love