openGL 光线拾取

Posted

技术标签:

【中文标题】openGL 光线拾取【英文标题】:openGL ray pick 【发布时间】:2014-03-05 02:06:41 【问题描述】:

一般的Ray拾取过程如下(实验结果证明是正确的):

    将屏幕点转换为标准化的设备空间方向向量:

    float x = (2.0f * mouse_x) / width - 1.0f;
    float y = 1.0f - (2.0f * mouse_y) / height;
    float z = 1.0f;
    vec3 ray_nds = vec3 (x, y, z);
    

    将方向向量转换为齐次剪辑坐标

    vec4 ray_clip = vec4 (ray_nds.xy, -1.0, 1.0);
    

    将方向向量转换为眼睛空间方向向量

    vec4 ray_eye = inverse (projection_matrix) * ray_clip;
    

    将方向向量转换到世界空间,得到一个带有世界空间相机位置和方向向量的拾取射线

我的问题是,在标准化设备空间中,为什么方向向量的 z 分量是 1.0? 我的意思是,在OpenGL规范化的设备空间中,xyz分量应该都在-1~1的范围内,所以相机应该在平面z=-1的中心。所以方向向量应该是:view target position - camera position,z分量应该是1-(-1)=2.0f。 (在 DirectX 归一化设备空间中,xy 分量在 -1~1 范围内,z 分量在 0~1 范围内,相机位置应该在平面 z=0 的中心,例如,(0, 0,0),方向向量的z分量应该是1-0=1)

【问题讨论】:

【参考方案1】:

ray_nds.z 完全无关紧要,因为无论如何你都不使用它。那是因为你不知道像素的深度。

ray_clip不是方向,而是投影后近剪裁平面(z=-1)上的位置。如果您撤消此投影(使用逆投影矩阵),您最终会在相机空间中得到相同的点。在相机空间中,相机以(0, 0, 0) 为中心。射线的方向向量可以用ray_eye - (0, 0, 0)计算,本质上就是ray_eye。所以如果我们忽略 w 分量,我们可以使用位置作为方向。这仅适用于相机空间!剪辑空间和世界空间最有可能将投影中心放在其他地方。

不要混淆不同空间中的相机位置。在相机空间中,它位于原点。在剪辑空间中,可以假设它位于(0, 0, -infinity)。点(x, y, ...) 只是被相应像素覆盖的任意点。您需要其中任何一个来定义射线。

【讨论】:

【参考方案2】:

摄像头不在 z=-1(或 0)处,它甚至位于其后面。

near clip plane 位于 z=-1。这使得这类数学变得复杂,因为所有涉及的方程如果被追踪,就会产生不通过 0 的曲线。因此,我们总是会携带大量的 znzm

检查一下,等式 4.2:http://www.arcsynthesis.org/gltut/Positioning/Tut04%20Perspective%20Projection.html

更可怕但更完整:http://www.songho.ca/opengl/gl_projectionmatrix.html

更多链接: http://unspecified.wordpress.com/2012/06/21/calculating-the-gluperspective-matrix-and-other-opengl-matrix-maths/

http://schabby.de/projection-matrix/

【讨论】:

以上是关于openGL 光线拾取的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL C++ 鼠标光线拾取 glm:unproject

OpenGL ES on android 微调光线拾取代码

OpenGL 中的射线球相交

OpenGL 射线 OBB 相交

深入理解OpenGL拾取模式(OpenGL Picking)

OpenGL 3D拾取文章(转)