Skip to content

Commit

Permalink
Fix bounding boxes
Browse files Browse the repository at this point in the history
Each time an AABB is rotated, it gets bigger. That means opposite rotations don't cancel out.

The previous implementation repeatedly rotates children AABBs as it climbs up the tree. This often resulted in selection boxes looking bigger than their contents.

This implementation calculates and applies a single final transformation to each AABB before it is merged with the others. After merging, there are no additional rotations, so AABBs remain accurate.

Co-Authored-By: Robert Yevdokimov <[email protected]>
  • Loading branch information
cooperra and ryevdokimov committed Feb 2, 2024
1 parent 10e1114 commit 30914c0
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 19 deletions.
35 changes: 17 additions & 18 deletions editor/plugins/node_3d_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2790,8 +2790,7 @@ void Node3DEditorViewport::_notification(int p_what) {
}

Transform3D t = sp->get_global_gizmo_transform();
VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(sp);
AABB new_aabb = vi ? vi->get_aabb() : _calculate_spatial_bounds(sp);
AABB new_aabb = _calculate_spatial_bounds(sp);

exist = true;
if (se->last_xform == t && se->aabb == new_aabb && !se->last_xform_dirty) {
Expand Down Expand Up @@ -4087,35 +4086,35 @@ Vector3 Node3DEditorViewport::_get_instance_position(const Point2 &p_pos) const
return world_pos + world_ray * FALLBACK_DISTANCE;
}

AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, bool p_exclude_top_level_transform) {
AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, const Node3D *p_top_level_parent) {
AABB bounds;

if (!p_top_level_parent) {
p_top_level_parent = p_parent;
}

if (!p_parent) {
return AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
}

Transform3D xform_to_top_level_parent_space = p_top_level_parent->get_global_transform().affine_inverse() * p_parent->get_global_transform();

const VisualInstance3D *visual_instance = Object::cast_to<VisualInstance3D>(p_parent);
if (visual_instance) {
bounds = visual_instance->get_aabb();
} else {
bounds = AABB();
}
bounds = xform_to_top_level_parent_space.xform(bounds);

for (int i = 0; i < p_parent->get_child_count(); i++) {
Node3D *child = Object::cast_to<Node3D>(p_parent->get_child(i));
if (child) {
AABB child_bounds = _calculate_spatial_bounds(child, false);

if (bounds.size == Vector3() && p_parent) {
bounds = child_bounds;
} else {
bounds.merge_with(child_bounds);
}
AABB child_bounds = _calculate_spatial_bounds(child, p_top_level_parent);
bounds.merge_with(child_bounds);
}
}

if (bounds.size == Vector3() && !p_parent) {
bounds = AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
}

if (!p_exclude_top_level_transform) {
bounds = p_parent->get_transform().xform(bounds);
}

return bounds;
}

Expand Down
2 changes: 1 addition & 1 deletion editor/plugins/node_3d_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ class Node3DEditorViewport : public Control {
Point2i _get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const;

Vector3 _get_instance_position(const Point2 &p_pos) const;
static AABB _calculate_spatial_bounds(const Node3D *p_parent, bool p_exclude_top_level_transform = true);
static AABB _calculate_spatial_bounds(const Node3D *p_parent, const Node3D *p_top_level_parent = nullptr);

Node *_sanitize_preview_node(Node *p_node) const;

Expand Down

0 comments on commit 30914c0

Please sign in to comment.