帧缓冲,显卡渲染出的图像会保存在默认的帧缓冲之中,其包括的附件有颜色、深度、模板缓冲。
我们可以创建自己的帧缓冲。
glGenFramebuffers(1, &this->framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, this->framebuffer);
我们需要为其附加一些附件(如,颜色、深度、模板缓冲)。
对于颜色,我们可能有时需要在渲染后做后期处理,那么就需要获取渲染后的像素值,这种情况下好的选择是使用颜色纹理作为附件。
glGenTextures(1, &texColorBuffer); glBindTexture(GL_TEXTURE_2D, texColorBuffer); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); // 将它附加到当前绑定的帧缓冲对象 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texColorBuffer, 0);
而深度和模板我们不需要获取其值,系统自己做深度和模板测试就行,这时我们对于深度和模板附件使用渲染缓冲对象。
unsigned int rbo; glGenRenderbuffers(1, &rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800, 600); glBindRenderbuffer(GL_RENDERBUFFER, 0); //将渲染缓冲对象附加到帧缓冲的深度和模板附件上 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
检查我们创建的帧缓冲是否完整
//检查帧缓冲是否完整 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl; else std::cout << "Successful:: Framebuffer is complete..." << std::endl;
渲染时,先使用我们创建的帧缓冲,将场景渲染至颜色纹理中。然后将帧缓冲改回屏幕默认的帧缓冲,将纹理直接渲染到屏幕上并在片段着色器中做后期处理。
void SceneRendering::Draw() { // 第一处理阶段(Pass) glBindFramebuffer(GL_FRAMEBUFFER, this->framebuffer); glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 我们现在不使用模板缓冲 glEnable(GL_DEPTH_TEST); this->NormalBlendRendering(); // 第二处理阶段 glBindFramebuffer(GL_FRAMEBUFFER, 0); // 返回默认 glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_DEPTH_TEST); this->shader_quad->use(); glBindTexture(GL_TEXTURE_2D, this->texColorBuffer); quad->Draw(); }
展示几个后期处理的效果:
1、反相,用1 - color
2、灰度,对rgb三个颜色分量加权输出
3、核处理
#version 330 core out vec4 FragColor; in vec2 TexCoords; uniform sampler2D screenTexture; const float offset=1.0f/300.0f; void main() { vec2 offsets[9]=vec2[]( vec2(-offset,offset), // 左上 vec2( 0.0f, offset), // 正上 vec2( offset, offset), // 右上 vec2(-offset, 0.0f), // 左 vec2( 0.0f, 0.0f), // 中 vec2( offset, 0.0f), // 右 vec2(-offset, -offset), // 左下 vec2( 0.0f, -offset), // 正下 vec2( offset, -offset) // 右下 ); float kernel[9]=float[]( 1,1,1, 1,-8,1, 1,1,1 ); vec3 sampleTex[9]; for(int i = 0; i < 9; i++) { sampleTex[i] = vec3(texture(screenTexture, TexCoords.st + offsets[i])); } vec3 col = vec3(0.0); for(int i = 0; i < 9; i++) col += sampleTex[i] * kernel[i]; FragColor = vec4(col, 1.0); }
锐化:
模糊:
边缘检测: