# How to Integrate Custom Models Using Assimp in Equilibrium Engine

> Integrate custom 3D models using Assimp in Equilibrium Engine. Load GLTF, OBJ, or FBX files easily into your game engine with automated material creation.

- Repository: [Alexander/equilibriumengine](https://github.com/clibequilibrium/equilibriumengine)
- Tags: how-to-guide
- Published: 2026-02-27

---

**Call `assimp_scene_load()` from [`equilibrium/utils/assimp_utils.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/utils/assimp_utils.h) with your model path and ECS world pointer to import GLTF, OBJ, or FBX files as renderable entities with automatic material generation.**

The Equilibrium Engine provides a built-in Assimp import pipeline that converts standard 3D formats into engine-native Mesh components. By leveraging the utilities in [`equilibrium/utils/assimp_utils.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/utils/assimp_utils.h), you can load custom assets with automatic material and texture handling according to the `clibequilibrium/equilibriumengine` source code. This guide walks through the exact integration steps, file paths, and function signatures required to bring your own 3D assets into the engine.

## Understanding the Assimp Import Pipeline

The import process centers on `assimp_scene_load()` defined in [`equilibrium/utils/assimp_utils.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/utils/assimp_utils.h). This function orchestrates the conversion from Assimp's scene graph to the engine's ECS entity hierarchy through five distinct phases:

1. **Property store creation**: Initializes an Assimp property store and configures import flags to enforce triangle-only geometry and 16-bit index limits (lines 30-41).
2. **Scene import**: Calls `aiImportFileExWithProperties` and validates the returned pointer (lines 24-28).
3. **Material processing**: Iterates over `aiMaterial` objects and converts them to engine `Material` structs via `material_load()` (lines 61-112).
4. **Mesh conversion**: Transforms vertex data into packed `PosNormalTangentTexcoordVertex` buffers and creates BGFX resources through `group_load()` (lines 13-98).
5. **Entity instantiation**: Creates ECS entities for each mesh, attaching `Mesh` components and optional `Material` components when base-color textures are detected (lines 58-67).

### Vertex Processing in group_load

The `group_load()` function packs interleaved vertex attributes (position, normal, tangent, UV) into the `PosNormalTangentTexcoordVertex` structure. It allocates BGFX vertex buffers using `bgfx_create_vertex_buffer` and constructs 16-bit index buffers via `bgfx_create_index_buffer` to match the engine's rendering constraints.

### Material Processing in material_load

The `material_load()` function extracts GLTF PBR parameters including base-color, metallic/roughness, normal, occlusion, and emissive properties. It resolves texture paths relative to the model file's directory and loads them using `load_texture()` from [`equilibrium/utils/bgfx_utils.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/utils/bgfx_utils.h).

## Loading Your First Custom Model

To integrate a custom model, place your asset files in the repository and invoke the loader from a system.

First, place your model and associated textures in a directory such as `assets/models/MyCharacter/character.gltf`.

Next, modify the bootstrap system or create a custom loader. The reference implementation in [`launcher/sandbox/bootstrap_system.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/launcher/sandbox/bootstrap_system.c) (line 13) demonstrates the invocation pattern:

```c
// launcher/sandbox/bootstrap_system.c
#include "utils/assimp_utils.h"

static void Bootstrap(ecs_iter_t *it) {
    /* Load a custom GLTF model */
    if (!assimp_scene_load("assets/models/MyCharacter/character.gltf", it->world)) {
        ecs_err("Failed to load character model");
    }
    
    /* Additional scene setup (lights, camera) continues here */
}

```

The `assimp_scene_load()` function returns a boolean indicating success. Upon completion, the engine contains new ECS entities representing your model's hierarchy, each equipped with renderable components.

## Customizing the Import Behavior

The default configuration enforces specific constraints optimized for the engine's rendering pipeline. You can modify these behaviors by editing [`equilibrium/utils/assimp_utils.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/utils/assimp_utils.h).

### Modifying Import Flags

The loader configures Assimp's property store with `aiSetImportPropertyInteger` to enforce triangle-only geometry and 16-bit index limits. To change these constraints—for example, to enable explicit triangulation or UV flipping—adjust the `flags` variable passed to `aiImportFileExWithProperties` around lines 11-22:

```c
// In assimp_scene_load() - modify the flags parameter
unsigned int flags = aiProcess_Triangulate | 
                     aiProcess_FlipUVs | 
                     aiProcess_CalcTangentSpace;

```

### Extending Vertex Attributes

To support additional vertex data such as vertex colors or multiple UV sets, extend the `PosNormalTangentTexcoordVertex` struct and modify `group_load()` to copy the new data. You must also update the BGFX vertex layout using `bgfx_vertex_layout_add()` to describe the new attribute offsets and types.

### Custom Texture Search Paths

By default, `material_load()` constructs texture paths by concatenating the model's directory (`dir`) with texture filenames. If your pipeline stores textures in a separate location, modify the path construction logic in `material_load()` (lines 88-110) to prepend your asset root or implement a custom resolution scheme.

## Key Source Files and Functions

| File | Purpose | Key Functions |
|------|---------|---------------|
| [`equilibrium/utils/assimp_utils.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/utils/assimp_utils.h) | Core import implementation | `assimp_scene_load()`, `material_load()`, `group_load()` |
| [`launcher/sandbox/bootstrap_system.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/launcher/sandbox/bootstrap_system.c) | Example integration point | `Bootstrap()` system demonstrating loader invocation |
| `cmake/assimp-config.cmake` | Build configuration | Assimp include directories and library linking |
| [`equilibrium/utils/bgfx_utils.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/utils/bgfx_utils.h) | Texture loading utilities | `load_texture()` for BGFX texture handle creation |

## Summary

- **Use `assimp_scene_load()`** from [`equilibrium/utils/assimp_utils.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/utils/assimp_utils.h) to import GLTF, OBJ, FBX, and other Assimp-supported formats.
- The loader automatically creates ECS entities with **Mesh** and **Material** components backed by BGFX GPU buffers using 16-bit indices.
- **Modify `assimp_scene_load()`** to change import flags for triangulation, UV flipping, or coordinate system conversion.
- **Customize `group_load()`** and `PosNormalTangentTexcoordVertex` to support additional vertex attributes beyond the default position/normal/tangent/UV layout.
- The CMake configuration in `cmake/assimp-config.cmake` handles all third-party linking requirements; no additional build setup is required.

## Frequently Asked Questions

### Does Equilibrium Engine support FBX and OBJ files, or only GLTF?

Yes. Because the integration uses the Assimp library, it supports any format Assimp can parse, including FBX, OBJ, Collada, and glTF. Simply provide the correct file extension in the path argument to `assimp_scene_load()`; no code changes are required to support different formats.

### How are textures loaded when importing a model?

The `material_load()` function extracts texture filenames from the `aiMaterial` and resolves them relative to the model file's directory using the `dir` variable. It then calls `load_texture()` to create BGFX texture handles. If textures reside in a different directory structure, modify the path concatenation logic in `material_load()` around lines 88-110 of [`assimp_utils.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/assimp_utils.h).

### What entity hierarchy is created for imported models?

For each mesh in the Assimp scene, `assimp_scene_load()` creates a distinct ECS entity with a `Mesh` component containing the geometry groups. If the mesh references a material with textures, a `Material` component is also attached. The function preserves the scene's transform hierarchy, creating parent-child relationships between entities as defined in the source file.

### Why does the loader enforce 16-bit indices and triangle-only geometry?

The engine uses 16-bit index buffers for memory efficiency and compatibility with mobile GPU architectures. The `aiSetImportPropertyInteger` calls in `assimp_scene_load()` configure Assimp to split meshes exceeding 65535 vertices and to reject non-triangle primitives. These constraints ensure the resulting geometry can be rendered directly by the engine's BGFX-based pipeline without runtime conversion.