如何在iOS中正确地线性化OpenGL ES的深度?

我正在尝试使用OpenGL渲染一个iOS应用程序的forrest场景。 为了使它更好一些,我想在场景中实现深度效果。 不过,我需要OpenGL深度缓冲区的线性化深度值。 目前我正在片段着色器(我在这里find)使用计算。

因此,我的地形片段着色器看起来像这样:

#version 300 es precision mediump float; layout(location = 0) out lowp vec4 out_color; float linearizeDepth(float depth) { return 2.0 * nearz / (farz + nearz - depth * (farz - nearz)); } void main(void) { float depth = gl_FragCoord.z; float linearized = (linearizeDepth(depth)); out_color = vec4(linearized, linearized, linearized, 1.0); } 

但是,这会导致以下输出:

产生的输出 正如你所看到的那样,你越走越远,得到的深度值越“有条不紊”(特别是在船后面)。 如果地形贴图靠近摄像机,输出就可以了。

我甚至尝试过另一个计算:

 float linearizeDepth(float depth) { return 2.0 * nearz * farz / (farz + nearz - (2.0 * depth - 1.0) * (farz - nearz)); } 

这导致了一个太高的价值,所以我按比例缩小:

 float linearized = (linearizeDepth(depth) - 2.0) / 40.0; 

第二个结果输出

尽pipe如此,它也给出了类似的结果。

那么,如何在近平面和远平面之间实现平滑,线性的过渡,而没有任何条纹呢? 有没有人有类似的问题?

问题是你存储的非线性值被截断,所以当你偷看深度值后,你得到了不稳定的结果,因为你失去了更多的准确性离远离平面。 不pipe你评价什么,你都不会得到更好的结果,除非:

  1. 精确度损失较低

    你可以改变znear,zfar值,使它们靠得更近。 尽可能多地放大znear,以便更准确的区域覆盖更多的场景。

    另一个select是每深度缓冲区使用更多的位(16位太低)不确定是否可以在OpenGL ES中执行此操作,但在标准OpenGL中,可以在大多数卡上使用24,32位。

  2. 使用线性深度缓冲区

    因此将线性值存储到深度缓冲区中。 有两种方法。 一个是计算深度,所以在所有的基本操作之后,您将获得线性值。

    另一个select是使用单独的纹理/ FBO,并将线性深度直接存储到它。 问题是你不能在同一个渲染过程中使用它的内容。

[编辑1]线性深度缓冲区

为了使深度缓冲区本身线性化(不仅是从中获取的值),请尝试:

顶点:

 varying float depth; void main() { vec4 p=ftransform(); depth=pz; gl_Position=p; gl_FrontColor = gl_Color; } 

分段:

 uniform float znear,zfar; varying float depth; // original z in camera space instead of gl_FragCoord.z because is already truncated void main(void) { float z=(depth-znear)/(zfar-znear); gl_FragDepth=z; gl_FragColor=gl_Color; } 

在CPU端线性化的非线性深度缓冲区(与您一样): 中央处理器

线性深度缓冲GPU一侧(你应该): GPU

场景参数是:

 // 24 bits per Depth value const double zang = 60.0; const double znear= 0.01; const double zfar =20000.0; 

和简单的旋转板覆盖整个深度的视野。 展台图像由glReadPixels(0,0,scr.xs,scr.ys,GL_DEPTH_COMPONENT,GL_FLOAT,zed); 并在CPU端转换为2D RGB纹理。 然后渲染为单个matrix中的单个QUAD覆盖整个屏幕。

现在要从线性深度缓冲区获得原始深度值,只需执行以下操作:

 z = znear + (zfar-znear)*depth_value; 

我使用古老的东西,只是为了保持这个简单,所以移植到您的个人资料…

当心我不在OpenGL ESIOS编写代码,所以我希望我不会错过与之相关的东西(我习惯Win和PC)。

为了显示差异,我添加了另一个旋转的板到同一场景(所以他们相交),并使用彩色输出(没有深度获得了):

相交

正如您所看到的,线性深度缓冲区要好得多(对于覆盖大部分深度FOV的场景)。