使用具有不同分辨率的深度和颜色缓冲区(子采样深度缓冲区)

时间:2011-11-17 18:13:01

标签: objective-c opengl opengl-es-2.0 framebuffer depth-buffer

我想使用子采样深度缓冲区来提高程序的性能。在我的情况下,如果会出现瑕疵或几何弹出并不重要。

我已经设置了这样的帧缓冲:

// Color attachment
glBindTexture(GL_TEXTURE_2D, colorAttachment);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 640, 360, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);

// Depth attachment
glBindRenderbuffer(GL_RENDERBUFFER, depthAttachment);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 160, 90);

// Framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorAttachment, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthAttachment);

但是,现在,glCheckFramebufferStatus(GL_FRAMEBUFFER)会根据documentation返回GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,代表“并非所有附加图像都具有相同的宽度和高度”。

有一篇名为“Full-3D Edge Tracking with a Particle Filter”的研究论文在3.5节中描述了他们实际上使用了一个子采样深度缓冲来提高其应用的性能。

  

子采样深度缓冲器:沿图像边缘的相邻像素是如此紧密相关   测试每个单独的边缘像素是多余的。对于单假设跟踪器,   通常将样本点沿边缘分开10-20个像素的距离。   仅对每第n个边缘像素进行采样也会减少所需的图形带宽   所以只对每第4个像素进行采样。这里不是明确地绘制点画线,而是通过使用子采样深度缓冲区(160 x 120)来实现,因为这进一步实现了   用于清除和填充深度缓冲区的带宽减少。不过,这也是   意味着隐藏线移除可能不准确到大约四个像素。距离   由此,系统的准确性不受影响。

唯一明显的解决方法是

  • 使用片段着色器程序执行先前渲染的深度缓冲区的查找,以手动应用深度检查。
  • 以较低的分辨率渲染深度缓冲区,然后将其重新取样至更高的分辨率,然后像以前一样使用它。

这两种方法听起来都不像是最有效的想法。实现子采样深度缓冲的最简洁方法是什么?

1 个答案:

答案 0 :(得分:2)

您引用的文档页面是指OpenGL ES 1.0和2.0。 OpenGL wiki有关于2.0和3.0之间差异的更多信息,即从3.0(和ARB_framebuffer_object)开始,帧缓冲纹理可以具有不同的大小。但是,如果我没记错的话,当你附加了不同大小的纹理时,使用的实际纹理大小是所有FBO附加纹理的交集。我认为这不是你想要的。

为了减小深度纹理的大小,我建议使用glBlitFramebuffer将大纹理转换为较小的纹理。此操作完全在GPU上完成,因此速度非常快。然后可以将最终较小的纹理用作着色器中进一步渲染操作的输入,这肯定可以节省带宽。不是为每个像素着色器执行执行多个深度值的平均,而是在较小纹理中每个纹素元素执行一次。较小的纹理本身也具有更快的采样速度,因为它更适合缓存。

然而,保持平均深度样本会产生野性不准确,因为深度值不会线性扩散。