Search Unity

Overlay canvas and world space coordinates

Discussion in 'Unity UI (uGUI) & TextMesh Pro' started by tosiabunio, Jan 14, 2015.

  1. tosiabunio

    tosiabunio

    Joined:
    Jun 29, 2010
    Posts:
    107
    I'm looking for good and reliable ways of translating coordinates between screen space (and overlay canvas) position and vice versa, that also take canvas scaling into consideration.

    My common use cases are:

    1. Translate mouse position to world position.
    2. Translate game object position from the world to overlay position in order to place UI element near that object.
    3. Translate anchored overlay UI element to world position.

    For case 1 I use Camera.main.ScreenToWorldPoint(Input.mousePosition) and it seems to work okay for my purposes.

    For case 2 I use RectTransformUtility.WorldToScreenPoint(Camera.main, obj.transform.position);

    For case 3 I use Camera.main.ScreenToWorldPoint(rectTransform.transform.position) and it seems to give good results.

    Are there any officially advised ways of translating between overlay canvas and world space coordinates?
     
    pcg, erfan_unity, GrandBOOM and 11 others like this.
  2. karma0413

    karma0413

    Joined:
    Dec 24, 2014
    Posts:
    5
    this is the best way to translate between these two coordinate systems.

    You could do a Matrix 4x4 transform, but it's alot more complicated than the provided Unity Methods
     
    tosiabunio likes this.
  3. reinfeldx

    reinfeldx

    Joined:
    Nov 23, 2013
    Posts:
    85
    Hallelujah! I've been fighting with case 3 for a little while now. Appears to work for mapping an object in world space to a point on the overlay UI.

    The only issue I had is that it maps my sprite to the depth (z) of the camera, and the sprite won't render that way initially. Easy to work around. Does anyone know of a built-in fix?
     
  4. Dan-MacDonald

    Dan-MacDonald

    Joined:
    Oct 25, 2013
    Posts:
    11
    I just want to say I keep coming back to this post. So helpful.
     
    tosiabunio and brunobortolotto like this.
  5. karma0413

    karma0413

    Joined:
    Dec 24, 2014
    Posts:
    5
    I found this after a couple years because i was having a problem with the conversion between world coordinates back to screen coordinate position..

    WorldToScreenPoint is slightly off!

    When canvas scaler mode is set to: stretch to screen size

    The problem is that the canvas screen point is not actually the same screen size as the current resolution... the canvas screen size is more like, the best optimized view screen resolution... under the stretch parameters you can see the variables for Reference Resolution.. this is the resolution of the canvas.

    A better explanation of CANVAS SCALING is by using my most recent problem...


    Quick Description of my problem:
    I was using the Canvas to display a sprite ( a healthbar) which floats over all the characters. The problem however, was when i tried to obtain the WorldToScreenPoint it kept giving a result that was slightly off.... for example: the healthbar looked a little okay when the character was immediately in front of the camera... but as the character walks to the edge of the camera's fulstrum, the screens x,y placement becomes more and more incorrect.

    Days and days of research and trying different combinations finally showed me that maybe there is a scaling issue which pointed me to look at **Canvas / Canvas Scaler / scaling mode: scale with screen**

    Originally, this worked wonderfully when i had only 1 character and his healthbar stayed stuck to the top of the screen like old classic double dragon games. BUT when i made the decision to have many characters and they all need "floating healthbars", i didnt come back to re-evaluate whether this option needed to change.

    **Setting the canvas Scaler to: keep constant pixel size**
    , fixes the problem and i now have the correct WORLDtoSCREENpoint that i needed! And now the healthbar floats beautifully above the characters...

    BUT WAIT, ANOTHER PROBLEM! Now, if the screen resolution is small... the Ui sprite is obsurdly large..... and if the screen resolution is high definition then Ui sprite is way too small!

    QUESTION: So how do i use the "scale with screen size" mode, but yet also still get back a correct WorldToScreenPoint?

    ANSWER: you must take into consideration the overal scaling of the canvas when it is stretched to fit (whatever current resolution that you are using)

    INSTEAD OF:
    Code (CSharp):
    1.    RectTransform myRect = GetComponent<RectTransform>();
    2.     Vector2 myPositionOnScreen = Camera.main.WorldToScreenPoint (myOwner);
    3.     myRect.anchoredPosition = myPositionOnScreen
    YOU CALCULATE THE OVERALL SCALE FACTOR LIKE THIS:
    Code (CSharp):
    1. RectTransform myRect = GetComponent<RectTransform>();
    2.         Vector2 myPositionOnScreen = Camera.main.WorldToScreenPoint (myOwner);
    3.  
    4.     Canvas copyOfMainCanvas = GameObject.Find ("Canvas").GetComponent <Canvas>();
    5.     float scaleFactor = copyOfMainCanvas.scaleFactor
    6.  
    7.     Vector2 finalPosition = new Vector2 (myPositionOnScreen.x / scaleFactor , myPositionOnScreen.y / scaleFactor);
    8.     myRect.anchoredPosition = finalPosition;

    If this helped anyone please log in to give me a thumbs up....
     
    sier_ua, Mohamed-Anis, alfish and 6 others like this.
  6. IndieForger

    IndieForger

    Joined:
    Dec 31, 2012
    Posts:
    48
    Great answer @karma0413. Thanks a lot!
     
  7. FlightOfOne

    FlightOfOne

    Joined:
    Aug 1, 2014
    Posts:
    133
    Thanks for this thread! and this reply!

    @karma0413, One question though. This doesn't work from we when I assign this to "RectTransform.AnchoredPosition".
    Don't I need to use below?
    Vector2 myPositionOnScreen = Camera.main.WorldToViewportPoint(myOwner);


    Code (CSharp):
    1.  
    2.    
    3.  public static Vector2 GetAnchoredPositionFromWorldPosition(Vector3 _worldPostion, Camera _camera,  Canvas _canvas)
    4.         {
    5.             //Vector2 myPositionOnScreen = _camera.WorldToScreenPoint(_worldPostion); // for transform.position?
    6.             Vector2 myPositionOnScreen = _camera.WorldToViewportPoint(_worldPostion); //for RectTransform.AnchoredPosition?
    7.             float scaleFactor = _canvas.scaleFactor;
    8.              return new Vector2(myPositionOnScreen.x / scaleFactor, myPositionOnScreen.y / scaleFactor);
    9.         }
    10.  
    11.  
     
  8. lifeisfunxyz

    lifeisfunxyz

    Joined:
    Aug 9, 2017
    Posts:
    8
    work with me
     
    tosiabunio likes this.