创建帧缓冲
unsigned int fbo; glGenFramebuffers(1, &fbo);
|
绑定帧缓冲
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
此时绑定的fbo能读能写,长相十分英俊
我们也可以单独设置读取的fbo和写入的fbo
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
|
帧缓冲需要满足的条件
通过执行上面的步骤,我们可以创建一个fbo,但是还不能使用它,因为一个完整的帧缓冲需要满足以下条件:
- 附加至少一个缓冲(颜色,深度,模板)
- 至少有一个Attachment(颜色附件)
- 所有附件都必须是完整的(有内存)
- 每个缓冲应该都有相同的样本数
我们可以使用glCheckFramebufferStatus函数来检查帧缓冲的状态,如果状态为GL_FRAMEBUFFER_COMPLETE,则说明帧缓冲满足条件,可以用了.
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status == GL_FRAMEBUFFER_COMPLETE) { }
|
附加缓冲
附加的缓冲有两种类型:
- 材质
- 渲染缓冲
附加材质
unsigned int texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); 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, texture, 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);
|
检查帧缓冲状态
我们可以使用glCheckFramebufferStatus函数来检查帧缓冲的状态,如果状态为GL_FRAMEBUFFER_COMPLETE,则说明帧缓冲满足条件,可以用了.
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { std::cout << "Framebuffer not complete!" << std::endl; throw std::runtime_error("Framebuffer not complete!"); } glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
利用帧缓冲实现后处理
步骤:
- 将渲染结果写入帧缓冲
- 绑定默认帧缓冲
- 将帧缓冲中的材质提出输入到片段着色器中
- 在片段着色器中实现后处理
那么首先我们需要创建一个四边形.
float quadVertices[] = { -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f }; unsigned int quadVAO, quadVBO; glGenVertexArrays(1, &quadVAO); glGenBuffers(1, &quadVBO); glBindVertexArray(quadVAO); glBindBuffer(GL_ARRAY_BUFFER, quadVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
|
我们为其编写最简单的Shader,实现一个反相操作.
#version 330 core layout (location = 0) in vec2 aPos; layout (location = 1) in vec2 aTexCoords;
out vec2 TexCoords;
void main() { gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); TexCoords = aTexCoords; }
|
#version 330 core out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D screenTexture;
void main() { FragColor = vec4(vec3(1.0 - texture(screenTexture, TexCoords)), 1.0); }
|
接下来更改我们的渲染循环
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); model.Draw(); glBindFramebuffer(GL_FRAMEBUFFER, 0); glClearColor(1.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture); screenShader.Use(); unsigned short textureLoc = glGetUniformLocation(screenShader.shaderProgramID, "screenTexture"); glUniform1i(textureLoc, GL_TEXTURE0); glBindVertexArray(quadVAO); glDisable(GL_DEPTH_TEST); glDrawArrays(GL_TRIANGLES, 0, 6);
glfwSwapBuffers(window); glfwPollEvents();
|
这样就可以得到反相的效果了.
