Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix look_to resulting in NaN rotations #7817

Merged
merged 4 commits into from
Mar 15, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions crates/bevy_transform/src/components/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ impl Transform {

/// Returns this [`Transform`] with a new rotation so that [`Transform::forward`]
/// points towards the `target` position 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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this means we should be returning Result<Self, SomeError> instead, seems odd to silently fail here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO we're not silently failing: we're performing a "best-attempt". I'd be open to try variants too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to work by default, instead of having to add unwrap / error management everywhere this pops up

/// * if `target` is the same as the transform translation, `Vec3::Z` is used instead
/// * if `up` is zero, `Vec3::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 {
Expand All @@ -129,6 +134,11 @@ impl Transform {

/// Returns this [`Transform`] with a new rotation so that [`Transform::forward`]
/// 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` 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 {
Expand Down Expand Up @@ -325,17 +335,31 @@ impl Transform {

/// Rotates this [`Transform`] so that [`Transform::forward`] points towards the `target` position,
/// 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 `target` is the same as the transtorm translation, `Vec3::Z` is used instead
/// * if `up` is zero, `Vec3::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) {
self.look_to(target - self.translation, up);
}

/// Rotates this [`Transform`] so that [`Transform::forward`] 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` 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 forward = -direction.normalize();
let right = up.cross(forward).normalize();
let forward = -direction.try_normalize().unwrap_or(Vec3::Z);
let up = up.try_normalize().unwrap_or(Vec3::Y);
let right = up
.cross(forward)
.try_normalize()
.unwrap_or_else(|| up.any_orthonormal_vector());
let up = forward.cross(right);
self.rotation = Quat::from_mat3(&Mat3::from_cols(right, up, forward));
}
Expand Down