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

[Merged by Bors] - Add helper methods for rotating Transforms #5151

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
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
4 changes: 2 additions & 2 deletions crates/bevy_animation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,8 @@ pub fn animation_player(
rot_end = -rot_end;
}
// Rotations are using a spherical linear interpolation
transform.rotation = Quat::from_array(rot_start.normalize().into())
.slerp(Quat::from_array(rot_end.normalize().into()), lerp);
transform.rotation =
rot_start.normalize().slerp(rot_end.normalize(), lerp);
}
Keyframes::Translation(keyframes) => {
let translation_start = keyframes[step_start];
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_gltf/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ async fn load_gltf<'a, 'b>(
scale,
} => Transform {
translation: bevy_math::Vec3::from(translation),
rotation: bevy_math::Quat::from_vec4(rotation.into()),
rotation: bevy_math::Quat::from_array(rotation),
scale: bevy_math::Vec3::from(scale),
},
},
Expand Down
77 changes: 64 additions & 13 deletions crates/bevy_transform/src/components/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,20 +195,81 @@ impl Transform {
self.local_z()
}

/// Rotates the transform by the given rotation.
/// Rotates this [`Transform`] by the given rotation.
#[inline]
pub fn rotate(&mut self, rotation: Quat) {
self.rotation = rotation * self.rotation;
}

/// Rotates this [`Transform`] around a point in space.
/// If the point is a zero vector, this will rotate around the parent (if any) or the origin.
/// Rotates this [`Transform`] around the given `axis` by `angle` (in radians).
///
/// If this [`Transform`] has a parent, the `axis` is relative to the rotation of the parent.
#[inline]
pub fn rotate_axis(&mut self, axis: Vec3, angle: f32) {
self.rotate(Quat::from_axis_angle(axis, angle));
}

/// Rotates this [`Transform`] around the X axis by `angle` (in radians).
///
/// If this [`Transform`] has a parent, the axis is relative to the rotation of the parent.
#[inline]
pub fn rotate_x(&mut self, angle: f32) {
self.rotate(Quat::from_rotation_x(angle));
}

/// Rotates this [`Transform`] around the Y axis by `angle` (in radians).
///
/// If this [`Transform`] has a parent, the axis is relative to the rotation of the parent.
#[inline]
pub fn rotate_y(&mut self, angle: f32) {
self.rotate(Quat::from_rotation_y(angle));
}

/// Rotates this [`Transform`] around the Z axis by `angle` (in radians).
///
/// If this [`Transform`] has a parent, the axis is relative to the rotation of the parent.
#[inline]
pub fn rotate_z(&mut self, angle: f32) {
self.rotate(Quat::from_rotation_z(angle));
}

/// Rotates this [`Transform`] around its X axis by `angle` (in radians).
#[inline]
pub fn rotate_local_x(&mut self, angle: f32) {
self.rotate_axis(self.local_x(), angle);
}

/// Rotates this [`Transform`] around its Y axis by `angle` (in radians).
#[inline]
pub fn rotate_local_y(&mut self, angle: f32) {
self.rotate_axis(self.local_y(), angle);
}

/// Rotates this [`Transform`] around its Z axis by `angle` (in radians).
#[inline]
pub fn rotate_local_z(&mut self, angle: f32) {
self.rotate_axis(self.local_z(), angle);
}

/// Rotates this [`Transform`] around a `point` in space.
///
/// If this [`Transform`] has a parent, the `point` is relative to the [`Transform`] of the parent.
#[inline]
pub fn rotate_around(&mut self, point: Vec3, rotation: Quat) {
self.translation = point + rotation * (self.translation - point);
self.rotation *= rotation;
}

/// Rotates this [`Transform`] so that its local negative z direction is toward
/// `target` and its local y direction is toward `up`.
#[inline]
pub fn look_at(&mut self, target: Vec3, up: Vec3) {
let forward = Vec3::normalize(self.translation - target);
let right = up.cross(forward).normalize();
let up = forward.cross(right);
self.rotation = Quat::from_mat3(&Mat3::from_cols(right, up, forward));
}

/// Multiplies `self` with `transform` component by component, returning the
/// resulting [`Transform`]
#[inline]
Expand Down Expand Up @@ -239,16 +300,6 @@ impl Transform {
pub fn apply_non_uniform_scale(&mut self, scale_factor: Vec3) {
self.scale *= scale_factor;
}

/// Rotates this [`Transform`] so that its local z direction is toward
/// `target` and its local y direction is toward `up`.
#[inline]
pub fn look_at(&mut self, target: Vec3, up: Vec3) {
let forward = Vec3::normalize(self.translation - target);
let right = up.cross(forward).normalize();
let up = forward.cross(right);
self.rotation = Quat::from_mat3(&Mat3::from_cols(right, up, forward));
}
}

impl Default for Transform {
Expand Down
14 changes: 4 additions & 10 deletions examples/2d/rotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,8 @@ fn player_movement_system(
movement_factor += 1.0;
}

// create the change in rotation around the Z axis (perpendicular to the 2D plane of the screen)
let rotation_delta = Quat::from_rotation_z(rotation_factor * ship.rotation_speed * TIME_STEP);
// update the ship rotation with our rotation delta
transform.rotation *= rotation_delta;
// update the ship rotation around the Z axis (perpendicular to the 2D plane of the screen)
transform.rotate_z(rotation_factor * ship.rotation_speed * TIME_STEP);

// get the ship's forward vector by applying the current rotation to the ships initial facing vector
let movement_direction = transform.rotation * Vec3::Y;
Expand Down Expand Up @@ -168,7 +166,7 @@ fn snap_to_player_system(

// get the quaternion to rotate from the initial enemy facing direction to the direction
// facing the player
let rotate_to_player = Quat::from_rotation_arc(Vec3::Y, Vec3::from((to_player, 0.0)));
let rotate_to_player = Quat::from_rotation_arc(Vec3::Y, to_player.extend(0.));

// rotate the enemy to face the player
enemy_transform.rotation = rotate_to_player;
Expand Down Expand Up @@ -243,11 +241,7 @@ fn rotate_to_player_system(
// calculate angle of rotation with limit
let rotation_angle = rotation_sign * (config.rotation_speed * TIME_STEP).min(max_angle);

// get the quaternion to rotate from the current enemy facing direction towards the
// direction facing the player
let rotation_delta = Quat::from_rotation_z(rotation_angle);

// rotate the enemy to face the player
enemy_transform.rotation *= rotation_delta;
enemy_transform.rotate_z(rotation_angle);
}
}
6 changes: 3 additions & 3 deletions examples/3d/lighting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn setup(

// left wall
let mut transform = Transform::from_xyz(2.5, 2.5, 0.0);
transform.rotate(Quat::from_rotation_z(std::f32::consts::FRAC_PI_2));
transform.rotate_z(std::f32::consts::FRAC_PI_2);
commands.spawn_bundle(PbrBundle {
mesh: meshes.add(Mesh::from(shape::Box::new(5.0, 0.15, 5.0))),
transform,
Expand All @@ -47,7 +47,7 @@ fn setup(
});
// back (right) wall
let mut transform = Transform::from_xyz(0.0, 2.5, -2.5);
transform.rotate(Quat::from_rotation_x(std::f32::consts::FRAC_PI_2));
transform.rotate_x(std::f32::consts::FRAC_PI_2);
commands.spawn_bundle(PbrBundle {
mesh: meshes.add(Mesh::from(shape::Box::new(5.0, 0.15, 5.0))),
transform,
Expand Down Expand Up @@ -214,7 +214,7 @@ fn animate_light_direction(
mut query: Query<&mut Transform, With<DirectionalLight>>,
) {
for mut transform in query.iter_mut() {
transform.rotate(Quat::from_rotation_y(time.delta_seconds() * 0.5));
transform.rotate_y(time.delta_seconds() * 0.5);
}
}

Expand Down
2 changes: 1 addition & 1 deletion examples/3d/parenting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ struct Rotator;
/// rotates the parent, which will result in the child also rotating
fn rotator_system(time: Res<Time>, mut query: Query<&mut Transform, With<Rotator>>) {
for mut transform in query.iter_mut() {
transform.rotation *= Quat::from_rotation_x(3.0 * time.delta_seconds());
transform.rotate_x(3.0 * time.delta_seconds());
}
}

Expand Down
8 changes: 4 additions & 4 deletions examples/3d/render_to_texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,15 +145,15 @@ fn setup(
/// Rotates the inner cube (first pass)
fn rotator_system(time: Res<Time>, mut query: Query<&mut Transform, With<FirstPassCube>>) {
for mut transform in query.iter_mut() {
transform.rotation *= Quat::from_rotation_x(1.5 * time.delta_seconds());
transform.rotation *= Quat::from_rotation_z(1.3 * time.delta_seconds());
transform.rotate_x(1.5 * time.delta_seconds());
transform.rotate_z(1.3 * time.delta_seconds());
}
}

/// Rotates the outer cube (main pass)
fn cube_rotator_system(time: Res<Time>, mut query: Query<&mut Transform, With<MainPassCube>>) {
for mut transform in query.iter_mut() {
transform.rotation *= Quat::from_rotation_x(1.0 * time.delta_seconds());
transform.rotation *= Quat::from_rotation_y(0.7 * time.delta_seconds());
transform.rotate_x(1.0 * time.delta_seconds());
transform.rotate_y(0.7 * time.delta_seconds());
}
}
4 changes: 2 additions & 2 deletions examples/3d/shapes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ fn setup(
2.0,
0.0,
),
rotation: Quat::from_rotation_x(-std::f32::consts::PI / 4.),
..default()
},
..default()
Expand Down Expand Up @@ -86,8 +87,7 @@ fn setup(

fn rotate(mut query: Query<&mut Transform, With<Shape>>, time: Res<Time>) {
for mut transform in query.iter_mut() {
transform.rotation = Quat::from_rotation_y(time.seconds_since_startup() as f32 / 2.)
* Quat::from_rotation_x(-std::f32::consts::PI / 4.);
transform.rotate_y(time.delta_seconds() / 2.);
}
}

Expand Down
4 changes: 2 additions & 2 deletions examples/ecs/hierarchy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,14 @@ fn rotate(
let angle = std::f32::consts::PI / 2.0;
for (parent, children) in parents_query.iter_mut() {
if let Ok(mut transform) = transform_query.get_mut(parent) {
transform.rotate(Quat::from_rotation_z(-angle * time.delta_seconds()));
transform.rotate_z(-angle * time.delta_seconds());
}

// To iterate through the entities children, just treat the Children component as a Vec
// Alternatively, you could query entities that have a Parent component
for child in children.iter() {
if let Ok(mut transform) = transform_query.get_mut(*child) {
transform.rotate(Quat::from_rotation_z(angle * 2.0 * time.delta_seconds()));
transform.rotate_z(angle * 2.0 * time.delta_seconds());
}
}

Expand Down
2 changes: 1 addition & 1 deletion examples/games/alien_cake_addict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ fn spawn_bonus(
fn rotate_bonus(game: Res<Game>, time: Res<Time>, mut transforms: Query<&mut Transform>) {
if let Some(entity) = game.bonus.entity {
if let Ok(mut cake_transform) = transforms.get_mut(entity) {
cake_transform.rotate(Quat::from_rotation_y(time.delta_seconds()));
cake_transform.rotate_y(time.delta_seconds());
cake_transform.scale = Vec3::splat(
1.0 + (game.score as f32 / 10.0 * time.seconds_since_startup().sin() as f32).abs(),
);
Expand Down
2 changes: 1 addition & 1 deletion examples/games/contributors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ fn move_system(time: Res<Time>, mut query: Query<(&Velocity, &mut Transform)>) {

for (velocity, mut transform) in query.iter_mut() {
transform.translation += delta * velocity.translation;
transform.rotate(Quat::from_rotation_z(velocity.rotation * delta));
transform.rotate_z(velocity.rotation * delta);
}
}

Expand Down
4 changes: 2 additions & 2 deletions examples/shader/post_processing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ fn main_camera_cube_rotator_system(
mut query: Query<&mut Transform, With<MainCube>>,
) {
for mut transform in query.iter_mut() {
transform.rotation *= Quat::from_rotation_x(0.55 * time.delta_seconds());
transform.rotation *= Quat::from_rotation_z(0.15 * time.delta_seconds());
transform.rotate_x(0.55 * time.delta_seconds());
transform.rotate_z(0.15 * time.delta_seconds());
}
}

Expand Down
5 changes: 3 additions & 2 deletions examples/stress_tests/many_cubes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,9 @@ fn spherical_polar_to_cartesian(p: DVec2) -> DVec3 {
// System for rotating the camera
fn move_camera(time: Res<Time>, mut camera_query: Query<&mut Transform, With<Camera>>) {
let mut camera_transform = camera_query.single_mut();
camera_transform.rotate(Quat::from_rotation_z(time.delta_seconds() * 0.15));
camera_transform.rotate(Quat::from_rotation_x(time.delta_seconds() * 0.15));
let delta = time.delta_seconds() * 0.15;
camera_transform.rotate_z(delta);
camera_transform.rotate_x(delta);
}

// System for printing the number of meshes on every tick of the timer
Expand Down
4 changes: 1 addition & 3 deletions examples/stress_tests/many_foxes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,7 @@ fn update_fox_rings(
let dt = time.delta_seconds();
for (ring, rotation_direction, mut transform) in rings.iter_mut() {
let angular_velocity = foxes.speed / ring.radius;
transform.rotate(Quat::from_rotation_y(
rotation_direction.sign() * angular_velocity * dt,
));
transform.rotate_y(rotation_direction.sign() * angular_velocity * dt);
}
}

Expand Down
5 changes: 3 additions & 2 deletions examples/stress_tests/many_lights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,9 @@ fn spherical_polar_to_cartesian(p: DVec2) -> DVec3 {
// System for rotating the camera
fn move_camera(time: Res<Time>, mut camera_query: Query<&mut Transform, With<Camera>>) {
let mut camera_transform = camera_query.single_mut();
camera_transform.rotate(Quat::from_rotation_z(time.delta_seconds() * 0.15));
camera_transform.rotate(Quat::from_rotation_x(time.delta_seconds() * 0.15));
let delta = time.delta_seconds() * 0.15;
camera_transform.rotate_z(delta);
camera_transform.rotate_x(delta);
}

// System for printing the number of meshes on every tick of the timer
Expand Down
2 changes: 1 addition & 1 deletion examples/stress_tests/many_sprites.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>) {
// System for rotating and translating the camera
fn move_camera(time: Res<Time>, mut camera_query: Query<&mut Transform, With<Camera>>) {
let mut camera_transform = camera_query.single_mut();
camera_transform.rotate(Quat::from_rotation_z(time.delta_seconds() * 0.5));
camera_transform.rotate_z(time.delta_seconds() * 0.5);
*camera_transform = *camera_transform
* Transform::from_translation(Vec3::X * CAMERA_SPEED * time.delta_seconds());
}
Expand Down
6 changes: 4 additions & 2 deletions examples/tools/scene_viewer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use bevy::{
scene::InstanceId,
};

use std::f32::consts::TAU;

#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)]
struct CameraControllerCheckSystem;

Expand Down Expand Up @@ -327,8 +329,8 @@ fn update_lights(
transform.rotation = Quat::from_euler(
EulerRot::ZYX,
0.0,
time.seconds_since_startup() as f32 * std::f32::consts::TAU / 30.0,
-std::f32::consts::FRAC_PI_4,
time.seconds_since_startup() as f32 * TAU / 30.0,
-TAU / 8.,
);
}
}
Expand Down
18 changes: 8 additions & 10 deletions examples/transforms/3d_rotation.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
//! Illustrates how to (constantly) rotate an object around an axis.
//! Illustrates how to rotate an object around an axis.

use bevy::prelude::*;

use std::f32::consts::PI;

const FULL_TURN: f32 = 2.0 * PI;
use std::f32::consts::TAU;

// Define a component to designate a rotation speed to an entity.
#[derive(Component)]
Expand Down Expand Up @@ -41,19 +39,19 @@ fn setup(
..default()
});

// Add a light source for better 3d visibility.
// Add a light source so we can see clearly.
commands.spawn_bundle(PointLightBundle {
transform: Transform::from_translation(Vec3::ONE * 3.0),
..default()
});
}

// This system will rotate any entity in the scene with an assigned Rotatable around its z-axis.
// This system will rotate any entity in the scene with a Rotatable component around its y-axis.
fn rotate_cube(mut cubes: Query<(&mut Transform, &Rotatable)>, timer: Res<Time>) {
for (mut transform, cube) in cubes.iter_mut() {
// The speed is taken as a percentage of a full 360 degree turn.
// The timers delta_seconds is used to smooth out the movement.
let rotation_change = Quat::from_rotation_y(FULL_TURN * cube.speed * timer.delta_seconds());
transform.rotate(rotation_change);
// The speed is first multiplied by TAU which is a full rotation (360deg) in radians,
// and then multiplied by delta_seconds which is the time that passed last frame.
// In other words. Speed is equal to the amount of rotations per second.
transform.rotate_y(cube.speed * TAU * timer.delta_seconds());
}
}
4 changes: 2 additions & 2 deletions examples/transforms/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ fn setup(
// Define a start transform for an orbiting cube, that's away from our central object (sphere)
// and rotate it so it will be able to move around the sphere and not towards it.
let angle_90 = PI / 2.0;
let mut cube_spawn = Transform::from_translation(Vec3::Z * -10.0);
cube_spawn.rotation = Quat::from_rotation_y(angle_90);
let cube_spawn =
Transform::from_translation(Vec3::Z * -10.0).with_rotation(Quat::from_rotation_y(angle_90));
commands
.spawn_bundle(PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
Expand Down
Loading