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

时间:2015-11-28 19:39:49

标签: ios swift opengl-es opengl-es-2.0

所以我一直试图用OpenGL ES 2.0创建一个尾随粒子效果(seen here)。不幸的是,似乎OpenGL命令(累积缓冲区)无法在OpenGL中使用。这意味着有必要采用LONG方式。

This主题描述了做这种事情的可能方法。但是我对如何在缓冲区中存储内容并组合缓冲区感到很困惑。所以我的想法是做到以下几点。

  1. 使用写入纹理的缓冲区
  2. 将当前帧绘制到纹理中
  3. 将之前的帧(但已淡入)绘制到另一个缓冲区中。
  4. 将步骤1放在步骤2的顶部。然后显示。
  5. 保存下一帧显示的内容。
  6. 到目前为止,我的理解是缓冲区以与纹理相同的方式存储像素数据,只需使用着色器就可以更容易地绘制缓冲区。

    所以想法可能是渲染到缓冲区,然后将其移动到纹理中。

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

      

    回想起来,你应该创建两个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))
    
    }
    

    BTW这里有一些我觉得有用的资料。

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

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

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

1 个答案:

答案 0 :(得分:1)

使用相同的变量tex1调用glGenTextures(1, &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;
}

一些笔记。为了使它工作,我不得不添加纹理参数。

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

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

此外,请确保使用

启用纹理
glEnable(GL_TEXTURE_2D)

我希望这会有所帮助。