Repository navigation
Description
Problem
Follow-up to #442. Slice 1 (cached local world matrix + self-validating dirty cache on TransformComponent::GetTransform()) shipped on feature/transform-world-matrix-cache. This issue tracks slice 2: the flat, depth-sorted hierarchy propagation pass that #442's proposal also called for.
While implementing slice 1 it was confirmed that the engine currently renders and queries every entity with its local transform — there is no parent→child world-matrix composition anywhere in Scene.cpp (no GetWorldTransform, no parent-chain walk in the render/submission paths). So this is net-new feature work, not merely an optimization of an existing on-demand walk.
Proposed approach
- Add a derived world-matrix cache (a parallel cache component, or a
mutableworld field alongside the local cache) that is not serialized — same runtime-only discipline as slice 1's local cache. - Once per frame, iterate entities in depth order over a flat array (not recursive per-entity pointer chasing over
RelationshipComponentlinks):world[child] = world[parent] * local[child], roots first. - Mark children dirty when a parent's local transform changes; only re-propagate dirty subtrees.
- Point world-transform consumers (rendering, physics sync, audio positioning, culling, AI) at the cached world matrix instead of the local
GetTransform().
Acceptance criteria
- Parented entities compose their parent's transform into their rendered/queried world matrix (a visible behavior change — children currently ignore parent transforms).
- World-matrix reads are O(1) cache hits within a frame; a deep-hierarchy profiling scene shows reduced transform-rebuild time.
- No change to serialized data / scene round-trip (world matrices stay derived-only).
- Visual verification per CLAUDE.md: screenshot a parented hierarchy from multiple angles, confirm children follow parents.
Notes
- Depends on nothing now that slice 1 has landed; slice 1's local-matrix cache is the natural per-entity
local[]input for the propagation. - Because it changes what parented entities render as, this is higher-risk than slice 1 and needs the rendering visual-verification loop, not just CPU/contract tests.
Score
capability: 5
craft: 2
stability: 3
decay: 2
effort: 5
confidence: 0.7
learning: 3
fun: 3
kano: performance
blocked_by: []
blocks: []
Rated per issue-scoring · score = confidence × (capability + craft + stability + decay) / effort, derived by the picker.
Activity
coderabbitai commentedon Jul 1, 2026
🔗 Related PRs
#100 - Feature/rendercommand_sorting [closed]
#199 - Add Quality Tiering System and Refactor Transform Component [closed]
#467 - feat(codegen): SceneSerializer blocks for AssetHandle/UUID-field components (
#451) [merged]#468 - feat(physics): wire Jolt HeightFieldShape into terrain collision (
#428) [merged]#483 - feat(net): generalize snapshot interpolation/reconciliation to a per-component policy registry (
#462) [merged]🧪 Issue enrichment is currently in open beta.
To disable automatic issue enrichment, add the following to your
.coderabbit.yaml:💬 Have feedback or questions? Drop into our discord!
drsnuggles8 commentedon Jul 5, 2026
Slice 1 shipped on
feature/flat-world-matrix-propagation(PR #562).What shipped — flat depth-sorted world-matrix propagation pass
Scene::PropagateWorldTransforms(): a flat BFS from root entities overRelationshipComponent, composing parent-chain world matrices in one linear sweep per tick (parents always written before children, not recursive per-entity pointer chasing). Result lands in a new runtime-onlyWorldTransformComponent(excluded from the scene-copy tuple / save-games / auto-serialization — same*StateComponentexclusion pattern used elsewhere).TransformComponent::GetTransform()(local space) directly. This is net-new behavior (as Perf/DOD: cache world matrix on TransformComponent (dirty flag) + flat hierarchy update pass #442 flagged), and it's now a visible, verified change: a rotated parent's child/grandchild render diagonally offset along the parent's rotated axis instead of ignoring it.SimulateRuntimeStep,OnUpdateSimulation,OnUpdateEditor), and migrated the primary render/debug-gizmo submission paths (2D sprites/circles/text, static + animated mesh, models, tile renderer, camera frustum + AABB gizmos) to read the composed world transform.Entity::GetWorldTransform()/Scene::GetWorldTransform(entt::entity)accessors, falling back to local transform if the pass hasn't run yet for an entity.WorldTransformPropagationTestFunctional tests (deep chains, rotation composition, re-parenting, un-parenting, dangling/destroyed-parent safety) + a new opt-in-assert perf benchmark (100k flat entities, 100k across 1000×100 chains) confirming linear scaling. Full suite green.Deferred — the rest of the original proposal
Leaving this issue open until those two follow-ups land; the acceptance criteria that matter most for a first slice (parented entities visibly compose parent transforms, verified with screenshots; O(N) linear-sweep propagation) are satisfied.
feat(scene): flat depth-sorted world-matrix propagation pass (#499)
drsnuggles8 commentedon Jul 6, 2026
Resolved by #562 (merged 2026-07-05):
Scene::PropagateWorldTransforms()adds the flat, depth-sorted BFS world-matrix propagation this issue asked for, wired into all three per-tick update paths, with 6 Functional tests + a 100k-entity benchmark and visual verification (rotated-parent composition confirmed in editor). All acceptance criteria met. Flagging for closure.drsnuggles8 commentedon Jul 6, 2026
Appears resolved by #562 (merged 2026-07-05): PR #562 ("Perf/DOD: flat depth-sorted hierarchy world-matrix propagation pass") — title matches this issue exactly and implements the proposed flat depth-order world-matrix propagation pass as slice 2 following #442's slice 1. Flagging for closure.
drsnuggles8 commentedon Jul 6, 2026
Closing — confirmed resolved by #562 (merged 2026-07-05).