@@ -106,6 +106,50 @@ impl GlobalTransform {
106106 }
107107 }
108108
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+
109153 /// Extracts `scale`, `rotation` and `translation` from `self`.
110154 ///
111155 /// The transform is expected to be non-degenerate and without shearing, or the output
@@ -209,3 +253,60 @@ impl Mul<Vec3> for GlobalTransform {
209253 self . transform_point ( value)
210254 }
211255}
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