Unity中的坐标系详解
前言
网上关于Unity坐标系讲解的不计其数,但真正讲的透彻明白的寥寥无几。作为新手,被Unity这几个坐标系搞的晕头转向,痛定思痛,翻阅多篇博客和帖子,汇总如下,希望给后来者提供些帮助,同时也勉励自己在IT行业走的更高更远。
如有不足之处,还望海涵,不吝批评指教,评论留言,共同进步。
Unity中经常用到的坐标系有4个,分别为世界坐标系,屏幕坐标系,视口坐标系和GUI坐标系
坐标系综述
1、世界坐标系
表示实际场景中的模型或UI元素物理位置,模型的话,就是其固有组件Transform中显示的position【父物体坐标不归零的除外】;UI元素则很少使用世界坐标去表示,主要用RectTransform表示,涉及锚点、轴心点,自行百度。
2、屏幕坐标系
所有UI或模型渲染出现在屏幕里才有意义,屏幕中显现的位置信息构成屏幕坐标系。屏幕坐标系为三维坐标系,但显示屏是二维平面的,(x,y)表示位置信息,屏幕左下角为(0,0)点【原点】,右上角为(Screen.宽度,Screen高度),以1920*1080的屏幕分辨率为例,右上角为(1920,1080),超出视野之外依然有数值,只是不显示在Game窗口中。z值表示深度,坐标系转换时细讲。
模型的屏幕坐标:(x,y)用分辨率宽高表示,z=模型pos.z-(摄像机pos.z);
UI元素的屏幕坐标:同上。
输入的鼠标位置和触摸位置,其屏幕坐标为横纵由分辨率表示,z值默认为0.
3、视口坐标系
做分屏界面时用到(赛车游戏后视镜看到的画面渲染在一个独立的窗口,这里称之为视口) 。与屏幕坐标系雷同,但略有区别。最小值(0,0)点为摄像机视野左下角,最大值(1,1)在摄像机视野右上角。z值后面坐标系转换时细讲。
4、GUI坐标系
Untiy老版UI界面,纯二维坐标系。数值类型与屏幕坐标系一样,用分辨率宽高表示。不同的是(0,0)点为左上角,(Screen.宽度,Screen高度)为右下角。【真的不常用,打脸了】
常见函数 【zInfo:深度信息】
//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();
详解
以下讲解以发布平台为PC端为例,屏幕分辨率为1920-1080,Canvas Mode为Screen Space-Camera

屏幕坐标<—>世界坐标
WorldToScreenPoint函数
接收一个世界空间下的位置信息,然后返回其所在的屏幕空间信息,x,y表示位置信息,z表示其相对于摄像机的深度信息。该深度信息由世界空间下摄像机和输入位置的z值来决定。
例子:摄像机的位置为(0.0, 0.0 , -10.0),输入的位置为(0.0,0.0,1.0)。则返回的结果为(960.0,540.0,11)【(screen.width/2 , screen.height/2 , 1-(-10))】【摄像机指向z方向,默认坐标为(0.0, 0.0 , -10.0)】
ScreenToWorldPoint函数
与WorldToScreenPoint相反,输入屏幕坐标及深度信息,返回其世界坐标位置。
需要注意的是,通常我们使用的Input.mousePosition是没有深度信息的,默认其z值为0,同理还有触摸touch形式的。类比理解:投影仪和幕布。幕布相当于屏幕,是二维平面,只有x,y位置信息;投影仪相当于摄像机,z值就如同投影仪到幕布的距离,只有知道z值才能将幕布上的点转换到三维世界坐标系中。
例子1:
public Vector3 myscreenToworld(Vector3 mousepos,Transform targetTransform)
{
//先计算相机到目标的向量
Vector3 dir = targetTransform.position - Camera.main.transform.position;
//计算投影
Vector3 normardir = Vector3.Project(dir, Camera.main.transform.forward);
//计算是节点,需要知道处置屏幕的投影距离
Vector3 worldpos = Camera.main.ScreenToWorldPoint(
new Vector3(mousepos.x,
mousepos.y,
normardir.magnitude)
);
return worldpos;
}
例子2
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//点击鼠标左键拖拽物体
public class DrageObj : MonoBehaviour
{
private Vector3 TargetScreenSpace;// 目标物体的屏幕空间坐标
private Vector3 TargetWorldSpace;// 目标物体的世界空间坐标
private Vector3 MouseScreenSpace;// 鼠标的屏幕空间坐标
private Vector3 OffsetDis;// 世界空间距离偏移量
void Awake()
{
}
IEnumerator OnMouseDown()
{
// 把目标物体的世界空间坐标转换到它自身的屏幕空间坐标
TargetScreenSpace = Camera.main.WorldToScreenPoint(transform.position);
// 存储鼠标的屏幕空间坐标(Z值使用目标物体的屏幕空间坐标)
MouseScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, TargetScreenSpace.z);
// 计算目标物体与鼠标物体在世界空间中的偏移量
OffsetDis = transform.position - Camera.main.ScreenToWorldPoint(MouseScreenSpace);
// 鼠标左键按下
while (Input.GetMouseButton(0))
{
// 存储鼠标的屏幕空间坐标(Z值使用目标物体的屏幕空间坐标)
MouseScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, TargetScreenSpace.z);
// 把鼠标的屏幕空间坐标转换到世界空间坐标(Z值使用目标物体的屏幕空间坐标),加上偏移量,以此作为目标物体的世界空间坐标
TargetWorldSpace = Camera.main.ScreenToWorldPoint(MouseScreenSpace) + OffsetDis;
// 更新目标物体的世界空间坐标
transform.position = TargetWorldSpace;
// 等待固定更新
yield return new WaitForFixedUpdate();
}
}
}
视口坐标<—>世界坐标
WorldToViewportPoint:
输入世界坐标,返回的是对应的点所在的视口位置信息,当然以及其相对于摄像机的深度信息(距离)深度信息与同一摄像机下的屏幕坐标系的深度信息相同。
ViewportToWorldPoint:
输入视口坐标(记得对应的深度信息),返回点所在的世界坐标
例子:2D游戏 角色始终在视口范围内,不能越过四周边界
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;
}
视口坐标<—>屏幕坐标
前提:知道屏幕分辨率
ViewportToScreenPoint函数
乘法:视口位置坐标 * 宽高分辨率===>屏幕坐标位置信息
视口坐标深度信息=屏幕坐标深度信息(视口pos.z=屏幕pos.z)
ScreenToViewportPoint函数
反向运算
除法:屏幕位置坐标/宽高分辨率===>视口坐标位置信息
视口坐标深度信息=屏幕坐标深度信息(视口pos.z=屏幕pos.z)
智能推荐
matlab中的三维坐标变换,从直角坐标系转换到球坐标系
使用Matlab画图时,有时三维的球坐标图更直观,需要把直角坐标转换球坐标。 代码如下: 看起来很简单的,下面写个小程序调用一下。 结果如下:...
最简单的理解android中的坐标系
一、由于自定义控件中涉及到非常多的坐标的计算,特别是ViewGroup的自定义,所以很有必要对坐标这个东西进行多些的了解,如果有了解过Path、Canvas这些东西的使用的话,肯定会知道不管你画一条线、还是一个圆或者是一个正方形,没有坐标是完成不了的,当然那些坐标是基于canvas的坐标系的,那下面我们先看一张图,看看android的坐标系跟我们日常生活中所认识得坐标系有什么不一样的: ...
PCL点云库中的坐标系(CoordinateSystem)
讲一下我所理解的PCL点云库中的坐标系统。 引言 正文 代码 参考 引言 世上本没有坐标系,用的人多了,便定义了坐标系统用来定位。地理坐标系统用于定位地球上的位置,PCL点云库可视化窗口中的坐标系统用于定位其三维世界中的位置。 本人刚开始接触学习PCL点云库,计算机图形学基础为零,以下内容基于自己的理解,如有错误,欢迎指出。 正文 首先介绍一下PCL点云库visualization模块中的PCLV...
17.ROS中的坐标系管理系统
17.ROS中的坐标系管理系统 参考书籍“”“机器人学导论” 1、机器人中的坐标变换 1.1.安装tf功能包 1.2启动roslaunch的一个脚本文件来启动很多节点 1.3运行海龟的键盘控制节点 通过键盘移动发现,后面的海龟会跟随前面的海龟运动。 2、查看系统中TF坐标系之间的关系 生成了一个pdf文件,在主目录下 有三个坐标系,海龟1,2,世界坐...
Canvas 绘制坐标系中的点以及折线
需求 上一篇章介绍了如何使用Canvas绘制坐标系,那么本篇章来看看怎么简单绘制坐标系中的点。 示例图如下: 可以看到这里绘画的坐标点比较大,为了更好看一些。其实不管大小,基本的绘制步骤如下: 设置坐标点的中心圆点位置(x0,y0) 设置坐标点的大小 dotSize 计算坐标点的上下左右四角的点坐标 条件1和2可以直接通过设置获取,而坐标点上下左右四角坐标看看下面的计算示意图。 计算坐标点的上下左...
猜你喜欢
Java运行原理
1.Java运行原理 我们可通过文本编辑板生成Java源代码(.java)经过dos窗口由Java编译器(javac.exe)生成字节码文件(.class),字节码可由Java虚拟机转化为机器码供计算机读取处理。由于Java可以生成字节码可供虚拟机转译所以可跨平台运行。运行过程如下: 所以相对于C语言还需要转化为exe文件才能运行的权限,Java具有跨平台...
Python由放弃到入门,基础篇七(类)下
类的实例化 有感于现在python教程多如牛毛,且大多高不可攀,多次拜读而不得其门道,遂由入门到放弃。偶有机缘,得一不错教程,得以入门,现博客分享,想要获取完整教程,ff17328081445。 通过对比可以看到,实例化后再使用的格式,①是空着的,意思是这里不再需要@classmethod的声明,并且在第②处,把cls替换成了self。同时,实例化后再使用的格式,需要先赋值然后再调用(第③处): ...
pytorch CNN手写字体识别
数据整体训练一次,对于accuracy都是0的问题,由于刚开始学,有些代码的细节我也没看懂,不过整体结果是对的,可能是由于pytorch版本的更新,导致accuracy的计算方式有所改变 内容转载自:https://www.bilibili.com/video/av15997678/?p=19...
linux后台运行命令总结
linux后台运行命令总结 问题: 我们有时候需要登录远程服务器跑运行时间非常长的脚本,这个时候你要让脚本后台运行,不然占着终端窗口看着不舒服。但万一网络不好,(比如我这儿的破校园网,高峰时几秒钟断一次),终端突然和服务器之间的连接断了,那脚本就会自动停了(因为运行test.sh进程的父进程就是当前的shell终端进程,关闭当前shell终端时,父进程退出,会发送hangup信号给所有子进程,子进...
类对象模型和this指针
关于类/对象大小的计算 类只是一种类型定义,它本身是没有大小可言的。 我们这里指的类的大小,其实指的是类的对象所占的大小。因此,如果用sizeof运算符对一个类型名操作,得到的是具有该类型实体的大小。 首先,类大小的计算遵循结构体的对齐原则 类的大小与普通数据成员有关,与成员函数和静态成员无关。即普通成员函数,静态成员函数,静态数据成员,静态常量数据成员均对类的大小无影响 虚函数对类的大小有影响,...
