forked from bevyengine/bevy
-
Notifications
You must be signed in to change notification settings - Fork 1
/
global_transform.rs
210 lines (180 loc) · 6.32 KB
/
global_transform.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
use std::ops::Mul;
use super::Transform;
use bevy_ecs::{component::Component, reflect::ReflectComponent};
use bevy_math::{Affine3A, Mat4, Quat, Vec3, Vec3A};
use bevy_reflect::{std_traits::ReflectDefault, FromReflect, Reflect};
/// Describe the position of an entity relative to the reference frame.
///
/// * To place or move an entity, you should set its [`Transform`].
/// * To get the global transform of an entity, you should get its [`GlobalTransform`].
/// * For transform hierarchies to work correctly, you 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.
///
/// # Examples
///
/// - [`global_vs_local_translation`]
///
/// [`global_vs_local_translation`]: https://github.com/bevyengine/bevy/blob/latest/examples/transforms/global_vs_local_translation.rs
#[derive(Component, Debug, PartialEq, Clone, Copy, Reflect, FromReflect)]
#[reflect(Component, Default, PartialEq)]
pub struct GlobalTransform(Affine3A);
macro_rules! impl_local_axis {
($pos_name: ident, $neg_name: ident, $axis: ident) => {
#[doc=std::concat!("Return the local ", std::stringify!($pos_name), " vector (", std::stringify!($axis) ,").")]
#[inline]
pub fn $pos_name(&self) -> Vec3 {
(self.0.matrix3 * Vec3::$axis).normalize()
}
#[doc=std::concat!("Return the local ", std::stringify!($neg_name), " vector (-", std::stringify!($axis) ,").")]
#[inline]
pub fn $neg_name(&self) -> Vec3 {
-self.$pos_name()
}
};
}
impl GlobalTransform {
/// An identity [`GlobalTransform`] that maps all points in space to themselves.
pub const IDENTITY: Self = Self(Affine3A::IDENTITY);
#[doc(hidden)]
#[inline]
pub fn from_xyz(x: f32, y: f32, z: f32) -> Self {
Self::from_translation(Vec3::new(x, y, z))
}
#[doc(hidden)]
#[inline]
pub fn from_translation(translation: Vec3) -> Self {
GlobalTransform(Affine3A::from_translation(translation))
}
#[doc(hidden)]
#[inline]
pub fn from_rotation(rotation: Quat) -> Self {
GlobalTransform(Affine3A::from_rotation_translation(rotation, Vec3::ZERO))
}
#[doc(hidden)]
#[inline]
pub fn from_scale(scale: Vec3) -> Self {
GlobalTransform(Affine3A::from_scale(scale))
}
/// Returns the 3d affine transformation matrix as a [`Mat4`].
#[inline]
pub fn compute_matrix(&self) -> Mat4 {
Mat4::from(self.0)
}
/// Returns the 3d affine transformation matrix as an [`Affine3A`].
#[inline]
pub fn affine(&self) -> Affine3A {
self.0
}
/// Returns the transformation as a [`Transform`].
///
/// The transform is expected to be non-degenerate and without shearing, or the output
/// will be invalid.
#[inline]
pub fn compute_transform(&self) -> Transform {
let (scale, rotation, translation) = self.0.to_scale_rotation_translation();
Transform {
translation,
rotation,
scale,
}
}
/// Extracts `scale`, `rotation` and `translation` from `self`.
///
/// The transform is expected to be non-degenerate and without shearing, or the output
/// will be invalid.
#[inline]
pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) {
self.0.to_scale_rotation_translation()
}
impl_local_axis!(right, left, X);
impl_local_axis!(up, down, Y);
impl_local_axis!(back, forward, Z);
/// Get the translation as a [`Vec3`].
#[inline]
pub fn translation(&self) -> Vec3 {
self.0.translation.into()
}
/// Mutably access the internal translation.
#[inline]
pub fn translation_mut(&mut self) -> &mut Vec3A {
&mut self.0.translation
}
/// Get the translation as a [`Vec3A`].
#[inline]
pub fn translation_vec3a(&self) -> Vec3A {
self.0.translation
}
/// Get an upper bound of the radius from the given `extents`.
#[inline]
pub fn radius_vec3a(&self, extents: Vec3A) -> f32 {
(self.0.matrix3 * extents).length()
}
/// Transforms the given `point`, applying shear, scale, rotation and translation.
///
/// This moves `point` into the local space of this [`GlobalTransform`].
#[inline]
pub fn transform_point(&self, point: Vec3) -> Vec3 {
self.0.transform_point3(point)
}
/// Multiplies `self` with `transform` component by component, returning the
/// resulting [`GlobalTransform`]
#[inline]
pub fn mul_transform(&self, transform: Transform) -> Self {
Self(self.0 * transform.compute_affine())
}
}
impl Default for GlobalTransform {
fn default() -> Self {
Self::IDENTITY
}
}
impl From<Transform> for GlobalTransform {
fn from(transform: Transform) -> Self {
Self(transform.compute_affine())
}
}
impl From<Affine3A> for GlobalTransform {
fn from(affine: Affine3A) -> Self {
Self(affine)
}
}
impl From<Mat4> for GlobalTransform {
fn from(matrix: Mat4) -> Self {
Self(Affine3A::from_mat4(matrix))
}
}
impl Mul<GlobalTransform> for GlobalTransform {
type Output = GlobalTransform;
#[inline]
fn mul(self, global_transform: GlobalTransform) -> Self::Output {
GlobalTransform(self.0 * global_transform.0)
}
}
impl Mul<Transform> for GlobalTransform {
type Output = GlobalTransform;
#[inline]
fn mul(self, transform: Transform) -> Self::Output {
self.mul_transform(transform)
}
}
impl Mul<Vec3> for GlobalTransform {
type Output = Vec3;
#[inline]
fn mul(self, value: Vec3) -> Self::Output {
self.transform_point(value)
}
}