HDRFBO = new QOpenGLFramebufferObject(size(),QOpenGLFramebufferObject::CombinedDepthStencil,GL_TEXTURE,GL_RGBA16F);
HDRFBO->addColorAttachment(size(),GL_RGBA16F);
core = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
core->glDrawBuffers(2, buffers);
HDRFBO->release();
使用QOpenGLFunctions_3_3_Core
调用glDrawBuffers
显式告知OpenGL渲染到多个颜色缓冲。
补充:
QOpenGLFunctions 是OpenGL ES 2.0 API,所以只有部分接口可用。
The QOpenGLFunctions class provides cross-platform access to the OpenGL ES 2.0 API. More…
在官方文档中可以看到ES中没有glDrawBuffers。
//输出
layout (location = 0) out vec4 FragColor;
layout (location = 1) out vec4 BrightColor;
//检查该像素亮度是否高于阈值
float brightness = dot(FragColor.rgb, vec3(0.2126, 0.7152, 0.0722));
if(brightness > 1.0) BrightColor = vec4(FragColor.rgb, 1.0);
HDRFBO->release();
//HDR输出
glViewport(0,0,width(),height());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
BloomShader->bind();//shader
BloomShader->setUniformValue("RenderResult",0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,HDRFBO->textures().at(HDRNUM));
renderQuad();
BloomShader->release();
提取高光效果并没有想象中的好,按照直觉,应该只提取发光物的高光效果,但是环境中也出现了大量提取点。
且,若背对光源(发光面不可见,但发光物体可见),则不会出现泛光现象,与想象中不同。
高斯函数的这两个性质都给我们提供了优化的空间。
uniform sampler2D image;
out vec4 FragmentColor;
uniform float offset[5] = float[](0.0, 1.0, 2.0, 3.0, 4.0);
uniform float weight[5] = float[](0.2270270270, 0.1945945946, 0.1216216216,
0.0540540541, 0.0162162162);
void main(void) {
FragmentColor = texture2D(image, vec2(gl_FragCoord) / 1024.0) * weight[0];
for (int i=1; i<5; i++) {
FragmentColor +=
texture2D(image, (vec2(gl_FragCoord) + vec2(0.0, offset[i])) / 1024.0)
* weight[i];
FragmentColor +=
texture2D(image, (vec2(gl_FragCoord) - vec2(0.0, offset[i])) / 1024.0)
* weight[i];
}
}
引用GPU硬件加速,使用GPU双线性滤波器优化
uniform sampler2D image;
out vec4 FragmentColor;
uniform float offset[3] = float[](0.0, 1.3846153846, 3.2307692308);
uniform float weight[3] = float[](0.2270270270, 0.3162162162, 0.0702702703);
void main(void) {
FragmentColor = texture2D(image, vec2(gl_FragCoord) / 1024.0) * weight[0];
for (int i=1; i<3; i++) {
FragmentColor +=
texture2D(image, (vec2(gl_FragCoord) + vec2(0.0, offset[i])) / 1024.0)
* weight[i];
FragmentColor +=
texture2D(image, (vec2(gl_FragCoord) - vec2(0.0, offset[i])) / 1024.0)
* weight[i];
}
}
垂直过滤一次:红色色块的颜色为上下5个色块颜色的加权和
使用LearnOpenGL
代码
#version 450 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D image;
uniform bool horizontal;
uniform float weight[5] = float[] (0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);
void main()
{
vec2 tex_offset = 1.0 / textureSize(image, 0); // gets size of single texel
vec3 result = texture(image, TexCoords).rgb * weight[0]; // current fragment's contribution
if(horizontal)
{
for(int i = 1; i < 5; ++i)
{
result += texture(image, TexCoords + vec2(tex_offset.x * i, 0.0)).rgb * weight[i];
result += texture(image, TexCoords - vec2(tex_offset.x * i, 0.0)).rgb * weight[i];
}
}
else
{
for(int i = 1; i < 5; ++i)
{
result += texture(image, TexCoords + vec2(0.0, tex_offset.y * i)).rgb * weight[i];
result += texture(image, TexCoords - vec2(0.0, tex_offset.y * i)).rgb * weight[i];
}
}
FragColor = vec4(result, 1.0);
}
//高斯模糊缓冲
GBHorizontal = new QOpenGLFramebufferObject(size(),QOpenGLFramebufferObject::NoAttachment,GL_TEXTURE_2D,GL_RGBA16F);
GBVertical = new QOpenGLFramebufferObject(size(),QOpenGLFramebufferObject::NoAttachment,GL_TEXTURE_2D,GL_RGBA16F);
注意再resizeGL中也要设置。
//高斯模糊
GLboolean horizontal = true, first_iteration = true;
GLuint amount = 10;
GaussianBlurShader->bind();
for (GLuint i = 0; i < amount; i++)
{
if(horizontal)GBHorizontal->bind();
else GBVertical->bind();
//glClear(GL_COLOR_BUFFER_BIT);
GaussianBlurShader->setUniformValue("horizontal",horizontal);
GaussianBlurShader->setUniformValue("image",0);
glActiveTexture(GL_TEXTURE0);
unsigned int id = 0;
if(first_iteration){
id = HDRFBO->textures().at(1);
}
else{
if(horizontal)id = GBVertical->texture();
else id = GBHorizontal->texture();
}
glBindTexture(GL_TEXTURE_2D, id);
renderQuad();
horizontal = !horizontal;
if (first_iteration)
first_iteration = false;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
模糊前
模糊后
有了场景的HDR纹理和模糊处理的亮区纹理,我们只需把它们结合起来就能实现泛光或称光晕效果了。最终的像素着色器(大部分和HDR教程用的差不多)要把两个纹理混合:
最简单的混合(直接相加)
#version 450 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D RenderResult;
uniform sampler2D bloomBlur;
void main()
{
vec3 hdrColor = texture(RenderResult, TexCoords).rgb;
vec3 bloomColor = texture(bloomBlur, TexCoords).rgb;
if(addBloom) hdrColor += bloomColor;
FragColor = vec4(hdrColor , 1.0f);
}
头顶光源出现泛光现象
但除了光源其他物体也有泛光现象(这不合理)。
应该修改为只有光源才出现泛光现象
待更新…