如何将屏幕上的一个点取消投影到 vulkan 中的对象 space 坐标?
How to unproject a point on screen to object space coordinates in vulkan?
我需要能够使用 Vulkan 将屏幕像素取消投影到对象 space 中,但是我的数学运算出了问题。
这是今天的着色器供参考:
void main()
{
//the depth of this pixel is between 0 and 1
vec4 obj_space = vec4( float(gl_FragCoord.x)/ubo.screen_width, float(gl_FragCoord.y)/ubo.screen_height, gl_FragCoord.z, 1.0f);
//this puts us in normalized device coordinates [-1,1 ] range
obj_space.xy = ( obj_space.xy * 2.0f ) -1.0f;
//this two lines will put is in object space coordinates
//mvp_inverse is derived from this in the c++ side:
//glm::inverse(app.three_d_camera->get_projection_matrix() * app.three_d_camera->view_matrix * model);
obj_space = ubo.mvp_inverse * obj_space;
obj_space.xyz /= obj_space.w;
//the resulting position here is wrong
out_color = obj_space;
}
当我输出颜色的位置时,颜色是关闭的。我知道我可以简单地将对象 space 位置从顶点着色器传递到片段着色器,但我想了解为什么我的数学不起作用,它会帮助我理解 Vulkan 并可能学习一点数学我自己。
谢谢!
我不完全确定你的问题是什么,但让我们讨论一下潜在的问题。
记住,vulkan 剪辑 space 是:
- 正 y = 向下,
- 正 x = 正确,
- 正 z = out,
- 居中于屏幕中间。
此外,尽管 OpenGL 的 GLSL 文档说它在 vulkan 中居中于左下角 gl_FragCoord is centered at the top left corner。
在这一步中:
obj_space.xy = ( obj_space.xy * 2.0f ) -1.0f;
obj_space 现在是:
- 左 x : -1.0
- 右 x : 1.0
- 顶部 y = -1.0
- 底部 y = 1.0
- out z = 1.0
- 后退 z = 0
我几乎完全确定你的意思不是你的对象 space 让 Y 在顶部是负数。 y 从上到下增加的原因是图像和纹理,它们在 CPU 上的排序方式相同,现在在 vulkan 中也是如此排序。
一些其他注意事项:
你声称你的逆是从 glm::inverse 推导出来的:
glm::inverse(app.three_d_camera->get_projection_matrix() * app.three_d_camera->view_matrix * model);
但是 GLM 使用 OpenGL 符号表示矩阵维度和惯用手性,除非您将其强制到正确的坐标系,否则它将假定右手正 Y 向上,z 负向外。您需要包含以下 #defines
才能正常工作(或实际更改您的计算以适应这一点)。
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#define GLM_FORCE_LEFT_HANDED
此外,您需要修改矩阵以说明负 Y 方向。这是我过去如何处理的示例(直接修改透视矩阵):
ubo.model = glm::translate(glm::mat4(1.0f), glm::vec3(pos_x,pos_y,pos_z));
ubo.model *= glm::rotate(glm::mat4(1.0f), time * glm::radians(0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
ubo.view = glm::lookAt(glm::vec3(0.0f, 0.0f, -10.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float) swapChainExtent.height, 0.1f, 100.0f);
ubo.proj[1][1] *= -1; // makes the y axis projected to the same as vulkans
我需要能够使用 Vulkan 将屏幕像素取消投影到对象 space 中,但是我的数学运算出了问题。
这是今天的着色器供参考:
void main()
{
//the depth of this pixel is between 0 and 1
vec4 obj_space = vec4( float(gl_FragCoord.x)/ubo.screen_width, float(gl_FragCoord.y)/ubo.screen_height, gl_FragCoord.z, 1.0f);
//this puts us in normalized device coordinates [-1,1 ] range
obj_space.xy = ( obj_space.xy * 2.0f ) -1.0f;
//this two lines will put is in object space coordinates
//mvp_inverse is derived from this in the c++ side:
//glm::inverse(app.three_d_camera->get_projection_matrix() * app.three_d_camera->view_matrix * model);
obj_space = ubo.mvp_inverse * obj_space;
obj_space.xyz /= obj_space.w;
//the resulting position here is wrong
out_color = obj_space;
}
当我输出颜色的位置时,颜色是关闭的。我知道我可以简单地将对象 space 位置从顶点着色器传递到片段着色器,但我想了解为什么我的数学不起作用,它会帮助我理解 Vulkan 并可能学习一点数学我自己。
谢谢!
我不完全确定你的问题是什么,但让我们讨论一下潜在的问题。
记住,vulkan 剪辑 space 是:
- 正 y = 向下,
- 正 x = 正确,
- 正 z = out,
- 居中于屏幕中间。
此外,尽管 OpenGL 的 GLSL 文档说它在 vulkan 中居中于左下角 gl_FragCoord is centered at the top left corner。
在这一步中:
obj_space.xy = ( obj_space.xy * 2.0f ) -1.0f;
obj_space 现在是:
- 左 x : -1.0
- 右 x : 1.0
- 顶部 y = -1.0
- 底部 y = 1.0
- out z = 1.0
- 后退 z = 0
我几乎完全确定你的意思不是你的对象 space 让 Y 在顶部是负数。 y 从上到下增加的原因是图像和纹理,它们在 CPU 上的排序方式相同,现在在 vulkan 中也是如此排序。
一些其他注意事项:
你声称你的逆是从 glm::inverse 推导出来的:
glm::inverse(app.three_d_camera->get_projection_matrix() * app.three_d_camera->view_matrix * model);
但是 GLM 使用 OpenGL 符号表示矩阵维度和惯用手性,除非您将其强制到正确的坐标系,否则它将假定右手正 Y 向上,z 负向外。您需要包含以下 #defines
才能正常工作(或实际更改您的计算以适应这一点)。
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#define GLM_FORCE_LEFT_HANDED
此外,您需要修改矩阵以说明负 Y 方向。这是我过去如何处理的示例(直接修改透视矩阵):
ubo.model = glm::translate(glm::mat4(1.0f), glm::vec3(pos_x,pos_y,pos_z));
ubo.model *= glm::rotate(glm::mat4(1.0f), time * glm::radians(0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
ubo.view = glm::lookAt(glm::vec3(0.0f, 0.0f, -10.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float) swapChainExtent.height, 0.1f, 100.0f);
ubo.proj[1][1] *= -1; // makes the y axis projected to the same as vulkans