mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +00:00
Use Dir3
in Transform
APIs (#12530)
# Objective Make `Transform` APIs more ergonomic by allowing users to pass `Dir3` as an argument where a direction is needed. Fixes #12481. ## Solution Accept `impl TryInto<Dir3>` instead of `Vec3` for direction/axis arguments in `Transform` APIs --- ## Changelog The following `Transform` methods now accept an `impl TryInto<Dir3>` argument where they previously accepted directions as `Vec3`: * `Transform::{look_to,looking_to}` * `Transform::{look_at,looking_at}` * `Transform::{align,aligned_by}` ## Migration Guide This is not a breaking change since the arguments were previously `Vec3` which already implements `TryInto<Dir3>`, and behavior is unchanged. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
This commit is contained in:
parent
16107385af
commit
ec3e7afa4e
1 changed files with 50 additions and 50 deletions
|
@ -122,11 +122,11 @@ impl Transform {
|
|||
///
|
||||
/// In some cases it's not possible to construct a rotation. Another axis will be picked in those cases:
|
||||
/// * if `target` is the same as the transform translation, `Vec3::Z` is used instead
|
||||
/// * if `up` is zero, `Vec3::Y` is used instead
|
||||
/// * if `up` fails converting to `Dir3` (e.g if it is `Vec3::ZERO`), `Dir3::Y` is used instead
|
||||
/// * if the resulting forward direction is parallel with `up`, an orthogonal vector is used as the "right" direction
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn looking_at(mut self, target: Vec3, up: Vec3) -> Self {
|
||||
pub fn looking_at(mut self, target: Vec3, up: impl TryInto<Dir3>) -> Self {
|
||||
self.look_at(target, up);
|
||||
self
|
||||
}
|
||||
|
@ -135,39 +135,39 @@ impl Transform {
|
|||
/// points in the given `direction` and [`Transform::up`] points towards `up`.
|
||||
///
|
||||
/// In some cases it's not possible to construct a rotation. Another axis will be picked in those cases:
|
||||
/// * if `direction` is zero, `Vec3::Z` is used instead
|
||||
/// * if `up` is zero, `Vec3::Y` is used instead
|
||||
/// * if `direction` fails converting to `Dir3` (e.g if it is `Vec3::ZERO`), `Dir3::Z` is used instead
|
||||
/// * if `up` fails converting to `Dir3`, `Dir3::Y` is used instead
|
||||
/// * if `direction` is parallel with `up`, an orthogonal vector is used as the "right" direction
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn looking_to(mut self, direction: Vec3, up: Vec3) -> Self {
|
||||
pub fn looking_to(mut self, direction: impl TryInto<Dir3>, up: impl TryInto<Dir3>) -> Self {
|
||||
self.look_to(direction, up);
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns this [`Transform`] with a rotation so that the `handle` vector, reinterpreted in local coordinates,
|
||||
/// points in the given `direction`, while `weak_handle` points towards `weak_direction`.
|
||||
///
|
||||
/// Rotates this [`Transform`] so that the `main_axis` vector, reinterpreted in local coordinates, points
|
||||
/// in the given `main_direction`, while `secondary_axis` points towards `secondary_direction`.
|
||||
/// For example, if a spaceship model has its nose pointing in the X-direction in its own local coordinates
|
||||
/// and its dorsal fin pointing in the Y-direction, then `Transform::aligned_by(Vec3::X, v, Vec3::Y, w)` will
|
||||
/// make the spaceship's nose point in the direction of `v`, while the dorsal fin does its best to point in the
|
||||
/// direction `w`.
|
||||
/// and its dorsal fin pointing in the Y-direction, then `align(Dir3::X, v, Dir3::Y, w)` will make the spaceship's
|
||||
/// nose point in the direction of `v`, while the dorsal fin does its best to point in the direction `w`.
|
||||
///
|
||||
///
|
||||
/// In some cases a rotation cannot be constructed. Another axis will be picked in those cases:
|
||||
/// * if `handle` or `direction` is zero, `Vec3::X` takes its place
|
||||
/// * if `weak_handle` or `weak_direction` is zero, `Vec3::Y` takes its place
|
||||
/// * if `handle` is parallel with `weak_handle` or `direction` is parallel with `weak_direction`, a rotation is
|
||||
/// constructed which takes `handle` to `direction` but ignores the weak counterparts (i.e. is otherwise unspecified)
|
||||
/// * if `main_axis` or `main_direction` fail converting to `Dir3` (e.g are zero), `Dir3::X` takes their place
|
||||
/// * if `secondary_axis` or `secondary_direction` fail converting, `Dir3::Y` takes their place
|
||||
/// * if `main_axis` is parallel with `secondary_axis` or `main_direction` is parallel with `secondary_direction`,
|
||||
/// a rotation is constructed which takes `main_axis` to `main_direction` along a great circle, ignoring the secondary
|
||||
/// counterparts
|
||||
///
|
||||
/// See [`Transform::align`] for additional details.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn aligned_by(
|
||||
mut self,
|
||||
main_axis: Vec3,
|
||||
main_direction: Vec3,
|
||||
secondary_axis: Vec3,
|
||||
secondary_direction: Vec3,
|
||||
main_axis: impl TryInto<Dir3>,
|
||||
main_direction: impl TryInto<Dir3>,
|
||||
secondary_axis: impl TryInto<Dir3>,
|
||||
secondary_direction: impl TryInto<Dir3>,
|
||||
) -> Self {
|
||||
self.align(
|
||||
main_axis,
|
||||
|
@ -373,10 +373,10 @@ impl Transform {
|
|||
///
|
||||
/// In some cases it's not possible to construct a rotation. Another axis will be picked in those cases:
|
||||
/// * if `target` is the same as the transform translation, `Vec3::Z` is used instead
|
||||
/// * if `up` is zero, `Vec3::Y` is used instead
|
||||
/// * if `up` fails converting to `Dir3` (e.g if it is `Vec3::ZERO`), `Dir3::Y` is used instead
|
||||
/// * if the resulting forward direction is parallel with `up`, an orthogonal vector is used as the "right" direction
|
||||
#[inline]
|
||||
pub fn look_at(&mut self, target: Vec3, up: Vec3) {
|
||||
pub fn look_at(&mut self, target: Vec3, up: impl TryInto<Dir3>) {
|
||||
self.look_to(target - self.translation, up);
|
||||
}
|
||||
|
||||
|
@ -384,26 +384,26 @@ impl Transform {
|
|||
/// and [`Transform::up`] points towards `up`.
|
||||
///
|
||||
/// In some cases it's not possible to construct a rotation. Another axis will be picked in those cases:
|
||||
/// * if `direction` is zero, `Vec3::NEG_Z` is used instead
|
||||
/// * if `up` is zero, `Vec3::Y` is used instead
|
||||
/// * if `direction` fails converting to `Dir3` (e.g if it is `Vec3::ZERO`), `Dir3::NEG_Z` is used instead
|
||||
/// * if `up` fails converting to `Dir3`, `Dir3::Y` is used instead
|
||||
/// * if `direction` is parallel with `up`, an orthogonal vector is used as the "right" direction
|
||||
#[inline]
|
||||
pub fn look_to(&mut self, direction: Vec3, up: Vec3) {
|
||||
let back = -direction.try_normalize().unwrap_or(Vec3::NEG_Z);
|
||||
let up = up.try_normalize().unwrap_or(Vec3::Y);
|
||||
pub fn look_to(&mut self, direction: impl TryInto<Dir3>, up: impl TryInto<Dir3>) {
|
||||
let back = -direction.try_into().unwrap_or(Dir3::NEG_Z);
|
||||
let up = up.try_into().unwrap_or(Dir3::Y);
|
||||
let right = up
|
||||
.cross(back)
|
||||
.cross(back.into())
|
||||
.try_normalize()
|
||||
.unwrap_or_else(|| up.any_orthonormal_vector());
|
||||
let up = back.cross(right);
|
||||
self.rotation = Quat::from_mat3(&Mat3::from_cols(right, up, back));
|
||||
self.rotation = Quat::from_mat3(&Mat3::from_cols(right, up, back.into()));
|
||||
}
|
||||
|
||||
/// Rotates this [`Transform`] so that the `main_axis` vector, reinterpreted in local coordinates, points
|
||||
/// in the given `main_direction`, while `secondary_axis` points towards `secondary_direction`.
|
||||
///
|
||||
/// For example, if a spaceship model has its nose pointing in the X-direction in its own local coordinates
|
||||
/// and its dorsal fin pointing in the Y-direction, then `align(Vec3::X, v, Vec3::Y, w)` will make the spaceship's
|
||||
/// and its dorsal fin pointing in the Y-direction, then `align(Dir3::X, v, Dir3::Y, w)` will make the spaceship's
|
||||
/// nose point in the direction of `v`, while the dorsal fin does its best to point in the direction `w`.
|
||||
///
|
||||
/// More precisely, the [`Transform::rotation`] produced will be such that:
|
||||
|
@ -411,62 +411,62 @@ impl Transform {
|
|||
/// * applying it to `secondary_axis` produces a vector that lies in the half-plane generated by `main_direction` and
|
||||
/// `secondary_direction` (with positive contribution by `secondary_direction`)
|
||||
///
|
||||
/// [`Transform::look_to`] is recovered, for instance, when `main_axis` is `Vec3::NEG_Z` (the [`Transform::forward`]
|
||||
/// direction in the default orientation) and `secondary_axis` is `Vec3::Y` (the [`Transform::up`] direction in the default
|
||||
/// [`Transform::look_to`] is recovered, for instance, when `main_axis` is `Dir3::NEG_Z` (the [`Transform::forward`]
|
||||
/// direction in the default orientation) and `secondary_axis` is `Dir3::Y` (the [`Transform::up`] direction in the default
|
||||
/// orientation). (Failure cases may differ somewhat.)
|
||||
///
|
||||
/// In some cases a rotation cannot be constructed. Another axis will be picked in those cases:
|
||||
/// * if `main_axis` or `main_direction` is zero, `Vec3::X` takes its place
|
||||
/// * if `secondary_axis` or `secondary_direction` is zero, `Vec3::Y` takes its place
|
||||
/// * if `main_axis` or `main_direction` fail converting to `Dir3` (e.g are zero), `Dir3::X` takes their place
|
||||
/// * if `secondary_axis` or `secondary_direction` fail converting, `Dir3::Y` takes their place
|
||||
/// * if `main_axis` is parallel with `secondary_axis` or `main_direction` is parallel with `secondary_direction`,
|
||||
/// a rotation is constructed which takes `main_axis` to `main_direction` along a great circle, ignoring the secondary
|
||||
/// counterparts
|
||||
///
|
||||
/// Example
|
||||
/// ```
|
||||
/// # use bevy_math::{Vec3, Quat};
|
||||
/// # use bevy_math::{Dir3, Vec3, Quat};
|
||||
/// # use bevy_transform::components::Transform;
|
||||
/// # let mut t1 = Transform::IDENTITY;
|
||||
/// # let mut t2 = Transform::IDENTITY;
|
||||
/// t1.align(Vec3::X, Vec3::Y, Vec3::new(1., 1., 0.), Vec3::Z);
|
||||
/// let main_axis_image = t1.rotation * Vec3::X;
|
||||
/// t1.align(Dir3::X, Dir3::Y, Vec3::new(1., 1., 0.), Dir3::Z);
|
||||
/// let main_axis_image = t1.rotation * Dir3::X;
|
||||
/// let secondary_axis_image = t1.rotation * Vec3::new(1., 1., 0.);
|
||||
/// assert!(main_axis_image.abs_diff_eq(Vec3::Y, 1e-5));
|
||||
/// assert!(secondary_axis_image.abs_diff_eq(Vec3::new(0., 1., 1.), 1e-5));
|
||||
///
|
||||
/// t1.align(Vec3::ZERO, Vec3::Z, Vec3::ZERO, Vec3::X);
|
||||
/// t2.align(Vec3::X, Vec3::Z, Vec3::Y, Vec3::X);
|
||||
/// t1.align(Vec3::ZERO, Dir3::Z, Vec3::ZERO, Dir3::X);
|
||||
/// t2.align(Dir3::X, Dir3::Z, Dir3::Y, Dir3::X);
|
||||
/// assert_eq!(t1.rotation, t2.rotation);
|
||||
///
|
||||
/// t1.align(Vec3::X, Vec3::Z, Vec3::X, Vec3::Y);
|
||||
/// t1.align(Dir3::X, Dir3::Z, Dir3::X, Dir3::Y);
|
||||
/// assert_eq!(t1.rotation, Quat::from_rotation_arc(Vec3::X, Vec3::Z));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn align(
|
||||
&mut self,
|
||||
main_axis: Vec3,
|
||||
main_direction: Vec3,
|
||||
secondary_axis: Vec3,
|
||||
secondary_direction: Vec3,
|
||||
main_axis: impl TryInto<Dir3>,
|
||||
main_direction: impl TryInto<Dir3>,
|
||||
secondary_axis: impl TryInto<Dir3>,
|
||||
secondary_direction: impl TryInto<Dir3>,
|
||||
) {
|
||||
let main_axis = main_axis.try_normalize().unwrap_or(Vec3::X);
|
||||
let main_direction = main_direction.try_normalize().unwrap_or(Vec3::X);
|
||||
let secondary_axis = secondary_axis.try_normalize().unwrap_or(Vec3::Y);
|
||||
let secondary_direction = secondary_direction.try_normalize().unwrap_or(Vec3::Y);
|
||||
let main_axis = main_axis.try_into().unwrap_or(Dir3::X);
|
||||
let main_direction = main_direction.try_into().unwrap_or(Dir3::X);
|
||||
let secondary_axis = secondary_axis.try_into().unwrap_or(Dir3::Y);
|
||||
let secondary_direction = secondary_direction.try_into().unwrap_or(Dir3::Y);
|
||||
|
||||
// The solution quaternion will be constructed in two steps.
|
||||
// First, we start with a rotation that takes `main_axis` to `main_direction`.
|
||||
let first_rotation = Quat::from_rotation_arc(main_axis, main_direction);
|
||||
let first_rotation = Quat::from_rotation_arc(main_axis.into(), main_direction.into());
|
||||
|
||||
// Let's follow by rotating about the `main_direction` axis so that the image of `secondary_axis`
|
||||
// is taken to something that lies in the plane of `main_direction` and `secondary_direction`. Since
|
||||
// `main_direction` is fixed by this rotation, the first criterion is still satisfied.
|
||||
let secondary_image = first_rotation * secondary_axis;
|
||||
let secondary_image_ortho = secondary_image
|
||||
.reject_from_normalized(main_direction)
|
||||
.reject_from_normalized(main_direction.into())
|
||||
.try_normalize();
|
||||
let secondary_direction_ortho = secondary_direction
|
||||
.reject_from_normalized(main_direction)
|
||||
.reject_from_normalized(main_direction.into())
|
||||
.try_normalize();
|
||||
|
||||
// If one of the two weak vectors was parallel to `main_direction`, then we just do the first part
|
||||
|
|
Loading…
Reference in a new issue