FBO后处理必须显式切换渲染目标、确保附件完整、并在后续Pass中作为纹理采样,漏掉任一环节都会黑屏或无效果;需正确调用glBindFramebuffer、glViewport、glFramebufferTexture2D、glCheckFramebufferStatus及全屏四边形采样。

FBO 不是“加个缓冲就能后处理”,而是必须显式切换渲染目标、确保附件完整、并在后续 Pass 中作为纹理采样——漏掉任一环节都会黑屏或无效果。
glBindFramebuffer 之后必须调用 glViewport
离屏渲染的目标尺寸通常和窗口不同(比如后处理常用半分辨率),但 glViewport 默认继承上一次设置。如果只绑了 FBO 却没重设视口,渲染会写入错误区域,轻则画面错位,重则被裁剪为全黑。
- 每次
glBindFramebuffer(GL_FRAMEBUFFER, fbo)后,立即调用glViewport(0, 0, width, height),其中width和height必须与附件纹理/渲染缓冲的尺寸一致 - 切回默认帧缓冲时(
glBindFramebuffer(GL_FRAMEBUFFER, 0)),也需重设为窗口尺寸,否则全屏四边形可能拉伸或偏移 - 不要依赖初始化时的
glViewport值——FBO 渲染阶段和屏幕显示阶段是两个独立视口上下文
颜色附件必须用 glFramebufferTexture2D 绑定,不能只 glGenTextures
只生成纹理 ID 并调用 glTexImage2D 不等于它已接入渲染管线。FBO 需要明确将纹理“挂载”到某个颜色附着点,否则 glCheckFramebufferStatus 返回 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,且后续绘制静默失败。
- 绑定前确保纹理已启用:调用
glBindTexture(GL_TEXTURE_2D, texture),再设过滤和包裹参数 - 必须使用
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0)—— 注意第 2 个参数是附着点枚举,不是纹理目标 - 若需多渲染目标(MRT),可依次绑定
GL_COLOR_ATTACHMENT1、GL_COLOR_ATTACHMENT2等,但需用glDrawBuffers显式声明哪些附着点有效
深度附件不配 RBO 或纹理,后处理会丢失深度测试
很多教程只配颜色附件就跑通了简单三角形,但一旦场景含重叠物体或启用了 glEnable(GL_DEPTH_TEST),没有深度附件会导致片元被错误丢弃,表现为模型穿帮、Z-fighting 或部分消失。
立即学习“C++免费学习笔记(深入)”;
- 优先选
GL_RENDERBUFFER:用glRenderbufferStorage分配GL_DEPTH_COMPONENT24或GL_DEPTH32F,写入快、不占纹理单元 - 若需在后期 Pass 中读取深度(如景深模糊),必须用纹理附件:
glTexImage2D(..., GL_DEPTH_COMPONENT, ...)+glFramebufferTexture2D(..., GL_DEPTH_ATTACHMENT, ...) - 模板附件同理;但若完全不用模板测试,就别挂
GL_STENCIL_ATTACHMENT,避免GL_FRAMEBUFFER_UNSUPPORTED
后处理 Pass 必须用全屏四边形 + 纹理采样,不能直接 drawArrays 场景
离屏渲染结果存在纹理里,不是“自动变成屏幕内容”。后处理本质是另一个渲染 Pass:把那张纹理当输入,用全屏四边形(two-triangle quad)覆盖整个视口,由片元着色器做计算。
- 顶点着色器只需输出标准化设备坐标(NDC)位置,如
vec4(aPos.x, aPos.y, 0.0, 1.0) - 片元着色器中声明
uniform sampler2D screenTexture,用texture(screenTexture, TexCoords)采样离屏结果 - 务必在后处理 Pass 前绑定该纹理:
glActiveTexture(GL_TEXTURE0)→glBindTexture(GL_TEXTURE_2D, texture) - 切记解绑 FBO 后再开始后处理:若仍处于
glBindFramebuffer(GL_FRAMEBUFFER, fbo)状态,所有绘制会继续写进离屏缓冲,而非屏幕
最容易被忽略的是附件完整性检查和状态切换顺序:每次创建/修改 FBO 后都应调用 glCheckFramebufferStatus,返回值不是 GL_FRAMEBUFFER_COMPLETE 就别往下走;而 glBindFramebuffer 和 glViewport 的配对、以及纹理绑定时机,稍有错位就会让整条链路中断——它不像普通绘图函数那样容错,而是沉默地失效。


















