return Direction3d from Transform::up and friends (#11604)

# Objective
Drawing a `Gizmos::circle` whose normal is derived from a Transform's
local axes now requires converting a Vec3 to a Direction3d and
unwrapping the result, and I think we shold move the conversion into
Bevy.

## Solution
We can make
`Transform::{left,right,up,down,forward,back,local_x,local_y,local_z}`
return a Direction3d, because they know that their results will be of
finite non-zero length (roughly 1.0).

---

## Changelog
`Transform::up()` and similar functions now return `Direction3d` instead
of `Vec3`.

## Migration Guide
Callers of `Transform::up()` and similar functions may have to
dereference the returned `Direction3d` to get to the inner `Vec3`.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
This commit is contained in:
Rose Hudson 2024-02-02 15:05:35 +00:00 committed by GitHub
parent 91c467ebfc
commit d6f1649646
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 34 additions and 17 deletions

View file

@ -71,6 +71,12 @@ impl TryFrom<Vec3> for Direction3d {
}
}
impl From<Direction3d> for Vec3 {
fn from(value: Direction3d) -> Self {
value.0
}
}
impl std::ops::Deref for Direction3d {
type Target = Vec3;
fn deref(&self) -> &Self::Target {
@ -85,6 +91,13 @@ impl std::ops::Neg for Direction3d {
}
}
impl std::ops::Mul<f32> for Direction3d {
type Output = Vec3;
fn mul(self, rhs: f32) -> Self::Output {
self.0 * rhs
}
}
impl std::ops::Mul<Direction3d> for Quat {
type Output = Direction3d;

View file

@ -1,5 +1,6 @@
use super::GlobalTransform;
use bevy_ecs::{component::Component, reflect::ReflectComponent};
use bevy_math::primitives::Direction3d;
use bevy_math::{Affine3A, Mat3, Mat4, Quat, Vec3};
use bevy_reflect::prelude::*;
use bevy_reflect::Reflect;
@ -185,55 +186,58 @@ impl Transform {
/// Get the unit vector in the local `X` direction.
#[inline]
pub fn local_x(&self) -> Vec3 {
self.rotation * Vec3::X
pub fn local_x(&self) -> Direction3d {
// Direction3d::new(x) panics if x is of invalid length, but quat * unit vector is length 1
Direction3d::new(self.rotation * Vec3::X).unwrap()
}
/// Equivalent to [`-local_x()`][Transform::local_x()]
#[inline]
pub fn left(&self) -> Vec3 {
pub fn left(&self) -> Direction3d {
-self.local_x()
}
/// Equivalent to [`local_x()`][Transform::local_x()]
#[inline]
pub fn right(&self) -> Vec3 {
pub fn right(&self) -> Direction3d {
self.local_x()
}
/// Get the unit vector in the local `Y` direction.
#[inline]
pub fn local_y(&self) -> Vec3 {
self.rotation * Vec3::Y
pub fn local_y(&self) -> Direction3d {
// Direction3d::new(x) panics if x is of invalid length, but quat * unit vector is length 1
Direction3d::new(self.rotation * Vec3::Y).unwrap()
}
/// Equivalent to [`local_y()`][Transform::local_y]
#[inline]
pub fn up(&self) -> Vec3 {
pub fn up(&self) -> Direction3d {
self.local_y()
}
/// Equivalent to [`-local_y()`][Transform::local_y]
#[inline]
pub fn down(&self) -> Vec3 {
pub fn down(&self) -> Direction3d {
-self.local_y()
}
/// Get the unit vector in the local `Z` direction.
#[inline]
pub fn local_z(&self) -> Vec3 {
self.rotation * Vec3::Z
pub fn local_z(&self) -> Direction3d {
// Direction3d::new(x) panics if x is of invalid length, but quat * unit vector is length 1
Direction3d::new(self.rotation * Vec3::Z).unwrap()
}
/// Equivalent to [`-local_z()`][Transform::local_z]
#[inline]
pub fn forward(&self) -> Vec3 {
pub fn forward(&self) -> Direction3d {
-self.local_z()
}
/// Equivalent to [`local_z()`][Transform::local_z]
#[inline]
pub fn back(&self) -> Vec3 {
pub fn back(&self) -> Direction3d {
self.local_z()
}

View file

@ -224,7 +224,7 @@ fn setup_color_gradient_scene(
camera_transform: Res<CameraTransform>,
) {
let mut transform = camera_transform.0;
transform.translation += transform.forward();
transform.translation += *transform.forward();
commands.spawn((
MaterialMeshBundle {
@ -248,7 +248,7 @@ fn setup_image_viewer_scene(
camera_transform: Res<CameraTransform>,
) {
let mut transform = camera_transform.0;
transform.translation += transform.forward();
transform.translation += *transform.forward();
// exr/hdr viewer (exr requires enabling bevy feature)
commands.spawn((

View file

@ -171,8 +171,8 @@ fn run_camera_controller(
controller.velocity = Vec3::ZERO;
}
}
let forward = transform.forward();
let right = transform.right();
let forward = *transform.forward();
let right = *transform.right();
transform.translation += controller.velocity.x * dt * right
+ controller.velocity.y * dt * Vec3::Y
+ controller.velocity.z * dt * forward;

View file

@ -127,7 +127,7 @@ fn rotate_cube(
// Update the rotation of the cube(s).
for (mut transform, cube) in &mut cubes {
// Calculate the rotation of the cube if it would be looking at the sphere in the center.
let look_at_sphere = transform.looking_at(center, transform.local_y());
let look_at_sphere = transform.looking_at(center, *transform.local_y());
// Interpolate between the current rotation and the fully turned rotation
// when looking a the sphere, with a given turn speed to get a smooth motion.
// With higher speed the curvature of the orbit would be smaller.