Plane-constrained translation handles

This commit is contained in:
Danny McGee
2023-10-11 20:48:21 -04:00
parent fef5840343
commit 7d121af4a1
5 changed files with 127 additions and 39 deletions
+59 -29
View File
@@ -2,7 +2,7 @@ use std::f32::consts;
use bevy::{prelude::*, window::PrimaryWindow};
use crate::design_system;
use crate::{design_system, math::Lerp};
use super::{InteractionMode, InteractionTransform, Selected, TransformSpace};
@@ -50,7 +50,7 @@ pub(super) fn draw(
};
if mode.transform.contains(InteractionTransform::TRANSLATE) {
draw_translate_gizmo(&mut gizmos, variant, &xform, mode.space, size);
draw_translate_gizmo(&mut gizmos, variant, &xform, camera_xform, mode.space, size);
}
if mode.transform.contains(InteractionTransform::ROTATE) {
draw_rotate_gizmo(&mut gizmos, variant, &xform, camera_xform, mode.space, size);
@@ -67,6 +67,7 @@ fn draw_translate_gizmo(
gizmos: &mut Gizmos,
variant: GizmoVariant,
xform: &Transform,
camera_xform: &Transform,
space: TransformSpace,
size: f32,
) {
@@ -76,36 +77,65 @@ fn draw_translate_gizmo(
TransformSpace::World => &Transform::IDENTITY,
};
match variant {
GizmoVariant::Full => {
gizmos.sphere(origin, Quat::IDENTITY, size * 0.125, Color::WHITE);
gizmos.circle(origin, camera_xform.forward(), size * 0.2, Color::WHITE);
for (direction, color) in [
(basis.local_x(), design_system::Color::RED),
(basis.local_y(), design_system::Color::GREEN),
(basis.local_z(), design_system::Color::BLUE),
] {
let end = origin + direction * size * 1.4;
gizmos.line(origin, end, color);
for (direction, mut color) in [
(basis.local_x(), design_system::Color::RED),
(basis.local_y(), design_system::Color::GREEN),
(basis.local_z(), design_system::Color::BLUE),
] {
let alpha = (1. - Vec3::dot(camera_xform.forward(), direction).abs())
.remap((0., 0.1), (0., 1.))
.clamp(0., 1.);
let cone_base = origin + direction * size;
let radius = size * 0.1;
let length = size * 0.4;
gizmos.cone(cone_base, direction, radius, length, color);
color = color.with_a(alpha);
let cone_base = match variant {
GizmoVariant::Full => {
let start = origin + direction * size * 0.25;
let end = origin + direction * size * 1.6;
gizmos.line(start, end, color);
let midpoint_self = origin + ((end - origin) / 2.);
let (ortho, mut color_ortho) = get_ortho(basis, direction);
let ortho_alpha = (1. - Vec3::dot(camera_xform.forward(), ortho).abs())
.remap((0., 0.1), (0., 1.))
.clamp(0., 1.);
color_ortho = color_ortho.with_a(f32::min(ortho_alpha, alpha));
let ortho_end = origin + ortho * size * 1.6;
let midpoint_ortho = origin + ((ortho_end - origin) / 2.);
gizmos.line_gradient(midpoint_self, midpoint_ortho, color, color_ortho);
origin + direction * size * 1.2
}
}
GizmoVariant::Partial => {
for (direction, color) in [
(basis.local_x(), design_system::Color::RED),
(basis.local_y(), design_system::Color::GREEN),
(basis.local_z(), design_system::Color::BLUE),
] {
let cone_base = origin + direction * size * 1.4;
let radius = size * 0.1;
let length = size * 0.4;
gizmos.cone(cone_base, direction, radius, length, color);
}
}
GizmoVariant::Partial => origin + direction * size * 1.4,
};
let radius = size * 0.1;
let length = size * 0.4;
gizmos.cone(cone_base, direction, radius, length, color);
}
}
#[inline]
fn get_ortho(xform: &Transform, compare: Vec3) -> (Vec3, Color) {
let x = xform.local_x();
let y = xform.local_y();
let z = xform.local_z();
let diff_x = (compare - x).length_squared();
let diff_y = (compare - y).length_squared();
let diff_z = (compare - z).length_squared();
if diff_x < diff_y && diff_x < diff_z {
(y, design_system::Color::GREEN)
} else if diff_y < diff_x && diff_y < diff_z {
(z, design_system::Color::BLUE)
} else {
(x, design_system::Color::RED)
}
}
+54
View File
@@ -0,0 +1,54 @@
use std::ops;
use super::NearlyEq;
pub trait Lerp {
fn lerp(self, a: Self, b: Self) -> Self;
fn inv_lerp(self, a: Self, b: Self) -> Self;
fn remap(self, from: (Self, Self), to: (Self, Self)) -> Self
where
Self: Sized;
}
#[rustfmt::skip] trait One { fn one() -> Self; }
#[rustfmt::skip] impl One for f32 { fn one() -> Self { 1. } }
#[rustfmt::skip] impl One for f64 { fn one() -> Self { 1_f64 } }
#[rustfmt::skip] trait Zero { fn zero() -> Self; }
#[rustfmt::skip] impl Zero for f32 { fn zero() -> Self { 0. } }
#[rustfmt::skip] impl Zero for f64 { fn zero() -> Self { 0_f64 } }
// lol it would have been faster and less code to just copy/paste. At least I tried.
impl<T> Lerp for T
where
T: ops::Add<Output = T>
+ ops::Sub<Output = T>
+ ops::Mul<Output = T>
+ ops::Div<Output = T>
+ NearlyEq<T>
+ One
+ Zero
+ Sized
+ Copy,
{
fn lerp(self, a: Self, b: Self) -> Self {
(<Self as One>::one() - self) * a + b * self
}
fn inv_lerp(self, a: Self, b: Self) -> Self {
let dividend = b - a;
if !dividend.nearly_eq(<Self as Zero>::zero()) {
(self - a) / dividend
} else {
b
}
}
fn remap(self, from: (Self, Self), to: (Self, Self)) -> Self
where
Self: Sized,
{
let t = self.inv_lerp(from.0, from.1);
t.lerp(to.0, to.1)
}
}
+2
View File
@@ -1,3 +1,5 @@
mod interpolation;
mod util;
pub use interpolation::*;
pub use util::*;
+10
View File
@@ -1,3 +1,5 @@
use std::f32::consts;
use bevy::prelude::Vec3;
pub trait NearlyEq<Rhs> {
@@ -15,3 +17,11 @@ impl NearlyEq<Vec3> for Vec3 {
self.x.nearly_eq(rhs.x) && self.y.nearly_eq(rhs.y) && self.z.nearly_eq(rhs.z)
}
}
/// Fit a [0, 1] `t` interpolation parameter to a sine curve
///
/// https://www.desmos.com/calculator/k9x4c4cr5y
#[inline]
pub fn curve_sin(t: f32) -> f32 {
-1. * (f32::cos(t * consts::PI) / 2.) + 0.5
}
+2 -10
View File
@@ -8,7 +8,7 @@ use bevy::{
use crate::{
input::{Action, CameraMotion, InputAction, Lifecycle},
math::NearlyEq,
math::{self, NearlyEq},
};
pub struct OrbitCamPlugin;
@@ -157,7 +157,7 @@ fn update_velocity(
} else if t.0.nearly_eq(1.) {
target_vel
} else {
Vec3::lerp(velocity.0, target_vel, curve_sin(t.0))
Vec3::lerp(velocity.0, target_vel, math::curve_sin(t.0))
};
}
}
@@ -281,11 +281,3 @@ fn do_rotate(win: &Window, delta: Vec2, xform: &mut Transform, orbit_cam: &mut O
// Update focus point
orbit_cam.focus = xform.translation + xform.forward() * orbit_cam.radius;
}
/// Fit a [0, 1] `t` interpolation parameter to a sine curve
///
/// https://www.desmos.com/calculator/k9x4c4cr5y
#[inline]
fn curve_sin(t: f32) -> f32 {
-1. * (f32::cos(t * consts::PI) / 2.) + 0.5
}