阴影
阴影让场景对象具有落地感,传达深度和空间关系,同时增强真实感和视觉品质。
PlayCanvas 通过阴影映射技术渲染实时动态阴影。所有灯光类型都支持,且适用于从桌面到移动端的所有平台。本页介绍如何启用阴影、选择投射和接收对象、选择阴影类型及调整质量。
启用阴影
PlayCanvas 默认禁用灯光投射阴影,需要显式启用。先确定哪些灯光应投影,每盏灯都提供 Cast Shadows(投射阴影)选项。再选择哪些图形对象投射和接收阴影:渲染与模型组件默认都投射并接收,可逐实体切换。Gsplat 组件也能投射阴影,但不能接收,且默认禁用投影。
- 引擎
- 编辑器
- React
- Web Components
// Enable shadow casting on a light
entity.light.castShadows = true;
// Mesh entities cast & receive shadows by default (render or model component);
// toggle per entity as needed
meshEntity.render.castShadows = true;
meshEntity.render.receiveShadows = true;
// Gsplat entities can cast shadows too (off by default)
splatEntity.gsplat.castShadows = true;
在层级面板中选择灯光,在灯光组件启用 Cast Shadows。
要控制参与的对象,选中实体,在渲染或模型组件中切换 Cast Shadows / Receive Shadows(接收阴影),或在 gsplat 组件上启用 Cast Shadows。
// Enable shadow casting on a light
<Entity name="light">
<Light type="directional" castShadows />
</Entity>
// Render components cast & receive shadows by default; toggle as needed
<Entity>
<Render type="box" castShadows receiveShadows />
</Entity>
// GSplat components can cast shadows too (off by default)
<Entity>
<GSplat asset={splat} castShadows />
</Entity>
<!-- Enable shadow casting on a light -->
<pc-entity>
<pc-light type="directional" cast-shadows></pc-light>
</pc-entity>
<!-- Render components cast & receive shadows by default; toggle as needed -->
<pc-entity>
<pc-render type="box" cast-shadows receive-shadows></pc-render>
</pc-entity>
<!-- Gsplat components can cast shadows too (off by default) -->
<pc-entity>
<pc-gsplat asset="my-splat" cast-shadows></pc-gsplat>
</pc-entity>
阴影类型
阴影滤波技术按灯光选择,在边缘柔和度、质量和性能之间权衡。PlayCanvas 提供三种技术:
PCF(百分比渐近滤波)
阴影从暗到亮的柔和过渡区域称为半影。默认的 PCF 在阴影贴图局部读取多个样本并求平均,以固定程度柔化边缘。

滤波核尺寸决定权衡:1×1 边缘最硬,3×3 为默认,5×5 最柔和。更大的核采样更多纹素,GPU 开销也更高。
将阴影类型设为某个 PCF 变体:
- 引擎
- 编辑器
- React
- Web Components
// SHADOW_PCF1_32F | SHADOW_PCF3_32F (default) | SHADOW_PCF5_32F
entity.light.shadowType = SHADOW_PCF5_32F;
在灯光组件中,将 Shadow Type(阴影类型)设为 Shadow Map PCF 1x1、3x3 或 5x5。
import { SHADOW_PCF5_32F } from 'playcanvas';
<Entity name="light">
<Light type="directional" castShadows shadowType={SHADOW_PCF5_32F} />
</Entity>
<!-- shadow-type: pcf1-32f | pcf3-32f | pcf5-32f -->
<pc-entity>
<pc-light type="directional" cast-shadows shadow-type="pcf5-32f"></pc-light>
</pc-entity>
VSM(方差阴影贴图)
方差阴影贴图存储可预先模糊的深度统计信息,产生平滑软边,适合平行光阴影等大范围区域。提供 16 位和更高精度的 32 位变体,某些场景中可能产生漏光伪影。
VSM 仅适用于平行光和非簇光照的聚光灯。
将阴影类型设为 VSM 并调整:
- 引擎
- 编辑器
- React
- Web Components
entity.light.shadowType = SHADOW_VSM_16F;
// Optional tuning
entity.light.vsmBlurSize = 11; // blur kernel size, 1-25
entity.light.vsmBlurMode = BLUR_GAUSSIAN; // or BLUR_BOX (cheaper)
entity.light.vsmBias = 0.0025; // reduces shadow acne, 0-1
在灯光组件中,将 Shadow Type 设为 Variance Shadow Map (16bit) 或 (32bit),随后会显示 VSM Blur Mode(模糊模式)和 VSM Blur Size(模糊尺寸)。
import { SHADOW_VSM_16F, BLUR_GAUSSIAN } from 'playcanvas';
<Entity name="light">
<Light type="directional" castShadows shadowType={SHADOW_VSM_16F}
vsmBlurSize={11} vsmBlurMode={BLUR_GAUSSIAN} vsmBias={0.0025} />
</Entity>
<!-- vsm-blur-mode is not currently exposed as an attribute -->
<pc-entity>
<pc-light type="directional" cast-shadows shadow-type="vsm-16f"
vsm-blur-size="11" vsm-bias="0.0025"></pc-light>
</pc-entity>
PCSS(百分比渐近软阴影)
PCF 的软边宽度固定。真实阴影在两个对象接触处清晰,投射者离接收表面越远就越柔和。PCSS 根据两者距离改变半影宽度,重现这种接触硬化行为。

PCSS 仅适用于平行光。
PCSS 还要求设备支持向浮点纹理渲染并进行线性滤波。现代桌面 GPU 普遍支持,但并非所有设备都支持,特别是旧款或低端移动设备。不支持时灯光自动回退到 PCF,因此可以安全启用。
将阴影类型设为 PCSS 并细调:
- 引擎
- 编辑器
- React
- Web Components
entity.light.shadowType = SHADOW_PCSS_32F;
// Optional fine-tuning
entity.light.penumbraSize = 2; // overall penumbra size (softness)
entity.light.penumbraFalloff = 1; // how fast softness grows with distance, >= 1
entity.light.shadowSamples = 16; // filter samples; higher = smoother, costlier
entity.light.shadowBlockerSamples = 16; // 0 disables contact hardening
在层级面板选中灯光,在灯光组件中将 Shadow Type 设为 PCSS (Soft Shadows),随后显示 Penumbra Size(半影大小)和 Penumbra Falloff(半影衰减)。采样次数目前未暴露在编辑器 UI 中,需通过脚本设置。
import { SHADOW_PCSS_32F } from 'playcanvas';
<Entity name="light">
<Light type="directional" castShadows shadowType={SHADOW_PCSS_32F}
penumbraSize={2} penumbraFalloff={1} shadowSamples={16} shadowBlockerSamples={16} />
</Entity>
<pc-entity>
<pc-light type="directional" cast-shadows shadow-type="pcss-32f"
penumbra-size="2" penumbra-falloff="1" shadow-samples="16" shadow-blocker-samples="16"></pc-light>
</pc-entity>
调整阴影
PlayCanvas 的阴影映射只有有限分辨率,因此可能需要调整参数以改善外观。以下属性均可通过编辑器灯光组件界面或代码(entity.light.*)设置。
阴影分辨率
每盏灯通过阴影贴图投影。分辨率(light.shadowResolution)范围为 16x16 到 4096x4096,也可在组件界面设置。分辨率越高,阴影越清晰,但渲染更昂贵,应平衡性能和质量。
阴影距离
阴影距离(light.shadowDistance)表示从视点起、平行光阴影不再渲染的距离。值越小,阴影越清晰;但视点移动时,读者可能看到阴影突然出现。应根据玩家可见距离和实际观感权衡。
阴影级联
平行光阴影覆盖大范围时,经常出现近相机阴影分辨率不足的锯齿。若只用一张贴图改善,需要不切实际的高分辨率。
阴影级联沿视线方向划分相机视锥体,每段使用独立阴影贴图。近处对象使用一张,远处使用另一张,还可在中间增加贴图。
级联数量影响性能,因为每个投射阴影的网格可能需要渲染到多张贴图。
级联数(light.numCascades)表示视锥体分段数,可为 1、2、3 或 4。默认 1 表示单张阴影贴图。
单个阴影级联的截图:

四个阴影级联的截图:

light.cascadeDistribution 控制各级联对相机视锥体的划分分布,取值 0 到 1。0 为线性分布,1 为对数分布。视觉上,较高值将更多分辨率分配到前景,较低值分配到更远对象。
阴影边界
默认平行光为各相机视图拟合阴影贴图,将分辨率分配到相机前方的阴影距离内。如果仅在小部分场景需要阴影,例如烘焙光照场景中的角色周围,可改设阴影边界(light.shadowBounds):这是包围投射者的世界空间包围盒。灯光按自身视角将单张贴图拟合到边界,让所有分辨率集中到需要阴影处。贴图为所有相机只渲染一次,阴影不受相机距离限制。
// shadows of the casters in a 10 x 4 x 10 area around the origin
entity.light.shadowBounds = new BoundingBox(new Vec3(0, 2, 0), new Vec3(5, 2, 5));
边界只需包含投射者,无需包含接收者。阴影沿灯光方向延伸,因此沿该方向位于边界之后的接收者,例如角色下方地面,仍接收边界内对象的阴影。灯光与边界之间的投射者也会投影。从灯光看位于边界侧面,或沿光方向位于边界之后的投射者则不会。
灯光保存边界副本,因此更改时需修改包围盒后重新赋值。例如要保持移动角色阴影清晰,每帧随角色移动边界:
const bounds = new BoundingBox(new Vec3(), new Vec3(1, 1.5, 1));
app.on('update', () => {
bounds.center.copy(character.getPosition());
entity.light.shadowBounds = bounds;
});
设置边界期间,灯光不使用 numCascades、shadowDistance、cascadeBlend 和 cascadeDistribution。将边界设为 null 可恢复按相机拟合。阴影按 light.shadowUpdateMode 更新,边界变化时也会重新渲染,因此 SHADOWUPDATE_NONE 下静态投射者的阴影只渲染一次,之后仅在边界移动时更新。
阴影边界仅适用于平行光,支持所有阴影类型。编辑器没有对应设置,需通过脚本设置。
引擎的阴影边界示例比较按边界拟合与按相机拟合的效果:
阴影强度
阴影强度(light.shadowIntensity)为 1 时表示完整强度,为 0 时表示没有阴影。

修复阴影伪影
阴影映射容易产生难看的渲染伪影,以下属性有助于消除它们。
阴影偏移
若不该出现阴影的地方有条带或斑点,可调整阴影偏移(light.shadowBias)解决。
法线偏移
“阴影痤疮”是常见问题,阴影偏移可有效缓解,但通常会引入一定程度的“彼得潘”现象,即阴影让对象看起来悬空。
法线偏移(light.normalOffsetBias)可解决这一问题。除深度偏移外,还对阴影贴图查询所用 UV 做微调,将片元位置沿几何法线偏移,从而同时避免阴影痤疮和阴影脱离。该技术比仅使用固定阴影偏移的结果好得多。
性能注意事项
启用阴影会影响性能: