bevyengine / bevyengine/bevy

`DebugUiPlugin` does not handle node with custom transform correctly

Open
#12,576 1 comment 0 reactions 0 assignees View on GitHub
A-Dev-Tools A-UI C-Bug
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 22h
Merged PRs (30d)
161

Description

## Bevy version
main

## What you did
Example code, note that the second box has a transform.
```
commands.spawn(NodeBundle {
style: Style {
width: Val::Px(100.0),
height: Val::Px(100.0),
..default()
},
background_color: Color::WHITE.into(),
..default()
});
commands.spawn(NodeBundle {
style: Style {
width: Val::Px(100.0),
height: Val::Px(100.0),
..default()
},
transform: Transform::from_scale(Vec3::splat(2.)),
background_color: Color::WHITE.into(),
..default()
});
```
## What went wrong
The outline of the second box does not display correctly. It should be scaled with the box.
Here is how it should be
![image](https://github.com/bevyengine/bevy/assets/33456881/f4bd1265-24ab-43d3-b9b9-0d56b715eef0)
But on main, it like this
![image](https://github.com/bevyengine/bevy/assets/33456881/e0ffa8c7-37ea-46d4-b877-b3400ea855f2)
## Additional information
- This can be fixed by handling the transform when drawing the outline with the change below. ~~However, the real problem might be in the [ui_layout_system](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/layout/mod.rs#L272) that it does not update the `Node.calculated_size` correctly~~

Code

```diff
--- a/crates/bevy_dev_tools/src/debug_overlay/mod.rs
+++ b/crates/bevy_dev_tools/src/debug_overlay/mod.rs
@@ -14,7 +14,7 @@ use bevy_render::{
prelude::*,
view::{RenderLayers, VisibilitySystems},
};
-use bevy_transform::{prelude::GlobalTransform, TransformSystem};
+use bevy_transform::{components::Transform, prelude::GlobalTransform, TransformSystem};
use bevy_ui::{DefaultUiCamera, Display, Node, Style, TargetCamera, UiScale};
use bevy_utils::{default, warn_once};
use bevy_window::{PrimaryWindow, Window, WindowRef};
@@ -37,10 +37,15 @@ struct LayoutRect {
}

impl LayoutRect {
- fn new(trans: &GlobalTransform, node: &Node, scale: f32) -> Self {
+ fn new(
+ global_transform: &GlobalTransform,
+ node: &Node,
+ node_transform: &Transform,
+ scale: f32,
+ ) -> Self {
let mut this = Self {
- pos: trans.translation().xy() * scale,
- size: node.size() * scale,
+ pos: global_transform.translation().xy() * scale,
+ size: node.size() * node_transform.scale.truncate() * scale,
};
this.pos -= this.size / 2.;
this
@@ -120,12 +125,18 @@ fn update_debug_camera(
}

/// The function that goes over every children of given [`Entity`], skipping the not visible ones and drawing the gizmos outlines.
-fn outline_nodes(outline: &OutlineParam, draw: &mut InsetGizmo, this_entity: Entity, scale: f32) {
+fn outline_nodes(
+ outline: &OutlineParam,
+ draw: &mut InsetGizmo,
+ this_entity: Entity,
+ node_transform: &Transform,
+ scale: f32,
+) {
let Ok(to_iter) = outline.children.get(this_entity) else {
return;
};

- for (entity, trans, node, style, children) in outline.nodes.iter_many(to_iter) {
+ for (entity, global_transform, node, style, children) in outline.nodes.iter_many(to_iter) {
if style.is_none() || style.is_some_and(|s| matches!(s.display, Display::None)) {
continue;
}
@@ -135,10 +146,10 @@ fn outline_nodes(outline: &OutlineParam, draw: &mut InsetGizmo, this_entity: Ent
continue;
}
}
- let rect = LayoutRect::new(trans, node, scale);
+ let rect = LayoutRect::new(global_transform, node, node_transform, scale);
outline_node(entity, rect, draw);
if children.is_some() {
- outline_nodes(outline, draw, entity, scale);
+ outline_nodes(outline, draw, entity, node_transform, scale);
}
draw.clear_scope(rect);
}
@@ -181,6 +192,7 @@ fn outline_roots(
Entity,
&GlobalTransform,
&Node,
+ &Transform,
Option<&ViewVisibility>,
Option<&TargetCamera>,
),
@@ -209,7 +221,9 @@ fn outline_roots(
.map_or(2., |(config, _)| config.line_width)
/ window_scale;
let mut draw = InsetGizmo::new(draw, cam.debug_camera, line_width);
- for (entity, trans, node, view_visibility, maybe_target_camera) in &roots {
+ for (entity, global_transform, node, node_transform, view_visibility, maybe_target_camera) in
+ &roots
+ {
if let Some(view_visibility) = view_visibility {
// If the entity isn't visible, we will not draw any lines.
if !view_visibility.get() {
@@ -240,9 +254,9 @@ fn outline_roots(
}
}

- let rect = LayoutRect::new(trans, node, scale_factor);
+ let rect = LayoutRect::new(global_transform, node, node_transform, scale_factor);
outline_node(entity, rect, &mut draw);
- outline_nodes(&outline, &mut draw, entity, scale_factor);
+ outline_nodes(&outline, &mut draw, entity, node_transform, scale_factor);
}
}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.