Vulkan新手求教:获取光标世界坐标为何需乘相机Z轴距离?
问题
我是Vulkan新手,从未接触过3D图形开发。我希望将物体移动到光标点击的位置,参考Stack Overflow和Reddit的内容实现了代码:
int width, height; glfwGetWindowSize(gWindow, &width, &height); double x_ndc = (2.0 * x / width) - 1; double y_ndc = (2.0 * y / height) - 1; glm::mat4 viewProjectionInverse = glm::inverse(m_activeCam.m_projectionMatrix * m_activeCam.m_viewMatrix); glm::vec4 worldSpacePosition(x_ndc, y_ndc, 0.0f, 1.0f); auto world = viewProjectionInverse * worldSpacePosition; m_objects[0].transform.position.x = world.x * abs(m_activeCam.mPosition.z); m_objects[0].transform.position.y = world.y * abs(m_activeCam.mPosition.z);
我看到的示例中计算世界坐标时没有abs(m_activeCam.mPosition.z)这个乘数,但此时物体几乎不动;加上该乘数后功能符合预期。请问为何需要添加这个乘数?注:m_activeCam.mPosition.z是相机的距离。
回答
你遇到的核心原因是逆变换得到的点位于近裁剪平面,坐标分量数值过小,具体解释如下:
- 当你用
(x_ndc, y_ndc, 0.0)作为NDC坐标进行逆投影变换时,得到的world点实际上处于相机的近裁剪平面上。近平面通常离相机非常近,所以这个点的x、y分量数值极小,直接赋值给物体位置时,自然看不到明显移动。 - 你乘以
abs(m_activeCam.mPosition.z),本质是把近平面上的点缩放至相机z轴距离对应的深度位置——相当于把这个点从近平面“拉”到了你期望物体所在的深度层面上,刚好匹配你的需求。 - 正常的标准做法应该是:构造NDC坐标时,使用对应物体目标深度的NDC值,或者在逆变换后将点投影到目标深度平面。你当前的缩放方式是一种简化的近似方案,刚好适配了你的场景。
另外需要注意:如果你的相机是透视投影,近平面和远处平面的NDC映射是非线性的,这种缩放只是近似;如果是正交投影,这种额外缩放本不该需要,说明你的投影矩阵设置和参考示例存在差异。
内容的提问来源于stack exchange,提问作者Wusiki Jeronii
相关产品推荐
相关产品推荐

