-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Add a viewport UI widget #17253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a viewport UI widget #17253
Conversation
d9fd0cc
to
8e2ebb3
Compare
f9181aa
to
8e43dde
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code wise seems good to me, just needs updating to deal with conflicts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The demo works really well, just think the UI side can be simplified a bit.
The image should just be shown on the viewport node, the child node isn't necessary I think. And instead of using an ImageNode
, you can add an extraction system to the UI extraction schedule like:
pub fn extract_viewport_nodes_system(
mut commands: Commands,
mut extracted_uinodes: ResMut<ExtractedUiNodes>,
camera_query: Extract<Query<&Camera>>,
uinode_query: Extract<
Query<(
Entity,
&ComputedNode,
&GlobalTransform,
&InheritedVisibility,
Option<&CalculatedClip>,
Option<&UiTargetCamera>,
&ViewportNode,
)>,
>,
camera_map: Extract<UiCameraMap>,
) {
let mut camera_mapper = camera_map.get_mapper();
for (entity, uinode, transform, inherited_visibility, clip, camera, viewport_node) in
&uinode_query
{
// Skip invisible images
if !inherited_visibility.get() || uinode.is_empty() {
continue;
}
let Some(extracted_camera_entity) = camera_mapper.map(camera) else {
continue;
};
let Some(image) = camera_query
.get(viewport_node.camera)
.ok()
.and_then(|camera| camera.target.as_image())
else {
continue;
};
extracted_uinodes.uinodes.push(ExtractedUiNode {
render_entity: commands.spawn(TemporaryRenderEntity).id(),
stack_index: uinode.stack_index,
color: LinearRgba::WHITE,
rect: Rect {
min: Vec2::ZERO,
max: uinode.size,
},
clip: clip.map(|clip| clip.clip),
image: image.id(),
extracted_camera_entity,
item: ExtractedUiItem::Node {
atlas_scaling: None,
transform: transform.compute_matrix(),
flip_x: false,
flip_y: false,
border: uinode.border(),
border_radius: uinode.border_radius(),
node_type: NodeType::Rect,
},
main_entity: entity.into(),
});
}
}
Then there's no need for the user to pass in the image handle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to my inexperienced eyes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy enough with this to start experimenting with it.
It looks like your PR has been selected for a highlight in the next release blog post, but you didn't provide a release note. Please review the instructions for writing release notes, then expand or revise the content in the release notes directory to showcase your changes. |
Kicked this back to Just a basic draft is fine. You may also want to consider linking to the video, so that it's easy to find and embed later (do not commit the video to the repo).
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Don't see any further problems, eager to see this merged.
Release notes are in! Marking this as |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Release notes look good.
Objective
Add a viewport widget.
Solution
ViewportNode
component to turn a UI node into a viewport.viewport_picking
to pass pointer inputs from other pointers to the viewport's pointer.update_viewport_render_target_size
to update the viewport node's render target's size if the node size changes.bevy_ui_picking_backend
.Testing
I've been using an example I made to test the widget (and added it as
viewport_node
):Code
Showcase
2025-01-11.13-49-15.mp4
Open Questions
Not sure whether the entire widget should be feature gated behindbevy_ui_picking_backend
or not? I chose a partial approach since maybe someone will want to use the widget without any picking being involved.IsPickSet::Last
the expected set forviewport_picking
? PerhapsPickSet::Input
is more suited.Candragged_last_frame
be removed in favor of a better dragging check? Another option that comes to mind is readingDrag
andDragEnd
events, but this seems messier.