# Animated vs Static Model Components in Pyrite64: Data Structures and Build Pipeline Integration

> Discover the differences between animated and static model components in Pyrite64. Understand data structures, build pipeline integration, and runtime costs for your game assets.

- Repository: [Max Bebök/pyrite64](https://github.com/hailtododongo/pyrite64)
- Tags: deep-dive
- Published: 2026-02-19

---

**Animated model components store skeleton hierarchies and animation clips requiring GPU skinning buffers, while static model components store only pre-baked vertex data, resulting in fundamentally different build pipeline stages and runtime costs.**

The **pyrite64** engine distinguishes between animated and static geometry through its component registration system. While both implement the same `CompInfo` interface defined in [`src/project/component/components.h`](https://github.com/HailToDodongo/pyrite64/blob/main/src/project/component/components.h), their data structures, build pipeline integration, and runtime execution paths diverge significantly. Understanding these differences is critical for optimizing asset workflows and rendering performance in Nintendo 64-style development.

## Component Registration and Metadata

Both component types register through the master component table in [`src/project/component/components.h`](https://github.com/HailToDodongo/pyrite64/blob/main/src/project/component/components.h), but they occupy different IDs and invoke distinct function implementations.

The animated model component occupies entry **#10** with the display name `"Model (Animated)"`:

```cpp
CompInfo{
    .id   = 10,
    .icon = ICON_MDI_HUMAN " ",
    .name = "Model (Animated)",
    .funcInit        = AnimModel::init,
    .funcDraw        = AnimModel::draw,
    .funcDraw3D      = AnimModel::draw3D,
    .funcSerialize   = AnimModel::serialize,
    .funcDeserialize = AnimModel::deserialize,
    .funcBuild       = AnimModel::build,
};

```

Static mesh components typically register as `"Mesh Filter"` (ID 3) and bind to `MeshFilter` methods instead. Both entries share the same structure but point to different implementation files: [`src/project/component/shared/animModel.h`](https://github.com/HailToDodongo/pyrite64/blob/main/src/project/component/shared/animModel.h) for animated models and [`src/project/component/shared/meshFilter.h`](https://github.com/HailToDodongo/pyrite64/blob/main/src/project/component/shared/meshFilter.h) for static geometry.

## Data Structure Differences

The underlying C++ classes reflect the distinct requirements of skeletal animation versus rigid geometry.

### Animated Model Data Structures

The `AnimModel` class maintains a complex hierarchy required for skinning:

- **Skeleton data**: Bone hierarchy and bind poses
- **Animation clips**: Keyframe data for skeletal animation
- **Skinned vertex buffers**: Vertex data containing bone indices and weights
- **Per-frame bone matrices**: Uploaded each frame to uniform buffers or texture memory for GPU skinning

These structures require significantly more memory than static equivalents, as they must store both the mesh deformation data and the animation state.

### Static Model Data Structures

The `MeshFilter` class implements a lightweight storage model:

- **Static mesh data**: Vertex positions, normals, UV coordinates, and indices
- **Material reference**: Optional pointer to rendering material
- **Static vertex buffer**: GPU buffer created once at build time

No bone data or per-frame transform buffers exist in this implementation, resulting in lower memory overhead and simpler cache patterns.

## Build Pipeline Integration

The asset build pipeline, orchestrated through [`src/utils/toolchain.cpp`](https://github.com/HailToDodongo/pyrite64/blob/main/src/utils/toolchain.cpp), treats these components differently when executing `CompInfo::funcBuild` callbacks.

### Animated Model Build Process

When the toolchain encounters an animated model, `AnimModel::build` performs three critical steps:

1. **Skeleton parsing**: Extracts bone hierarchy from source assets (e.g., glTF, FBX)
2. **Skinning buffer generation**: Creates bone-matrix textures or uniform buffer objects (UBOs) for runtime skinning
3. **Binary export**: Generates `.skel` and `.anim` files alongside the mesh data

The [`src/utils/meshGen.cpp`](https://github.com/HailToDodongo/pyrite64/blob/main/src/utils/meshGen.cpp) utility handles the vertex buffer generation for animated meshes, specifically adding bone-weight attributes to the vertex format that the static path omits.

### Static Model Build Process

Static models follow a simplified pipeline via `MeshFilter::build`:

1. **Mesh import**: Loads geometry files (OBJ, static glTF)
2. **Buffer generation**: Creates static vertex and index buffers
3. **Binary export**: Outputs only a `.mesh` file

No additional animation processing occurs, and the build step completes without generating skeleton or animation metadata.

## Runtime Execution and Performance

The divergence continues into the rendering loop through the `funcDraw` and `funcDraw3D` callbacks.

**Animated models** incur higher CPU and GPU costs. Each frame, `AnimModel::draw` updates bone matrices based on animation state, uploads these to GPU memory, and issues draw calls using skinned vertex buffers. The fragment shader performs matrix palette skinning, consuming additional ALU cycles.

**Static models** execute `MeshFilter::draw` with minimal overhead. The function binds the pre-baked vertex buffer and issues a single draw call. No per-frame matrix updates or vertex transformations occur on the GPU, resulting in optimal cache utilization and lower bandwidth requirements.

## Summary

- Both component types register through the `CompInfo` table in [`src/project/component/components.h`](https://github.com/HailToDodongo/pyrite64/blob/main/src/project/component/components.h), but bind to different function pointer implementations.
- **Animated models** use the `AnimModel` class to store skeletons, animation clips, and skinning buffers, while **static models** use `MeshFilter` to store only rigid vertex data.
- The build pipeline generates `.skel` and `.anim` files for animated components via `AnimModel::build`, whereas static components produce only `.mesh` files through `MeshFilter::build`.
- Runtime costs differ significantly: animated models require per-frame bone matrix updates and GPU skinning, while static models execute single draw calls with pre-baked geometry.

## Frequently Asked Questions

### How does the build pipeline know which processing steps to run for each component type?

The build pipeline iterates over the `CompInfo::funcBuild` function pointers defined in [`src/project/component/components.h`](https://github.com/HailToDodongo/pyrite64/blob/main/src/project/component/components.h). For component ID 10 (animated model), this pointer references `AnimModel::build`, which internally triggers skeleton parsing and skinning buffer generation. For static mesh components, the pointer references `MeshFilter::build`, which skips all animation-related processing and generates only static vertex buffers.

### Can a single entity contain both animated and static model components?

While technically possible through the component system architecture, this configuration is generally redundant. The `AnimModel` class already contains mesh data within its skinned vertex buffers. Static geometry that needs to attach to bones should be implemented as separate mesh sections within the same animated model asset rather than distinct components.

### What file formats does the animated model build pipeline output?

According to the implementation in [`src/utils/toolchain.cpp`](https://github.com/HailToDodongo/pyrite64/blob/main/src/utils/toolchain.cpp) and `AnimModel::build`, the pipeline exports three distinct binary formats: `.mesh` files containing the skinned vertex data, `.skel` files storing the bone hierarchy and bind poses, and `.anim` files containing the animation keyframe data. Static models export only the `.mesh` format.

### Why do animated models require specific vertex attributes that static models lack?

GPU skinning requires per-vertex bone influence data. During the build phase in [`src/utils/meshGen.cpp`](https://github.com/HailToDodongo/pyrite64/blob/main/src/utils/meshGen.cpp), animated model vertices include bone index and bone weight attributes (typically 4 bones per vertex) that static meshes omit. These attributes allow the vertex shader to blend transformation matrices from the bone matrix texture/UBO, enabling mesh deformation at runtime.