应用投影矩阵后Vulkan右手坐标系变左手系,如何与原坐标系保持一致?
嘿,这个问题我碰到过好多次了,Vulkan的坐标系规则确实容易和之前的OpenGL搞混,我来给你一步步说清楚怎么解决:
Vulkan本身是右手坐标系(X+右、Y+下、Z+向屏幕内),但它的裁剪空间(NDC)是左手坐标系,而且Z轴范围是[0, 1](OpenGL的NDC Z范围是[-1, 1])。我们常用的投影矩阵(比如GLM的默认perspective)是为OpenGL的右手裁剪空间设计的,直接套用就会导致坐标系翻转,看起来像是变成了左手系。
要让整个渲染管线的坐标系逻辑和Vulkan保持一致,有两种靠谱的方法:
方法一:用适配Vulkan的投影矩阵生成函数
如果用GLM这类数学库,别再用默认的glm::perspective了,直接用专门为Vulkan设计的glm::perspectiveRH_ZO:
RH代表右手坐标系,ZO代表Z轴范围是[0, 1],完美匹配Vulkan的要求。- 生成的投影矩阵会自动把你的右手世界空间坐标转换到Vulkan的裁剪空间,不会出现坐标系翻转的问题。
要是你手动写投影矩阵,记得把Z轴的映射逻辑改成适配[0,1]的:
原来OpenGL风格的Z转换部分是:
float z_near = ...; float z_far = ...; float A = (z_far + z_near) / (z_far - z_near); float B = -2 * z_far * z_near / (z_far - z_near);
改成Vulkan适配的:
float A = z_far / (z_far - z_near); float B = -z_far * z_near / (z_far - z_near);
这样就能保证右手坐标系的逻辑不变,同时满足Vulkan的裁剪空间要求。
方法二:按需调整Y轴(可选)
如果你的模型是按Y+向上制作的,除了投影矩阵的调整,还可以在投影矩阵里加入Y轴翻转,或者在顶点着色器里简单处理:
gl_Position.y = -gl_Position.y;
不过更推荐在投影矩阵里统一处理,这样着色器代码更干净,也方便后续维护。
看你提到的顶点着色器代码gl_Position = scene.cameraProjection * scene.cameraView ...,只要确保scene.cameraProjection是用上面说的适配Vulkan的方式生成的,就能让整个坐标系逻辑和Vulkan保持一致,不会再出现左手系的问题。
另外要记住:Vulkan不会帮你做任何默认的坐标系转换,所有空间转换都得靠你自己的矩阵控制,所以投影矩阵的正确性是核心关键。
内容的提问来源于stack exchange,提问作者Andrea Catania

