如何使用深度缓冲区的OpenGL正交投影?

chr*_*ris 3 opengl buffer orthographic depth

我使用glFrustum()透视模式渲染了3D场景.然后,我将一个2D对象放在3D场景上,作为特定3D对象的标签.我使用gluProject()在哪个位置然后放置我的2D标签对象来计算3D对象的2D位置.使用glOrtho()正交模式渲染2D标签对象.这完美地工作,并且2D标签对象悬停在3D对象上.

现在,我想要做的是给2D对象的az值,以便它可以使用深度缓冲区隐藏在场景中的其他3D对象后面.我已经给出了我知道应该被深度缓冲区隐藏的2D对象az值,但是当我渲染对象时它总是可见的.

所以问题是,为什么2D对象仍然可见而不是隐藏?

我确实读过正交和透视投影存储不兼容的深度缓冲值的地方.这是真的,如果是这样,我如何在它们之间进行转换?

Nic*_*las 10

我不希望它被转换,而是我希望它看起来像是平面的2D标签,它始终面向相机,并且始终保持在屏幕上相同的大小.但是,如果隐藏在某些东西背后,我希望它隐藏起来.

首先,你应该把放在你的问题中; 它解释了你所做的比你的问题更多的事情.

要实现这一点,您需要做的是在正交投影中找到与您希望标签出现的前投影空间中的z坐标匹配的z坐标.

当你使用时gluProject,你有三个坐标.Z坐标很重要.您需要做的是根据您给出的zNear和zFar值反向变换Z坐标glOrtho.

迂腐: gluProject不会将Z坐标转换为窗口空间.为此,它必须采取glDepthRange参数.它真正做的是假设深度范围接近= 0.0且远= 1.0.

所以我们的第一步是从窗口空间Z转换为规范化设备坐标(NDC)空间Z.我们使用这个简单的等式:

ndcZ = (2 * winZ) - 1
Run Code Online (Sandbox Code Playgroud)

很简单.现在,我们需要去剪辑空间.这是一个无操作,因为使用正交投影,W坐标假定为1.0.W的除法是剪辑空间和NDC空间之间的差异.

clipZ = ndcZ
Run Code Online (Sandbox Code Playgroud)

但是我们不需要剪辑空间Z.我们需要预拼图投影空间Z(又名:相机空间Z).这需要您提供的zNear和zFar参数glOrtho.为了获得相机空间,我们这样做:

cameraZ = ((clipZ + (zFar + zNear)/(zFar - zNear)) * (zFar - zNear))/-2
Run Code Online (Sandbox Code Playgroud)

而且你已经完成了.在渲染中使用Z位置.哦,并确保您的模型视图矩阵不包括Z方向上的任何变换(除非您使用模型视图矩阵将此Z位置应用于标签,这很好).

  • 只是为了澄清:必须这样做的原因是透视变换将Z值非线性映射到深度缓冲值,而正交投影映射Z值是线性的.因此,您首先需要将透视深度取消投影到Z,以便找到在正投影下将产生相同深度的眼睛坐标. (4认同)