Skip to content

fix(flame_3d): Invalidate the AABBs of nested components when an ancestor moves - #4167

Merged
ufrshubham merged 4 commits into
mainfrom
devkage/fix-3d-aabb-on-ancestor-move
Oct 31, 2026
Merged

ufrshubham merged 4 commits into
mainfrom
devkage/fix-3d-aabb-on-ancestor-move

Conversation

@ufrshubham

@ufrshubham ufrshubham commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

Description

When the transform of a Component3D changed, only the world transform dirty flag was propagated down to its descendants, while the AABB dirty flag was only propagated up. The descendants kept the AABB cached for their old world position, so they were frustum culled based on where they used to be. This affected regular MeshComponents and ModelComponents inside any group that moves.

This PR marks the AABB dirty together with the world transform when propagating down the subtree in _markWorldTransformDirty, and marks the parent's AABB dirty from _onTransformChanged (calling markAabbDirty() on the component itself would now return early, since the downward propagation already marked it).

The early return in _markWorldTransformDirty now only happens when both flags are already dirty, since the world transform and the AABB are recomputed independently and one can be dirty while the other is not. This relies on a recomputed AABB also refreshing the world transforms of its ancestors, which holds for every component with geometry. A component without geometry or children still uses its local position for its AABB (#4165), so it doesn't depend on its ancestors yet, and it will once that is fixed.

The tests cover a nested child, a deeply nested child and repeated moves where only the leaf is read in between, which exercises that early return. All of them fail without the fix. I also verified the fix with the repro from #4163 on Windows.

before_4167_annotated.mp4
after_4167_annotated.mp4

Checklist

  • I have followed the Contributor Guide when preparing my PR.
  • I have updated/added tests for ALL new/updated/fixed functionality.
  • I have updated/added relevant documentation in docs and added dartdoc comments with ///.
  • [-] I have updated/added relevant examples in examples or docs.

Breaking Change?

  • Yes, this PR is a breaking change.
  • No, this PR is not a breaking change.

Related Issues

Closes #4163

…stor moves

When a Component3D's transform changed, only the world transform dirty flag
was propagated down to its descendants, while the AABB dirty flag was only
propagated up. Descendants kept the AABB cached for their old world position
and were frustum culled based on it.

The AABB is now marked dirty together with the world transform when
propagating down the subtree, and the parent's AABB is marked dirty from the
component whose transform changed.
@ufrshubham ufrshubham self-assigned this Oct 29, 2026
@ufrshubham
ufrshubham merged commit 423a2e4 into main Oct 31, 2026
9 checks passed
@ufrshubham
ufrshubham deleted the devkage/fix-3d-aabb-on-ancestor-move branch October 31, 2026 16:09
ufrshubham added a commit that referenced this pull request Oct 31, 2026
…or removed (#4180)

A `Component3D`'s AABB is the hull of its own geometry and the AABBs of
its children, but adding or removing a child didn't invalidate the
parent's cached AABB. `Object3D.renderTree` culls a component together
with its whole subtree using its AABB, so a child added inside the view
was never rendered when the parent's cached AABB was outside of it, for
example a spawner or pool that adds children to itself at runtime.

This PR marks the parent's AABB as dirty when a component is mounted, so
new children are included in it. It does the same when a component is
removed, which isn't visible but keeps the parent's AABB from staying
bigger than its children. Marking stops at the first ancestor that is
already dirty and the AABB is only recomputed lazily, so this costs the
same as a child moving, which already marks its ancestors dirty.

The tests cover a child added to a parent, a child added deeper in the
hierarchy and a child being removed, and all of them fail without the
fix. I also verified the fix with the repro from #4164 on Windows.

This PR is stacked on top of #4167, as both add the same test file. It
will be retargeted to `main` once #4167 is merged.


https://github.com/user-attachments/assets/9630091a-7c4c-43e9-aea4-68fdbcf92e2b


https://github.com/user-attachments/assets/2751d5e7-8c61-4acb-8ea7-e540fc899c70
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[flame_3d] Nested components are culled at their old position after an ancestor moves

2 participants