Finding position of an object relative to a parent

How can we find the position of an object relative to some ancestor? This would be sort of like decomposing matrixWorld, but instead of being relative to the root node (Scene) I’m looking to have it be relative to some ancestor that isn’t the root node.

Maybe, I can temporarily place the ancestor node in another non-rendered Scene, update world matrices, then once I have that I can place it back into the original Scene. I haven’t tried it yet, but I can imagine a downs side of this approach would be that it will calculate world transforms of all nodes that are under the ancestor node.

Is there another way that is more efficient that only involves the single branch from ancestor to object of interest?
How can we do this?

Assume that the object has also arbitrary rotation in any of it’s ancestors all the way up to the target ancestor. So all the rotations affect the object’s final position. For example, suppose we have this branch:

              o ancestor
               \
                \
                 o
                /
               o
                \     o object whose position we want relative to ancestor
                 \   /
                  \ /
                   o

If there’s no rotation in any nodes of the branch, obviously we just add the positions and we’ll get the final result. How do we take into account rotation?

1 Like

I would use localToWorld and worldToLocal:

var v = new THREE.Vector3();
v.copy(object.position);
object.localToWorld(v);
parent.worldToLocal(v);
console.log(v);
5 Likes

Ah, sweeeet, that’s simple. Thanks!

What I’m trying to do is then find relative position to the parent of two objects (that may have completely different ancestors between them and parent) and I want to animate one object to the other object.

I think I can do this in onBeforeRender by turning off matrixAutoUpdate, animating the position of the matrixWorld of first object to second object (using decompose and compose), then reenabling matrixAutoUpdate after the animation is complete (and being sure to decompose the final matrixWorld back into the object’s position/quaternion/scale). Does that seem about right? Or is there a better way?

So, you want to keep the hierarchy the same right, but just move object 1 until it is in the same relative position as object 2? In that case I don’t think you need to worry about either object’s parent, because the transforms are baked into matrixWorld. It’s enough just to use the code snippet above replacing object with target and parent with object:

// compute `v`, position of `target` in `object` coordinate space
var v = new THREE.Vector3();
v.copy( target.position );
target.localToWorld( v );
object.worldToLocal( v );

// convert `v` into vector from object to target
v.sub( object.position );

// break early if target is close
if ( v.manhattanLength() < 0.001 ) return;

// scale vector to step size
v.setLength( speed * clock.getDelta() );

// move object toward target
object.position.add( v );

Or you could use tweenjs to move toward that local target position, once you have it.

2 Likes

What if the ancestors of target and of object all have rotation. So to get to the common ancestor of both target and object it requires traversing up 3 or 5 ancestors (respectively, arbitrary numbers for she of example). And all ancestors of both target and object have various differing rotations (and, maybe differing scales too, but let’s ignore that for now).

Then does the above method still work?

worldToLocal and localToWorld will apply or undo the entire matrixWorld transformation, which represents the combined position, scale, and rotation of all an object’s ancestors. So this method should work regardless of any of that, assuming matrixWorld is up to date. By default it updates once per frame, I think, or you can force an update.