【问题标题】:precision in Depth buffer on OpenGL ESOpenGL ES 上深度缓冲区的精度
【发布时间】:2014-04-18 15:36:57
【问题描述】:

我正在尝试从深度缓冲区(渲染为颜色纹理,然后使用 glReadPixels 读取)中获取正确的 Z 值,然后取消投影以获得真实的 3D 空间坐标。在 iPad Air 上它可以完美运行,但在 iPad 3 或 iPad 4 上却不行。

iPad 3/4 和 iPad Air 具有:
OpenGL ES 2.0 IMGSGX554-97.7 和 OpenGL ES 2.0 Apple A7 GPU - 27.23
GLSL 版本 OpenGL ES GLSL ES 1.00
OpenGL 深度位 24 - 在所有设备上

glDepthFunc(GL_LEQUAL);
glDepthRangef(0, 1.0);
glClearDepthf(1.0);

在片段着色器中:

precision highp float;  

// .... some code and variables  

const float maxnum = 256.0;

vec4 pack (float depth)
{

    const vec4 bitSh = vec4(maxnum * maxnum * maxnum,
                            maxnum * maxnum,
                            maxnum,
                            1.0);
    const vec4 bitMsk = vec4(0,
                             1.0 / maxnum,
                             1.0 / maxnum,
                             1.0 / maxnum);
    vec4 comp = fract(depth * bitSh);
    comp -= comp.xxyz * bitMsk;
    return comp;
}

void main()
{
   gl_FragColor = pack(gl_FragCoord.z);
}

在 iPad Air 上我们可以看到:


在 iPad 3/4 上:

【问题讨论】:

  • 我知道 Apple A7 GPU 和之前的 PowerVR SGX GPU 之间的唯一精度差异是 lowpmediump 在 A7(均为 16 位)上是相同的。旧型号有lowp = 12 位和mediump = 16 位。
  • @AndonM.Coleman 好的,如果它是正确的 - 那么我不能使用 gl_FragCoord.z,因为它不准确。我尝试使用顶点着色器中的坐标,但这并没有太大帮助。你会建议尝试什么?

标签: opengl-es precision framebuffer depth-buffer


【解决方案1】:

我遇到了 2 个问题:
1.nearZfarZ之间距离大
2.我尝试使用精度较低的gl_FragCoord.z。它通过渲染到只有深度分量(没有颜色缓冲区!)的帧缓冲区来解决,然后在第二遍中将深度纹理的结果渲染到另一个帧缓冲区,该帧缓冲区具有与问题相同的pack 函数的颜色渲染缓冲区和着色器。

Answer is here on OpenGL.org FAQ

12.050 为什么我的深度缓冲精度这么差?

眼睛坐标中的深度缓冲区精度受 zFar 与 zNear 的比率、zFar 剪裁平面以及对象与 zNear 剪裁平面的距离的影响很大。

您需要尽一切可能将 zNear 剪裁平面推出并尽可能将 zFar 平面拉入。

12.070 为什么深度缓冲区前面的精度更高?

投影矩阵转换剪辑坐标后,XYZ 顶点值除以其剪辑坐标 W 值,得到归一化的设备坐标。此步骤称为透视划分。剪辑坐标 W 值表示与眼睛的距离。随着与眼睛的距离增加,1/W 接近 0。因此,X/W 和 Y/W 也接近于零,导致渲染的图元占用更少的屏幕空间,看起来更小。这就是计算机模拟透视图的方式。

实际上,朝向或远离眼睛的运动对已经在远处的物体的影响较小。例如,如果您将电脑屏幕移近 6 英寸,靠近您的脸前,它的外观尺寸应该会显着增加。另一方面,如果计算机屏幕已经离您 20 英尺,那么靠近 6 英寸对其外观尺寸几乎没有明显影响。视角划分考虑了这一点。

作为透视除法的一部分,Z 也除以 W,结果相同。对于已经靠近视图体后部的对象,一个坐标单位的距离变化对 Z/W 的影响要小于对象靠近视图体前部的情况。换句话说,一个对象坐标 Z 单元在靠近视图体积前部的 NDC 深度空间中占据比靠近视图体积后部的更大的切片。

总而言之,透视分割就其性质而言,导致靠近视图体积前部的 Z 精度高于靠近后部的 Z 精度。

12.080 标准大小的深度缓冲区不可能有足够的精度用于我的天文大场景。我有哪些选择?

典型的方法是使用多通道技术。应用程序可能会将几何数据库划分为在 Z 中不会相互干扰的区域。然后渲染每个区域中的几何,从最远的区域开始,在渲染每个区域之前清除深度缓冲区。这样,每个区域都可以使用整个深度缓冲区的精度。

【讨论】:

  • 谢谢,这解决了我的 web-gl 问题。我使用 mat4.perspective 的值:near=0 和 far=100。它造成了奇怪的伪影。现在,值 0.01 和 0.4 一切正常。
  • @User1 很高兴能帮到你:)
  • @SAKrisT: 您能否为点#2 发布一些代码渲染到刚刚为深度组件附加纹理的帧缓冲区(没有颜色缓冲区!),然后将此深度纹理​​渲染到另一个带有附加颜色渲染缓冲区的帧缓冲区 ?
  • @deblocker 它是带有 2 个帧缓冲区的操作序列,很难在这里发布一些易于理解的内容。
【解决方案2】:

也许深度缓冲区中的值没问题,但在采样过程中是精度问题?

您是否检查过您在 GLSL 中对深度纹理采样器的声明,并确保它被声明为“highp”?

如果您要求的精度太低而无法满足您的需求(或者因为您没有设置它而被默认为 lowp),某些设备可能会为您提供比您要求的更多的信息,并掩盖遗漏。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-05
    • 1970-01-01
    • 2016-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多