OpenGL:一次只有一个 FBO 工作

Posted

技术标签:

【中文标题】OpenGL:一次只有一个 FBO 工作【英文标题】:OpenGL: only one FBO at a time works 【发布时间】:2014-11-26 14:28:06 【问题描述】:

我正在尝试渲染到纹理,然后复制该纹理并通过后期处理运行它,然后将过滤后的图像与原始图像结合起来。我有它,所以我可以渲染到纹理,然后处理它并显示它,但我只能处理一次。我真的不知道出了什么问题。

这是我的 FBO 设置代码:

for (int i = 0; i < 3; i++) 
    glGenFramebuffers(1, &postfboId[i]);
    glGenTextures(1, &postTextureId[i]);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, postTextureId[i]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    //float color[4] = 0.0, 0.0, 0.0, 1.0;
    //glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, screenSize.x, screenSize.y, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);

    // create a framebuffer object
    glBindFramebuffer(GL_FRAMEBUFFER, postfboId[i]);


    glGenRenderbuffers(1, &depthrenderbuffer[i]);
    glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbuffer[i]);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, screenSize.x, screenSize.y);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthrenderbuffer[i]);


    // attach the texture to FBO depth attachment point
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D, postTextureId[i], 0);

    
    GLenum DrawBuffers[] = GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2;
    glDrawBuffers(1, DrawBuffers);
    // check FBO status
    FBOstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if(FBOstatus != GL_FRAMEBUFFER_COMPLETE)
        printf("hey man, you might want to sit down a minute, i didn't want to have to say this to you, but the FBO failed.\n");

我想也许我需要 glDrawBuffers 来制作 3 而不是 1,但这只会导致 FBO 不完整。 这是我的渲染代码:

glBindFramebuffer(GL_FRAMEBUFFER,postfboId[0]);
sf::Vector2u size = screenSize;
changeSize(size.x, size.y);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 
//clear viewport
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glUseProgram(prog);

glPushMatrix();

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
setLookat();
glCullFace(GL_BACK);
setLights();
drawObjs();

glPopMatrix();

//first round post process
glClearColor(0, 0, 0, 1);
glUseProgram(postProg);

glBindFramebuffer(GL_FRAMEBUFFER,postfboId[1]);
glUniform1i(postProcessMode, 1);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPushMatrix();
glLoadIdentity();
glOrtho(0,screenSize.x,0,screenSize.y,-1,20);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPushMatrix();
glLoadIdentity();
glColor4f(1,1,1,1);
glUniform1i(texUniform3, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,postTextureId[0]);
glEnable(GL_TEXTURE_2D);
glTranslated(0,0,-19.5);
glBegin(GL_QUADS);
glTexCoord2d(0,0);glVertex3f(0,0,0);
glTexCoord2d(1,0);glVertex3f(screenSize.x,0,0);
glTexCoord2d(1,1);glVertex3f(screenSize.x,screenSize.y,0);
glTexCoord2d(0,1);glVertex3f(0,screenSize.y,0);
glEnd();


// round 2 post
glUniform1i(postProcessMode, 2);
glBindFramebuffer(GL_FRAMEBUFFER,0);

glUniform1i(texUniform3, 3);
glActiveTexture(GL_TEXTURE3);
// bind postTextureId[0] to draw real screen.
glBindTexture(GL_TEXTURE_2D,postTextureId[1]);
glEnable(GL_TEXTURE_2D);
glTranslated(0,0,0.5);
glBegin(GL_QUADS);
glTexCoord2d(0,0);glVertex3f(0,0,0);
glTexCoord2d(1,0);glVertex3f(screenSize.x,0,0);
glTexCoord2d(1,1);glVertex3f(screenSize.x,screenSize.y,0);
glTexCoord2d(0,1);glVertex3f(0,screenSize.y,0);
glEnd();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();

无论出于何种原因,将 FBO 纹理绘制到另一个 FBO 会导致废话,但将 FBO 纹理绘制到屏幕上是可以的。此外,所有 3 个 FBO 都可以工作,只是不能同时工作,这很奇怪,因为我有另一个 FBO,它只有一个用于正确显示阴影贴图的深度缓冲区。

【问题讨论】:

注意:您可以将循环中的glGenFramebuffers(1, &amp;postfboId[i]); 替换为之前的glGenFramebuffers(3, postfboId)。与glGenTextures 相同。 谢谢三十二上校 你可能会得到有用的回应,如果你发布最小的完全可编译的例子来证明问题 【参考方案1】:

一个明显的问题是您缺少glClear() 对除第一个渲染目标之外的所有调用。绑定 fbo 0 后调用一次:

glBindFramebuffer(GL_FRAMEBUFFER,postfboId[0]);
...
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

但是你还需要在绑定fbo 1后清除:

glBindFramebuffer(GL_FRAMEBUFFER,postfboId[1]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

并绑定默认帧缓冲后:

glBindFramebuffer(GL_FRAMEBUFFER,0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

您的一些glPushMatrix()glPopMatrix() 电话看起来也有些可疑。但是如果不查看整个代码,很难判断它们是否不正确。您可能需要仔细检查它们是否都平衡,并且在调用它们时您处于正确的矩阵模式。例如在这个序列中:

glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPushMatrix();
glLoadIdentity();

glPopMatrix()glPushMatrix() 调用是多余的。如果有的话,它们可能是有害的,因为如果您之前没有调用 glPushMatrix(),则会出现错误。否则,它将首先将前一个矩阵复制到顶部条目,然后立即用单位矩阵覆盖它。这与单独调用glLoadIdentity() 相同。

【讨论】:

哦,哇,谢谢。我知道我忘记了类似的事情。我没有清除缓冲区!

以上是关于OpenGL:一次只有一个 FBO 工作的主要内容,如果未能解决你的问题,请参考以下文章

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

需要带有 FBO 扩展的 OpenGL 2.0 或更高版本 - LibGDX 错误

OpenGL 帧缓冲区 + LibGDX

使用 OpenGL 使用延迟渲染绑定 FBO 后卡在渲染灯上

OpenGL:渲染到 FBO 时是不是支持纹理组合器功能?

Intel和Nvidia之间的OpenGL fbo blitting不一致