Android OpenGL ES 2.0重用上一帧

时间:2015-03-12 19:25:47

标签: android opengl-es framebuffer

我正在寻找一个最小的例子,其中每个帧将重用前一帧中的三角形。我一直在尝试不成功,所以我没有任何值得展示的代码,虽然我有一个程序可以通过绘制到默认的帧缓冲区来工作。

在绘制过程中,我会向帧缓冲对象添加新的三角形,并将帧复制到默认的帧缓冲区。由于我不会清除帧缓冲区对象,它将保留其rgba值和深度,因此当我在下一帧添加更多三角形时,之前的那些仍将保留。 (稍后我将减少前一帧中三角形的alpha值以产生淡入淡出效果,但为了简单起见,请重复使用前面的三角形,因为它们很好。)

我发现很难理解帧缓冲区对象是如何工作的,以及我是否需要创建渲染,深度和纹理缓冲区。我怀疑我需要渲染和深度缓冲,因为我想在绘制之间保留该信息,但不需要纹理缓冲区。

我认为onDrawFrame方法看起来像这样:

  1. 将新数据添加到帧缓冲对象中。
  2. 清除默认的帧缓冲区。
  3. 来自framebuffer对象的信息被复制到默认的帧缓冲区,然后渲染默认的帧缓冲区。
  4. 我相信我正在通过绑定framebuffer对象,renderbuffer和深度缓冲区来正确地执行步骤1和2,但我无法找到从一个帧缓冲区复制到另一个帧缓冲区的方法。

2 个答案:

答案 0 :(得分:2)

对于第3步,使用渲染的纹理(用作FBO颜色附件的纹理),并在绘制屏幕尺寸四边形时从中进行采样。您可以使用非常简单的着色器。副本的顶点着色器将如下所示:

#version 100
attribute vec2 Pos;
varying vec2 TexCoord;
void main() {
    TexCoord = 0.5 * Pos + 0.5;
    gl_Position = vec4(Pos, 0.0, 1.0);
}

和片段着色器:

#version 100
uniform sampler2D Tex;
varying vec2 TexCoord;
void main() {
    gl_FragColor = texture2D(Tex, TexCoord);
}

然后绘制一个四边形,覆盖x和y中的范围[-1.0,1.0]。

还有另一种选择。不幸的是,它不便携,但可以在某些设备上运行。以下是我最近的答案:Fast Screen Flicker while NOT drawing on Android OpenGL

对于这种方法,请致电:

eglSurfaceAttrib(display, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
设置上下文/表面时

。这要求在eglSwapBuffers()之后保留缓冲区内容。但它有一个很大的警告:所有设备都不支持此功能。您可以测试它是否支持:

EGLint surfType = 0;
eglGetConfigAttrib(display, config, EGL_SURFACE_TYPE, &surfType);
if (surfType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) {
    // supported!
}

您也可以在选择配置时请求此功能。作为传递给eglChooseConfig()的属性的一部分,请添加:

...
EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT,
...

但同样,在所有设备上不支持。因此,如果您针对特定设备进行定位,那么它只是一个选项,如果不支持则具有功能性后备功能。

答案 1 :(得分:1)

帧缓冲对象实际上只是一个元对象,它是包含它的表面(纹理或渲染缓冲区)的容器。您需要创建所需的颜色/深度/模板,并且"附加"他们到了 帧缓冲对象中的相关附着点。

在从一个表面复制到另一个表面方面,你可以使用glBlitFramebuffer,或者只是渲染一个2D四边形,将屏幕外表面加载为纹理,并设置纹理坐标,使其为1:1副本。

注意"渲染超过内存中的内容"在大多数基于磁贴的移动GPU上都是相对昂贵的(它们必须将旧状态读入GPU本地内存),特别是如果您需要单独的副本将屏幕外缓冲区插入到屏幕缓冲区中。我建议进行性能分析,以确保这个方案真的比重新渲染更快,因为它听起来可能不是。