upstream: jackdaw transform gizmo#23435
Conversation
c12d861 to
cba6a4c
Compare
PatrickChodowski
left a comment
There was a problem hiding this comment.
I hope you don't mind review from common user :) I tried out this transform gizmo in my own project and I really like the design. I think separating the translation, rotation and scale is a very good idea.
I added some comments that I believe is useful feedback ( the Single camera especially surprised me in the beginning because in the project I have a general main camera but also another camera to get a depth texture)
Thank you for your work
|
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. |
Bevy explicitly encourages this! Thanks; this is really helpful feedback. |
Much appreciated for the review, I'll go through these and address them |
|
@PatrickChodowski I'm pretty sure I've addressed all your feedback, and all very valid! I've pushed the latest changes here if you want to take another look |
8c1ae4f to
5a2cbb6
Compare
PatrickChodowski
left a comment
There was a problem hiding this comment.
Thank you for the changes! It looks good to me. I have been using this gizmo last couple of days in my project and It feels good
|
I've added the release note as well, once CI is passing ready for a final review @alice-i-cecile :) |
| drag_state.axis = None; | ||
| drag_state.entity = None; | ||
| if config.confine_cursor { | ||
| cursor_opts.grab_mode = CursorGrabMode::None; |
There was a problem hiding this comment.
This isn't quite right: we need to be resetting the cursor grab mode to the previous state, not None. Caching this in a Local is probably the way.
| } | ||
|
|
||
| // End drag | ||
| if drag_state.active && mouse.just_released(MouseButton::Left) { |
There was a problem hiding this comment.
This is not robust enough: just_released events can be missed if focus is lost.
We need to be careful that the drag state doesn't persist indefinitely.
I can actually reproduce this bug by starting to drag, then Alt-Tabbing away.
| //! # use bevy_app::App; | ||
| //! # use bevy_gizmos::transform_gizmo::{TransformGizmoPlugin, TransformGizmoFocus}; | ||
| //! // 1. Add the plugin | ||
| //! // app.add_plugins(TransformGizmoPlugin); |
There was a problem hiding this comment.
I don't like this style where we comment out lines and no_run the doc test.
IMO simply using words is going to be clearer.
|
|
||
| /// Marker component for the camera the transform gizmo should use. | ||
| /// | ||
| /// If no camera has this component, the gizmo systems will silently do nothing. |
There was a problem hiding this comment.
This behavior kind of sucks. We should fallback more gracefully, using the only camera that exists, and then warning loudly if more than one are present and we need to choose.
| Scale, | ||
| } | ||
|
|
||
| /// Whether the gizmo operates in world or local space. |
There was a problem hiding this comment.
| /// Whether the gizmo operates in world or local space. | |
| /// Whether the gizmo transforms the object using world or local space axes. |
| /// Which manipulation mode the gizmo is in. | ||
| #[derive(Resource, Default, PartialEq, Eq, Clone, Copy, Debug, Reflect)] | ||
| #[reflect(Resource, Default)] | ||
| pub enum TransformGizmoMode { |
There was a problem hiding this comment.
There are a lot of resources here, which will almost always be accessed together. Could we cut this down to 2: TransformGizmoState and TransformGizmoSettings?
|
|
||
| let raw_delta = axis_dir * projected * scale; | ||
| let snapped_delta = match config.snap_translate { | ||
| Some(inc) => snap_vec3(raw_delta, inc), |
There was a problem hiding this comment.
We should only be snapping the axis that is being modified.
examples/gizmos/transform_gizmo.rs
Outdated
| )) | ||
| .observe(on_click_select); | ||
|
|
||
| // Sphere |
There was a problem hiding this comment.
There are a number of subtle interactions in this code WRT local vs global behavior and parenting.
I would prefer to swap the sphere and cylinder out for a compound object of some form.
| let scale = cam_dist * config.translate_sensitivity; | ||
|
|
||
| let raw_delta = axis_dir * projected * scale; | ||
| let snapped_delta = match config.snap_translate { |
There was a problem hiding this comment.
Is this correct? Shouldn't we be snapping the final coordinates, not the delta?
| )); | ||
| } | ||
|
|
||
| fn on_click_select( |
There was a problem hiding this comment.
This should have a quick filter for PointButton::Primary just to teach good practices.
| normal: Vec3, | ||
| radius: f32, | ||
| ) -> f32 { | ||
| const RING_SAMPLES: usize = 16; |
There was a problem hiding this comment.
| const RING_SAMPLES: usize = 16; | |
| const RING_SAMPLES: usize = 64; |
There was a problem hiding this comment.
We don't need to cheap out here.
examples/gizmos/transform_gizmo.rs
Outdated
| // Instructions | ||
| commands.spawn(( | ||
| Text::new( | ||
| "Click an object to select it\n1: Translate | 2: Rotate | 3: Scale | X: Toggle space", |
There was a problem hiding this comment.
We should just use the standard Blender hotkey shortcuts for these modes.
There was a problem hiding this comment.
i believe in blender it's 'S' to scale, but that conflicts with the free camera WASD movement right?
| commands.spawn(( | ||
| Text::new( | ||
| "Click an object to select it\n1: Translate | 2: Rotate | 3: Scale | X: Toggle space", | ||
| ), |
There was a problem hiding this comment.
"Toggle space" is unclear. "World/Local space" or something would be better.
This is all handled in bevy_transform_gizmo fwiw. 227469248-726b21c8-5308-49f0-9b04-e567833774e1.mp4Not saying we should upstream that instead, it is horribly out of date, but the math has already been written, we should do it correctly. |
oh sick, thank you i'll have a look at the math here |
|
Adding to Aevyrie's comments about prior art - I mentioned this on Discord as well but also mentioning on here for visibility. I think it's also worth checking out transform-gizmo. Its bevy integration is only slightly out of date (0.17). It is agnostic w.r.t. rendering and transforms, and the UX feels great (I think it's just like Blender's?) Being transform agnostic is pretty important for a gizmo like this IMO. |
|
https://github.com/8th-Boundary/bevy_transform_tools |
Objective
Upstream
jackdaw'sTransformGizmo!Solution
Add
TransformGizmoPluginto bevy_gizmos as an optional plugin that draws on a focused entity and lets the user click/drag to manipulate its transform. Rotate, Translate, and Scale are all individual gizmos - perfect opportunity for someone to extend and create a combined gizmo in a follow-up :)Testing
Showcase
Mark any entity with
TransformGizmoFocusto get interactive handles:The
transform_gizmoexample shows input cycling and keyboard mode switching (1/2/3 for translate/rotate/scale, X to toggle world/local space)Video
Jackdaw
gizmo_demo.mp4
Transform Example
bevy_transform_gizmo.mp4