Search Unity

InverseTransformPoint returning incorrect results

Discussion in 'Scripting' started by createthiscom, Jan 10, 2017.

  1. createthiscom

    createthiscom

    Joined:
    Dec 19, 2016
    Posts:
    67
    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.
     
    Last edited: Jan 10, 2017
    Mandark likes this.
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,539
    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?
     
  3. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,537
    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?
     
  4. createthiscom

    createthiscom

    Joined:
    Dec 19, 2016
    Posts:
    67
    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?
     
  5. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,537
    No, it gives you `newWorldPosition` value relative to `transform`.
     
  6. createthiscom

    createthiscom

    Joined:
    Dec 19, 2016
    Posts:
    67
    apparently my post is "spam like or contains inappropriate elements" so I can't fix the formatting with code tags. sigh.
     
  7. createthiscom

    createthiscom

    Joined:
    Dec 19, 2016
    Posts:
    67
    Sorry, I'm feeling super dense. How is newWorldPosition translated into local space not the same as newWorldPosition relative to transform?
     
  8. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,537
    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.
     
  9. createthiscom

    createthiscom

    Joined:
    Dec 19, 2016
    Posts:
    67
    Ok. So I can't trust
    Code (CSharp):
    1. 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?
     
  10. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,537
    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).
     
  11. createthiscom

    createthiscom

    Joined:
    Dec 19, 2016
    Posts:
    67
    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?
     
  12. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,537
    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
     
    Rodolinc likes this.
  13. createthiscom

    createthiscom

    Joined:
    Dec 19, 2016
    Posts:
    67
    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.
     
  14. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,537
    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.
     
  15. createthiscom

    createthiscom

    Joined:
    Dec 19, 2016
    Posts:
    67
    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.
     
  16. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,539
    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.
     
    mikeohc and LaneFox like this.
  17. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,539
    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:

    Code (csharp):
    1.  
    2. transform.position = newWorldPosition;
    3.  
    is the same as:

    Code (csharp):
    1.  
    2. transform.localPosition = transform.parent.InverseTransformPoint(newWorldPosition);
    3.  
    Noting that if there is no parent, position and localPosition mean the same thing.
     
  18. createthiscom

    createthiscom

    Joined:
    Dec 19, 2016
    Posts:
    67
    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.
     
    LaneFox likes this.
  19. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,539
    See my follow up response.

    You have context off by 1 degree.
     
    LaneFox likes this.
  20. createthiscom

    createthiscom

    Joined:
    Dec 19, 2016
    Posts:
    67
    Thank you. That works. It makes sense too. I'm not sure why I didn't see it earlier.
     
    LaneFox likes this.
  21. cameronhorst

    cameronhorst

    Joined:
    Jul 20, 2017
    Posts:
    1
    Been struggling with this exact thing. Thanks for clarifications!
     
  22. Reahreic

    Reahreic

    Joined:
    Mar 23, 2011
    Posts:
    254
    @lordofduct
    Please ignore my stupidity, It finally dawned on me. Using the entity's local position but calculating using the entity's transform itself and not it's parent transform meant I was actually calculating the position of the entity as if it was it's own child and not itself.

    Spoiler'd my post to compact it for the future as I'm sure to find myself back here again at some point down the line once I've forgotten...
    My apologies for the necro, but I'm trying to understand a bug in my code and believe it's related to my misunderstanding of this, but am unable to wrap my head around the below Log output.

    I've created a test article that prints out position and localPosition values before the Entity changes parent's as well as afterwards but am unable to reconcile the bolded values below from Debug.Log.

    There are three gameObjcts which don't move in an otherwise empty debug scene:
    • Parent A at world (0, 0.5, 0)
    • Parent B at world (11, 0.5, 0)
    • Entity at world (0, 0.5, 0)
    Conceptually: (These make sense)
    1. When Entity is a child of Parent A it's position is (0, 0.5, 0) and it's localPosition is (0, 0, 0)
    2. When Entity is a child of Parent B it's position is (0, 0.5, 0) and it's localPosition is (-11, 0, 0)
    Debug.Log Values: (Err...)
    1. Entity is moved from Parent A to Parent B
      (BeforeParentChanged)
      W: (0.0, 0.5, 0.0) | L: (0.0, 0.0, 0.0)
      W: (0.0, 0.5, 0.0) | L: (0.0, 0.0, 0.0)
      W: (0.0, 0.5, 0.0) | L: (0.0, 0.0, 0.0)

      (AfterParentChanged)
      W: (0.0, 0.5, 0.0) | L: (-11.0, 0.0, 0.0)
      W: (-11.0, 0.5, 0.0) | L: (0.0, 0.0, 0.0) //World X showing local X, and local X showing world X
      W: (0.0, 0.5, 0.0) | L: (-11.0, 0.0, 0.0)

    2. Entity is moved from Parent B to Parent A
      (BeforeParentChanged)
      W: (0.0, 0.5, 0.0) | L: (-11.0, 0.0, 0.0)
      W: (-11.0, 0.5, 0.0) | L: (0.0, 0.0, 0.0) //World X showing local X, and local X showing world X
      W: (0.0, 0.5, 0.0) | L: (-11.0, 0.0, 0.0)

      (AfterParentChanged)
      W: (0.0, 0.5, 0.0) | L: (0.0, 0.0, 0.0)
      W: (0.0, 0.5, 0.0) | L: (0.0, 0.0, 0.0)
      W: (0.0, 0.5, 0.0) | L: (0.0, 0.0, 0.0)

    Test article Code
    Code (CSharp):
    1. using System;
    2. [ExecuteAlways]
    3. public class TestArticle: MonoBehaviour {
    4.     public event Action OnBeforeParentChange;
    5.     public event Action OnAfterParentChange;
    6.  
    7.     void OnBeforeTransformParentChanged() {
    8.         OnBeforeParentChange?.Invoke();
    9.     }
    10.     void OnTransformParentChanged() {
    11.         OnAfterParentChange?.Invoke();
    12.     }
    13.  
    14.     void OnEnable() {
    15.         OnBeforeParentChange += BeforeParentChanged;
    16.         OnAfterParentChange += AfterParentChanged;
    17.     }
    18.     void OnDisable() {
    19.         OnBeforeParentChange -= BeforeParentChanged;
    20.         OnAfterParentChange -= AfterParentChanged;
    21.     }
    22.  
    23.     void BeforeParentChanged() {
    24.         Debug.Log("W: "+transform.position+" | L: "+transform.localPosition);
    25.         Debug.LogWarning("W: " + transform.TransformPoint(transform.localPosition) + " | L: " + transform.InverseTransformPoint(transform.position));
    26.         Debug.LogError("W: "+transform.localPosition.parent.TransformPoint(transform) + " | L: " + transform.position.parent.InverseTransformPoint(transform));
    27.     }
    28.     void AfterParentChanged() {
    29.         Debug.Log("W: " + transform.position + " | L: " + transform.localPosition);
    30.         Debug.LogWarning("W: " + transform.TransformPoint(transform.localPosition) + " | L: " + transform.InverseTransformPoint(transform.position));
    31.         Debug.LogError("W: " + transform.localPosition.parent.TransformPoint(transform) + " | L: " + transform.position.parent.InverseTransformPoint(transform));
    32.     }
    33. }
    34.  
     
    Last edited: Jan 25, 2021
    SantiagoIsAFK likes this.