U3d坐标系欧拉角浅析:你了解的XYZ
2022/5/28 22:44:18
2022/5/28 22:44:18
Unity引擎时非常成熟的,引擎内部运用了很多的数学知识,他对开发者来说是不可见的,而且他已经封装好的算法也不是很全面。此外,要是使用引擎封装好的算法也要明白其实现的原理。主要从这五个方面来简要说说,分别是Unity坐标系,向量,矩阵,四元数,欧拉角。
在介绍Unity的坐标系之前,我想先谈谈3D坐标系,它存在着三个坐标轴,分别是X轴,Y轴,Z轴。3D坐标系分为左手坐标系和右手坐标系。左手坐标系就是Y轴指上方,X轴指向右方,而Z轴指向前方;而右手坐标系和左手坐标系的X轴和Y轴志向相同,Z轴的方向正好相反。便于理解:大拇指指向的方向就是Z轴的方向,四指弯曲的方向就是从X轴到Y轴的方向,左右手都可以这样判断。
(1)世界坐标(World Space)
Unity中的世界坐标系和本地坐标系都是左手坐标系,在旋转的时候都遵循左手定则,即将大拇指指向旋转轴正向,握拳方向即为旋转方向。在默认情况下,局部坐标和世界坐标系的原点是重合的,不能把所有的模型都叠加在世界坐标系的原点上,因此需要移动模型。模型移动式就会发生模型的局部坐标到世界坐标的转换,这个移动的过程就是把模型的局部坐标转化成世界坐标。知识这个转化的过程是在引擎编辑器内部实现的,实际上就是将模型的各个点与世界矩阵相乘得到。
X轴:左负右正;Y轴:上正下负;Z轴:里正外负。
transform.position就是获取到当前物体的世界坐标的位置。
transform.localPosition获取的是当前模型的局部坐标。
(2)屏幕坐标(Screen Space)
Unity开发的移动端手游经常会用到屏幕坐标系,屏幕坐标是就是通常使用的电脑屏幕,它是以像素为单位的,屏幕左下角(0,0)点,右上角为(Screen.Width,Screen.Height)点,Z的位置是根据相机的Z缓存值确定的。通常使用鼠标在屏幕上单机物体,它就是屏幕坐标。通过Input.mousePosition可以获得鼠标位置的坐标。对虚拟摇杆的滑动可以通过Input.GetTouch(0),position获取到手指触碰屏幕的坐标。对UI的操作以及单机3D物体发射射线判断是否选中物体也是基于屏幕坐标系的。
(3)相机坐标(ViewPort Space)
通过相机才能看到虚拟世界的物体。相机有自己的适口坐标,物体要转换到视口坐标才能被看到。相机的视口左下角为(0,0)点,右上角为(1,1)点,Z的位置是以相机的世界单位来衡量的。(0,0)点和(1,1)点是通过公式进行缩放计算的。
(4)坐标转换
获取物体位置的通常写法是transform.position,它表示的时立方体在3D世界中的世界坐标的位置。如果使用的是触摸屏幕,那么可以通过函数Input.GetTouch(0).position获取到屏幕坐标系。
世界坐标和本地坐标可以直接从position和localPosition中获取;
世界坐标到屏幕坐标的转化:camera.WorldToScreenPoint(transform.position);
世界坐标到视口坐标的转化:camera.WorldToViewportPoint(obj.transform.position);
屏幕坐标到视口坐标的转化:camera.ScreenToViewportPoint(Input.GetTouch(0).position);
视口坐标到世界坐标的转化:camera.ViewportToWorldPoint(0.2f,0.3f,0);
视口坐标到屏幕坐标的转化:camera.ViewportToScreenPoint(0.2f,0.3f,0);
Vector3 targetDir = targetPos.position - transform.position; // 目标坐标与当前坐标差的向量
Vector3.Angle(transform.forward,targetDir) // 返回当前坐标与目标坐标的角度
(5)欧拉角
在游戏开发中,经常会接触到旋转,常用的旋转方式有使用矩阵旋转,使用欧拉角旋转和使用四元数旋转。在本篇中,主要研究欧拉角和四元数。在Unity的Transform中,Rotation属性对应的就是欧拉角,一共分为3个轴,x、y和z,而每一个数值对应的是绕对应的轴旋转的度数。
Transfrom属性,表示按照坐标顺序旋转,X轴旋转30°,Y轴旋转90°,Z轴旋转10°。
但欧拉角会出现一个问题:万向锁。什么是万向锁?这个不好解释,假设我们按照z-y-x的顺序对物体进行旋转,先绕X轴旋转30度,再绕Y轴旋转90度,再绕Z轴旋转10度得到的最终姿态和先绕X轴旋转20度,再绕Y轴旋转90度的结果一样。因此相对于最初姿态而言,当一个欧拉角包含绕Y轴旋转90度时,绕X轴和绕Z轴旋转已经是在绕同一个轴在进行旋转,这个时候只有两个轴在起作用。这就是万向锁状态。
为什么要使用四元数?原因有很多,下面是其中的两个我觉得比较重要的原因:
在效率上,四元数是比矩阵变换要高效的,想想矩阵变换的乘法量,按3X3的来算,进行一个点的变换要进行3X3X3=27次乘法,而四元数可以把乘法次数降低到16次。四元数是可以通过欧拉角进行构建的:
Quaternion.Euler(0, 30, 0); //通过欧拉角(0,30,0)构建
通过轴-角构建:
Quaternion.AngleAxis(30, Vector3.up); //通过轴Vector3.up,30°角构建
当然还有其他方式,需要大家自行查询官方文档。
(6) transform.ratation属性
这是一个四元数 (x, y, z, w),由三个虚数,加一个实数构成。
但是不要理解为这是x,y,z坐标,w也不是旋转角度
比如物体绕Z轴旋转60度,打印出来transform.ratation就是(0, 0, 0.5, 0.866)
q表示一个四元数,aix表示旋转轴向量,绕Z轴旋转时Aix.x=0,Aix.y=0,Aix.z=1
q.w=cos(60°/2) = 0.866
q.x=Aix.x*sin(60°/2) = 0*0.5=0
q.y=Aix.y*sin(60°/2) = 0*0.5=0
q.z=Aix.z*sin(60°/2) = 1*0.5=0.5
[1] [2] [3]
相关文章(向右看)..
在介绍Unity的坐标系之前,我想先谈谈3D坐标系,它存在着三个坐标轴,分别是X轴,Y轴,Z轴。3D坐标系分为左手坐标系和右手坐标系。左手坐标系就是Y轴指上方,X轴指向右方,而Z轴指向前方;而右手坐标系和左手坐标系的X轴和Y轴志向相同,Z轴的方向正好相反。便于理解:大拇指指向的方向就是Z轴的方向,四指弯曲的方向就是从X轴到Y轴的方向,左右手都可以这样判断。
(1)世界坐标(World Space)
Unity中的世界坐标系和本地坐标系都是左手坐标系,在旋转的时候都遵循左手定则,即将大拇指指向旋转轴正向,握拳方向即为旋转方向。在默认情况下,局部坐标和世界坐标系的原点是重合的,不能把所有的模型都叠加在世界坐标系的原点上,因此需要移动模型。模型移动式就会发生模型的局部坐标到世界坐标的转换,这个移动的过程就是把模型的局部坐标转化成世界坐标。知识这个转化的过程是在引擎编辑器内部实现的,实际上就是将模型的各个点与世界矩阵相乘得到。
X轴:左负右正;Y轴:上正下负;Z轴:里正外负。
transform.position就是获取到当前物体的世界坐标的位置。
transform.localPosition获取的是当前模型的局部坐标。
(2)屏幕坐标(Screen Space)
Unity开发的移动端手游经常会用到屏幕坐标系,屏幕坐标是就是通常使用的电脑屏幕,它是以像素为单位的,屏幕左下角(0,0)点,右上角为(Screen.Width,Screen.Height)点,Z的位置是根据相机的Z缓存值确定的。通常使用鼠标在屏幕上单机物体,它就是屏幕坐标。通过Input.mousePosition可以获得鼠标位置的坐标。对虚拟摇杆的滑动可以通过Input.GetTouch(0),position获取到手指触碰屏幕的坐标。对UI的操作以及单机3D物体发射射线判断是否选中物体也是基于屏幕坐标系的。
(3)相机坐标(ViewPort Space)
通过相机才能看到虚拟世界的物体。相机有自己的适口坐标,物体要转换到视口坐标才能被看到。相机的视口左下角为(0,0)点,右上角为(1,1)点,Z的位置是以相机的世界单位来衡量的。(0,0)点和(1,1)点是通过公式进行缩放计算的。
(4)坐标转换
获取物体位置的通常写法是transform.position,它表示的时立方体在3D世界中的世界坐标的位置。如果使用的是触摸屏幕,那么可以通过函数Input.GetTouch(0).position获取到屏幕坐标系。
世界坐标和本地坐标可以直接从position和localPosition中获取;
世界坐标到屏幕坐标的转化:camera.WorldToScreenPoint(transform.position);
世界坐标到视口坐标的转化:camera.WorldToViewportPoint(obj.transform.position);
屏幕坐标到视口坐标的转化:camera.ScreenToViewportPoint(Input.GetTouch(0).position);
视口坐标到世界坐标的转化:camera.ViewportToWorldPoint(0.2f,0.3f,0);
视口坐标到屏幕坐标的转化:camera.ViewportToScreenPoint(0.2f,0.3f,0);
Vector3 targetDir = targetPos.position - transform.position; // 目标坐标与当前坐标差的向量
Vector3.Angle(transform.forward,targetDir) // 返回当前坐标与目标坐标的角度
(5)欧拉角
在游戏开发中,经常会接触到旋转,常用的旋转方式有使用矩阵旋转,使用欧拉角旋转和使用四元数旋转。在本篇中,主要研究欧拉角和四元数。在Unity的Transform中,Rotation属性对应的就是欧拉角,一共分为3个轴,x、y和z,而每一个数值对应的是绕对应的轴旋转的度数。
Transfrom属性,表示按照坐标顺序旋转,X轴旋转30°,Y轴旋转90°,Z轴旋转10°。
但欧拉角会出现一个问题:万向锁。什么是万向锁?这个不好解释,假设我们按照z-y-x的顺序对物体进行旋转,先绕X轴旋转30度,再绕Y轴旋转90度,再绕Z轴旋转10度得到的最终姿态和先绕X轴旋转20度,再绕Y轴旋转90度的结果一样。因此相对于最初姿态而言,当一个欧拉角包含绕Y轴旋转90度时,绕X轴和绕Z轴旋转已经是在绕同一个轴在进行旋转,这个时候只有两个轴在起作用。这就是万向锁状态。
为什么要使用四元数?原因有很多,下面是其中的两个我觉得比较重要的原因:
在效率上,四元数是比矩阵变换要高效的,想想矩阵变换的乘法量,按3X3的来算,进行一个点的变换要进行3X3X3=27次乘法,而四元数可以把乘法次数降低到16次。四元数是可以通过欧拉角进行构建的:
Quaternion.Euler(0, 30, 0); //通过欧拉角(0,30,0)构建
通过轴-角构建:
Quaternion.AngleAxis(30, Vector3.up); //通过轴Vector3.up,30°角构建
当然还有其他方式,需要大家自行查询官方文档。
(6) transform.ratation属性
这是一个四元数 (x, y, z, w),由三个虚数,加一个实数构成。
但是不要理解为这是x,y,z坐标,w也不是旋转角度
比如物体绕Z轴旋转60度,打印出来transform.ratation就是(0, 0, 0.5, 0.866)
q表示一个四元数,aix表示旋转轴向量,绕Z轴旋转时Aix.x=0,Aix.y=0,Aix.z=1
q.w=cos(60°/2) = 0.866
q.x=Aix.x*sin(60°/2) = 0*0.5=0
q.y=Aix.y*sin(60°/2) = 0*0.5=0
q.z=Aix.z*sin(60°/2) = 1*0.5=0.5
相关文章(向右看)..