我正在尝试使用OpenGL为iOS应用程序渲染forrest场景。为了使它更好一些,我想在场景中实现深度效果。但是我需要OpenGL深度缓冲区的线性化深度值才能这样做。目前我在片段着色器中使用了一个计算(我发现here)。
因此我的地形片段着色器看起来像这样:
#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;
然而,它给出了类似的结果。
那么如何在近平面和远平面之间实现平滑,线性的过渡,没有任何条纹?有没有人有类似的问题?
答案 0 :(得分:4)
问题是你存储了被截断的非线性值,所以当你稍后偷看深度值时,你会得到不稳定的结果,因为你失去了准确性,你离znear平面越远。无论你评价什么,你都不会得到更好的结果,除非:
精度下降
您可以更改znear,zfar
值,使它们更加接近。尽可能多地放大znear,以便更准确的区域覆盖更多的场景。
另一个选择是每个深度缓冲区使用更多位(16位太低)不确定是否可以在OpenGL ES中执行此操作,但在标准OpenGL中,您可以在大多数卡上使用24,32位。
使用线性深度缓冲
因此将线性值存储到深度缓冲区中。有两种方法。一个是计算深度,因此在所有基础操作之后,您将获得线性值。
另一种选择是使用单独的纹理/ FBO并将线性深度直接存储到它。问题是你不能在同一个渲染过程中使用它的内容。
[Edit1]线性深度缓冲区
要线性化深度缓冲区本身(不仅仅是从中获取的值),请尝试:
<强>顶点:强>
varying float depth;
void main()
{
vec4 p=ftransform();
depth=p.z;
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;
}
场景参数为:
// 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 纹理。然后渲染为单个QUAD
覆盖单位矩阵上的整个屏幕...
现在要从线性深度缓冲区获取原始深度值,您只需执行以下操作:
z = znear + (zfar-znear)*depth_value;
我使用古老的东西只是为了保持这个简单,所以把它移到你的个人资料......
注意我不会在 OpenGL ES 中编码,也不会在 IOS 中编码,所以我希望我没有错过与此相关的内容(我习惯于Win和PC)。
为了显示差异,我将另一个旋转的平板添加到同一场景(因此它们相交)并使用彩色输出(不再获取深度):
正如您所见,线性深度缓冲区要好得多(对于覆盖大部分深度FOV的场景)。