在Unity中我们通常会用到以下几个坐标系下的点:

  • 世界坐标系World Space
    简单来讲,我们通过 transform.position | transform.rotation 获取得到的位置和旋转信息都是基于世界坐标系的,可以说,我们的很大一部分操作都是基于世界坐标系。
  • 观察坐标Eye Space
    我们在Unity的Game视图中观察的画面始终是由摄像机提供的,基于摄像机的一个坐标系也就是"Eye Space"(简单来讲就是把摄像机看作原点位置)。
  • 视口坐标View Port
    视口是针对游戏显示的画面进行描述的,View Port用于描述整个游戏画面的坐标,左下角为(0,0),右上角为(1,1),我们在设计分屏游戏的时候可以通过设置摄像机所占据的视口空间来控制。
  • 屏幕坐标Screen Space
    屏幕坐标开始和像素扯上关系了,也就是说屏幕坐标和分辨率有关,屏幕的左下角为(0,0),但右上角为(screen.width,screen.height)。比如游戏的分辨率为500*600,则screen.width=500;screen.height=600

这里需要说明的是,我们在获取鼠标位置的时候,Input.mousePosition来获取鼠标的位置,这里获取到的鼠标位置是基于屏幕坐标的。通过该函数返回的是Vector3类型的变量,但z分量始终为0。

 
我们先来看一下Unity提供的相关常见函数:
//1.屏幕转世界坐标
Vector3 Camera.main.ScreenToWorldPoint(new Vector3(screenPos.x , screenPos.y , zInfo));
//2.世界转屏幕坐标
Vector3 Camera.main.WorldToScreenPoint(new Vector3(worldPos.x , worldPos.y , worldPos.z));
//3.世界转视口坐标
Vector3 Camera.main.WorldToViewportPoint();
//4.视口转世界坐标
Vector3 Camera.main.ViewportToWorldPoint(new Vector3(viewPortPos.x , viewPortPos.y , zInfo));
//5.视口转屏幕坐标
Vector3 Camera.main.ViewportToScreenPoint();
//6.屏幕转视口坐标
Vector3 Camera.main.ScreenToViewportPoint();

观察这些个函数,首先一个很明显的共同点,就是这些函数都是Camera的成员函数,输入和输出都为Vector3类型的变量。也即这些函数都是针对当前摄像机的一个变换操作。这很容易理解,因为3D游戏中的坐标从模型空间到最终的屏幕空间经过了model,view,projection,以及之后的NDC变换等,其中除model是用于从模型空间到世界空间的变换外,之后的viewprojection都是基于摄像机的。他们会随着使用相机的变化而变化。至于具体的内容,变化过程,这里不做过多描述,可以查看网上的相关文章。

当然,我们在使用这些API的时候,只需要清楚我们的输入和输出的内容及其关系就好了。

接下来,我们来聊一聊这些函数:


首先是屏幕坐标和世界坐标的相互转换:

WorldToScreenPoint函数接收一个世界空间下的位置信息,然后返回其所在的屏幕空间位置,以及其相对于摄像机的深度信息,该深度信息由世界空间下摄像机和输入位置的z值来决定。
一个例子是:摄像机的位置为(0.0, 0.0 , -10.0),输入的位置为(0.0,0.0,1.0)。则返回的结果为(screen.width/ , screen.height/ , -(-));
注意摄像机指向-z方向!
ScreenToWorldPoint则是与之相反,输入屏幕空间位置以及相应的深度信息(注意深度信息应该为目标z值金和相机z值的差值),可以返回其所在的世界坐标位置。

视口坐标和世界坐标与之相似:

WorldToViewportPoint:输入世界坐标,返回的是对应的点所在的视口位置,当然以及其相对于摄像机的深度信息(距离)
ViewportToWorldPoint:输入视口坐标(记得对应的深度信息),返回点所在的世界坐标

视口坐标和屏幕坐标非常简单,正如上面的说明,只要知道分辨率就可以轻松转换,这里不再赘述。

一个简单的应用

我们在设计某些游戏的时候(比如摄像机固定不动的类型),会对物体的运动范围进行限制,以防止其跑出边界。比如一盒横屏的飞行射击游戏(雷电),我们可以获得物体的位置信息:transform.position,我们希望对物体的x,y两个轴向的移动进行限制(同时冻结物体的z轴移动)。一个简单的思路如下:

public float leftBorder;
public float rightBorder;
public float topBorder;
public float bottomBorder; .... Vector3 leftBtm_cornerPos = Camera.main.ViewportToWorldPoint(new Vector3(0f, 0f,
Mathf.Abs(-Camera.main.transform.position.z))); //这里的z轴在正交视图下意义不大
Vector3 rightTop_cornerPos = Camera.main.ViewportToWorldPoint(new Vector3(1f, 1f,
Mathf.Abs(-Camera.main.transform.position.z)));
.... leftBorder = leftBtm_cornerPos.x;
rightBorder = rightTop_cornerPos.x;
topBorder = rightTop_cornerPos.y;
bottomBorder = leftBtm_cornerPos.y; .... if (pos.x <= leftBorder)
{
pos.x = leftBorder;
}
else if (pos.x >= rightBorde
{
pos.x = rightBorder;
} if (pos.y <= bottomBorder)
{
pos.y = bottomBorder;
}
else if (pos.y >= topBorder)
{
pos.y = topBorder;
}

上面的代码通过ViewportToWorldPoint获取到了四个边界。之后通过限制位置的xy轴向移动就可以控制避免移动过度。

说明一下,这里假设了雷电类型的游戏,使用的摄像机为正交类型的投影方式,了解正交投影的朋友就知道,视锥体变成了长方体形,因子这里的z轴并无太大的作用。即使我使用ViewportToWorldPoint的时候使用0作为z轴数据,也一样没关系。但是对于透视投影就不太一样了。若这里使用的透视投影,在不同的深度下,其的边界范围肯定也会变化,这个时候就必须输入正确的z轴数据了。

 
 

Unity 坐标系转换的更多相关文章

  1. 3D数学基础(一)Unity坐标系

    Unity引擎时非常成熟的,引擎内部运用了很多的数学知识,他对开发者来说是不可见的,而且他已经封装好的算法也不是很全面.此外,要是使用引擎封装好的算法也要明白其实现的原理. 写过一些代码,也参考了一些 ...

  2. [转]iOS开发中的火星坐标系及各种坐标系转换算法

     iOS开发中的火星坐标系及各种坐标系转换算法 源:https://my.oschina.net/u/2607703/blog/619183   其原理是这样的:保密局开发了一个系统,能将实际的坐标转 ...

  3. Objective-C上地球坐标系到火星坐标系转换算法

    Objective-C上地球坐标系到火星坐标系转换算法 http://blog.csdn.net/zhaoxy_thu/article/details/17033347

  4. GCJ-02火星坐标系和WGS-84坐标系转换关系

    GCJ-02火星坐标系和WGS-84坐标系转换关系 WGS-84:GPS坐标系 GCJ-02:火星坐标系,国测局02年发布的坐标体系,高德,腾讯等使用. BD-09:百度坐标系,百度自研,百度地图使用 ...

  5. PROJ.4学习——坐标系转换

    PROJ.4学习——坐标系转换 前言 PROJ可以做任从最简单的投影到许多参考数据非常复杂的转换.PROJ最初是作为地图投影工具开发的,但随着时间的推移,它已经发展成为一个强大的通用坐标转换引擎,可以 ...

  6. ArcGIS坐标系转换出错:Error 999999执行函数出错 invalid extent for output coordinate system

    本文主要介绍在用ArcGIS做坐标系转换过程中可能会遇到的一个问题,并分析其原因和解决方案. 如下图,对一份数据做坐标系转换: 过了一会儿,转换失败了.错误消息如下: “消息”中提示,“执行函数出错 ...

  7. iOS开发中的火星坐标系及各种坐标系转换算法

    原文地址:http://m.oschina.net/blog/619183?ref=myread 其原理是这样的:保密局开发了一个系统,能将实际的坐标转换成虚拟的坐标.所有在中国销售的数字地图必须使用 ...

  8. ios开发之坐标系转换

    1:坐标系转换最核心的问题就是:比较两个坐标是否包含,或者是重叠等,最主要的问题是先将两个坐标转换到同一个坐标系下再去比较.第一步先确定矩形框在某个view坐标系下的frame(该矩形框是以该view ...

  9. NX二次开发-UFUN CSYS坐标系转换UF_CSYS_map_point

    1 NX9+VS2012 2 3 #include <uf.h> 4 #include <uf_curve.h> 5 #include <uf_csys.h> 6 ...

随机推荐

  1. 2019年IT事故盘点【IT必读】

    昀哥@老兵笔记 2020农历新年开局不容易,新冠肺炎仍在攻艰克难阶段.回首过去的9102年,总有一些事主要是事故值得去记录.下面我们来盘点一下9102年的“外部事故”. 一,我们遭遇的IT基础设施服务 ...

  2. c#Socket通信基本使用

    基本流程 Server private void btnStart_Click(object sender, EventArgs e) { try { //当点击开始监听时在服务器端创建一个负责监视I ...

  3. BZOJ #5457: 城市 [线段树合并]

    线段树合并的板子题,每次从下到上合并就完事了 // by Isaunoya #include <bits/stdc++.h> using namespace std; #define re ...

  4. LCT[Link-Cut-Tree学习笔记]

    部分摘抄于 FlashHu candy99 所以文章篇幅较长 请有足够的耐心(不是 其实不用学好splay再学LCT的-/kk (至少现在我平衡树靠fhq) 如果学splay的话- 也许我菜吧-LCT ...

  5. STM32学习笔记 —— 0.1 Keil5安装和DAP仿真下载器配置的相关问题与注意事项

    Keil5安装的注意事项 安装细节在此不再做过多赘述,主要介绍一下注意事项: 安装路径中不能有中文. ARM的Keil的路径不能与51的Keil的有冲突,必须将目录分开. Keil5中不会自动添加芯片 ...

  6. 详解 CUDA By Example 中的 Julia Set 绘制GPU优化

    笔者测试环境VS2019. 基本介绍 原书作者引入Julia Sets意在使用GPU加速图形的绘制.Julia Set 是指满足下式迭代收敛的复数集合 \[ Z_{n+1}=Z_{n}^2+C \] ...

  7. SDN-数据控制分离

    严格来说,控制面与数据面分离并不是SDN的专利.从一个chassis角度看,传统路由器其实控制面和转发面也是分离的.Route-enginee和line card分别负责控制面板和转发面.但是传统网络 ...

  8. 题解【POJ1062】昂贵的聘礼

    题面 比较复杂的最短路模型转换. 我们考虑一种建图方式: 建立一个超级源点 \(S\),它向每一个节点连一条权值为那一个节点物品价值的边,表示直接购买那一个物品: 对于每一个节点,由它每一个可用的替代 ...

  9. 小白月赛22 E : 方格涂色

    E:方格涂色 考察点 : 思维,模拟 坑点 : long long 其他的好像没什么,读懂题意就可以 AC 不要被样例画的图所迷惑 Code: #include <vector> #inc ...

  10. 【Unity|C#】基础篇(20)——枚举器与迭代器(IEnumerable/IEnumerator)

    [学习资料] <C#图解教程>(第18章):https://www.cnblogs.com/moonache/p/7687551.html 电子书下载:https://pan.baidu. ...