OpenGL Qt: проблема с использованием кадровых буферов для эффекта цветения - PullRequest
0 голосов
/ 09 декабря 2018

Я следую этому учебнику по эффекту цветения.

Я работаю с Qt , и сцена, которую я пытаюсь визуализировать, состоит изпять кубов и пять источников света расположены случайным образом, что-то вроде этоготолько цвет фона).

Это соответствующие части кода.

метод initializeGL :

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);
}

В данный момент я еще не реализовал размытие, чтобы получить эффект цветения, но я просто извлек два изображения из отрисованной сцены и добавил их вместе.

Где я делаю не так?Большое спасибо за вашу помощь!

1 Ответ

0 голосов
/ 09 декабря 2018

Вы не должны использовать

glBindFramebuffer(GL_FRAMEBUFFER, 0);

, поскольку Qt может использовать FBO вместо кадрового буфера GL по умолчанию за вашей спиной.Вы можете использовать QOpenGLContext::defaultFramebufferObject для запроса имени FBO, которое используется Qt как кадровый буфер по умолчанию, которое может быть или не быть 0.

...