打开 Godot 4 的渲染器选择下拉框,前两个选项(Forward+、Mobile)是 RD 家族的,第三个 Compatibility 是个异类:它完全不经过 RenderingDevice。display/rendering/drive 选 opengl3 后,整条渲染栈走的是 drivers/gles3/ 下一套自 3.x 延续下来的光栅器——RasterizerStorageGLES3、RasterizerCanvasGLES3、RasterizerSceneGLES3。要理解这个渲染器,得先回答一个问题:都 4.x 了,为什么还养一套不走红 abstraction 的老代码?
为什么 Compatibility 不走 RD
RD 的设计底线是 Vulkan 1.0 级别的能力:显式屏障、subpass、compute、storage buffer。GLES3 有其中一部分(3.1 有 compute),但 WebGL2——Compatibility 必须覆盖的目标——没有 storage image、没有 SSBO 的原生等价物(WebGL2 只有 UBO),更没有显式 barrier 概念。也就是说RD 的抽象面在 GLES3/WebGL2 上无法无损映射,强套抽象的结果是每个调用点塞 if-else 降级,抽象层退化成装饰。
Godot 的选择是诚实的:WebGL2 设备就不配走现代抽象,给它们一条直通驱动的老路。代价是要维护两套渲染器代码(RD 系 + GLES3 系),servers/rendering/renderer_rd/ 和 drivers/gles3/ 各自演进;收益是 Godot 4 保住了 Godot 3 的全部设备面——尤其是浏览器。对引擎团队这是理性的账:Web 游戏的性能上限本来就低,渲染器新旧不重要,能跑才重要。
代码血统与结构
drivers/gles3/rasterizer_gles3.cpp 是入口,初始化顺序和 RD 系对称:创建上下文、初始化 storage/canvas/scene 三个子光栅器、注册到 RenderingServer。功能对照:
| RD 系 | GLES3 系 |
|---|---|
servers/rendering/renderer_rd/storage_rd/ |
drivers/gles3/storage/(mesh/material/texture) |
servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp |
drivers/gles3/rasterizer_canvas_gles3.cpp |
forward_clustered/render_forward_clustered.cpp |
drivers/gles3/rasterizer_scene_gles3.cpp |
scene 那栏能看出量级差异:Forward+ 的主渲染器是一万多行的文件加十几个 effect 模块,GLES3 的 scene 光栅器把所有前向光照塞在一个大文件里——不是 4.x 写得偷懒,是 GLES3 路径本来就没有那么多 pass 可拆。
静默降级清单
Compatibility 的文档(doc/classes/RenderingServer.xml 和各版本迁移指南)列了明确的降级项,实战中容易"静默"踩到的有这些:
- 全局光照归零:SDFGI、VoxelGI 运行时全部不可用,烘焙的 LightmapGI 是唯一的 GI 来源,GIProbe 老工程迁移过来直接没效果。
- 光源数硬上限:GLES3 路径用 uniform 数组传灯参数,WebGL2 的 UBO 上限(普遍 16KB~64KB)卡死了灯数,超出部分不是丢灯是不渲染。
- shader 语言能力收缩:
hint_screen_texture类屏幕采样在 WebGL2 上有副本限制;部分内建函数(如某些 textureLod 组合)在 ANGLE 转译层上行为不一致。 - MSAA 受限:WebGL2 的 multisample renderbuffer 不普遍支持解析到纹理,引擎按能力检测降级。
- compute 不存在:粒子 GPU 模拟、cluster 构建全部回退 CPU 版(粒子回 CPU 模拟是 Compatibility 掉帧的头号原因)。
"静默"的意思是:项目设置里这些选项照样能勾,勾了不报错,只是没有效果——编辑器预览用 Compatibility 跑的时候一切正常,导出到 Web 才发现 GI 没了。防御办法只有一个:开发期就用目标渲染器跑,项目设置里和 RD 系绑定的选项(SDFGI 相关、volumetric fog 相关)在 Compatibility 下视为无效。
ANGLE 这个中间层
Windows 和 Web 上的 Compatibility 实际不直接对 GLES3 驱动,而是经过 ANGLE(Chrome 的同源项目):Windows 上 ANGLE 把 GLES3 翻译成 D3D11,macOS 上翻译成 Metal,浏览器里各家 WebGL 实现自己就是翻译层。这意味着 Compatibility 的 bug 面是两层翻译的复合——同样一个 shader,在原生 GLES3 驱动上正常,过 ANGLE 转 D3D 可能因为 varying 打包规则差异挂掉。Godot 的 CI 对 Web 导出跑的是 Chromium headless,恰好也是 ANGLE 路径,所以这类问题大多在合入前被拦住,但冷门组合(Firefox + 老核显)仍偶有漏网。
定位一图流
实操结论
Compatibility 的正确用法是作为目标而不是过渡:如果你的发行目标里有 Web 或十年前的核显,第一天就切 Compatibility 开发,shader、光照、GI 全部按它的能力面设计,把"降级"从风险清单里划掉。反过来,如果你的目标只有桌面和当代手机,别让兼容性焦虑把你按在 GLES3 上——RD 系的两个渲染器才是 Godot 4 的主航道,Compatibility 三年内的演进明显慢于 RD 系,这是观察资源分配就能看出来的事实。
本文基于 Godot 4.x 源码:drivers/gles3/rasterizer_gles3.cpp 及同目录光栅器家族、servers/rendering/renderer_rd/ 对照;能力降级以 doc/classes/RenderingServer.xml 与官方 Web 导出文档为准。