use super::GlobalTransform; use bevy_ecs::{component::Component, reflect::ReflectComponent}; use bevy_math::{Affine3A, Mat3, Mat4, Quat, Vec3}; use bevy_reflect::prelude::*; use bevy_reflect::Reflect; use std::ops::Mul; /// Describe the position of an entity. If the entity has a parent, the position is relative /// to its parent position. /// /// * To place or move an entity, you should set its [`Transform`]. /// * To get the global transform of an entity, you should get its [`GlobalTransform`]. /// * To be displayed, an entity must have both a [`Transform`] and a [`GlobalTransform`]. /// * You may use the [`TransformBundle`](crate::TransformBundle) to guarantee this. /// /// ## [`Transform`] and [`GlobalTransform`] /// /// [`Transform`] is the position of an entity relative to its parent position, or the reference /// frame if it doesn't have a [`Parent`](bevy_hierarchy::Parent). /// /// [`GlobalTransform`] is the position of an entity relative to the reference frame. /// /// [`GlobalTransform`] is updated from [`Transform`] in the system /// [`transform_propagate_system`](crate::transform_propagate_system). /// /// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you /// update the [`Transform`] of an entity in this stage or after, you will notice a 1 frame lag /// before the [`GlobalTransform`] is updated. #[derive(Component, Debug, PartialEq, Clone, Copy, Reflect)] #[reflect(Component, Default, PartialEq)] pub struct Transform { /// Position of the entity. In 2d, the last value of the `Vec3` is used for z-ordering. pub translation: Vec3, /// Rotation of the entity. pub rotation: Quat, /// Scale of the entity. pub scale: Vec3, } impl Transform { /// Creates a new [`Transform`] at the position `(x, y, z)`. In 2d, the `z` component /// is used for z-ordering elements: higher `z`-value will be in front of lower /// `z`-value. #[inline] pub const fn from_xyz(x: f32, y: f32, z: f32) -> Self { Self::from_translation(Vec3::new(x, y, z)) } /// Creates a new identity [`Transform`], with no translation, rotation, and a scale of 1 on /// all axes. #[inline] pub const fn identity() -> Self { Transform { translation: Vec3::ZERO, rotation: Quat::IDENTITY, scale: Vec3::ONE, } } /// Extracts the translation, rotation, and scale from `matrix`. It must be a 3d affine /// transformation matrix. #[inline] pub fn from_matrix(matrix: Mat4) -> Self { let (scale, rotation, translation) = matrix.to_scale_rotation_translation(); Transform { translation, rotation, scale, } } /// Creates a new [`Transform`], with `translation`. Rotation will be 0 and scale 1 on /// all axes. #[inline] pub const fn from_translation(translation: Vec3) -> Self { Transform { translation, ..Self::identity() } } /// Creates a new [`Transform`], with `rotation`. Translation will be 0 and scale 1 on /// all axes. #[inline] pub const fn from_rotation(rotation: Quat) -> Self { Transform { rotation, ..Self::identity() } } /// Creates a new [`Transform`], with `scale`. Translation will be 0 and rotation 0 on /// all axes. #[inline] pub const fn from_scale(scale: Vec3) -> Self { Transform { scale, ..Self::identity() } } /// Updates and returns this [`Transform`] by rotating it so that its unit vector in the /// local `Z` direction is toward `target` and its unit vector in the local `Y` direction /// is toward `up`. #[inline] #[must_use] pub fn looking_at(mut self, target: Vec3, up: Vec3) -> Self { self.look_at(target, up); self } /// Returns this [`Transform`] with a new translation. #[inline] #[must_use] pub const fn with_translation(mut self, translation: Vec3) -> Self { self.translation = translation; self } /// Returns this [`Transform`] with a new rotation. #[inline] #[must_use] pub const fn with_rotation(mut self, rotation: Quat) -> Self { self.rotation = rotation; self } /// Returns this [`Transform`] with a new scale. #[inline] #[must_use] pub const fn with_scale(mut self, scale: Vec3) -> Self { self.scale = scale; self } /// Returns the 3d affine transformation matrix from this transforms translation, /// rotation, and scale. #[inline] pub fn compute_matrix(&self) -> Mat4 { Mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation) } /// Returns the 3d affine transformation matrix from this transforms translation, /// rotation, and scale. #[inline] pub fn compute_affine(&self) -> Affine3A { Affine3A::from_scale_rotation_translation(self.scale, self.rotation, self.translation) } /// Get the unit vector in the local `X` direction. #[inline] pub fn local_x(&self) -> Vec3 { self.rotation * Vec3::X } /// Equivalent to [`-local_x()`][Transform::local_x()] #[inline] pub fn left(&self) -> Vec3 { -self.local_x() } /// Equivalent to [`local_x()`][Transform::local_x()] #[inline] pub fn right(&self) -> Vec3 { self.local_x() } /// Get the unit vector in the local `Y` direction. #[inline] pub fn local_y(&self) -> Vec3 { self.rotation * Vec3::Y } /// Equivalent to [`local_y()`][Transform::local_y] #[inline] pub fn up(&self) -> Vec3 { self.local_y() } /// Equivalent to [`-local_y()`][Transform::local_y] #[inline] pub fn down(&self) -> Vec3 { -self.local_y() } /// Get the unit vector in the local `Z` direction. #[inline] pub fn local_z(&self) -> Vec3 { self.rotation * Vec3::Z } /// Equivalent to [`-local_z()`][Transform::local_z] #[inline] pub fn forward(&self) -> Vec3 { -self.local_z() } /// Equivalent to [`local_z()`][Transform::local_z] #[inline] pub fn back(&self) -> Vec3 { self.local_z() } /// Rotates this [`Transform`] by the given rotation. /// /// If this [`Transform`] has a parent, the `rotation` is relative to the rotation of the parent. #[inline] pub fn rotate(&mut self, rotation: Quat) { self.rotation = rotation * self.rotation; } /// 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`] by the given `rotation`. /// /// The `rotation` is relative to this [`Transform`]'s current rotation. #[inline] pub fn rotate_local(&mut self, rotation: Quat) { self.rotation *= rotation; } /// Rotates this [`Transform`] around its local `axis` by `angle` (in radians). #[inline] pub fn rotate_local_axis(&mut self, axis: Vec3, angle: f32) { self.rotate_local(Quat::from_axis_angle(axis, angle)); } /// Rotates this [`Transform`] around its local `X` axis by `angle` (in radians). #[inline] pub fn rotate_local_x(&mut self, angle: f32) { self.rotate_local(Quat::from_rotation_x(angle)); } /// Rotates this [`Transform`] around its local `Y` axis by `angle` (in radians). #[inline] pub fn rotate_local_y(&mut self, angle: f32) { self.rotate_local(Quat::from_rotation_y(angle)); } /// Rotates this [`Transform`] around its local `Z` axis by `angle` (in radians). #[inline] pub fn rotate_local_z(&mut self, angle: f32) { self.rotate_local(Quat::from_rotation_z(angle)); } /// Translates 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 translate_around(&mut self, point: Vec3, rotation: Quat) { self.translation = point + rotation * (self.translation - point); } /// 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.translate_around(point, rotation); self.rotate(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] #[must_use] pub fn mul_transform(&self, transform: Transform) -> Self { let translation = self.mul_vec3(transform.translation); let rotation = self.rotation * transform.rotation; let scale = self.scale * transform.scale; Transform { translation, rotation, scale, } } /// Returns a [`Vec3`] of this [`Transform`] applied to `value`. #[inline] pub fn mul_vec3(&self, mut value: Vec3) -> Vec3 { value = self.scale * value; value = self.rotation * value; value += self.translation; value } /// Changes the `scale` of this [`Transform`], multiplying the current `scale` by /// `scale_factor`. #[inline] pub fn apply_non_uniform_scale(&mut self, scale_factor: Vec3) { self.scale *= scale_factor; } } impl Default for Transform { fn default() -> Self { Self::identity() } } /// The transform is expected to be non-degenerate and without shearing, or the output /// will be invalid. impl From for Transform { fn from(transform: GlobalTransform) -> Self { transform.compute_transform() } } impl Mul for Transform { type Output = Transform; fn mul(self, transform: Transform) -> Self::Output { self.mul_transform(transform) } } impl Mul for Transform { type Output = Vec3; fn mul(self, value: Vec3) -> Self::Output { self.mul_vec3(value) } }