使用" OpenGL深度缓冲区具有短距离"我并不是说远平面太近了,深度缓冲区的问题就像纹理一样。如果我查看缓冲区,它只显示非常接近的对象。我不知道如何更好地解释它只是看看图片。
在右上角,您可以看到深度缓冲区。 图片可以在这里找到:http://imgur.com/a/wL87b
正如你所看到的,我必须非常接近地看到深度缓冲区中的一些黑暗。
以下是为FBO创建深度缓冲区的代码:
对于深度纹理:
depthTexture = GL11.glGenTextures();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, depthTexture);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL14.GL_DEPTH_COMPONENT24, width, height, 0, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, (ByteBuffer) null);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL11.GL_TEXTURE_2D, depthTexture, 0);
对于深度缓冲区:
depthBuffer = GL30.glGenRenderbuffers();
GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, depthBuffer);
GL30.glRenderbufferStorageMultisample(GL30.GL_RENDERBUFFER, multisampleing, GL14.GL_DEPTH_COMPONENT24, width, height);
GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL30.GL_RENDERBUFFER, depthBuffer);
您可以忽略GLXX。在OpenGL方法的开头。
如果您需要更多代码,请告诉我。
答案 0 :(得分:1)
正如你所看到的,我必须非常接近地看到深度缓冲区中的一些黑暗。
这就是双曲线深度缓冲区的工作原理。
让我们看看投影矩阵(我使用经典的OpenGL约定,其中相机在眼睛空间中沿-z
看,而投影矩阵从右手到左手空间翻转):
. 0 . 0
0 . . 0
0 0 -(f+n)/(f-n) -2*f*n/(f-n)
0 0 -1 0
(。象征着我们在这里不需要关心的一些数字)。
当您将该矩阵与某个眼睛空间向量(x_eye, y_eye, z_eye, 1)
相乘时,您将最终得到
x_clip = ...
y_clip = ....
z_clip = [-(f+n)/(f-n) ] *z_eye + [-2*f*n/(f-n)] * 1
w_clip = -z_eye
在透视除以w_clip
之后,我们最终得到标准化设备坐标(ndc)中的z
值:
z_ndc = z_clip / w_clip = (f+n)/(f-n) + 2*f*n/[(f-n)*z_eye]
最后,应用glDepthRange
来覆盖窗口空间z
。默认是从[-1,1]变为[0,1],所以让我们这样做:
z_win = 0.5 * z_ndc + 0.5 = 0.5*(f+n)/(f-n) + f*n/[(f-n)*z_eye] + 0.5
这显然是z_eye
以及f
和n
的函数。假设您使用距离1处的近平面和距离1001处的远平面,因此这将评估为:
z_win(z_eye) = 1002/2000 + 1001/(1000 *z_eye) + 0.5 = 1001/1000 + 1001/(1000 * z_eye)
所以,让我们看看到目前为止我们得到了什么:
z_win(-1) = 0. a point on the near plane ends up as 0 in the depth buffer
z_win(-1001) = 1. a point on the far plane ends up as 1 in the depth buffer
这不应该让我们感到惊讶,因为这是每个结构。但是两者之间的关系会发生什么:
z_win(-50) = 1001/1000 - 1001/50000 = 0.98098
z_win(-100) = 1001/1000 - 1001/100000 = 0.99099
z_win(-250) = 1001/1000 - 1001/250000 = 0.996996
z_win(-500) = 1001/1000 - 1001/500000 = 0.998998
z_win(-750) = 1001/1000 - 1001/750000 = 0.999665333
因此,如您所见,任何远离眼睛空间100个单位的物体将以深度缓冲值>结束。 0.99。
换句话说,我们可以计算一个在深度缓冲区中得到0.5的点的眼睛空间z:
z_eye(z_win) = 1001/(1000*z_win -1001)
z_eye(0.5) = -1.99800399
是的,没错,从1到1001单位的平截头体,只有相机前面一到两个单位的范围将被映射到深度缓冲区范围的前半部分,之后的998单位被塞进了下半场。
因此,如果您尝试将深度缓冲区视为颜色,您将看不到除最近部分之外的任何内容。对于8位颜色,高于254/255 = .996的所有内容都将完全饱和(在我的示例中将是~200个单位),甚至在此之下,差异将是如此微小,几乎看不到。
如果您想直观地显示深度缓冲区,您应该反转双曲线失真,并可视化线性(=眼睛空间)深度。