Skip to content
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
55 changes: 48 additions & 7 deletions crates/bevy_transform/src/components/global_transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,35 @@ use bevy_math::{Mat3, Mat4, Quat, Vec3};
use bevy_reflect::Reflect;
use std::ops::Mul;

/// Describe the position of an entity relative to the reference frame.
///
/// * To place or move an entity, you should set its [`Transform`].
/// * To be displayed, an entity must have both a [`Transform`] and a [`GlobalTransform`].
/// * To get the global position of an entity, you should get its [`GlobalTransform`].
///
/// ## [`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`](super::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::transform_propagate_system).
///
/// In pseudo code:
/// ```ignore
/// for entity in entities_without_parent:
/// set entity.global_transform to entity.transform
/// recursively:
/// set parent to current entity
/// for child in parent.children:
/// set child.global_transform to parent.global_transform * child.transform
/// ```
///
/// 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(Debug, PartialEq, Clone, Copy, Reflect)]
#[reflect(Component, PartialEq)]
pub struct GlobalTransform {
Expand All @@ -13,12 +42,14 @@ pub struct GlobalTransform {
}

impl GlobalTransform {
/// Create a new [`GlobalTransform`] at the position `(x, y, z)`
#[doc(hidden)]
#[inline]
pub fn from_xyz(x: f32, y: f32, z: f32) -> Self {
Self::from_translation(Vec3::new(x, y, z))
}

/// Creates a new identity [`GlobalTransform`], with no translation, rotation, and a scale of 1
/// on all axes.
#[inline]
pub const fn identity() -> Self {
GlobalTransform {
Expand All @@ -28,6 +59,7 @@ impl GlobalTransform {
}
}

#[doc(hidden)]
#[inline]
pub fn from_matrix(matrix: Mat4) -> Self {
let (scale, rotation, translation) = matrix.to_scale_rotation_translation();
Expand All @@ -39,6 +71,7 @@ impl GlobalTransform {
}
}

#[doc(hidden)]
#[inline]
pub fn from_translation(translation: Vec3) -> Self {
GlobalTransform {
Expand All @@ -47,6 +80,7 @@ impl GlobalTransform {
}
}

#[doc(hidden)]
#[inline]
pub fn from_rotation(rotation: Quat) -> Self {
GlobalTransform {
Expand All @@ -55,6 +89,7 @@ impl GlobalTransform {
}
}

#[doc(hidden)]
#[inline]
pub fn from_scale(scale: Vec3) -> Self {
GlobalTransform {
Expand All @@ -63,43 +98,46 @@ impl GlobalTransform {
}
}

/// Returns transform with the same translation and scale, but rotation so that
/// transform.forward() points at target
#[doc(hidden)]
#[inline]
pub fn looking_at(mut self, target: Vec3, up: Vec3) -> Self {
self.look_at(target, up);
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)
}

#[inline]
/// Get the unit vector in the local x direction
#[inline]
pub fn local_x(&self) -> Vec3 {
self.rotation * Vec3::X
}

#[inline]
/// Get the unit vector in the local y direction
#[inline]
pub fn local_y(&self) -> Vec3 {
self.rotation * Vec3::Y
}

#[inline]
/// Get the unit vector in the local z direction
#[inline]
pub fn local_z(&self) -> Vec3 {
self.rotation * Vec3::Z
}

#[doc(hidden)]
#[inline]
/// Rotate the transform by the given rotation
pub fn rotate(&mut self, rotation: Quat) {
self.rotation *= rotation;
}

/// Multiplies `self` with `transform` component by component, returning the
/// resulting [`GlobalTransform`]
#[inline]
pub fn mul_transform(&self, transform: Transform) -> GlobalTransform {
let translation = self.mul_vec3(transform.translation);
Expand All @@ -112,6 +150,7 @@ impl GlobalTransform {
}
}

/// Returns a [`Vec3`] of this [`Transform`] applied to `value`.
#[inline]
pub fn mul_vec3(&self, mut value: Vec3) -> Vec3 {
value = self.rotation * value;
Expand All @@ -120,11 +159,13 @@ impl GlobalTransform {
value
}

#[doc(hidden)]
#[inline]
pub fn apply_non_uniform_scale(&mut self, scale: Vec3) {
self.scale *= scale;
}

#[doc(hidden)]
#[inline]
pub fn look_at(&mut self, target: Vec3, up: Vec3) {
let forward = Vec3::normalize(self.translation - target);
Expand Down
73 changes: 64 additions & 9 deletions crates/bevy_transform/src/components/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,58 @@ use bevy_math::{Mat3, Mat4, Quat, Vec3};
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 be displayed, an entity must have both a [`Transform`] and a [`GlobalTransform`].
/// * To get the global position of an entity, you should get its [`GlobalTransform`].
///
/// ## [`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`](super::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::transform_propagate_system).
///
/// In pseudo code:
/// ```ignore
/// for entity in entities_without_parent:
/// set entity.global_transform to entity.transform
/// recursively:
/// set parent to current entity
/// for child in parent.children:
/// set child.global_transform to parent.global_transform * child.transform
/// ```
///
/// 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(Debug, PartialEq, Clone, Copy, Reflect)]
#[reflect(Component, 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 {
/// Create a new [`Transform`] at the position `(x, y, z)`
/// 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 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 {
Expand All @@ -28,6 +65,8 @@ impl Transform {
}
}

/// 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();
Expand All @@ -39,6 +78,8 @@ impl Transform {
}
}

/// Creates a new [`Transform`], with `translation`. Rotation will be 0 and scale 1 on
/// all axes.
#[inline]
pub fn from_translation(translation: Vec3) -> Self {
Transform {
Expand All @@ -47,6 +88,8 @@ impl Transform {
}
}

/// Creates a new [`Transform`], with `rotation`. Translation will be 0 and scale 1 on
/// all axes.
#[inline]
pub fn from_rotation(rotation: Quat) -> Self {
Transform {
Expand All @@ -55,6 +98,8 @@ impl Transform {
}
}

/// Creates a new [`Transform`], with `scale`. Translation will be 0 and rotation 0 on
/// all axes.
#[inline]
pub fn from_scale(scale: Vec3) -> Self {
Transform {
Expand All @@ -63,43 +108,48 @@ impl Transform {
}
}

/// Returns transform with the same translation and scale, but rotation so that
/// transform.forward() points at target
/// 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]
pub fn looking_at(mut self, target: Vec3, up: Vec3) -> Self {
self.look_at(target, up);
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)
}

/// Get the unit vector in the local x direction.
#[inline]
/// Get the unit vector in the local x direction
pub fn local_x(&self) -> Vec3 {
self.rotation * Vec3::X
}

/// Get the unit vector in the local y direction.
#[inline]
/// Get the unit vector in the local y direction
pub fn local_y(&self) -> Vec3 {
self.rotation * Vec3::Y
}

/// Get the unit vector in the local z direction.
#[inline]
/// Get the unit vector in the local z direction
pub fn local_z(&self) -> Vec3 {
self.rotation * Vec3::Z
}

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

/// Multiplies `self` with `transform` component by component, returning the
/// resulting [`Transform`]
#[inline]
pub fn mul_transform(&self, transform: Transform) -> Self {
let translation = self.mul_vec3(transform.translation);
Expand All @@ -112,6 +162,7 @@ impl Transform {
}
}

/// Returns a [`Vec3`] of this [`Transform`] applied to `value`.
#[inline]
pub fn mul_vec3(&self, mut value: Vec3) -> Vec3 {
value = self.rotation * value;
Expand All @@ -120,11 +171,15 @@ impl Transform {
value
}

/// Changes the `scale` of this [`Transform`], multiplying the current `scale` by
/// `scale_factor`.
#[inline]
pub fn apply_non_uniform_scale(&mut self, scale: Vec3) {
self.scale *= scale;
pub fn apply_non_uniform_scale(&mut self, scale_factor: Vec3) {
self.scale *= scale_factor;
}

/// Rotates this [`Transform`] 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]
pub fn look_at(&mut self, target: Vec3, up: Vec3) {
let forward = Vec3::normalize(self.translation - target);
Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_transform/src/transform_propagate_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use bevy_ecs::{
system::Query,
};

/// Update [`GlobalTransform`] component of entities based on entity hierarchy and
/// [`Transform`] component.
pub fn transform_propagate_system(
mut root_query: Query<
(Entity, Option<&Children>, &Transform, &mut GlobalTransform),
Expand Down