跳到主要内容

体积雾

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。环境项仍贡献光照,但单独环境项不会激活效果。

外观​

设置默认值作用
density0.01基准高度及其以下的雾密度。
heightBase0密度开始衰减的世界高度。
heightFalloff0.05基准高度以上的指数衰减,0 为均匀密度。
tint白色雾散射介质的颜色。
extinction1相对散射的吸收。较低值让远雾和光束更亮,但物理准确性降低。
anisotropy0.6前向散射,0–0.95。越高则朝向光源观察时雾越亮。
intensity1平行光散射强度。
localIntensity1点光源和聚光灯散射强度。
ambientColor白色雾散射的环境光颜色。
ambientIntensity0.02让阴影中雾保持可见的环境贡献。

质量与性能​

设置默认值权衡
steps24主射线步进采样数,4–128。越多质量越好,开销越高。
localSteps12各局部灯光体积内的采样数,2–64。详细光束可增加。
scale0.5雾纹理相对场景目标的分辨率,0.25–1。降低可减少像素工作量。
maxDistance300步进覆盖的最大世界距离,应限制到可见雾范围。

先用默认半分辨率和 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 平滑雾。已有项目缺少这些属性时,更新脚本资源并重新解析。

示例​

体积雾
体积雾局部灯光
体积雾光束