World Space(世界坐标): : 物体相对于世界来说的坐标系
左手坐标系
在unity中, 有一个肉眼可见的世界坐标系
以世界原点为坐标原点建立的三维坐标系(U3D场景中的整个球形世界的原点) unity中在物体身上自动显示的坐标系,获得GameObject世界坐标的接口为Transform.position 。局部坐标系是GameObject以Parent的世界坐标点为坐标原点建立的三维坐标系,GameObject的局部坐标即与Parent的相对位置。若GameObject无Parent,其局部坐标与世界坐标相同,获得GameObject局部坐标系的接口为
通过Transform.localPosition可以获得该位置坐标。
世界坐标转化为屏幕坐标 Camera.WorldToScreenPoint
世界坐标转化为视口坐标 Camera.WorldToViewportPoint
Screen Space(屏幕坐标):
以屏幕左下角为原点建立的一个二维坐标系,
屏幕的左下角坐标为(0, 0),右上角为(Screen.width, Screen.height) 。
通过Input.mousePosition获取 的鼠标坐标是一个屏幕坐标。
屏幕坐标转化为世界坐标 Camera.ScreenToWorldPoint
屏幕坐标转化为视口坐标 Camera.ScreenToViewportPoint
ViewPort Space(视口坐标): 相当于锚点的情况
视口坐标是标准是相对于相机的。
相机的左下角为(0,0)点,右上角为(1,1) 点,
Z的位置是以相机的世界单位来衡量的。
视口坐标转化为世界坐标 Camera.ViewportToWorldPoint
视口坐标转化为屏幕坐标 Camera.ViewportToScreenPoint
GUI坐标系: 主要记住上面三个坐标,这个GUI的不死记
GUI坐标是指通过OnGUI方法绘制UI时使用的坐标,这个坐标系
与屏幕坐标系相似 ,它同样是以像素来定义的,不同的是该坐标系以
~~屏幕的左上角为(0,0)点,右下角为(Screen.width,Screen.height)。~~
本地坐标系: 在unity中, 物体相对于父物体来说的坐标系
有一个肉眼可见的本地坐标系,
当我们选中一个物体时, 就会显示出其本地坐标系。
本地坐标系也是一个左手坐标系。*
本地坐标: 如果游戏对象没有父对象, 我们可以认为它的世界坐标和本地坐标都是相对于(0,0,0)点来说的, 本地坐标和世界坐标相等。如果游戏对象有父对象,
它的本地坐标是相对于父亲来说的。挂载在游戏对象上的脚本可以通过transform.localPosition来获得本地坐标
1)World Space(世界坐标):标准的D3D左手坐标系 unity每个物体自身都自动的显示了出来了自身的世界坐标系 ,旋转方向是左手法则包括法向量方向,背面剔除逆时针的。我们在场景中添加物体(如:Cube),他们都是以世界坐标显示在 transform.position 可以获得该位置坐标。例如:MainCamera的坐标系是(0,0,-10);
注意模型中的嵌套父子坐标系,连续的变换,和变换的累计(骨骼动画中的缩放旋转累计变换,平移不累计变换)。变换坐标系等同于相反的方向变换物体,但是最终还是要用矩阵的方式来表达,旋转用欧拉角/四元数/矩阵来表达。
2)view Space(视图坐标系):是标准的OPenGL右手坐标系 ,即初中学的立方体的右手坐标系,xy不变,-z向里,旋转方向是右手法则了,背面剔除顺时针的面;相比世界坐标系变了位置和旋转,所以除了顶点变换(z值),世界坐标系中的三角形索引也要改变,那么面法向量就不用取反(骨骼动画中需要每帧计算顶点位置和法向量位置,索引uv不变)。后面的ndc viewport坐标系和屏幕坐标系都是右手坐标系类型了。
3 )cull space (perspective space投影坐标系): 视图坐标系的放大(结果是没有除以w之前的值),x’=xxScale, y’=yyScale,
z’=a*z + b=(z + zn)*zf / (zn-zf) z’是比原来的|z|小一点的正数。
因为yScale = cot(fovy/2)=zoomy,变换后为x*xScale.也就是yScale越小也就是fovy/2越大,那么能够描述的空间越大,同理:
w / h = yScale / xScale 。
xScale = yScale * (h / w), w越大xScale越小,描述的空间越大。
因为是右手坐标系除以-z后计算只是用后面的关系方便,转换为前面的关系(4D中)还是az+b = z’的。所以在RH z NDC坐标系中转换到[0,1],OGL中转换到[-1,1],z’= (az + b)/-z => z’ = -a + b/-z =>当用zn代入时因为zn是正数,-z也是正数
所以为:z’ = -a + b/zn
z’ = -a + b/zf
例如:D3DXMatrixPerspectiveFovRH中得到:
0 = -a + b / zn;
1 = -a + b / zf;
得到:
xScale 0 0 0
0 yScale 0 0
0 0 zf/(zn-zf) -1
0 0 znzf/(zn-zf) 0
验证得到U3D引擎中中的perspective空间是在x’=xxScale, y’=yyScale,z’=az + b=(z + zn)*zf / (zn-zf)。zn,zf都是距离是正数,因为|z| > zn,且z是负数,所以z’是正数。
4)ndc space, ViewPort Space(视口坐标):视口坐标是标准的和相对于相机的。相机的左下角为(0,0)点,右上角为(1,1)点,屏幕中心为[0.5,0.5],z值保留了透视投影中的正值但是值的大小是世界坐标系的值。不同于D3D中的[-1,-1,0]到[1,1,1],也不同于OGL中的[-1,-1,-1]到[1,1,1]。
5)Screen Space(屏幕坐标,鼠标坐标):以像素来定义的,以屏幕的左下角为(0,0)点 ,右上角为(Screen.width,Screen.height),
z值保留了透视投影中的正值但是值的大小是世界坐标系的值。注:鼠标位置坐标属于屏幕坐标,Input.mousePosition可以获得该位置坐标幕也为屏幕坐标,Input.GetTouch(0).position可以获得单个手指触摸屏幕坐标。
6)绘制GUI界面的坐标系:这个坐标系与屏幕坐标系相似,不同的是该坐标系以屏幕的左上角为(0,0) 点,右下角为(Screen.width,Screen.height)。
其它坐标系:LineRender坐标:以屏幕中心为原点,向上向右增加。
UGUI设计坐标系和Unity屏幕坐标系是一致的,左下角为(0,0)右上角为(width,height)。
见u3d Camera类。
视图和透视投影的坐标系变换需要用矩阵来进行,一般在shader中需要操作。
世界坐标→屏幕坐标:
camera.WorldToScreenPoint(transform.position);
屏幕坐标→视口坐标:
camera.ScreenToViewportPoint(Input.GetTouch(0).position);
这样可以将屏幕坐标转换为视camera为场景中的camera对象。
视口坐标→屏幕坐标:
camera.ViewportToScreenPoint();
视口坐标→世界坐标:
camera.ViewportToWorldPoint();
InverseTransformPoint: 绝对坐标转相对坐标,也就是世界坐标转你想要放到的父节点下的相对坐标,
TransformPoint: 相对坐标转绝对坐标,也就是你想要放到的父节点下的相对坐标转成世界坐标,
调用方法就是,比如你想把鼠标点击的位置转换成你某一个父节点下的ngui坐标。
操作如下
Vector3 vec = new Vector3();
Ray ray=UICamera.mainCamera.ScreenPointToRay(Input.mousePosition);// 向屏幕发射线RaycastHit hit;
if(Physics.Raycast(ray,out hit))
{
// hit.point已经是世界坐标系位置了,vec是相对于父坐标系的位置
vec = 你想转到的父节点物体.transform.InverseTransformPoint(hit.point);
}
这样就得到了一个屏幕点击转向ngui的父节点的相对坐标,其他的物体也是用此类方法使用,这样保证了操作坐标的流畅性,不用创建那么多的虚拟体,当然相对坐标转绝对坐标也一样的用法,不用创建虚拟体,你想把某一个父节点下的相对于这个父节点的某一个位置转成世界坐标跟上边一样的用法,你当前的父物体.transform.TransformPoint(相对于该父物体的位置);
这样就可以转成世界坐标,世界坐标通用场景所有物体,想做什么就可以做什么了。
#pragma strict
public var moveTranform: Transform;
public var cameraMain: Camera;
function DisplayVector( tag:String, vecValue: Vector3)
{
print(tag + “pos:(”+vecValue.x + “,” + vecValue.y + “,” + vecValue.z + “)”);
}
function Start () {
// 观察输出结果,得到view space, perspective space, ndc viewport space, screen space的坐标系证明
var worldPos: Vector3;
var viewPos: Vector3;
var perspectivePos: Vector3;
var ndcPos: Vector3;
var screenPos: Vector3;
// 1.world
worldPos = moveTranform.position;
DisplayVector(“worldPos”, worldPos);
// 2.view
viewPos = cameraMain.worldToCameraMatrix.MultiplyPoint3x4(worldPos);
DisplayVector(“viewPos”, viewPos);
// 3.perspective
perspectivePos = cameraMain.projectionMatrix.MultiplyPoint3x4(viewPos);
DisplayVector(“perspectivePos”, perspectivePos);
// 4.ndcpos
ndcPos = cameraMain.WorldToViewportPoint (worldPos);
DisplayVector(“ndcPos”, ndcPos);
//5.screen pos
screenPos = cameraMain.WorldToScreenPoint (worldPos);
DisplayVector(“screenPos”, screenPos);
}
function Update () {
// 1.世界坐标系中cube在摄像机前方,且cube坐标为正情况下,x增加,cube从左往右则是left hand coordinate。
if( moveTranform.position.x > 3)
{
moveTranform.position.x = -3;
}
else if( moveTranform.position.x < -3 )
{
moveTranform.position.x = -3;
}
else
{
moveTranform.position.x += 0.01;
}
}
输出结果:
mainCamera在:(0,0,-10)处观察。