Search Unity

Question Camera.WorldToScreenPoint misunderstanding

Discussion in 'Scripting' started by Eyellen, Jan 30, 2023.

  1. Eyellen

    Eyellen

    Joined:
    Aug 9, 2021
    Posts:
    28
    Hi, I have an issue with Camera.WorldToScreenPoint() method. Im trying to use it like crosshair for raycast hits. I cast ray and then I convert hit.point coordinates from global space to screen space via Camera.WorldToScreenPoint(), and after that I try to draw GUI.Box by using screen space coordinates. It is alright with horizontal coordinates but vertical coordinates feel like it is inverted and also it draws GUI.Box like 100px above the actual hit.point for some reason. I cant understand why it happens and I was not able to find something similar so I decided to wrote about it here. The API didn't help.
    The code is too long but I can try to provide if needed.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,695
    That's because ... wait for it... it IS inverted!! :) Yaaaay coordinate systems!

    Yeah, OnGUI is one of the few things that start at (0,0) in upper left corner, and Y goes DOWN

    So if you have a point you can just subtract the y from Screen.height

    But if you have a Rect you want to copy out the .center property ( a struct!), flip that center.y from the Screen.height, then inserted it back into the Rect.
     
    Eyellen and chemicalcrux like this.
  3. chemicalcrux

    chemicalcrux

    Joined:
    Mar 16, 2017
    Posts:
    720
    From Camera.WorldToScreenPoint:

    From Rect:

    Hence the flip. WorldToScreenPoint has the origin in the bottom-left corner. All of the GUI functions put the origin at the top-left corner.

    Subtracting the screen's height from the y-value will fix the origin issue, but you'll also need to subtract the height of the box you're drawing -- the box will grow down and right when you were expecting up and right.

    Doing both should line things up as expected.
     
    Eyellen and Kurt-Dekker like this.
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,695
    Yes, this is another way. I still kinda like the pull-center-out-flip-it-jam-it-back-in way, but it's a lot of code:

    If your Rect built around WorldToScreen is
    r
    , then:

    Code (csharp):
    1. Vector2 center = r.center;
    2. center.y = Screen.height - center.y;
    3. r.center = center;
    The copy/in/out shenanigan is necessary because Vector2 is a value type, not a reference type.
     
    Eyellen likes this.
  5. Eyellen

    Eyellen

    Joined:
    Aug 9, 2021
    Posts:
    28
    Oh it helped, thanks a lot! I was trying to fix inversion by just using negative Y and it didnt help so I was confused, but the right way is to substract Y from Screen.height. How dumb I am xD