# What Is the Role of the Scene Graph in ArmorPaint?

> Discover the crucial role of the scene graph in ArmorPaint. Learn how this hierarchical structure manages 3D objects, cameras, and materials for efficient editing and rendering.

- Repository: [Armory 3D/armorpaint](https://github.com/armory3d/armorpaint)
- Tags: deep-dive
- Published: 2026-09-13

---

**The scene graph in ArmorPaint serves as the central hierarchical data structure that stores all 3D objects, cameras, materials, and environmental resources, enabling transform propagation, rendering coordination, scene editing, and project serialization.**

ArmorPaint relies on Armory3D's core engine to manage its 3D painting environment through a robust **scene graph** architecture. Defined primarily in [`base/sources/engine.h`](https://github.com/armory3d/armorpaint/blob/main/base/sources/engine.h), this system organizes every drawable element into a tree structure that drives real-time rendering and editing operations. Understanding the `scene_t` implementation reveals how the software maintains coherent spatial relationships and resource management during texture painting workflows.

## Core Architecture of the Scene Graph

At the heart of ArmorPaint's engine lies the `scene_t` structure, which acts as the root container for all scene data.

### The scene_t Container

According to the **armory3d/armorpaint** source code, the `scene_t` structure (located in [`base/sources/engine.h`](https://github.com/armory3d/armorpaint/blob/main/base/sources/engine.h)) maintains arrays of every asset type within a project:

- **Objects** (`obj_t[]`) – Each entry represents a node in the hierarchy
- **Meshes, cameras, materials, shaders** – Referenced resources attached to objects
- **World data** – Environmental and lighting information

### Hierarchical Object Relationships

Individual scene nodes are represented by `object_t` structures that contain a **transform_t** component, a parent reference, and a list of children. These links form a tree hierarchy where child objects inherit their parent's coordinate space. The engine provides dedicated functions such as `object_set_parent()` and `object_get_child()` to manipulate these relationships programmatically.

## Key Responsibilities of the Scene Graph

The hierarchical structure enables five critical architectural functions throughout the application.

### Transform Propagation

Child objects automatically inherit parent transformations through the `transform_update()` and `transform_build_matrix()` functions. When `object_set_parent()` re-links an object into a new branch of the tree, calling `transform_update()` recalculates the world matrix for that node and its descendants. This ensures that moving a parent container (like an empty group) correctly repositions all attached meshes without requiring manual updates to each child.

### Rendering Order and Culling

The main render loop in [`paint/sources/viewport.c`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/viewport.c) traverses `scene->objects` to submit geometry to the GPU. Before drawing, the engine applies **frustum culling** to eliminate objects outside the camera's view, improving performance in complex scenes. The active camera reference (`scene_camera`) and world data (`scene_world`) are singletons stored directly in the scene structure, ensuring consistent rendering parameters across all objects.

### Scene Editing and Tool Integration

UI tools and editing features interact with the graph through helper functions like `scene_get_child(".Gizmo")` or `scene_spawn_object(".Sphere", NULL, true)`. These calls retrieve existing nodes or instantiate new ones within the hierarchy, allowing gizmos, selection outlines, and procedural primitives to coexist with imported models. The naming convention using dot-prefixed strings (e.g., `.Gizmo`) identifies special engine objects versus user content.

### Resource Sharing

The scene graph centralizes shared resources through reference counting. The `camera_ref` and `world_ref` fields point to active environment data, while materials and shaders reside in arrays accessible to all objects. This design allows multiple mesh objects to reference the same material instance while maintaining independent transforms.

### Serialization and Import/Export

When saving projects, `util_encode_scene()` in [`paint/sources/util/util_encode.c`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/util/util_encode.c) serializes the entire graph structure to disk. Import plugins for **GLTF** ([`io_gltf/cgltf.h`](https://github.com/armory3d/armorpaint/blob/main/io_gltf/cgltf.h)) and **FBX** ([`io_fbx/ufbx/ufbx.h`](https://github.com/armory3d/armorpaint/blob/main/io_fbx/ufbx/ufbx.h)) parse external files into temporary `scene_t` structures before merging them into the active scene, preserving the original hierarchy from 3D modeling software.

## Practical Examples

The following C patterns demonstrate common scene graph operations in ArmorPaint's codebase.

Finding and manipulating the transform gizmo:

```c
object_t *gizmo = scene_get_child(".Gizmo");
if (gizmo) {
    transform_set_matrix(gizmo->transform, mat4_identity());
}

```

Re-parenting objects to establish new hierarchical relationships:

```c
object_t *child = scene_get_child(".Sphere");
object_t *new_parent = scene_get_child(".Plane");
if (child && new_parent) {
    object_set_parent(child, new_parent);
    transform_update(child->transform);
}

```

Iterating over all objects for game logic or culling:

```c
for (i32 i = 0; i < scene->objects->length; ++i) {
    object_t *obj = ((object_t **)scene->objects->buffer)[i];
    /* Perform frustum culling or UI highlighting */
}

```

Spawning new mesh objects at runtime:

```c
object_t *new_obj = scene_spawn_object(".Sphere", NULL, true);
if (new_obj) {
    new_obj->material = find_material("Default");
    transform_set_matrix(new_obj->transform, mat4_translation(vec3(0, 0, -2)));
}

```

## Summary

- The **scene_t** structure in [`base/sources/engine.h`](https://github.com/armory3d/armorpaint/blob/main/base/sources/engine.h) acts as the root container for all 3D data in ArmorPaint, organizing objects into a hierarchical tree via `object_t` nodes.
- **Transform propagation** relies on parent-child links updated through `object_set_parent()` and `transform_update()`, ensuring inherited coordinate spaces.
- The rendering pipeline in [`paint/sources/viewport.c`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/viewport.c) traverses the object array to submit meshes to the GPU while applying frustum culling for performance optimization.
- Editing tools utilize `scene_get_child()` and `scene_spawn_object()` to manipulate the graph directly, supporting gizmos, selection, and procedural generation.
- **Serialization** through [`util_encode.c`](https://github.com/armory3d/armorpaint/blob/main/util_encode.c) and import plugins (GLTF/FBX) enables persistent project storage and interoperability with external 3D applications.

## Frequently Asked Questions

### What data structure defines the scene graph in ArmorPaint?

The **scene_t** structure defined in [`base/sources/engine.h`](https://github.com/armory3d/armorpaint/blob/main/base/sources/engine.h) serves as the primary container. It holds arrays of objects, meshes, cameras, materials, and world data, along with references to the active camera (`scene_camera`) and environment (`scene_world`).

### How does ArmorPaint handle parent-child transform relationships?

Each `object_t` maintains a **transform_t** component and pointers to its parent and children. When `object_set_parent()` modifies the hierarchy, `transform_update()` recalculates the object's world matrix by combining its local transform with the parent's transformation, propagating changes down the tree.

### Where does the engine traverse the scene graph during rendering?

The main rendering loop resides in [`paint/sources/viewport.c`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/viewport.c), where the code iterates over `scene->objects` to process each `object_t`. Before submission to the GPU, the engine performs frustum culling against the active `scene_camera` to determine visibility.

### Can ArmorPaint import scene graphs from external 3D formats?

Yes. Import plugins located in `paint/plugins/io_gltf/` and `paint/plugins/io_fbx/` parse external files into temporary `scene_t` structures. These plugins preserve hierarchical relationships from the source files, allowing complex models with existing parent-child groupings to be used directly within ArmorPaint's painting environment.