如何将帧缓冲区对象绘制到默认帧缓冲区

How to draw a framebuffer object to the default framebuffer

此代码应该使用帧缓冲区对象和渲染缓冲区清除黄色背景,但我得到的是黑色背景。

#include <SDL2/SDL.h>
#include <GL/glew.h>

int main( int argc, char** argv)
    {
    SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 3);
    SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1);

    SDL_Window* gWindow= SDL_CreateWindow( "Title",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
        500, 500, SDL_WINDOW_OPENGL);
    SDL_GLContext gContext= SDL_GL_CreateContext( gWindow);

    glewExperimental= GL_TRUE;
    glewInit();

    GLuint fbo;
    glGenFramebuffers( 1, &fbo);
    glBindFramebuffer( GL_FRAMEBUFFER, fbo);

    GLuint color_rbr;
    glGenRenderbuffers(1, &color_rbr);
    glBindRenderbuffer( GL_RENDERBUFFER, color_rbr);
    glRenderbufferStorage( GL_RENDERBUFFER, GL_RGBA32UI, 500, 500);
    glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color_rbr);

    GLuint depth_rbr;
    glGenRenderbuffers( 1, &depth_rbr);
    glBindRenderbuffer( GL_RENDERBUFFER, depth_rbr);
    glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 500, 500);
    glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_rbr);

    if( glCheckFramebufferStatus( GL_DRAW_FRAMEBUFFER)!= GL_FRAMEBUFFER_COMPLETE)
        return 1;
    if( glCheckFramebufferStatus( GL_READ_FRAMEBUFFER)!= GL_FRAMEBUFFER_COMPLETE)
        return 2;

    glViewport( 0, 0, 500, 500);
    glClearColor( 1, 1, 0, 0);
    SDL_GL_SetSwapInterval( 1);

    int quit= 0;
    SDL_Event event;
    glReadBuffer( GL_COLOR_ATTACHMENT0);

    while( !quit)
        {
        while( SDL_PollEvent( &event))
            if( event.type== SDL_QUIT)
                quit= 1;

        glBindFramebuffer( GL_DRAW_FRAMEBUFFER, fbo);
        glDrawBuffer( GL_COLOR_ATTACHMENT0);
        glClear( GL_COLOR_BUFFER_BIT);
        glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0);
        glDrawBuffer( GL_BACK);
        glBlitFramebuffer(
            0, 0, 500, 500,
            0, 0, 500, 500,
            GL_COLOR_BUFFER_BIT, GL_NEAREST);
        SDL_GL_SwapWindow( gWindow);
        }
    SDL_DestroyWindow( gWindow);
    return 0;
    }

它首先清除具有指定颜色的帧缓冲区对象,然后将帧缓冲区对象blits到默认帧缓冲区。代码有问题吗?我似乎找不到问题的确切位置。

glBlitFramebuffer 操作失败,因为读取缓冲区包含无符号整数值而默认帧缓冲区不包含。这会导致 GL_INVALID_OPERATION 错误。

读取缓冲区的格式为GL_RGBA32UI

glRenderbufferStorage( GL_RENDERBUFFER, GL_RGBA32UI, 500, 500); 

而绘图缓冲区(默认帧缓冲区)的格式是无符号规范化整数格式(可能是GL_RGBA8)。

如果您将内部格式更改为 GL_RGBA16GL_RGBA32F,您的代码将正常工作。

注意,RGBA8RGBA16 等格式是规范化浮点格式,可以存储 [0.0, 1.0] 范围内的浮点值。
但是像RGBA16UIRGBA32UI这样的格式是无符号整数格式,可以存储相应范围内的整数值。

规范说无符号整数值只能复制为无符号整数值。所以源格式必须是 *UI,目标格式也必须是 *UI


参见 OpenGL 4.6 API Compatibility Profile Specification - 18.3.2 Blitting Pixel Rectangles 第 662 页:

void BlitFramebuffer( int srcX0, int srcY0, int srcX1, int srcY1, 
    int dstX0, int dstY0, int dstX1, int dstY1, bitfield mask, enum filter );

[...]

Errors

[...]

An INVALID_OPERATION error is generated if format conversions are not supported, which occurs under any of the following conditions:

  • The read buffer contains fixed-point or floating-point values and any draw buffer contains neither fixed-point nor floating-point values.
  • The read buffer contains unsigned integer values and any draw buffer does not contain unsigned integer values.
  • The read buffer contains signed integer values and any draw buffer does not contain signed integer values.