使用帧缓冲区对象 (FBO) 或?

Posted

技术标签:

【中文标题】使用帧缓冲区对象 (FBO) 或?【英文标题】:Off-screen multiple render targets using Frame Buffer Object (FBO) or? 【发布时间】:2011-05-27 21:15:59 【问题描述】:

情况: 使用不同的变换和旋转生成 N 个形状和对应边缘的样本(使用 Sobel 滤波器或我自己的),而视口(大小 = 600*600)和相机保持不变。即会有 N 个样本 + N 个对应的边。

我正在考虑这样做,

使用一个带有 2 个渲染缓冲区的 FBO [即每个缓冲区的大小将为 = (N *600) * 600]- N 个形状的第一个和相应形状的边缘的第二个

问题:

    实现上述目标的最佳方法是什么? 虽然视口大小为 600*600 像素,但形状仅占 50*50 像素左右。那么是否有任何有效的方法可以仅在第二个缓冲区上对边界框/AABB 区域应用边缘检测?也只能以有效的方式读取 2N 个边界框(N 个样本 + N 个对应边)?

【问题讨论】:

【参考方案1】:

1:我不确定您所说的“最佳方式”。使用多个渲染目标:创建两个 600*N 纹理,使用 glDrawArrays 将它们都绑定到 FBO,并在片段着色器中,类似这样:

layout(location = 0) out vec3 color;
layout(location = 1) out vec3 edges;

当写入“颜色”和“边缘”时,您将有效地写入纹理。

2 : 你不应该这样做。在 CPU 上计算你的边界框,并投影它们(即将每个角乘以你的 ModelViewProjection 矩阵)以获得 2D 中的边界框

顺便说一句:首先计算你的边界框,这样你就不需要 600*600 的纹理,而是 50*50...

编辑:您通常使用 glViewPort 限制绘制区域。但是只有一个视口,你需要几个。您可以尝试Viewport array extension 并生活在最前沿,或者通过纹理传递 AABB,或者在性能重要之前不要担心...

哦,你不能像那样使用 Sobel...Sobel 要求你可以读取周围的所有纹素,但情况并非如此,因为你当前正在渲染所述纹素。要么做一个没有 MRT 的两遍算法(第一个颜色,然后是边缘),或者不使用 Sobel 并猜测你在着色器中的边缘(我真的不知道如何)

【讨论】:

@Calvin- 谢谢。 2-它是'大约'50 * 50,即会有所不同,因为有时它可能会更大或更小,因为透视投影的z变换效果。所以不能那样做。我认为我们在这里唯一能做的就是阅读。 @Calvin- 请考虑我从未使用过着色器。我不能使用:layout(location = 0) out vec3 color;边缘 = iif ( (color[i, j-1] != color[i,j+1] || (color[i-1, j] != color[i+1,j] ) 1:0; 布局(location = 1) out vec3 边; @Calvin- 即如果我可以按照上面评论中所说的那样做(asseccing neighbour),那么现在忘记问题(2),我可以使用一个 FBO,两个纹理缓冲区和片段着色器来实现我的第一个目标?对吗? @Rudi 如果您将(通过 FBO)渲染到相同的纹理(这似乎合乎逻辑),则您无法访问纹理中的邻居。所以:在一个具有 1 个颜色纹理和 1 个深度缓冲区的 FBO 中渲染您的场景,然后使用 Sobel 片段着色器在 另一个 FBO 中渲染生成的纹理(在一个简单的四边形中)。更多信息:opengl-tutorial.org/intermediate-tutorials/… @Calvin,谢谢!我得到了它!现在我猜最后一个问题:D。使用 2 个 FBO 或 1 个 FBO 和 2 个纹理哪个更好:首先绘制到一个纹理,然后使用它作为纹理绘制到第二个纹理?我的意思是用 glWritePixels 改变绘图目标?因为我在很多地方读到改变 FBO 仍然比改变纹理/渲染缓冲区成本高?【参考方案2】:

就像 Calvin 所说,您必须首先将对象渲染到第一个帧缓冲区中,然后将其绑定为纹理(使用纹理附件而不是渲染缓冲区),以便第二遍找到边缘,因为边缘检测通常需要访问到一个像素的周围像素。

关于第二个问题,您可能可以使用模板缓冲区。只需在第一遍中绘制您的形状,然后让它们将参考值写入模板缓冲区。然后进行边缘检测(通常通过使用相应的片段着色器渲染屏幕大小的四边形)并将模板测试配置为仅在模板缓冲区包含参考值的地方通过。这种方式(假设 early-z 硬件,现在很常见)片段着色器只会在实际绘制形状的像素上执行。

【讨论】:

@Christian- 不使用一个带有 2 个纹理缓冲区的 FBO 并应用片段着色器,我们可以以最佳方式完成第一项任务吗?正如卡尔文建议的那样,而不是改变 FBO?即一个 textrue 将具有形状颜色输出,而另一个将具有使用片段着色器的边缘? @Rudi 是的,但就像 Calvin 说的那样,你不能在同一遍中绘制形状并计算边缘,因为边缘检测器需要访问相邻像素。 是的。因此我的新评论。顺便说一句,这是有道理的:你无法访问你的邻居,你甚至不知道它是否已经被计算过!

以上是关于使用帧缓冲区对象 (FBO) 或?的主要内容,如果未能解决你的问题,请参考以下文章

WebGL入门(四十一)-使用帧缓冲区对象(FBO)实现将渲染结果作为纹理绘制到另一个物体上

将我的场景渲染到帧缓冲区对象(FBO)然后将该 FBO 渲染到屏幕所需的步骤是啥?

iOS OpenGL ES Analyzer 列出“不存在的帧缓冲区附件”和“缺少帧缓冲区附件”,但 FBO 工作

OpenGL:复制帧缓冲区对象

OpenGL 帧缓冲区 + LibGDX

OpenGL ES 学习教程(十四) 帧缓冲区对象(FBO) 实现渲染到纹理(Render To Texture/RTT)