如何在OpenGL es 2.0中模拟累积缓冲区(尾随粒子效应)

J.D*_*Doe 10 opengl-es ios opengl-es-2.0 swift

所以我一直试图用OpenGL ES 2.0 创建一个尾随粒子效果(见到这里).不幸的是,似乎OpenGL命令(累积缓冲区)无法在OpenGL中使用.这意味着有必要走长路.

主题描述了执行此类操作的可能方法.但是我对如何在缓冲区中存储内容并组合缓冲区感到很困惑.所以我的想法是做以下事情.

  1. 使用写入纹理的缓冲区将当前帧绘制到纹理中
  2. 将之前的帧(但已淡入)绘制到另一个缓冲区中.
  3. 将步骤1置于步骤2的顶部.然后显示.
  4. 保存显示的任何内容以供下一帧使用.

到目前为止,我的理解是缓冲区以与纹理相同的方式存储像素数据,只需使用着色器可以更容易地绘制缓冲区.

因此,想法可能是渲染到缓冲区,然后将其移动到纹理中.

我发现这样做的一个理论就是这个

回想起来,你应该创建两个FBO(每个都有自己的纹理); 使用默认的帧缓冲区是不可靠的(不保证在帧之间保留内容).

绑定第一个FBO后,清除它然后正常渲染场景.渲染场景后,使用纹理作为源并使用混合将其渲染到第二个FBO(第二个FBO永远不会被清除).这将导致第二个FBO包含新场景和之前的场景的混合.最后,第二个FBO应直接渲染到窗口(这可以通过渲染纹理四边形来完成,类似于前一个操作,或者使用glBlitFramebuffer).

实质上,第一个FBO取代了默认的帧缓冲区,而第二个FBO取代了累积缓冲区.

综上所述:

初始化:

对于每个FBO: - glGenTextures - glBindTexture - glTexImage2D - glBindFrameBuffer - glFramebufferTexture2D

每一帧:

glBindFrameBuffer(GL_DRAW_FRAMEBUFFER,fbo1)glClear glDraw*//场景

glBindFrameBuffer(GL_DRAW_FRAMEBUFFER,fbo2)glBindTexture(tex1)glEnable(GL_BLEND)glBlendFunc glDraw*//全屏四边形

glBindFrameBuffer(GL_DRAW_FRAMEBUFFER,0)glBindFrameBuffer(GL_READ_FRAMEBUFFER,fbo2)glBlitFramebuffer

不幸的是它没有足够的代码(尤其是初始化让我开始).

但我已经尝试过,到目前为止我所得到的只是一个令人失望的空白屏幕.我真的不知道我在做什么,所以可能这段代码是错误的.

var fbo1:GLuint = 0
var fbo2:GLuint = 0
var tex1:GLuint = 0

Init()
{
    //...Loading shaders  OpenGL etc.   
    //FBO 1
        glGenFramebuffers(1, &fbo1)
        glBindFramebuffer(GLenum(GL_FRAMEBUFFER), fbo1)

        //Create texture for shader output
        glGenTextures(1, &tex1)
        glBindTexture(GLenum(GL_TEXTURE_2D), tex1)
        glTexImage2D(GLenum(GL_TEXTURE_2D), 0, GL_RGB, width, height, 0, GLenum(GL_RGB), GLenum(GL_UNSIGNED_BYTE), nil)

        glFramebufferTexture2D(GLenum(GL_FRAMEBUFFER), GLenum(GL_COLOR_ATTACHMENT0), GLenum(GL_TEXTURE_2D), tex1, 0)
        //FBO 2
        glGenFramebuffers(1, &fbo2)
        glBindFramebuffer(GLenum(GL_FRAMEBUFFER), fbo2)

        //Create texture for shader output
        glGenTextures(1, &tex1)
        glBindTexture(GLenum(GL_TEXTURE_2D), tex1)
        glTexImage2D(GLenum(GL_TEXTURE_2D), 0, GL_RGB, width, height, 0, GLenum(GL_RGB), GLenum(GL_UNSIGNED_BYTE), nil)

        glFramebufferTexture2D(GLenum(GL_FRAMEBUFFER), GLenum(GL_COLOR_ATTACHMENT0), GLenum(GL_TEXTURE_2D), tex1, 0)
}

func drawFullScreenTex()
{
        glUseProgram(texShader)
        let rect:[GLint] = [0, 0, GLint(width), GLint(height)]
        glBindTexture(GLenum(GL_TEXTURE_2D), tex1)
        //Texture is allready
        glTexParameteriv(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_CROP_RECT_OES), rect)
        glDrawTexiOES(0, 0, 0, width, height)
 }

fun draw()
{
    //Prep
        glBindFramebuffer(GLenum(GL_DRAW_FRAMEBUFFER), fbo1)
        glClearColor(0, 0.1, 0, 1.0)
        glClear(GLbitfield(GL_COLOR_BUFFER_BIT))

        //1
        glUseProgram(pointShader);
        passTheStuff() //Just passes in uniforms
        drawParticles(glGetUniformLocation(pointShader, "color"), size_loc: glGetUniformLocation(pointShader, "pointSize")) //Draws particles


        //2
        glBindFramebuffer(GLenum(GL_DRAW_FRAMEBUFFER), fbo2)
        drawFullScreenTex()


        //3
        glBindFramebuffer(GLenum(GL_DRAW_FRAMEBUFFER), 0)
        glBindFramebuffer(GLenum(GL_READ_FRAMEBUFFER), fbo2)
        glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GLbitfield(GL_COLOR_BUFFER_BIT), GLenum(GL_NEAREST))

}
Run Code Online (Sandbox Code Playgroud)

BTW这里有一些我认为有用的资料.

  1. 网站1
  2. 网站2
  3. 网站3
  4. 网站4

我的主要问题是: 有人可以为此写出代码.我想我理解所涉及的理论,但我花了很多时间徒劳地尝试应用它.

如果你想要一个地方开始,我有一个绘制点的Xcode项目,并且有一个蓝色的项目在这里定期移动屏幕,同样也没有工作的代码.

注意:如果你要编写代码,你可以使用任何语言c ++,java,swift,objective-c它将是完美的.只要它适用于OpenGL-ES

Rei*_*tje 2

glGenTextures(1, &tex1)使用同一变量 tex1 调用两次。这会覆盖该变量。当您稍后调用 时glBindTexture(GLenum(GL_TEXTURE_2D), tex1),它不会绑定 fbo1 对应的纹理,而是绑定 fbo2 对应的纹理。每个 fbo 都需要不同的纹理。

作为参考,下面是我的一个工作程序的示例,它使用多个 FBO 并渲染到纹理。

GLuint fbo[n];
GLuint tex[n];

init() {
    glGenFramebuffers(n, fbo);
    glGenTextures(n, tex);

    for (int i = 0; i < n; ++i) {
        glBindFramebuffer(GL_FRAMEBUFFER, fbo[i]);

        glBindTexture(GL_TEXTURE_2D, tex[i]);
        glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex[i], 0);
    }
}

render() {

    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo[0]);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 
    glClear(GL_COLOR_BUFFER_BIT);

    // Draw scene into buffer 0

    glBindFrameBuffer(GL_DRAW_FRAMEBUFFER, fbo[1]);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 
    glClear(GL_COLOR_BUFFER_BIT);

    glBindTexture(cbo[0]);

    //Draw full screen tex


    ...


    glBindFrameBuffer(GL_DRAW_FRAMEBUFFER, 0);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 
    glClear(GL_COLOR_BUFFER_BIT);

    glBindTexture(cbo[n - 1]);
    // Draw to screen

    return;
}
Run Code Online (Sandbox Code Playgroud)

一些笔记。为了让它工作,我必须添加纹理参数。

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Run Code Online (Sandbox Code Playgroud)

这是因为在我的系统上它们默认为 GL_NEAREST_MIPMAP_LINEAR。这对于 FBO 纹理不起作用,因为没有生成 mipmap。将它们设置为您喜欢的任何内容。

另外,请确保您启用了纹理

glEnable(GL_TEXTURE_2D)
Run Code Online (Sandbox Code Playgroud)

我希望这个能帮上忙。