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:使用帧缓冲区实现绽放效果的问题的主要内容,如果未能解决你的问题,请参考以下文章