objective-c – 两个FBO之间的乒乓渲染在第一帧之后失败.

我正在尝试创建两个FBO并实现乒乓渲染.但是,我只能让第一帧正常工作.我试图模拟生活游戏,在第一帧之后,我只得到一个黑屏.你能帮帮我查一下吗?我在这个问题上花了好几个小时.

编辑

也许我没有清楚地描述.实际上,我想使用textureB作为纹理并将其渲染为textureA,然后使用textureA渲染到屏幕,反之亦然.

编辑
我可以看到第一帧,即textureB.经过片段着色器后,它变为黑色.首先,我怀疑片段着色器,我将其更改为仅将黑色恢复为白色,将白色恢复为黑色.它仍然变得全黑.

设置fbo和纹理

glEnable(GL_TEXTURE_2D);
    glGenTextures(1,&textureA);
    glBindTexture(GL_TEXTURE_2D,textureA);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D,GL_RGBA,256,GL_UNSIGNED_BYTE,NULL);

    glGenTextures(1,&textureB);
    glBindTexture(GL_TEXTURE_2D,textureB);
    glTexParameteri(GL_TEXTURE_2D,GL_CLAMP_TO_EDGE);

    data=(GLubyte*)malloc(256*256*4*sizeof(GLubyte));
    GLubyte val;
    for (int i = 0; i < 256 * 256 * 4; i+=4) {   
        if (rand()%10 ==1) 
            { val = 0; } 
        else 
            { val = 255; }
        data[i] = data[i+1] = data[i+2] = val;
        data[i+3] = 255;
    }
    glTexImage2D(GL_TEXTURE_2D,data);

    glGenFramebuffers(1,&fboA);
    glBindFramebuffer(GL_FRAMEBUFFER,fboA);
    glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,textureA,0);

    glGenFramebuffers(1,&fboB);
    glBindFramebuffer(GL_FRAMEBUFFER,fboB);
    glFramebufferTexture2D(GL_FRAMEBUFFER,textureB,0);

渲染循环

if ([context API] == kEAGLRenderingAPIOpenGLES2) {


        if(counter%2==0)
        {
            glUseProgram(automateProg);
            glBindFramebuffer(GL_FRAMEBUFFER,fboA);
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D,textureB);
            glUniform1i(AUTOMATE_TEXT,0);
            glUniform1f(DU,1.0/256);
            glUniform1f(DV,1.0/256);
            // Update attribute values.
            glVertexAttribPointer(ATTRIB_VERTEX_2,2,GL_FLOAT,squareVertices);
            glEnableVertexAttribArray(ATTRIB_VERTEX_2);

            glVertexAttribPointer(ATTRIB_TEXCOORD_2,GL_FALSE,texCoord);    
            //glEnableVertexAttribArray(ATTRIB_TEXCOORD_2);
            glDrawArrays(GL_TRIANGLE_STRIP,4);
            if (![self validateProgram:automateProg]) {
                NSLog(@"Failed to validate program: %d",automateProg);
                return;
            }

            glBindFramebuffer(GL_FRAMEBUFFER,0);
            glUseProgram(0);
        }
        else
        {
            glUseProgram(automateProg);            
            glBindFramebuffer(GL_FRAMEBUFFER,fboB);
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D,textureA);
            glUniform1i(AUTOMATE_TEXT,squareVertices);
            glEnableVertexAttribArray(ATTRIB_VERTEX_2);
            glVertexAttribPointer(ATTRIB_TEXCOORD_2,texCoord); 
            //glEnableVertexAttribArray(ATTRIB_TEXCOORD_2);
            glDrawArrays(GL_TRIANGLE_STRIP,0);
            glUseProgram(0);
        }

        [(EAGLView *)self.view setFramebuffer];
        glClearColor(0.5f,0.5f,1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        if (counter % 2 == 0) {
            glUseProgram(normalProg);
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D,textureB);
            glUniform1i(NORMAL_TEXT,0);
            glVertexAttribPointer(ATTRIB_VERTEX,squareVertices);
            glEnableVertexAttribArray(ATTRIB_VERTEX);
            glVertexAttribPointer(ATTRIB_TEXCOORD,texCoord); 
            glEnableVertexAttribArray(ATTRIB_TEXCOORD);
            glDrawArrays(GL_TRIANGLE_STRIP,4);
            if (![self validateProgram:normalProg]) {
                NSLog(@"Failed to validate program: %d",normalProg);
                return;
            }
            glUseProgram(0);

        } else {
            glUseProgram(normalProg);
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D,textureA);
            glUniform1i(NORMAL_TEXT,normalProg);
                return;
            }
            glUseProgram(0);
        }
        counter++;

[(EAGLView *)self.view presentFramebuffer];

片段着色器

precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D tex; //the input texture
uniform float du; //the width of the cells
uniform float dv; //the height of the cells
    void main() {
        int count = 0;

        vec4 C = texture2D( tex,v_texCoord );
        vec4 E = texture2D( tex,vec2(v_texCoord.x + du,v_texCoord.y) );
        vec4 N = texture2D( tex,vec2(v_texCoord.x,v_texCoord.y + dv) );
        vec4 W = texture2D( tex,vec2(v_texCoord.x - du,v_texCoord.y) );
        vec4 S = texture2D( tex,v_texCoord.y - dv) );
        vec4 NE = texture2D( tex,v_texCoord.y + dv) );
        vec4 NW = texture2D( tex,v_texCoord.y + dv) );
        vec4 SE = texture2D( tex,v_texCoord.y - dv) );
        vec4 SW = texture2D( tex,v_texCoord.y - dv) );

        if (E.r == 1.0) { count++; }
        if (N.r == 1.0) { count++; }
        if (W.r == 1.0) { count++; }
        if (S.r == 1.0) { count++; }
        if (NE.r == 1.0) { count++; }
        if (NW.r == 1.0) { count++; }
        if (SE.r == 1.0) { count++; }
        if (SW.r == 1.0) { count++; }

        if ( (count == 2 || count == 3)) {
            gl_FragColor = vec4(1.0,1.0,1.0); //cell lives...
        } else {
            gl_FragColor = vec4(0.0,0.0,1.0); //cell dies...
        }
    }

解决方法

我是否理解你的代码,你想在第一个if-else块中将结果呈现给纹理,并将结果渲染到第二个if-else块中的屏幕?
如果是这样,那么看起来您在如何组织输入和输出时就会出错.
这是你第一次传递中发生的事情(我减少了你的代码):

if(counter%2==0)
{
    glBindFramebuffer(GL_FRAMEBUFFER,fboA); // will render to textureA
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D,textureB); // textureB is our input
} else {
    ...
}

if (counter % 2 == 0) {
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D,textureB); // textureB still as input? not textureA?
} else {
    ...
}

……这就是第二遍中发生的事情:

if(counter%2==0)
{
    ...
} else {
    glBindFramebuffer(GL_FRAMEBUFFER,fboB); // will render to textureB
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D,textureA); // textureA as input
}

if (counter % 2 == 0) {
    ...
} else {
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D,textureA); // textureA as input again?
}

您在第一帧中看到某些内容的原因是,因为您实际渲染了输入数据,而不是第一次传递的结果.您在第二次传递中出现黑屏的原因可能是您的片段着色器无法正常工作.从您的着色器代码判断,访问邻居纹素的错误似乎是最合理的原因.你能提供duand dv的价值吗?

而且我不认为只使用一个纹理单元应该会有任何麻烦,正如布拉德早先指出的那样.虽然我不确定.

旁注:对于乒乓,你应该考虑创建你的FBOs as an array以使你的代码更具可读性.

编辑:

我在使用glUniform1f()设置制服du和dv时遇到问题,请尝试使用glUniform1i()(您需要在着色器中使用float()进行转换)或者使用glUniform1fv().我曾经遇到过与PowerVR GLES2驱动程序相同的问题,这个函数没有做任何事情,导致统一为0.0.

相关文章

一.C语言中的static关键字 在C语言中,static可以用来修饰局...
浅谈C/C++中的指针和数组(二) 前面已经讨论了指针...
浅谈C/C++中的指针和数组(一)指针是C/C++...
从两个例子分析C语言的声明 在读《C专家编程》一书的第三章时...
C语言文件操作解析(一)在讨论C语言文件操作之前,先了解一下...
C语言文件操作解析(三) 在前面已经讨论了文件打开操作,下面...