Repository navigation
Why the scene graph is an array
Scene holds every node in one flat array, and each node records its parent's index. three.js holds a tree of objects that own their children. Mojo cannot express that tree, and the array turned out better.

three.js gives every Object3D a children array. In Mojo a struct cannot hold a List of its own type. The compiler rejects it with field 'children' has non-'Deinitable' type.
So the tree is stored the other way round. A node knows its parent. The scene owns the array.
A node's id is its place in the array. The id never changes, because every mesh, light, bone and animation track names its node by id.
The order of the tree is kept beside the array. The scene lists every node in the order it became a child, which is the order of three.js's children. update walks the tree from the roots in that order. A parent is therefore always final before its children, whatever the ids. So a node can move under a node that was added after it.
add and attach refuse a parent that is the node or under it. A reference from scene.node(id) can still set any parent. A node on a loop cannot be reached from a root. So update counts the nodes it reaches, and it raises when some are missing.
three.js's remove gives an object no parent, and something else can still hold that object. Here the scene holds every node, so a removed node stays in the array with a mark. It keeps its id, so nothing that names it goes wrong. The renderer, the raycaster, the mixer and the exporters skip it. The cost is that the array only grows.
update caches every world matrix. Any edit to a node marks the scene stale, and world_matrix raises until update runs again. Recomputing on read would hide the cost of a render. Serving the stale value would produce a plausible wrong image with no error at all.
three.js's scene.add takes a mesh or a light. Here add_mesh and add_light do the same. Both name a node by id and hold no transform. A light parented to a turning object moves with it, which a light stored on the renderer could not do.
scene.node(id) returns a mutable reference and marks the scene stale. That is what mesh.rotation.y += 0.01 needs in three.js terms: one persistent scene, one field changed, one update, one render.
Tutorials
How-to
Reference
- Scene graph
- Rotations
- Cameras
- Geometry
- Geometry addons
- Lofts and clipping groups
- Sculptor
- Procedural generators
- Meshes and assets
- Lines
- Points and sprites
- Helpers
- Scene objects
- Animated objects
- Raycasting
- Curves and paths
- Animation
- Skinning
- Materials
- Node materials
- TSL functions
- Lights
- Lighting addons
- Fog
- Textures
- Renderer
- Renderer hooks and material flags
- Rasterization
- GPU backend
- Render target
- Post-processing
- GPU computation
- Compute nodes
- Progressive light map
- Gaussian splats
- Voxel global illumination
- SVG renderer
- Image files
- Image decode queue
- Model files
- More model files
- Exporters
- Scene JSON
- Windowing and controls
- Math
- Norm consumers
- Math addons
- Units
- Coverage tool
- Commands
- Examples
- Benchmarks
- Extensions
- Shared physics
- Physics query snapshots
- Continuous collision
- Tick force restoration
- Water
- Animals
- Buildings
- CARLA
- Femur
- Tibia
- Fibula
- Patella
- Knee
- Muscles
- Vessels
- Lymph
- Nerves
- Integument
- Leg
- Foot
- Pelvis
- Torso
- Arm
- Hand
- Head
- Genome
- Game humanoid
- Humanoid fidelity
- Audio-aligned game faces
- Converted assets
- Mesh quality
- Segment inertia
Explanation
- Software rasterizer
- Scene graph as an array
- Linear color
- Normals are not colors
- Perspective correction
- Fixed-point coverage
- Per-fragment shading
- Mipmaps
- Sorted transparency
- Types and checks
- Render hooks as a trait
- Shared CPU and GPU code
- Bands and threads
- PNG structure
- Extensions beside the port
- CUDA teardown hang
- Mojo compiler hang