WebGL后期处理需通过帧缓冲(FBO)将场景渲染到纹理,再以该纹理为输入执行全屏着色器;具体流程包括创建绑定FBO、配置纹理附件、两阶段渲染(离屏绘制+全屏quad采样),并注意完整性检查与尺寸兼容性。

WebGL 中实现后期处理,核心是把画面先“画到一张纹理上”,再用这张纹理作为输入,跑一次全屏的着色器——这个“画到纹理上”的过程,就靠帧缓冲(Framebuffer)完成。直接渲染到屏幕没法做后期,因为片元着色器输出后就结束了,没机会再读取整张图。
创建并绑定自定义帧缓冲
先调用 gl.createFramebuffer() 创建一个帧缓冲对象,再用 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo) 切换渲染目标。此后所有 gl.drawArrays() 或 gl.drawElements() 都会写入这个 FBO,而不是屏幕。
- 必须在绑定后检查完整性:
gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE - 不完整常见原因:纹理尺寸为 0、附件格式不被支持、缺少颜色附件(比如没 attach 纹理)、深度附件未正确配置等
- 切换回屏幕渲染只需调用
gl.bindFramebuffer(gl.FRAMEBUFFER, null)
准备目标纹理作为颜色附件
帧缓冲本身不存像素,它需要一个纹理(或渲染缓冲区)来承载颜色数据。通常用纹理,因为后续要传给后期着色器采样。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 用
gl.createTexture()创建纹理,gl.bindTexture(gl.TEXTURE_2D, texture)绑定 - 调用
gl.texImage2D()分配存储空间(注意 width/height 必须明确,不能为 0) - 设置合适的纹理参数,如
gl.TEXTURE_WRAP_S/T和gl.TEXTURE_MIN_FILTER - 用
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0)把纹理挂到 FBO 上
两阶段渲染流程
后期处理本质是两个渲染阶段:第一阶段画场景到纹理,第二阶段用该纹理画全屏四边形并执行滤镜逻辑。
立即学习“Java免费学习笔记(深入)”;
- 第一阶段:绑定 FBO → 清屏(
gl.clear())→ 渲染场景 → 解绑 FBO - 第二阶段:绑定默认帧缓冲(
null)→ 激活并绑定刚才生成的纹理 → 渲染一个覆盖整个视口的矩形(常称“全屏 quad”)→ 片元着色器中对纹理采样并应用效果(如模糊、灰度、色调偏移等) - 关键点:全屏 quad 的顶点坐标通常是
[-1,-1], [1,-1], [1,1], [-1,1],配合正交投影,确保覆盖整个画布
常见注意事项
有些细节容易出错,但影响很大:
-
preserveDrawingBuffer: true不是必需的,也不推荐用于后期处理流程;它只是防止屏幕被清空,和离屏渲染无关 - FBO 的纹理尺寸最好为 2 的整数次幂(尤其在旧设备上),否则可能不支持某些格式
- 如果后期需要深度信息(如景深),需额外 attach 一个深度渲染缓冲区(
gl.RENDERBUFFER)并启用gl.DEPTH_TEST - 多级后期(如先模糊再发光)可链式使用多个 FBO,前一级输出作后一级输入

















