- Home /
Understanding Unity's coordinate system
I've been looking for a few hours now (both through Google searching and browsing the Unity documentation) but I can't find the information I need to help me understand the Unity coordinate system. I'm building a 2D game.
Right now I'm am instantiating a prefab and am struggling with knowing what values to pass in for the Vector3 argument. When I put in (0,0,0) it sits in the middle of my window. I initially expected to be able to put pixel coordinates in for x and y but that didn't even show up on screen. I did find the ScreenToWorldPoint method and thought that would allow me to use pixels but now putting in (0,0,1) puts the box almost off the screen all the way on the bottom-left. I can barely see any of the window but it's there.
Looking for a little help on this one. Here's my code for reference.
Instantiate(teamView, Camera.main.ScreenToWorldPoint(new Vector3(0, 0, gameObject.layer)), Quaternion.identity);
--edit--
Following Scribe's advice I was able to learn how the screen to world points is supposed to work and the coordinate system in general. Getting it centered works fine and seems to make sense but when I use what I know about centering it to try and place it flush with the top of the screen I have some unexpected results. The prefab is the rectangular box near the top of the screen. Here is what I'm seeing:
Code:
int worldUnits = 100;
Instantiate(teamView, Camera.main.ScreenToWorldPoint(new Vector3((Screen.width / 2), (Screen.height) - ((teamView.renderer.bounds.size.y * worldUnits) / 2), gameObject.layer)), Quaternion.identity);
Result:
Answer by Scribe · Aug 30, 2014 at 09:07 PM
(0, 0) is the bottom left corner in pixel coordinates, and the top-right corner is (Screen.width, Screen.height). Where do you want the object to be placed? do you want it to always be at a certain point in the cameras view?
Also I think the z value you give the ScreenToWorldPoint method is the distance away from the camera (on its forward axis) that the object will spawn.
All in all doing something like this should spawn the object in the centre of your screen:
Vector3 worldPos = Camera.main.ScreenToWorldPoint(new Vector3((float)Screen.width/2f, (float)Screen.height/2f, 10));
Scribe
EDIT:
Okay, so this is possible (as I show below) however my question would be why? Why are you not using the Unity GUI class, I know it is not very efficient however it does make this sort of thing a lot easier. Even using a GUITexture object would probably be easier, and that would be more efficient that the GUI class if that is the problem. Another alternative (if you don't need to be releasing in the very near future) might be to grab one of the open beta packages for the new unity UI system, which makes this very easy and again would be more efficient than the current GUI classes.
That said, if you are intent on doing it using word space objects then it is possible, though as @robertbu pointed out, the z position is actually very important to what size object will eventually be rendered and so I am not sure how well using gameObject.layer will work out for you, if you plan to layer several objects (you will end up having to do quite a bit of work to get them the same width for example).
Anyway, here is some code, as it looks like you have put some effort into solving this! But I would still suggest finding a different way to do this GUI.DrawTexture is just so easy!
Vector3 offset;
float yOff;
Vector3 worldPos = Vector3.zero;
Camera cam;
Vector3 screenPos = Vector3.zero;
void Start(){
cam = Camera.main;
offset = renderer.bounds.center - transform.position; //find the difference between the actual position and the renderers positioning
yOff = renderer.bounds.max.y + offset.y; // find the distance to offset on the y axis (in world space)
transform.forward = cam.transform.forward; // look in camera direction (might have to times by minus 1 as this is configured for a quad)
screenPos.x = (float)Screen.width/2f; //
screenPos.y = ((float)Screen.height); // find the world space of top-centre screen point
screenPos.z = gameObject.layer; //
worldPos = cam.ScreenToWorldPoint(screenPos);
worldPos -= (yOff*cam.transform.up); // Minus the world offset
transform.position = worldPos;
transform.parent = cam.transform; // make the camera the parent so we don't have to keep recalculating
}
I do everything on Start and then make the object a child of the camera so that the calculations don't need to be redone after rotating/moving the camera.
Hope that helps, feel free to ask any questions about that :)
Yes that does get it to instantiate in the center of the screen. I'd like the x to be centered horizontally so that's fine, but I would like it to be flush with the top of screen. I've updated my question with some more details that shows the problem I'm having with that. Appreciate it @Scribe
Answer by robertbu · Aug 30, 2014 at 11:43 PM
There are four coordinate system in Unity: Screen, World, Viewport, and GUI.
Screen coordinates are 2D, measured in pixels and start in the lower left corner at (0,0) and go to (Screen.width, Screen.height). Screen coordinates change with the resolution of the device, and even the orientation (if you app allows it) on mobile devices.
GUI coordinates are used by the GUI system. They are identical to Screen coordinates except that they start at (0,0) in the upper left and go to (Screen.width, Screen.height) in the lower right.
Viewport coordinates are the same no matter what the resolution. The are 2D, start at (0,0) in the lower left and go to (1,1) in the upper right. For example (0.5, 0.5) in viewport coordinates will be the center of the screen no matter what resolution or orientation.
World coordinates are a 3D coordinates system and where all of your object live.
So here you appear to be asking about converting Screen coordinates to World coordinates. What you can do to make that conversion will vary a bit between a Perspective camera and an Orthographic camera.
So to visualize a Perspective camera, imagine you are standing at a window, and you reach out and a bit to your right and touch the glass. Imagine you then sight down your finger looking at objects outside. The sighting might find a near object like a tree, or a far object like a cloud or a mountain. Though the finger does not move, the distance from the finger out into the world makes a big difference in the world coordinate of that object.
So to convert a Screen coordinate to a world coordinate, you need to specify the distance from the camera plane to the plane in the world...that is, a distance in front of the camera, as a 'z' parameter. The code might look like:
Vector3 pos = Input.mousePosition;
pos.z = 10;
Vector3 worldPos = Camera.main.ScreenToWorldPoint(pos);
This code finds the world position of the mouse ten units in front of the camera.
Thanks @robertbu, do you know a good place I can find really in-depth information like this on all aspects of these systems? I'm really in need of a better understanding of all of this to solve some of the problems I'm going to have to solve for my game. I'm planning on doing a hybrid 2D 3D and right now have really no idea how that's works. Also, how to do things like supporting multiple resolutions is something still unknown to me.
(+) Local Coordinates, which is based on each game object :)
@B$$anonymous$$ayne I'm pretty sure local coordinates are simply offset world coordinates.
But why does a 800x600 pixels image not display at 800x600 size in a 2D project? How can you set Unity's world to display images at 1,1 scale compared to the actual screen resolution?
What about the Camera coordinate system? I don't understand the relationship between Camera coordinates vs Viewport coordinates. For example, we have Camera.WorldToViewportPoint() method and a Camera.worldToCamera$$anonymous$$atrix, but it doesn't appear to make the same transformation. Is it something to do with the clipping frustum? How can I convert a rotation (Quat) in world coord frame into viewport coord frame, for example?
Answer by asish_cse · Aug 19, 2021 at 05:16 PM
I'm trying to calculate distance between gaze_origin(provided by vive pro API) and the target object using following code but the units are not same for these two points. So, how to get same type of coordinate system?
var d = GameObject.Find("CubeObject").transform.position;
var combine_gaze = eyeData.verbose_data.combined.eye_data.gaze_origin_mm;
float dist = Vector3.Distance(d, combine_gaze);