Fix CSG operations not respecting the top_level flag on child nodes#117657
Fix CSG operations not respecting the top_level flag on child nodes#117657ryevdokimov wants to merge 1 commit intogodotengine:masterfrom
top_level flag on child nodes#117657Conversation
kleonc
left a comment
There was a problem hiding this comment.
There are some issue with the gizmos. In the MRP from #117651 I've added another top level child (grandchild of root CSGShape3D). See it staying it the correct place, but the gizmo is at wrong spot until updated:
godot.windows.editor.x86_64_RlzXukvAxg.mp4
Also when having both top level shapes selected, the gizmo moves only the parent one shape. Shouldn't it move both, separately?
godot.windows.editor.x86_64_oVMFX1iTjo.mp4
| has_top_level_child = true; | ||
| break; | ||
| } | ||
| } |
There was a problem hiding this comment.
(it a comment for whole this loop)
Shouldn't this be cached? Usually there are probably no top level children, in which case this would needlessly iterate over all children. Seems like unnecessary overhead. On the other hand, trigerring NOTIFICATION_LOCAL_TRANSFORM_CHANGED on CSGShape3D is also probably an unusual case? 🤔
But I think adding virtual void _top_level_changed() to Node3D and calling it in Node3D::set_as_top_level should be fine (as changing top level is usually a one time thing so minimal overhead is not an issue there; also note a similar callback exists in CanvasItem (actually more complex as it's propagating to the children there)). Then CSGShape3D could have int top_level_child_shape_count = 0 member which would be incremented/decremented for the parent_shape on NOTIFICATION_PARENTED/NOTIFICATION_UNPARENTED, and in CSGShape3D::_top_level_changed override.
Then here you'd have if (top_level_child_shape_count > 0).
| transformed_brush.copy_from(*child_brush, child->get_transform()); | ||
| Transform3D child_xform; | ||
| if (child->is_set_as_top_level()) { | ||
| child_xform = get_global_transform().affine_inverse() * child->get_global_transform(); |
There was a problem hiding this comment.
That affine_inverse() could be potentially calculated only once. If going with the virtual void _top_level_changed() suggestion from the other comment it could be:
Transform3D global_transform_inverse;
if (top_level_child_shape_count > 0) {
global_transform_inverse = get_global_transform().affine_inverse();
}outside the loop, and here:
| child_xform = get_global_transform().affine_inverse() * child->get_global_transform(); | |
| child_xform = global_transform_inverse * child->get_global_transform(); |
Fixes: #117651
2026-03-19.17-56-13.mp4