一、前言

1、Unity3D采用的是左手坐标系。

unity经纬度转空间坐标 unity3d坐标_屏幕坐标

2、Inspector 中物体的 Position 的值是世界坐标系下的值。只有当一个物体具有父物体时,它才会以相对坐标来描述其位置。

3、目前来说我们所见过的三维建模软件或者游戏开发软件所用的坐标系分两种:左手坐标系和右手坐标系。

unity经纬度转空间坐标 unity3d坐标_屏幕坐标_02

区分坐标系可以按上图方法,这里我也有个简单的判断方法:用手握住 z 轴,大拇指朝向 z 轴正方向,然后用手的四指从 x 轴正方向握拳头,如果是左手 90 度就能把四指握到 y 轴就是左手坐标系,如果是右手 90 度握紧后到了 y 轴就是右手坐标系。


二、坐标体系: 水平方向为X轴,竖直方向为Y轴 
Unity3D 当中基本的坐标体系主要有下面这四种:

  1. 世界坐标系 (World Space)
  2. 屏幕坐标系 (Screen Space)
  3. 视口坐标系 (Viewport Space)
  4. GUI界面坐标系 (GUI System)

unity经纬度转空间坐标 unity3d坐标_屏幕坐标_03


这四种坐标系可以说没有一个是完全相同的,各个坐标系所代表的意思也可以从字面含义中理解出来,它们之间都是可以相互转换的,不过 GUI 坐标体系除外,它比较特殊,也相对来说是最简单的,那么我们就从最简单的说起吧。

1. 绘制 GUI 界面的坐标体系

我们在做 Unity 游戏开发的时候,经常会使用内置的 GUI 来做一些测试,比如显示一个按钮控制游戏,画一个文本显示相关信息等。它的代码全部控制在 OnGUI() 函数中:

private void OnGUI()
{
    if (GUI.Button(new Rect(0f, 0f, 160f, 40f), "Click Me"))
    {
        //button clicked and do something here...
    }
}
这个按钮 Button 所在的坐标系就是 GUI 绘制坐标系。大家稍微测试一下就知道了,它的原点 (0, 0) 在最左上角,因为屏幕宽度是 Screen.width ,高度是 Screen.height ,所以 GUI 体系右下角的坐标为: (Screen.width, Screen.height) , 这是一个二维的坐标体系,坐标 z的值都为 0 。大家可以看下图加深理解:

unity经纬度转空间坐标 unity3d坐标_屏幕坐标_04

2. 视口 Viewport 坐标体系

当我们使用多个相机,在同一个场景中显示多个视口的时候,我们就需要用上视口坐标系了。

视口坐标系对于场景的显示非常重要,对于新手来说我们经常使用一个相机就够了,但是当需要使用到多个视口的时候,我们就必须关注视口坐标体系了,大家可以在相机 Camera 的属性中看到 Viewport Rect 就是视口坐标系的设置:

unity经纬度转空间坐标 unity3d坐标_屏幕坐标_05

一个相机对应一个视口,视口预览( Camera Preview )展示了相机所看到的所有物体,很显然,它默认大小是 (width = 1, height = 1) ,位置也是从 0 到 1 ,这个位置就是我们所讨论的坐标系:左下角为 (0, 0) ,右上角是 (1, 1) ,一般视口坐标系主要用在相机显示中,我们简单的进行 Viewport Rect 的设置就可以了。

3. 屏幕 Screen 坐标体系

嗯,非常重要!不管怎样,最终我们所有的成果都会发布到各个平台(屏幕)上,所以,任何坐标系的坐标和屏幕坐标系的转换都是非常重要的。比如我们经常需要处理鼠标的相关事件(鼠标位置、单击、双击事件等),或者手机上的触摸反馈,这些原始数据都是屏幕坐标系相关的。

虽然重要,其实屏幕坐标系处理起来很简单直接, Input.mousePosition 获取的就是鼠标在屏幕中的位置坐标。大家可以测试一下,屏幕坐标系中原点 (0, 0) 位于左下角,那么右上角必然就是 (Screen.width, Screen.height) ,对了,还有一个 z 呢?都为 0 吗?答案是肯定的,既然是二维坐标系那么 z 肯定是 0 了,和 GUI 坐标系一样,但是话又说回来,屏幕坐标系转换成世界坐标系 z 还是 0 吗?其实不然,屏幕坐标转换成世界坐标后物体的 z 值是取决于相机的,因此: gameObject.z = camera.z ,其实在上面视口坐标系介绍中的图中我已经把 Mouse Point鼠标位置转换成世界坐标( World Point )了,大家应该注意到了吧。

那么,除了坐标系的转换,还有什么值得注意的呢?这里我要告诉大家的是,我们在控制相机的时候,因为屏幕显示的就是相机所看到的内容,而屏幕的宽高比直接影响了相机的显示,也就是 Aspect Ratio 的值,大家可以在 Game 面板中轻松地设置 Aspect 宽高比,查看对游戏画面的影响:

unity经纬度转空间坐标 unity3d坐标_世界坐标_06

4. 世界 World 三维坐标系

最后,世界坐标系!世界坐标系不是最简单的,但却是我们最常用的坐标系。记住一点,任何情况下: transform.position 都是返回物体的世界坐标值,及时你所使用的是子物体!另外,从上面所讲的屏幕坐标系转换成世界坐标系也是非常简单的,它以当前相机为参考:

var position = Input.mousePosition;
var worldPoint = Camera.main.ScreenToWorldPoint(position);

另一方面,我们在游戏开发过程中,经常要处理子物体的相对 transform 值,这个时候我们就需要稍微动点脑子了,当然如何转变 Unity 已经帮我们预制好相应的函数方法了,你只要把父物体当做世界,子物体当做世界中的物体,使用这些函数,换一下坐标就和处理绝对坐标一样了,不知道大家理解没有。我举个例子,我们在游戏开发中会遇到这种情况,你的相机如果直接放到世界中那么必然会需要调整它的旋转角度才能达到满意的视口位置,如何不让相机产生任何旋转就能把世界中的游戏物体放到合适的视口位置呢?

办法就是:我们把相机放到一个产生了合适旋转角度的父物体当中!这样做的效果就是:相机就相当于子物体,父物体旋转了,子物体就不需要额外旋转了,这时候相机的局部旋转就为 0 。这在有些场景中使用起来很方便,相机已经是父物体世界中的子物体了。

怎么计算相对坐标呢?在 Unity 中都有相应的函数,使用比较简单:

//获取的是世界坐标
var childPosition = childObject.transform.position;
//转化为父物体下的相对坐标,相当于位于父物体世界中
var relativePosition = parentObject.transform.InverseTransformPoint(childPosition);
//转化为世界坐标,注意:这里不能传入 childPosition ,因为 childPosition 就是世界坐标
var worldPosition = parentObject.transform.InverseTransformPoint(relativePosition);
//所以,下面结果是相等的!
print(childPosition == worldPosition);

U3D局部坐标和全局坐标详解(或世界坐标)