OpenGL Qt:使用帧缓冲区实现绽放效果的问题

Posted

技术标签:

【中文标题】OpenGL Qt:使用帧缓冲区实现绽放效果的问题【英文标题】:OpenGL Qt : problem using framebuffers for bloom effect 【发布时间】:2018-12-09 14:59:38 【问题描述】:

我正在关注这个tutorial 的绽放效果。

我正在使用 Qt,我尝试渲染的场景由五个立方体和五个随机放置的灯光组成,类似于这样。

不幸的是,当我尝试使用帧缓冲区时,渲染的场景完全是空的(只有背景颜色)。

这些是代码的相关部分。

初始化GL方法

void initializeGL()

    initializeOpenGLFunctions();

    // ...

    // hdr framebuffer

    glGenFramebuffers(1, &(FBOs[0]));

    glBindFramebuffer(GL_FRAMEBUFFER, FBOs[0]);

    glGenTextures(2, &(textures[0]));

    for (int i = 0; i < 2; i++)
    
        glBindTexture(GL_TEXTURE_2D, textures[i]);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, geometry().width(), geometry().height(), 0, GL_RGB, GL_FLOAT, NULL);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, textures[i], 0);
    

    GLuint rbo;
    glGenRenderbuffers(1, &rbo);
    glBindRenderbuffer(GL_RENDERBUFFER, rbo);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, geometry().width(), geometry().height());
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo);

    GLuint attachments[2] =  GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 ;
    glDrawBuffers(2, attachments);

    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    
        qDebug() << "framebuffer NOT complete";
    

    glBindFramebuffer(GL_FRAMEBUFFER, 0);

paintGL 方法

void paintGL()

    view.setToIdentity();
    view.lookAt(camera.eye, camera.center, camera.up);

    glClearColor(background.redF(), background.greenF(), background.blueF(), background.alphaF());
    glEnable(GL_DEPTH_TEST);

    // draw scene

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

    for (auto position : positions)
    
        drawCube(position);
    

    for (auto light : lights)
    
        drawLightMarker(light);
    

    // draw frame

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

    drawQuad();

    // draw next frame
    update();

drawQuad 方法

void drawQuad()

    GLuint* vao = &VAOs[BLOOM];

    if (*vao == 0)
    
        glGenVertexArrays(1, vao);

        float l = 1.0f;
        QVector2D LD(-l, -l); // left-down
        QVector2D LU(-l, +l); // left-up
        QVector2D RD(+l, -l); // right-down
        QVector2D RU(+l, +l); // right-up

        QVector<QVector2D> vertices =  LD, RD, LU, LU, RD, RU ;

        QVector<QVector2D> texcoords;

        for (auto v : vertices)
        
            texcoords += (v + QVector2D(l, l)) / (2.0f * l);
        

        // bind vao
        glBindVertexArray(*vao);
        // vertices
        GLuint vbo;
        glGenBuffers(1, &vbo);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(QVector2D), &(vertices[0]), GL_STATIC_DRAW);
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(QVector2D), static_cast<void*>(nullptr));
        glEnableVertexAttribArray(0);
        // texcoords
        GLuint tbo;
        glGenBuffers(1, &tbo);
        glBindBuffer(GL_ARRAY_BUFFER, tbo);
        glBufferData(GL_ARRAY_BUFFER, texcoords.size()*sizeof(QVector2D), &(texcoords[0]), GL_STATIC_DRAW);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(QVector2D), static_cast<void*>(nullptr));
        glEnableVertexAttribArray(1);
        // unbind buffer object
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        // unbind vao
        glBindVertexArray(0);
    

    GLuint program = programs[BLOOM];
    glUseProgram(program);

    glUniform1i(glGetUniformLocation(program, "scene"), 0);
    glUniform1i(glGetUniformLocation(program, "bloom"), 1);

    glUniform1i(glGetUniformLocation(program, "effect"), true);

    glBindVertexArray(*vao);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textures[0]);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, textures[1]);

    glDrawArrays(GL_TRIANGLES, 0, 6);
    glBindVertexArray(0);

立方体片段着色器

#version 450 core

layout (location = 0) out vec4 pixel;
layout (location = 1) out vec4 bloom;

struct Material

    // material properties
;

uniform Material material;

struct Light

    // light properties
;

uniform Light[5] lights;

uniform vec3 eye;

in FragData

    vec3 position;
    vec3 normal;
 data;

vec3 point(Light light, vec3 position, vec3 normal, vec3 eye)

    // lighting computation


void main()

    vec3 color = vec3(0.0f);

    for (int i = 0; i < 5; i++)
    
        color += point(lights[i], data.position, data.normal, eye);
    

    pixel = vec4(color, 1.0f);

    vec3 weights = vec3(0.2126f, 0.7152f, 0.0722f);
    float brightness = dot(pixel.rgb, weights);

    if (brightness > 1.0f)
    
        bloom = vec4(pixel.rgb, 1.0f);
    
    else
    
        bloom = vec4(vec3(0.0f), 1.0f);
    

光标记片段着色器

#version 450 core

layout (location = 0) out vec4 pixel;
layout (location = 1) out vec4 bloom;

struct Light

    // light properties
;

uniform Light light;

void main()

    pixel = vec4(light.diffuse, 1.0f);

    vec3 weights = vec3(0.2126f, 0.7152f, 0.0722f);
    float brightness = dot(pixel.rgb, weights);

    if (brightness > 1.0f)
    
        bloom = vec4(light.diffuse, 1.0f);
    
    else
    
        bloom = vec4(vec3(0.0f), 1.0f);
    

最终顶点着色器

#version 450 core

layout (location = 0) in vec2 position;
layout (location = 1) in vec2 texcoord;

out FragData

    vec2 texcoord;
 data;

void main()

    data.texcoord = texcoord;
    gl_Position = vec4(position, 0.0f, 1.0f);

最终片段着色器

#version 450 core

in FragData

    vec2 texcoord;
 data;

out vec4 pixel;

uniform sampler2D scene;
uniform sampler2D bloom;

uniform bool effect;

void main()

    vec3 hdr = texture(scene, data.texcoord).rgb;

    if (effect)
    
        hdr += texture(bloom, data.texcoord).rgb;
    

    // tone mapping
    float exposure = 1.0f;
    pixel = vec4(vec3(1.0f) - exp(-hdr * exposure), 1.0f);
    // gamma correction
    float gamma = 2.2f;
    pixel = vec4(pow(pixel.rgb, vec3(1.0 / gamma)), 1.0f);

目前,我还没有实现模糊以获得绽放效果,但我只是从渲染场景中提取了两张图像并将它们添加在一起。

我哪里做错了? 非常感谢您的帮助!

【问题讨论】:

你不应该在 Qt OpenGL 小部件中使用glBindFramebuffer(GL_FRAMEBUFFER, 0);,因为 Qt 可能在你背后使用 FBO。有QOpenGLContext::defaultFramebufferObject @derhass 非常感谢您的回答!使用defaultFramebufferObject() 而不是0 返回的值似乎可以解决问题。我会完成练习,如果我有任何其他问题,请告诉您。再次感谢! 好的,因为我的有根据的猜测确实解决了这个问题,所以我重新发布它作为真正的答案。 【参考方案1】:

你不应该使用

glBindFramebuffer(GL_FRAMEBUFFER, 0);

因为 Qt 可能在背后使用 FBO 而不是 GL 的默认帧缓冲区。您可以使用QOpenGLContext::defaultFramebufferObject 查询Qt 用作默认帧缓冲区的FBO 名称,它可能是也可能不是0

【讨论】:

以上是关于OpenGL Qt:使用帧缓冲区实现绽放效果的问题的主要内容,如果未能解决你的问题,请参考以下文章

如何定义 QT Opengl 帧缓冲区的大小

Qt OpenGL帧缓冲区到图像

OpenGL学习脚印: 帧缓冲对象(Frame Buffer Object)

Qt中的OpengL glDrawBuffers()?

如何将图像后处理着色器的结果添加到场景中

◮OpenGL-帧缓冲