InverseTransformPoint returning incorrect results

Hello,

This must be some obvious thing I’m doing wrong or some quirk I’m unaware of. I have three objects:

  1. MyMesh
    1.1 ReferenceImages (nested under MyMesh)
    1.1.1 ImagePlaneRight (nested under ReferenceImages)

All have scale 1,1,1, except ImagePlaneRight, which is 0.2,0.2,0.2.
All have 0 rotation, except ImagePlaneRight, which is 90,0,-180.
All have a localPosition set to something nonzero.

I’m calling transform.InverseTransformPoint(position) from a script on ImagePlaneRight. The resulting position is totally bogus. Here’s a log example:

newWorldPosition=(0.3, 1.9, -1.5),localPosition=(0.0, 0.0, -1.5),return=(-0.7, 0.1, 0.5)

Here, return is the result of InverseTransformPoint. I expect it to be very close to localPosition, because the world position I’m converting is colliding with ImagePlaneRight.

Is there something I’m not understanding about InverseTransformPoint? Are there situations in which it will not give correct results? I’m using Unity 5.5.0f3.

Thanks.

1 Like

well, it shouldn’t… it’s a fairly standard function.

You don’t actually show the code you use when calling it, and what code you do show mid sentence doesn’t have all the information:

What’s ‘position’, you define a bunch of other variables, but not ‘position’.

Also, what do you expect the answer to be?

If you run InverseTransformPoint it will take the input Transform Position from world space and give you its position relative to the Transform it was called from so your result is totally dependent on where you have placed the Transform you’re calling it from.

What are you expecting from it?

Sorry, I’ll attempt to be more precise. Here is an actual copy/paste snippet with no changes:

private void UpdateLocalPositionFromWorldPosition(Vector3 newWorldPosition) {
Debug.Log(“UpdateLocalPositionFromWorldPosition newWorldPosition=”+newWorldPosition+“,localPosition=” + transform.localPosition + “,transform.InverseTransformPoint=” + transform.InverseTransformPoint(newWorldPosition));
transform.position = newWorldPosition;
Debug.Log(“expectedLocalPosition=” + transform.localPosition);

And here is the output from the Log statements:
UpdateLocalPositionFromWorldPosition newWorldPosition=(0.3, 1.9, -1.5),localPosition=(0.0, 0.0, -1.5),transform.InverseTransformPoint=(-0.6, 0.1, 0.5)
expectedLocalPosition=(0.3, -0.1, -1.5)

You asked about the expected result. Apparently I get the expected result when I set:
transform.position = newWorldPosition
I don’t understand the difference between that and:
transform.localPosition = transform.InverseTransformPoint(newWorldPosition)
Shouldn’t they do the same thing?

No, it gives you newWorldPosition value relative to transform.

apparently my post is “spam like or contains inappropriate elements” so I can’t fix the formatting with code tags. sigh.

Sorry, I’m feeling super dense. How is newWorldPosition translated into local space not the same as newWorldPosition relative to transform?

Your transform stack is more than one level deep, so its only local to the first parent. If the grandparent is also a non-zero position then it adds to the offset.

Ok. So I can’t trust transform.InverseTransformPoint(newWorldPosition) when my object is nested more than one level? What’s the appropriate way to translate a world position to a local position in that case?

Just set the world position of the object instead, don’t even bother with the whole localposition mess. It’s still a child, so once it moves to that world position it will continue to behave normally (move/rotate by its parent etc).

So, when I need a localPosition, I shouldn’t use transform.InverseTransformPoint(newWorldPosition). I should set the position to the newWorldPosition and just read localPosition.

That’s… awkward. What if I need more than one localPosition in order to perform a calculation? Wouldn’t it be inefficient to move the object twice rather than calculate the position twice?

Before you use localPosition, you should ask why do you even need the local position? More importantly, why would you need the localPosition of two objects with completely different parents? That is an extremely obscure relationship.

“Awkward” would be localPosition returning the position relative to the uppermost grandparent, making it obscurely difficult to retrieve the much more commonly required local position relative to the first parent. In the majority of cases the world position can be used for calculations between objects and it will be more efficient than using localPosition and a bunch of InverseTransform methods. Even then if you had to structure it in such a way, the performance impact would be basically too miniscule to note

1 Like

I use localPosition anytime I want to think about position without relation to the world. My app is a VR vertex modeler so I tend to use localPosition to describe a vertex’s position in relation to the mesh origin. Also, snapping tends to be in relation to the local space rather than the world too.

If transform.InverseTransformPoint(newWorldPosition) doesn’t work reliably below X levels of nesting, it should say that in the documentation.

It gives you the position of itself relative to its parent. That is literally what it’s scope is. It sounds like you’re expecting it to do something outside that scope.

The docs are quite clear about what it does.

You linked to localPosition, not InverseTransformPoint: https://docs.unity3d.com/ScriptReference/Transform.InverseTransformPoint.html

All it says is “Transforms position from world space to local space.” There’s no mention of nesting issues.

I have no problem with localPosition. It works fine. My issue is that transform.InverseTransformPoint(newWorldPosition) doesn’t reliably transform a point from world space to local space.

I think you’re actually misunderstanding what “Transforms position from world space to local space.” actually means.

Not that it’s not reliable.

It IS reliable.

It’s reliable at giving the result as defined, not the result you expect.

You seem to be expecting a completely different functionality.

Give you an example.

TransformPoint takes a point in local space and makes it global. So if you had a Mesh on a GameObject, and that GameObject was nested in other gameobjects, that had scales and rotations on them, so on and so forth.

Then you accessed the ‘vertices’ of the Mesh, those vertices are in local space.

If you call TransformPoint on a vertice using the Transform of the gameobject it’s attached to. You’ll get the position of that vertex in world space.

on the flip side

InverseTransformPoint would take that resulting world space position, and return the position it would be as a vertex in the mesh.

This takes into consideration, all translations (positions), rotations, and scaling.

2 Likes

OK, i see the problem:

Nope…

Because InverseTrasnformPoint takes into consideration the transform you’re attached to.

localPosition is relative to the PARENT, not to itself. If it was relative to itself, setting it to the value <1,0,0> would move it 1 down the x-axis over and over every time you set it.

Rather it is:

transform.position = newWorldPosition;

is the same as:

transform.localPosition = transform.parent.InverseTransformPoint(newWorldPosition);

Noting that if there is no parent, position and localPosition mean the same thing.

8 Likes

That’s what I want it to do, but that’s not what it’s doing. I’m not sure why. I’m starting to think it’s a bug in this case as no one is pointing out why it’s happening.

1 Like

See my follow up response.

You have context off by 1 degree.

1 Like

Thank you. That works. It makes sense too. I’m not sure why I didn’t see it earlier.

1 Like