Monograph · 02 · Scene & ECS
Foundations · deep dive
Scene & ECS
How a world is represented before Vulkan: actors, components, loaders, physics attachment, and the hand-off when the renderer uploads. After this, “scene” is not a vague bag of meshes.
Scene lifecycle
- Scene(name) creates a root actor
"World", registers it, constructsPhysicsWorldwith default gravity (0,−9.81,0) - Examples/tools call
createActor/ load models into actors initialize()walks all actors → each componentinitialize()- Per-frame: optional physics
step, actorupdate, then renderer reads components destroy/ removeActor unregisters hierarchy and tears down components
Lookups: by id, by exact name, by partial name, by tag. Maps: actors (id) and actorsByName.
Actor & component workflow
Every Actor is a SceneObject with hierarchy (parent/children) and a component bag. Constructor always installs a TransformComponent.
Renderer queries components; physics binds through PhysicsComponent into the scene’s world.
- initialize — each component + children
- start — first-frame hooks
- update(dt) — logic; transform may be written by physics
- render — rarely used for GPU draw; visual path is renderer-driven
- destroy — reverse teardown
A light does not need a mesh; a static prop does not need a rigid body. Composition keeps loaders and the renderer generic: “for each MeshComponent, upload…”.
Asset load workflow
- Detect format (extension / header)
- GLTF/GLB → tinygltf: nodes, primitives, metallic-roughness, embedded images
- FBX/… → Assimp: meshes, materials, embedded textures
- OBJ → custom parser + texture folder heuristics; filter alpha-card junk materials
- Build CPU
Model/ mesh data; create or fill Mesh + Material components on actors - Auto up-axis fix (Y vs Z) so DamagedHelmet-class assets stand correctly
- Per-triangle material IDs for multi-material meshes (RT needs them)
Loaders do not touch Vulkan. GPU upload is a later phase owned by Ch. 03.
Physics attachment
Scene owns one PhysicsWorld. Attaching simulation: add PhysicsComponent, configure shape/body type, register with the world. Each step, transforms can write back so rendering sees motion. Details in Ch. 11.
Hand-off to renderer
Contract at the boundary:
- Scene pointer is stable for the frame
- MeshComponent → positions/indices/UVs/normals available on CPU (or already uploaded handles)
- MaterialComponent → PBR params + logical texture names/indices
- LightComponent → typed lights for UBO/SSBO packing
- Transform → world matrix for TLAS instances and model matrices
Scene never includes vulkan.h
Keeps unit tests and tools able to build scenes without a GPU. The renderer is the only Vulkan citizen for visual data.
Files
scene/scene.*Ownership, physics world, initializeactor/actor.*Hierarchy + componentscomponent/*Transform mesh material lightasset/model_*.cppGLTF / FBX / OBJcomponent_factory.*Primitive actor kitsDesign units in this module
Each card is a focused design page (what / how / why + sources). Full tree: Sitemap.
Actors & hierarchy
Actor as SceneObject with parent/children and lifecycle.
Components
Mesh, Material, Light, Transform, factory packs.
Asset loaders
GLTF (tinygltf), FBX (Assimp), OBJ custom, primitives.
Scene API
createActor, lookup, tags, physics world ownership, serialize hooks.
Transform math
TRS composition and world matrix used by upload/TLAS.