From 0a6b4401f579d85de06e3a01366d0636d3175d7f Mon Sep 17 00:00:00 2001 From: Danny McGee Date: Wed, 11 Oct 2023 16:07:35 -0400 Subject: [PATCH] Refined rotator gizmo --- studio/src/interaction/gizmos.rs | 55 ++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/studio/src/interaction/gizmos.rs b/studio/src/interaction/gizmos.rs index 031884e..d3c57f0 100644 --- a/studio/src/interaction/gizmos.rs +++ b/studio/src/interaction/gizmos.rs @@ -1,3 +1,5 @@ +use std::f32::consts; + use bevy::{prelude::*, window::PrimaryWindow}; use crate::design_system; @@ -33,10 +35,10 @@ pub(super) fn draw( let dist = Vec3::distance(camera_xform.translation, xform.translation); if transform.contains(InteractionTransform::TRANSLATE) { - draw_translate_gizmo(&xform, &mut gizmos, space, dist / 14.); + draw_translate_gizmo(&xform, &mut gizmos, space, dist / 12.5); } if transform.contains(InteractionTransform::ROTATE) { - draw_rotate_gizmo(&xform, &mut gizmos, space, dist / 20.); + draw_rotate_gizmo(&xform, camera_xform, &mut gizmos, space, dist / 20.); } } } @@ -61,14 +63,55 @@ fn draw_translate_gizmo(xform: &Transform, gizmos: &mut Gizmos, space: Transform } #[inline] -fn draw_rotate_gizmo(xform: &Transform, gizmos: &mut Gizmos, space: TransformSpace, radius: f32) { +fn draw_rotate_gizmo( + xform: &Transform, + camera_xform: &Transform, + gizmos: &mut Gizmos, + space: TransformSpace, + radius: f32, +) { let origin = xform.translation; let basis = match space { TransformSpace::Local => xform, TransformSpace::World => &Transform::IDENTITY, }; - gizmos.circle(origin, basis.local_x(), radius, design_system::Color::RED); - gizmos.circle(origin, basis.local_y(), radius, design_system::Color::GREEN); - gizmos.circle(origin, basis.local_z(), radius, design_system::Color::BLUE); + // Draw a screen-space rotator ring + gizmos.circle(origin, camera_xform.forward(), radius * 1.2, Color::WHITE); + + // Draw a semicircle for each of the X, Y and Z axes + for (normal, color) in [ + (basis.local_x(), design_system::Color::RED), + (basis.local_y(), design_system::Color::GREEN), + (basis.local_z(), design_system::Color::BLUE), + ] { + let perp = Vec3::cross(normal, camera_xform.forward()).normalize(); + let start = origin + perp * radius; + + gizmos.arc(origin, normal, start, consts::PI, color); + } +} + +trait Arc { + /// Draw an arc around `center` with angular `length` (in radians), + /// beginning at `point` and progressing counter-clockwise around `axis` + /// (if axis were pointed toward the viewer). The radius is derived from the + /// distance between `center` and `start`. + fn arc(&mut self, center: Vec3, axis: Vec3, start: Vec3, length: f32, color: Color); +} + +impl<'a> Arc for Gizmos<'a> { + fn arc(&mut self, center: Vec3, normal: Vec3, start: Vec3, length: f32, color: Color) { + let two_pi = consts::PI * 2.; + let segments = f32::round(32. * (length / two_pi)); + let angle_inc = length / segments; + let rotator = Mat3::from_axis_angle(normal, angle_inc); + + let mut vector = start - center; + for _ in 0..(segments as usize) { + let next = rotator * vector; + self.line(center + vector, center + next, color); + vector = next; + } + } }