左右手坐标系和相关定则的总结
左手坐标系和右手坐标系是三维空间下两种不同的坐标系,而且无法通过旋转将左手坐标系转换到右手坐标系。与其相对应的,有左手定则和右手定则,主要是用来确定叉积的朝向或者说旋向。首先,规定二维坐标,X轴朝右、Y轴朝上,推广到三维空间,需要确定的是Z轴是朝前还是朝后。一、左手坐标系所谓左手坐标系,指的是通过左手来确定的一个三维空间坐标系。1.1 确定左手坐标系的方式下面总结了三种可以确定左手坐标系的方法。1
左手坐标系和右手坐标系是三维空间下两种不同的坐标系,而且无法通过旋转将左手坐标系转换到右手坐标系。与其相对应的,有左手定则和右手定则,主要是用来确定叉积的朝向或者说旋向。
首先,规定二维坐标,X轴朝右、Y轴朝上,推广到三维空间,需要确定的是Z轴是朝前还是朝后。
一、左手坐标系
所谓左手坐标系,指的是通过左手来确定的一个三维空间坐标系。
1.1 确定左手坐标系的方式
下面总结了三种可以确定左手坐标系的方法。
1.1.1 拇指、食指、中指相互垂直确定法
如图,伸出左手,拇指朝上代表Y轴、食指朝前代表Z轴、中指朝右代表X轴。注意,中指这个时候是只能往右边弯曲的。
1.1.2 左手定则确定法
伸出左手,手指朝着右边X轴,握向Y轴,这个时候拇指指向的方向就是Z轴(朝前)。
1.1.3 人站立的正面朝向确定法
人朝前站立着,右手伸出的朝向是X轴,头顶的方向是Y轴,面向Z轴。
1.2 左手定则
假设,叉乘计算,C=A叉乘B。如何确定在C的朝向了?如果A和B都在左手坐标系下,那么使用左手定则来确定C的朝向。
类似1.1.2,伸出左手,手指朝着A,握向B,这个时候拇指指向的方向就是C。
二、右手坐标系
2.1 确定右手坐标系的方式
2.1.1 拇指、食指、中指相互垂直确定法
参考1.1.1,伸出右手,拇指朝上代表Y轴、食指朝前代表Z轴、中指朝左代表X轴。注意,中指这个时候是只能往左边弯曲的。
但是,我们一般假定X轴朝右,因此需要握着Z轴旋转180度。这个时候,拇指朝上代表Y轴、食指朝后代表Z轴、中指朝右代表X轴。注意,左右手坐标系旋转后不会改变。
2.1.2 左手定则确定法
伸出右手,手指朝着右边X轴,握向Y轴,这个时候拇指指向的方向就是Z轴(朝后)。
2.1.3 人站立的正面朝向确定法
人朝前站立着,右手伸出的朝向是X轴,头顶的方向是Y轴,背后的是Z轴。
2.2 右手定则
类似1.1,如果A和B都在,右手坐标系下,那么使用右手定则来确定C的朝向。
类似1.1.2,伸出右手,手指朝着A,握向B,这个时候拇指指向的方向就是C。
因此,左手定则和右手定则的区别是使用左手还是右手。
三、图形API的左右手坐标系
图形管线中,存在多个坐标系,每个坐标系都可以使用左手或者右手坐标系。下面按照,物体坐标系->世界坐标系->摄像机坐标系->裁剪坐标系->窗口坐标系来说明。
3.1 OpenGL
OpenGL默认是右手坐标系。不过到了窗口坐标系,OpenGL使用的是左手坐标系。为什么了?因为OpenGL的深度范围是[0,1],而且是摄像机越远,深度越大,这就是左手坐标系啦。
由于物体坐标系、世界坐标系、摄像机坐标系都是右手坐标系,但是窗口坐标系是左手坐标系,那么投影矩阵就需要乘以右手坐标系变换到左手坐标系这个变换,也就是Z变换成-Z。不过这个变换也可以放在摄像机坐标系,也就是MVP的V中。现在假定,都乘到P中了。
最终结论是:物体坐标系、世界坐标系、摄像机坐标系是右手坐标系;裁剪坐标系和窗口坐标系是左手坐标系,窗口坐标系实际上只是裁剪坐标系进行齐次除法后再平移缩放而已。
3.2 DirectX
DirectX默认是左手坐标系。
类似3.1,物体坐标系、世界坐标系、摄像机坐标系是左手坐标系。注意,DirectX的窗口坐标系是以左上角为原点的,深度是朝前的,那么跟OpenGL的反过来,是右手坐标系。
因此,裁剪坐标系和窗口坐标系是右手手坐标系。投影变化同样要乘以,右手坐标系变换到左手坐标系这个变换,也就是Z变换成-Z。
3.3 Vulkan
Vulkan的窗口坐标系和DirectX的一致,因此推测其余坐标系和DirectX的一致。
3.4 Metal
Vulkan的窗口坐标系和DirectX的一致,因此推测其余坐标系和DirectX的一致。
看来只有,历史遗留的奇葩OpenGL的窗口坐标系,原点在左下角啊。原点在哪,这个跟纹理的v坐标是否需要取反也有关系。
四、游戏引擎的左右手坐标系
游戏引擎中,物体和世界坐标系是固定的,对于所有的图形API都会一样。
4.1 Unity
根据上图,Unity的物体和世界坐标系可以推测都是左手系。
根据上图,出自Unity Shader入门精要,Unity的窗口坐标系和OpenGL的一致,是左手系。但是摄像机空间变换到了右手系。那么,在V中需要乘以Z到-Z的变换。同时,P中再乘以-Z到Z的变换变回左手系。
为啥多次一举了,怀疑这个结论的正确性。下面做实验,用IMGizmos绘制坐标轴。代码如下,
using UnityEngine;
namespace GYGame
{
/// <summary>
/// 出生点
/// </summary>
public class PlayerStart : MonoBehaviour
{
public float GizmosHeight { get; set; } = 2.0f;
void OnDrawGizmos()
{
IMGizmos.Line3D(transform.position, transform.position + transform.up * GizmosHeight, Color.green);
IMGizmos.Line3D(transform.position, transform.position + transform.right * GizmosHeight, Color.red);
IMGizmos.Line3D(transform.position, transform.position + transform.forward * GizmosHeight, Color.blue);
}
}
}
选中场景相机,可以得到下面结果,
可以看到右下角的场景相机画面里面有显示PlayerStart的Gizmos,Gizmos显示的坐标系是左手系,跟右上角显示的坐标系是一致的。同时,引擎自带的Gizmos显示的摄像机前向也是Z轴正向。
因此,推测我实验的Unity版本是2020,与UnityShader入门精要使用的Unity5.X版本,摄像机空间的旋向性已经发生了变化。
4.2 UnrealEngine
虚幻和Unity一样也是采用左手坐标系,不过其是Z轴朝上,Y轴朝外。沿着X轴旋转90度,可以得到Z轴朝内,Y轴朝上,那么和Unity的是一致的。
推测,其余的空间的坐标系旋向和Unity的是一致。摄像机空间的旋向也可以用类似4.1的方式绘制Gizmos,然后选中摄像机,查看摄像机的绘制结果。
五、参考资料
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)