WebGL不支持多光源自动处理,需在着色器中手动实现;主流优化方案包括分块剔除(Tiled Forward)、延迟渲染、光源预烘焙与IBL,辅以合理衰减和裁剪设置。

WebGL 本身不提供“多光源自动处理”机制,所有光源计算都得靠你写在着色器里的逻辑完成。核心难点在于:光源越多,每个像素的计算越重;直接在片元着色器里遍历全部光源(比如 50 个点光),性能会断崖式下降。所以实际做法不是“怎么加更多光源”,而是“怎么让每个像素只算它真正受影响的那几个光源”。
用分块剔除(Tiled Forward)减少每像素光源数量
这是目前最实用、兼容性最好的方案,Three.js 官方示例 webgl_tiled_forward 就是典型实现:
- 把屏幕划分为固定大小的 tile(如 16×16 像素一块)
- 在 CPU 或 compute shader 阶段,对每个 tile 预先计算哪些光源的光照范围覆盖了它
- 片元着色器里只遍历该 tile 对应的光源列表,跳过其余几十个
- 不需要额外 GBuffer,兼容所有 WebGL 2.0 设备,适合中高复杂度场景(几十个光源)
用延迟渲染(Deferred Rendering)解耦几何与光照
当光源数量上百、且多数为点光或聚光灯时,延迟渲染更高效:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 第一阶段:用自定义 ShaderMaterial 渲染场景到 GBuffer —— 把世界位置、法线、颜色、粗糙度等存进多个纹理(WebGLRenderTarget)
- 第二阶段:用全屏四边形 + 光照 Shader,从 GBuffer 采样数据,统一计算所有光源贡献
- 光照复杂度从 O(像素数 × 光源数) 降到 O(像素数 + 光源数),但需支持 MRT 和深度纹理
- Three.js 中需手动管理 render target、切换帧缓冲、编写两套着色器(GBuffer 输出 + 光照合成)
用光源预烘焙或 IBL 替代实时计算
并非所有光源都必须实时更新。对静态场景,可大幅减负:
立即学习“Java免费学习笔记(深入)”;
- 环境光 + 间接光用基于图像的光照(IBL):加载 HDR 环境贴图,用 prefiltered irradiance + specular BRDF LUT 实现 PBR 效果
- 静态物体上的主光源阴影可烘焙进 lightmap(用 MeshStandardMaterial 的
lightMap属性) - 动态光源只保留关键的 3–5 个(如角色手持灯、UI 聚光),其余由 IBL 和 lightmap 补足
注意光源衰减与裁剪边界
即使用了上述方法,不合理设置仍会导致性能浪费:
- 点光源和聚光灯必须设
distance(衰减距离),避免无效影响远处像素 - 聚光灯要设
angle和penumbra,缩小锥形范围 - 所有光源启用
castShadow = true时,确保 shadowMap 尺寸合理(如 1024×1024),并限制阴影投射对象数量 - 用
frustumCulled = false配合自定义 culling 逻辑,避免光源被相机视锥体错误剔除

















