【问题标题】:How to use OpenGL orthographic projection with the depth buffer?如何将 OpenGL 正交投影与深度缓冲区一起使用?
【发布时间】:2012-02-17 22:19:16
【问题描述】:

我使用glFrustum() 透视模式渲染了一个 3D 场景。然后,我将一个 2D 对象放置在 3D 场景上,作为特定 3D 对象的标签。我已经使用 gluProject() 计算了 3D 对象的 2D 位置,然后将我的 2D 标签对象放置在该位置。使用glOrtho() 正交模式渲染二维标签对象。这可以完美运行,并且 2D 标签对象悬停在 3D 对象上。

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

那么问题来了,为什么二维对象仍然可见而不是隐藏?

我确实在某处读到过正交投影和透视投影存储不兼容的深度缓冲区值。这是真的吗?如果是,我该如何在它们之间进行转换?

【问题讨论】:

  • 如果你想让标签表现得像一个普通的 3D 对象(隐藏在其他对象后面等等),为什么不把它像一个普通的 3D 对象一样直接绘制在被标记对象的上方(或旁边)呢?
  • 我不希望它表现得像一个普通的 3D 对象。我不希望它被转换,而是希望它显示为始终面向相机并始终在屏幕上保持相同大小的平面 2D 标签。但是,如果它隐藏在某些东西后面,我希望它看起来是隐藏的。
  • 如何设置二维对象深度?提交 Z 值还是使用 PolygonOffset?
  • 我只是将对象的 z 值设置为一个大的 -ve 数,理论上应该隐藏在场景中所有 3D 对象的后面

标签: opengl buffer depth orthographic


【解决方案1】:

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

首先,您应该将那个放在您的问题中;它比你的问题更能说明你想要做什么。

为此,您需要在正交投影中找到与您希望标签出现的预投影空间中的 z 坐标相匹配的 z 坐标。

当您使用gluProject 时,您得到了三个 坐标。 Z坐标很重要。您需要做的是根据您提供给glOrtho 的 zNear 和 zFar 值对 Z 坐标进行反向转换。

迂腐提示: gluProject 不会将 Z 坐标转换为窗口空间。为此,它必须采用glDepthRange 参数。它真正做的是假设深度范围为 near = 0.0 和 far = 1.0。

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

ndcZ = (2 * winZ) - 1

足够简单。现在,我们需要去剪辑空间。这是一个无操作,因为对于正交投影,W 坐标被假定为 1.0。而除以W就是clip space和NDC space的差。

clipZ = ndcZ

但我们不需要剪辑空间 Z。我们需要预正交投影空间 Z(又名:相机空间 Z)。这需要您提供给glOrtho 的zNear 和zFar 参数。为了进入相机空间,我们这样做:

cameraZ = ((clipZ + (zFar + zNear)/(zFar - zNear)) * (zFar - zNear))/-2

你就完成了。在渲染中使用该 Z 位置。哦,请确保您的模型视图矩阵不包含 Z 方向上的任何变换(除非您使用模型视图矩阵将此 Z 位置应用于标签,这很好)。

【讨论】:

  • 只是为了澄清:必须这样做的原因是透视变换将 Z 值非线性映射到深度缓冲区值,而正交投影映射 Z 值线性。因此,您首先需要将透视深度取消投影到 Z,以便找到在正射投影下会产生相同深度的眼睛坐标。
  • 非常感谢,这就像一个魅力。我虽然这与线性和非线性深度有关,但你解释得很好。干杯
【解决方案2】:

根据 Nicol 的回答,您可以简单地将 zNear 设置为 0(这通常对充当 GUI 一部分的 2D 元素有意义),然后您只需:

cameraZ = -winZ*zFar

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多