@@ -106,6 +106,50 @@ impl GlobalTransform {
106
106
}
107
107
}
108
108
109
+ /// Returns the [`Transform`] `self` would have if it was a child of an entity
110
+ /// with the `parent` [`GlobalTransform`].
111
+ ///
112
+ /// This is useful if you want to "reparent" an `Entity`. Say you have an entity
113
+ /// `e1` that you want to turn into a child of `e2`, but you want `e1` to keep the
114
+ /// same global transform, even after re-partenting. You would use:
115
+ ///
116
+ /// ```rust
117
+ /// # use bevy_transform::prelude::{GlobalTransform, Transform};
118
+ /// # use bevy_ecs::prelude::{Entity, Query, Component, Commands};
119
+ /// # use bevy_hierarchy::{prelude::Parent, BuildChildren};
120
+ /// #[derive(Component)]
121
+ /// struct ToReparent {
122
+ /// new_parent: Entity,
123
+ /// }
124
+ /// fn reparent_system(
125
+ /// mut commands: Commands,
126
+ /// mut targets: Query<(&mut Transform, Entity, &GlobalTransform, &ToReparent)>,
127
+ /// transforms: Query<&GlobalTransform>,
128
+ /// ) {
129
+ /// for (mut transform, entity, initial, to_reparent) in targets.iter_mut() {
130
+ /// if let Ok(parent_transform) = transforms.get(to_reparent.new_parent) {
131
+ /// *transform = initial.reparented_to(parent_transform);
132
+ /// commands.entity(entity)
133
+ /// .remove::<ToReparent>()
134
+ /// .set_parent(to_reparent.new_parent);
135
+ /// }
136
+ /// }
137
+ /// }
138
+ /// ```
139
+ ///
140
+ /// The transform is expected to be non-degenerate and without shearing, or the output
141
+ /// will be invalid.
142
+ #[ inline]
143
+ pub fn reparented_to ( & self , parent : & GlobalTransform ) -> Transform {
144
+ let relative_affine = parent. affine ( ) . inverse ( ) * self . affine ( ) ;
145
+ let ( scale, rotation, translation) = relative_affine. to_scale_rotation_translation ( ) ;
146
+ Transform {
147
+ translation,
148
+ rotation,
149
+ scale,
150
+ }
151
+ }
152
+
109
153
/// Extracts `scale`, `rotation` and `translation` from `self`.
110
154
///
111
155
/// The transform is expected to be non-degenerate and without shearing, or the output
@@ -209,3 +253,60 @@ impl Mul<Vec3> for GlobalTransform {
209
253
self . transform_point ( value)
210
254
}
211
255
}
256
+
257
+ #[ cfg( test) ]
258
+ mod test {
259
+ use super :: * ;
260
+
261
+ use bevy_math:: EulerRot :: XYZ ;
262
+
263
+ fn transform_equal ( left : GlobalTransform , right : Transform ) -> bool {
264
+ left. 0 . abs_diff_eq ( right. compute_affine ( ) , 0.01 )
265
+ }
266
+
267
+ #[ test]
268
+ fn reparented_to_transform_identity ( ) {
269
+ fn reparent_to_same ( t1 : GlobalTransform , t2 : GlobalTransform ) -> Transform {
270
+ t2. mul_transform ( t1. into ( ) ) . reparented_to ( & t2)
271
+ }
272
+ let t1 = GlobalTransform :: from ( Transform {
273
+ translation : Vec3 :: new ( 1034.0 , 34.0 , -1324.34 ) ,
274
+ rotation : Quat :: from_euler ( XYZ , 1.0 , 0.9 , 2.1 ) ,
275
+ scale : Vec3 :: new ( 1.0 , 1.0 , 1.0 ) ,
276
+ } ) ;
277
+ let t2 = GlobalTransform :: from ( Transform {
278
+ translation : Vec3 :: new ( 0.0 , -54.493 , 324.34 ) ,
279
+ rotation : Quat :: from_euler ( XYZ , 1.9 , 0.3 , 3.0 ) ,
280
+ scale : Vec3 :: new ( 1.345 , 1.345 , 1.345 ) ,
281
+ } ) ;
282
+ let retransformed = reparent_to_same ( t1, t2) ;
283
+ assert ! (
284
+ transform_equal( t1, retransformed) ,
285
+ "t1:{:#?} retransformed:{:#?}" ,
286
+ t1. compute_transform( ) ,
287
+ retransformed,
288
+ ) ;
289
+ }
290
+ #[ test]
291
+ fn reparented_usecase ( ) {
292
+ let t1 = GlobalTransform :: from ( Transform {
293
+ translation : Vec3 :: new ( 1034.0 , 34.0 , -1324.34 ) ,
294
+ rotation : Quat :: from_euler ( XYZ , 0.8 , 1.9 , 2.1 ) ,
295
+ scale : Vec3 :: new ( 10.9 , 10.9 , 10.9 ) ,
296
+ } ) ;
297
+ let t2 = GlobalTransform :: from ( Transform {
298
+ translation : Vec3 :: new ( 28.0 , -54.493 , 324.34 ) ,
299
+ rotation : Quat :: from_euler ( XYZ , 0.0 , 3.1 , 0.1 ) ,
300
+ scale : Vec3 :: new ( 0.9 , 0.9 , 0.9 ) ,
301
+ } ) ;
302
+ // goal: find `X` such as `t2 * X = t1`
303
+ let reparented = t1. reparented_to ( & t2) ;
304
+ let t1_prime = t2 * reparented;
305
+ assert ! (
306
+ transform_equal( t1, t1_prime. into( ) ) ,
307
+ "t1:{:#?} t1_prime:{:#?}" ,
308
+ t1. compute_transform( ) ,
309
+ t1_prime. compute_transform( ) ,
310
+ ) ;
311
+ }
312
+ }
0 commit comments