Search Unity

Pixel To World Unit Conversion

Discussion in 'Scripting' started by Healyourself, Mar 18, 2017.

  1. Healyourself

    Healyourself

    Joined:
    Jun 12, 2013
    Posts:
    4
    This is not a question, but I wanted to create a thread that would solve problems other developers may run into. I am sure this is a common topic, so I thought the code I wrote may help other people.

    It really took me a lot of thought to be able to convert pixel screen resolution units, into world units.

    A few things I should point out, this only works with an orthographic camera, and you really would only be using this if you are creating a 2D game. With a 3D game you are much better off using raycasting. This works if you game is operating on the X Y plane, I am sure you could retrofit it to other planes, but that is what it works for. Again if you have any Z depth you should probably use raycasting. Also if you change your othrographic size on your camera you need to update the variables in this script to reflect that to get accurate touch locations.

    What the code does is takes a the orthographic size from your camera you are using and finds the amount of world units in your camera, then when you touch it converts that touch directly to where in the world you touched.

    Hope it helps someone.


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class ResolutionCompensation : MonoBehavior
    5. {
    6. public Vector2 WorldUnitsInCamera;
    7. public Vector2 WorldToPixelAmount;
    8.  
    9. public GameObject Camera;
    10.  
    11. void Awake ()
    12. {
    13.         //Finding Pixel To World Unit Conversion Based On Orthographic Size Of Camera
    14.         WorldUnitsInCamera.y = Camera.GetComponent<Camera>().orthographicSize * 2;
    15.         WorldUnitsInCamera.x = WorldUnitsInCamera.y * Screen.width / Screen.height;
    16.  
    17.         WorldToPixelAmount.x = Screen.width / WorldUnitsInCamera.x;
    18.         WorldToPixelAmount.y = Screen.height / WorldUnitsInCamera.y;
    19. }
    20.  
    21.  
    22. //Taking Your Camera Location And Is Off Setting For Position And For Amount Of World Units In Camera
    23. public Vector2 ConvertToWorldUnits(Vector2 TouchLocation)
    24. {
    25.       Vector2 returnVec2;
    26.  
    27. returnVec2.x = ((TouchLocation.x / WorldToPixelAmount.x) - (WorldUnitsInCamera.x / 2)) +
    28. Camera.transform.position.x;
    29. returnVec2.y = ((TouchLocation.y / WorldToPixelAmount.y) - (WorldUnitsInCamera.y / 2)) +
    30. Camera.transform.position.y;
    31.  
    32.       return returnVec2;
    33. }
    34. }
     
    Last edited: Mar 18, 2017
  2. AndyGainey

    AndyGainey

    Joined:
    Dec 2, 2015
    Posts:
    216
  3. Healyourself

    Healyourself

    Joined:
    Jun 12, 2013
    Posts:
    4
    TBH, I am not familiar with how ScreenToWorldPoint calculates, I don't know how their back end works. It seems to act like a raycast in some respects, which is great is you have any depth, so definitely if you are creating a game with any depth that would be extremely useful. Especially a 2.5d game with a non orthographic camera, this would be a great option.

    I would imagine using a camera with orthographic view would give similar if not identical results? I haven't tested that, but I am trying to think of situations where they would give different results. I can't think of any off the top of my head. The difference is the clip planes, my code is unconcerned with clip planes or Z depth.

    So if you are not concerned with clipping planes and only want to use Vector2s. In terms of performance I would imagine it is slightly faster the way I did it, but you probably wouldn't notice any performance changes unless you casted this thousands and thousands of times a frame or something to that effect.

    So yeah, probably not a big difference now that I think about it.
     
    Arthur_Gentz likes this.
  4. IslamUni

    IslamUni

    Joined:
    Nov 29, 2015
    Posts:
    2
    Hello,
    I was looking for a quick method to replace the Camera.main.ScreenToWorldPoint() and I found that yours is significantly better @Helpyourself.
    I tested both to be sure with System.Diagnostics.StopWatch() and the results were awesome (for me).

    Capture.PNG
     
  5. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,431
    IslamUni, what was the reason you wanted to replace Camera.main.ScreenToWorldPoint()? What was its deficiency?

    If you're going to benchmark individual APIs, you should at least call the API a few thousand or even a million times. Measuring a single call for microseconds is useless. Every OS out there will have process variability that will throw off such a weak benchmarking.

    The internals of ScreenToWorldPoint have no such "ray casting" features, it's just a quick transform of coordinate systems.
     
  6. IslamUni

    IslamUni

    Joined:
    Nov 29, 2015
    Posts:
    2
    @halley , I didn't say it was deficient. i'm buidling a sprite/image slicer so i consider the slowest machines capabilities, therefore, i always favor methods that do simple mathmatical operations over the ones that depend on matrices like transformations and such, i know that my benchmark didn't consider or mention operation systems, processors, GPU ..etc but it's always better to know what the method does and how fast it is over the ones that are encapsulated or slower (so ScreenToWorldPoint() is just slower for me but not deficient), just my opinion :).
     
  7. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,518
    If no problem is observed on the target hardware then there is no need to spend time replacing it.
     
    Bunny83 and jrmgx like this.
  8. Mr_TEDDY

    Mr_TEDDY

    Joined:
    Feb 3, 2020
    Posts:
    2
    Thank you! I found this very useful to calculate my adaptive screen bounds in world units.
     
  9. LicketyCut

    LicketyCut

    Joined:
    Aug 13, 2015
    Posts:
    4
    @Helpyourself

    Calculating and defining WorldUnitsInCamera and WorldToPixelAmount has been very useful to my current project.

    Kudos!