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 3 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
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`] on the given `axis` by `angle` (in radians).
tim-blackbird marked this conversation as resolved.
Show resolved Hide resolved
///
/// 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`] on 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_axis(Vec3::X, angle);
tim-blackbird marked this conversation as resolved.
Show resolved Hide resolved
}

/// Rotates this [`Transform`] on 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_axis(Vec3::Y, angle);
tim-blackbird marked this conversation as resolved.
Show resolved Hide resolved
}

/// Rotates this [`Transform`] on 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_axis(Vec3::Z, angle);
tim-blackbird marked this conversation as resolved.
Show resolved Hide resolved
}

/// Rotates this [`Transform`] on 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`] on 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`] on 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
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
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
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
17 changes: 7 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,18 @@ 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 multiplied by TAU which is a full rotation (360deg) in radians, and 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());
}
}