Set Parent's transform to make Child's transform match Target's transform

Godot Version

4.2

Question

Considering next scene tree:


What transform needs to be set to Parent so that Child’s transform would match Target’s transform? Preferably need to get Parent’s global transform from Target’s and Child’s global transform. Would appreciate any help. Linear algebra sometimes is hard.

No algebra needed. If parent transform equals child then

Parent.global_transform = Target.global_transform

If you don’t care what parent is

Child.global_transform = Target.global_transform

If you want the child on the target but the parent offset? I think you have an hierarchy issue cause that is a little strange. Why not reorder them to be easy like above? but it’s also very easy. It’s linear.

# relative difference
var target_child_diff : vector2 = Target.global_position - Child.global_position

# position
Parent.global_position += target_child_diff

# rotation/scale
Child.global_transform.basis = Target.global_transform.basis

Yeah that would have been really easy problem if it was just like you described. But the thing is that I need to keep Child’s local Transform. I mean that the rotation, scale and position relations between Child and Parent should be the same. In your code Parent’s basis does not change, therefore the previous relations of rotations of Parent and Child are ignored.
I came up with the next code that works pretty well:

Parent.GlobalTransform = Target.GlobalTransform * Child.Transform.AffineInverse();

But I still need to get the same result with only global transforms of Target and Child. Because Child maybe not the direct child of Parent. I seek for general solution for such situation.

I think you have an hierarchy issue cause that is a little strange. Why not reorder them to be easy like above?

Oh well. I really would love to make them simply not related. But in project I work on they are parts of single object where Child defines offset of Parent connection to other similar objects. It mostly made so player and game designer have more freedom in making those objects. But to be honest this system brings me headache, and I’m not really willing to rewrite existing code base.

I think my approach would work as long as you have references to the child and parent. It would also save you the computation of computing an inverse affine transform, matrix multiplication.

Just need to rearrange it a little.

# set transform 
Parent.global_transform = Target.global_transform

# relative difference
var target_child_diff : vector2 = Target.global_position - Child.global_position

# position
Parent.global_position += target_child_diff

I guess to make it completely universal.

var xf : Transform2d
var cxf : Transform2D = Child.global_transform
var pxf : Transform2D = Parent.global_transform
var txf :  Transform2D = Target.global_transform

# A Transform with relative rotation difference 
# between globals: target and child. At target origin
xf = Transform2D( txf.get_rotation() - cxf.get_rotation(), txf.origin)

# transformed parent/child offset 
xf.origin += xf.basis_xform( pxf.origin - cxf.origin )

Parent.global_Trasnform = xf

Well this just sets transform of the Parent to be equal to Targets transform which is not what I need. I need to set Child’s global transform to Target’s global transform.

I have no idea how to make it work in 3D. You can’t really represent 3D rotation with just one angle and you can’t really just subtract one basis from another. So this doesn’t makes much sense in 3D as far as I know.

Oops I thought this was 2d, but I got you one sec

looks like you need this

as to how to use it? it’s quite “complex”
basically you add this as a child of your target transform
set the remote_path variable of this RemoteTransform3d node to the Node you want to make the Node follow the Target

so when the Target node move/rotate, the Node should follow

i might mixed up the way to set it up, either that or the other way around.

Here was my test bench

extends Node3D

@onready var target :Node3D= $Target
@onready var parent  :Node3D= $Parent
@onready var child :Node3D= $Parent/Child
var xf : Transform3D
var t : Transform3D  = $Target.global_transform
var p : Transform3D  = $Parent.global_transform
var c : Transform3D = $Parent/Child.global_transform

func _ready():
  xf = Transform3D(Basis(t.basis.get_rotation_quaternion() - c.basis.get_rotation_quaternion() ),t.origin)
  xf.origin += xf.basis * (p.origin-c.origin)

func _unhandled_input(event):
  if event is InputEventKey:
    if event.pressed and not event.is_echo():
      print("pressed")
      if event.keycode == KEY_0:
        print("0")
        xf = p
      if event.keycode == KEY_1:
        print("1")

        xf = Transform3D(Basis(t.basis.get_rotation_quaternion() - c.basis.get_rotation_quaternion() ),t.origin)
        xf.origin += xf.basis * (p.origin-c.origin)

var prc:float = 0.0
func _process(delta):
  if not parent.global_transform.is_equal_approx(xf):
    prc += delta * 4
    parent.global_transform = parent.transform.interpolate_with(xf, min(prc,1.0))
  else:
    prc = 0.0
 

I finally got it.

parent.global_transform = target.global_transform * child.global_transform.affine_inverse() * parent.global_transform

This was easier than the quaturnions, but funny enough the quaternions got me here.

I still don’t really understand how this works.

2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.