本节摘要:帧缓冲对象(FBO)是输出端的路由器——把渲染结果从默认屏幕帧缓冲改道到你自己指定的附件(纹理或渲染缓冲)。本节解剖 FBO 的结构与完整性检查,走完「渲染到纹理」的完整搭建案例,讲清纹理附件与渲染缓冲附件的选型、多渲染目标(MRT)一次绘制写多张图的机制,并把后处理、影子贴图、拾取三大应用串成同一闭环的三个出口。离屏渲染是第 5 章后处理与阴影的直接地基。
到目前为止,所有绘制都流向「默认帧缓冲」——那个由窗口系统管理的、直接上屏的缓冲。但很多任务天然需要渲染结果留在 GPU 里供下一步消费:后处理要把整帧场景先存成纹理再滤一遍;影子贴图要从光源视角把深度存下来,正式渲染时采样它;鼠标拾取要把每个物体的编号画进一张「身份证纹理」再读回。这些需求的共同点:渲染的产物不是给人看的,是给下一遍渲染用的。
FBO 的角色因此清晰:它不分配像素存储,它只是一组附件的挂载架。颜色、深度、模板各挂各的附件,附件可以是纹理(后续可采样)或渲染缓冲(纯写入、不可采样但更省)。

目标是经典的「两遍后处理」骨架第一遍。分四步走,每步都有可翻车点:
// 步骤一:造一张当附件的纹理(尺寸等于离屏目标分辨率) GLuint tex; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); // 数据给空:只为分配 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 步骤二:造深度用的渲染缓冲(纯裁判,不采样) GLuint rbo; glGenRenderbuffers(1, &rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h); // 步骤三:组装挂载架 GLuint fbo; glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); // 颜色挂纹理 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // 深度挂渲染缓冲 // 步骤四:体检——差一个附件整架罢工 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) printf("FBO 不完整:检查附件格式与尺寸是否匹配\n");
之后的绘制流程变成「绑定切换」:glBindFramebuffer(GL_FRAMEBUFFER, fbo) 后所有绘制进纹理;绑定编号 0 回默认帧缓冲上屏。一个高频坑:离屏渲染忘了给 FBO 配深度附件,2.4 节的深度测试没缓冲可写,3D 场景前后遮挡全乱、近的远的全叠在一起——症状像「深度测试坏了」,实际是输出端少挂了一个附件。完整性检查就是这道关的守门员,每个 FBO 组装完都该问一遍。
片元着色器的 out 变量可以有多个(2.3 节只用了单个 FragColor),每个 out 对应 FBO 的一个颜色附件——这就是 MRT(多渲染目标)。一次几何绘制,位置写附件0、法线写附件1、材质参数写附件2。它最大的受益者是延迟渲染:第一遍用 MRT 把几何信息打包进「G 缓冲」,第二遍全屏四边形逐像素读 G 缓冲算光照,光照计算量与场景三角形数量解耦(细节属于第 5 章光照选型)。管布局时注意:片元着色器里要显式声明输出绑定的编号(layout(location = N) out),编号与附件挂载序号一致,错位就是「法线图里出现颜色」式的串台事故。
纹理附件与渲染缓冲附件的分界线只有一条:要不要被采样。要采样(后处理、影子、拾取、G 缓冲)用纹理;纯当深度模板裁判用渲染缓冲——驱动对它有更省的布局余地。别为了「以后可能用」全上纹理,附件也要按需供给。
三个出口的应用预告把闭环收拢。后处理(第 5 章第 4 节):第一遍渲场景进纹理,第二遍全屏采样加 bloom、色调映射。影子贴图(第 5 章第 2 节):第一遍从光源视角只写深度,第二遍主渲染时采样这张深度图判断遮挡。拾取(第 7 章工具一节):第一遍把物体编号画成颜色图,读回鼠标位置一个像素判断点中了谁。三个应用共用本节的骨架,只换「第一遍的视角」与「第二遍的采样逻辑」——这就是解剖台二结尾的结论:FBO 把渲染从「画给屏幕」升级成「画给管线自己」,后续章节所有多遍技术都站在这个升级上。
解剖台二收官,管线的物流系统全部打通。下一章钻进管线的两个可编程插槽内部——GLSL 语言本身:类型、限定符、编译链接,以及那套每个图形工程师都要手熟的变换数学。