Vulkan 右手坐标系变为左手坐标系
Vulkan right handed coordinate system become Left handed
问题:
应用投影矩阵后,Vulkan 右手坐标系变为左手坐标系。如何使其与Vulkan坐标系一致?
详情:
我知道Vulkan是右手坐标系
- X+指向右边
- Y+指向下方
- Z+指向屏幕内部
我在顶点着色器中有这一行:https://github.com/AndreaCatania/HelloVulkan/blob/master/shaders/shader.vert#L23
gl_Position = scene.cameraProjection * scene.cameraView * meshUBO.model * vec4(vertexPosition, 1.0);
此时:https://github.com/AndreaCatania/HelloVulkan/blob/master/main.cpp#L62-L68我正在定义相机在场景中心的位置和盒子在 (4, 4, -10) World 的位置 space
结果是这样的:
正如您在上图中看到的那样,我得到 Z- 点在屏幕内,但它应该是正数。
这是预期的,我需要添加更多内容还是我做错了什么?
有用的部分代码:
投影计算:https://github.com/AndreaCatania/HelloVulkan/blob/master/VisualServer.cpp#L88-L98
void Camera::reloadProjection(){
projection = glm::perspectiveRH_ZO(FOV, aspect, near, far);
isProjectionDirty = false;
}
相机 UBO 填充:https://github.com/AndreaCatania/HelloVulkan/blob/master/VisualServer.cpp#L403-L414
SceneUniformBufferObject sceneUBO = {};
sceneUBO.cameraView = camera.transform;
sceneUBO.cameraProjection = camera.getProjection();
我不使用或不知道 Vulcan,但 透视投影矩阵(至少在 OpenGL 中)正在寻找 Z-
反转坐标系的一个轴的方向。这反转了坐标系的缠绕规则。
如果您想保留原始绕组而不是仅反转矩阵中的 Z
轴向量以获取更多信息,请参阅:
所以只需通过 -1
缩放 Z
轴,或者通过与 glScale(1.0,1.0,-1.0);
的某种类比,或者通过直接矩阵单元格访问。
所有 OpenGL 左坐标系与 Vulkan 右坐标系都发生在 NDC 的片段着色器期间 space,这意味着您的视图矩阵不关心。
如果您使用 glm,您在世界 space 或视图 space 中所做的一切都是通过右手坐标系完成的。
GLM,一个每个初学者都使用的非常流行的数学库,默认使用right-handed坐标系。
必须相应地设置您的视图矩阵,获得 x 从左到右、y 从下到上的右手系统的唯一方法是设置您的 z 方向向下看负值。如果您没有为您的 glm::lookat
调用提供右手系统,glm 将通过一系列 glm::cross
将其转换为您的一个轴翻转,请参阅 glm 源代码
正确的方法:
glm::vec3 eye = glm::vec3(0, 0, 10);
glm::vec3 up = glm::vec3(0, 1, 0);
glm::vec3 center = glm::vec3(0, 0, 0);
// looking in the negative z direction
glm::mat4 viewMat = glm::lookAt(eye, up, center);
我个人将坐标系转换的所有信息存储在投影矩阵中,因为默认情况下 glm 会为您分配 z 坐标
来自 songho: http://www.songho.ca/opengl/gl_projectionmatrix.html
注意眼睛坐标是在right-handed坐标系中定义的,但是NDC使用的是left-handed坐标系。也就是说,原点的相机在眼睛 space 中是沿 -Z 轴看,但在 NDC 中是沿 +Z 轴看。由于 glFrustum() 只接受近距离和远距离的正值,我们需要在 GL_PROJECTION 矩阵的构造过程中将它们取反。
因为我们看的是负z方向glm默认取负号。
事实证明,y 坐标在 vulkan 和 openGL 之间翻转,所以一切都会颠倒过来。解决问题的一种方法是同时否定 y 值:
glm::mat4 projection = glm::perspective(glm::radians(verticalFov), screenDimension.x / screenDimension.y, near, far);
// Vulkan NDC space points downward by default everything will get flipped
projection[1][1] \*= -1.0f;
如果您按照上述步骤操作,您最终得到的结果一定与旧的 openGL 应用程序非常相似,并且您的相机的向上矢量与大多数 3D 模型具有相同的符号。
问题:
应用投影矩阵后,Vulkan 右手坐标系变为左手坐标系。如何使其与Vulkan坐标系一致?
详情:
我知道Vulkan是右手坐标系
- X+指向右边
- Y+指向下方
- Z+指向屏幕内部
我在顶点着色器中有这一行:https://github.com/AndreaCatania/HelloVulkan/blob/master/shaders/shader.vert#L23
gl_Position = scene.cameraProjection * scene.cameraView * meshUBO.model * vec4(vertexPosition, 1.0);
此时:https://github.com/AndreaCatania/HelloVulkan/blob/master/main.cpp#L62-L68我正在定义相机在场景中心的位置和盒子在 (4, 4, -10) World 的位置 space
结果是这样的:
正如您在上图中看到的那样,我得到 Z- 点在屏幕内,但它应该是正数。
这是预期的,我需要添加更多内容还是我做错了什么?
有用的部分代码:
投影计算:https://github.com/AndreaCatania/HelloVulkan/blob/master/VisualServer.cpp#L88-L98
void Camera::reloadProjection(){
projection = glm::perspectiveRH_ZO(FOV, aspect, near, far);
isProjectionDirty = false;
}
相机 UBO 填充:https://github.com/AndreaCatania/HelloVulkan/blob/master/VisualServer.cpp#L403-L414
SceneUniformBufferObject sceneUBO = {};
sceneUBO.cameraView = camera.transform;
sceneUBO.cameraProjection = camera.getProjection();
我不使用或不知道 Vulcan,但 透视投影矩阵(至少在 OpenGL 中)正在寻找 Z-
反转坐标系的一个轴的方向。这反转了坐标系的缠绕规则。
如果您想保留原始绕组而不是仅反转矩阵中的 Z
轴向量以获取更多信息,请参阅:
所以只需通过 -1
缩放 Z
轴,或者通过与 glScale(1.0,1.0,-1.0);
的某种类比,或者通过直接矩阵单元格访问。
所有 OpenGL 左坐标系与 Vulkan 右坐标系都发生在 NDC 的片段着色器期间 space,这意味着您的视图矩阵不关心。
如果您使用 glm,您在世界 space 或视图 space 中所做的一切都是通过右手坐标系完成的。
GLM,一个每个初学者都使用的非常流行的数学库,默认使用right-handed坐标系。
必须相应地设置您的视图矩阵,获得 x 从左到右、y 从下到上的右手系统的唯一方法是设置您的 z 方向向下看负值。如果您没有为您的 glm::lookat
调用提供右手系统,glm 将通过一系列 glm::cross
将其转换为您的一个轴翻转,请参阅 glm 源代码
正确的方法:
glm::vec3 eye = glm::vec3(0, 0, 10);
glm::vec3 up = glm::vec3(0, 1, 0);
glm::vec3 center = glm::vec3(0, 0, 0);
// looking in the negative z direction
glm::mat4 viewMat = glm::lookAt(eye, up, center);
我个人将坐标系转换的所有信息存储在投影矩阵中,因为默认情况下 glm 会为您分配 z 坐标
来自 songho: http://www.songho.ca/opengl/gl_projectionmatrix.html
注意眼睛坐标是在right-handed坐标系中定义的,但是NDC使用的是left-handed坐标系。也就是说,原点的相机在眼睛 space 中是沿 -Z 轴看,但在 NDC 中是沿 +Z 轴看。由于 glFrustum() 只接受近距离和远距离的正值,我们需要在 GL_PROJECTION 矩阵的构造过程中将它们取反。 因为我们看的是负z方向glm默认取负号。
事实证明,y 坐标在 vulkan 和 openGL 之间翻转,所以一切都会颠倒过来。解决问题的一种方法是同时否定 y 值:
glm::mat4 projection = glm::perspective(glm::radians(verticalFov), screenDimension.x / screenDimension.y, near, far);
// Vulkan NDC space points downward by default everything will get flipped
projection[1][1] \*= -1.0f;
如果您按照上述步骤操作,您最终得到的结果一定与旧的 openGL 应用程序非常相似,并且您的相机的向上矢量与大多数 3D 模型具有相同的符号。