体积雾
CameraFrame.volumetricFog 渲染受场景灯光照亮的高度雾。平行光产生大气雾霭和太阳光束,点光源与聚光灯产生发亮体积和光锥。效果沿视线采样阴影,让对象阻挡雾中的光。
配置
使用透视相机。将平行光组件赋给 volumetricFog.light,或启用局部点光源、聚光灯。没有任一来源时效果不活动。将非平行光赋给 light 会禁用效果;点光源和聚光灯应使用局部灯光设置。
下例假定 cameraEntity 具有相机组件,sunEntity 具有平行光组件:
const cameraFrame = new pc.CameraFrame(app, cameraEntity.camera);
cameraFrame.rendering.toneMapping = pc.TONEMAP_NEUTRAL;
cameraFrame.taa.enabled = true;
sunEntity.light.castShadows = true;
cameraFrame.volumetricFog.enabled = true;
cameraFrame.volumetricFog.light = sunEntity.light;
cameraFrame.volumetricFog.density = 0.01;
cameraFrame.volumetricFog.heightBase = 0;
cameraFrame.volumetricFog.heightFalloff = 0.05;
cameraFrame.update();
按场景世界单位选择高度和密度。要看到光束,在光源与雾之间放置投影几何体,并调整阴影距离和分辨率覆盖目标区域。雾在 TAA 之前合成,因此 TAA 可跨帧平滑步进噪声。设置变化后调用 cameraFrame.update()。
点光源与聚光灯
局部灯光要求默认启用的簇光照。启用所需类型:
cameraFrame.volumetricFog.localSpotLights = true;
cameraFrame.volumetricFog.localOmniLights = true;
cameraFrame.volumetricFog.localIntensity = 1;
cameraFrame.volumetricFog.localSteps = 12;
cameraFrame.update();
// Adjust one spot light's contribution independently of its surface lighting.
spotEntity.light.volumetricScattering = 2;
LightComponent.volumetricScattering 默认 1,作用于点光源和聚光灯。设为 0 可排除该灯。localIntensity 缩放所有局部散射,intensity 控制平行光。窄光束只与视线短暂相交,可能需要更高 localIntensity。
局部灯光采样簇光照阴影与 cookie 图集。启用灯光投影让几何体阻挡光束,用 cookie 塑造光形。阴影图集分辨率影响光束细节。
仅局部灯光的场景中,保留 light 为 null,启用 localSpotLights 或 localOmniLights。环境项仍贡献光照,但单独环境项不会激活效果。
外观
| 设置 | 默认值 | 作用 |
|---|---|---|
density | 0.01 | 基准高度及其以下的雾密度。 |
heightBase | 0 | 密度开始衰减的世界高度。 |
heightFalloff | 0.05 | 基准高度以上的指数衰减,0 为均匀密度。 |
tint | 白色 | 雾散射介质的颜色。 |
extinction | 1 | 相对散射的吸收。较低值让远雾和光束更亮,但物理准确性降低。 |
anisotropy | 0.6 | 前向散射,0–0.95。越高则朝向光源观察时雾越亮。 |
intensity | 1 | 平行光散射强度。 |
localIntensity | 1 | 点光源和聚光灯散射强度。 |
ambientColor | 白色 | 雾散射的环境光颜色。 |
ambientIntensity | 0.02 | 让阴影中雾保持可见的环境贡献。 |
质量与性能
| 设置 | 默认值 | 权衡 |
|---|---|---|
steps | 24 | 主射线步进采样数,4–128。越多质量越好,开销越高。 |
localSteps | 12 | 各局部灯光体积内的采样数,2–64。详细光束可增加。 |
scale | 0.5 | 雾纹理相对场景目标的分辨率,0.25–1。降低可减少像素工作量。 |
maxDistance | 300 | 步进覆盖的最大世界距离,应限制到可见雾范围。 |
先用默认半分辨率和 TAA,仅在噪声或条带仍明显时增加采样。maxDistance 越长,相同样本分布越稀,长射线可能需要更多步。
局部灯光开销随参与数量、屏幕覆盖和 localSteps 增长。点光源填满球体,通常比聚光灯覆盖更多屏幕。应缩紧范围,对不需照雾的灯禁用散射。
高斯泼溅
雾和景深需要高斯泼溅贡献场景深度,才能遵循其表面。由于额外占用全屏目标,此功能默认禁用。通过 GSplatParams.sceneDepthWrite 启用:
if (pc.CameraFrame.isSplatSceneDepthSupported(app.graphicsDevice)) {
app.scene.gsplat.sceneDepthWrite = true;
cameraFrame.rendering.samples = 1;
cameraFrame.update();
}
CameraFrame.isSplatSceneDepthSupported 只检查设备支持,不检查完整相机配置。还要求:
- CameraFrame 不使用 MSAA,即
rendering.samples = 1,仍可用 TAA。 - 相机清除整个渲染目标。
- 没有为场景内深度采样要求的深度预通道。特别是
rendering.sceneDepthMap = true和ssao.type = pc.SSAOTYPE_LIGHTING会阻止此路径;同时需要 SSAO 时用pc.SSAOTYPE_COMBINE。
不支持的配置回退为不含高斯泼溅的深度,调试构建会在无法生成请求深度时警告。若场景依赖它,不可用时应禁用雾和景深,或提供合适深度几何体。通过深度调试视图检查。
部分设备使用较低精度场景深度。为保留准确性,相机裁剪距离应约在 0.000015 到 16384 世界单位之间。
编辑器中使用
添加并解析 camera-frame.mjs,将注册的 cameraFrame 脚本附加到相机实体,参见编辑器中的 CameraFrame。
启用 Volumetric Fog(体积雾)组。其 Light 字段接收平行光实体,而引擎 API 接收灯光组件。启用 Local Spot Lights 或 Local Omni Lights 添加局部照明,使用上述外观和质量参数。启用 TAA 平滑雾。已有项目缺少这些属性时,更新脚本资源并重新解析。