c++ - glBlitFramebuffer 无效操作

标签 c++ opengl render blit

我一直在摆弄帧缓冲区和渲染到纹理,我发现需要 blit 它们。在某些机器上,我在 glBlitFramebuffer 调用之后立即得到一个 GL_INVALID_OPERATION。每个绑定(bind)到帧缓冲区的纹理都以完全相同的方式设置,都具有相同的大小和参数。此外,当我尝试将整个纹理(之前成功渲染到)blit 到另一个帧缓冲区时,只有要写入的目标“矩形”小于要读取的矩形(例如,当我想将它 blit 到帧缓冲区的四分之一时屏幕),它也会抛出一个 GL_INVALID_OPERATION

编辑: 实际上,每当要读取和绘制的矩形具有不同的大小时,它总是会抛出错误,所以我不能 blit 到不同大小的纹理,或者大小相同但“渲染到”区域大小不同...?

每次我 blit 到手动生成的帧缓冲区时,都会通过 glCheckFramebufferStatus 检查状态,它总是返回 GL_FRAMEBUFFER_COMPLETE

-有史以来最大的片段-,请参阅下面的较短“源代码”,显然有几个 C++ 错误并且不完整,但它仅用于 GL 调用

当我调用视口(viewport)的最后一个方法 (Viewport::blit) 并将屏幕帧缓冲区作为目标(通过传递 NULL)时,会发生 OpenGL 错误。它首先设置自己的帧缓冲区的读取缓冲区(绘制缓冲区已经设置),然后调用 RenderTarget::blit,后者调用 glBlitFramebuffer。在 blit 方法中,它绑定(bind)了两个缓冲区,您可以看到它在那里调用了 glCheckFramebufferStatus,它没有返回错误。

我一直在阅读 this一遍又一遍,但我似乎找不到导致它的错误。当我 blit 颜色缓冲区时,我使用 GL_LINEAR,否则我使用 GL_NEAREST 所有颜色缓冲区都使用 GL_RGB32F 作为内部格式和深度缓冲区(我从不 blit)使用 GL_DEPTH_COMPONENT32F

EDIT,一个较短的例子,只接受了所有 GL 调用并填充了我使用的参数

glBindFramebuffer(GL_READ_FRAMEBUFFER, _GL_Framebuffer);
glReadBuffer(GL_COLOR_ATTACHMENT0 + index);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);

// OpenGL error check, does not return an error

glBindFramebuffer(GL_READ_FRAMEBUFFER, _GL_Framebuffer);
GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
{
    // Some error checking, fortunately status always turns out to be complete
}
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

glBlitFramebuffer(0, 0, screenWidth, screenHeight, 0, 0, screenWidth, screenHeight, target, (target == GL_COLOR_BUFFER_BIT) ? GL_LINEAR : GL_NEAREST);

// If the source/destination read/draw rectangles are different in size, GL_INVALID_OPERATION is cought here

以及帧缓冲区/纹理创建:

glGenFramebuffer(1, &_GL_Framebuffer);

glGenTextures(1, &_GL_ZBuffer);
glBindTexture(GL_TEXTURE_2D, _GL_ZBuffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, screenWidth, screenHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);

glBindFramebuffer(GL_FRAMEBUFFER, _GL_Framebuffer);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT + 0, _GL_ZBuffer, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

int writeIndices[BUFFER_COUNT];
for(unsigned int i = 0; i < BUFFER_COUNT; ++i)
{
    writeIndices[i] = i;

    glGenTextures(1, &_GL_Texture);
    glBindTexture(GL_TEXTURE_2D, _GL_Texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, screenWidth, screenHeight, 0, GL_RGB, GL_FLOAT, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, 0);

    glBindFramebuffer(GL_FRAMEBUFFER, _GL_Framebuffer);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, _GL_Texture, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    // In the actual code each texture is obviously saved in an object
}

GLenum *enums = new GLenum[BUFFER_COUNT];
for(unsigned int i = 0; i < BUFFER_COUNT; ++i)
{
    // Get index and validate
    int index = *(indices + i); // indices = writeIndices
    if(index < 0 || index >= maxAttachments)
    {
        delete[] enums;
        return false;
    }

    // Set index
    enums[i] = GL_COLOR_ATTACHMENT0 + index;
}

// Set indices
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _GL_Framebuffer);
glDrawBuffers(BUFFER_COUNT, enums);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

delete[] enums;

// OpenGL error check, no errors

最佳答案

经过仔细阅读,我发现多重采样的差异是问题所在。 “主要”FBO 由 SFML 设置,因此只需将启动时的抗锯齿级别设置为 0,问题就部分解决了。

如果绘制/读取矩形的大小不相等,它现在会 blits,但它会在某些它应该工作的机器上不断崩溃。

关于c++ - glBlitFramebuffer 无效操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11915267/

相关文章:

c++ - 无法使用 Eigen 库进行编译

opengl - 从顶点数据中获取像素法线

opengl - 权限被拒绝在Linux上运行我自己的程序?

ruby-on-rails - 如何将变量传递给 render_to_string?

html - AJAX 调用后显示数据,如何在 Controller 中呈现?

c++ - 难以理解的POD默认初始化

C++构造函数理解

不使用新的C++内存分配错误

opengl - GLSL:顶点着色器中的sampler3D,纹理显示为空白

java - java bufferedImage 真的给出黑色 Canvas 吗?