跳到主要内容
3D Playground
Three.js 核心第 4 / 13 节

灯光与阴影

进阶WebGL

五种光源

  • AmbientLight(环境光):各处等量照亮,没有方向,也不产生阴影。只用它,物体会显得扁平。
  • HemisphereLight(半球光):上方是天空色、下方是地面色,按法线朝向混合。非常便宜的户外补光。
  • DirectionalLight(平行光):光线互相平行,模拟太阳。只有方向有意义(从 position 指向 target)。
  • PointLight(点光源):从一点向四周发光,像灯泡。distance 与 decay 控制衰减。
  • SpotLight(聚光灯):一个锥形光束,angle 是锥角,penumbra 是边缘的柔和程度。

每种光都有对应的 Helper(DirectionalLightHelper、PointLightHelper、SpotLightHelper)把位置和方向画出来,调试时非常有用。

阴影需要三处开关

阴影默认关闭,因为它要额外渲染场景。需要:

  1. renderer.shadowMap.enabled = true
  2. 光源 light.castShadow = true
  3. 物体 mesh.castShadow = true(投射)和 mesh.receiveShadow = true(接收)

阴影贴图的原理

渲染器先从光源的视角渲染一张深度图(shadow map),再在正常渲染时比较:像素离光源比深度图里记录的更远,就说明被挡住了。这台“光源相机”就是 light.shadow.camera:

  • 平行光用正交阴影相机,要把 left/right/top/bottom 设得刚好包住场景,太大精度会浪费、太小阴影会被截断。打开 “show sun shadow camera” 就能看见它。
  • 聚光灯用透视阴影相机;点光源要渲染 6 个方向(立方体贴图),最贵。

shadow.mapSize 越大越清晰,代价是显存和带宽。shadow.bias 用来消除“阴影痤疮”(表面出现条纹自阴影)。

柔和的阴影

shadowMap.type 可选 Basic(硬边、最快)、PCF(多次采样过滤)和 VSM。r186 起 PCFSoftShadowMap 已被废弃并自动回退到 PCF;现在用 PCFShadowMap 加 light.shadow.radius 就能得到柔和的边缘。

把 sun mapSize 调到 256,观察阴影边缘的锯齿;再提高 blur radius 看看它如何被柔化。

核心 API

THREE.AmbientLightTHREE.HemisphereLightTHREE.DirectionalLightTHREE.PointLightTHREE.SpotLightrenderer.shadowMaplight.shadow.cameralight.shadow.mapSizeTHREE.PCFShadowMapTHREE.CameraHelperTHREE.SpotLightHelper

动手试试

  1. 1把太阳阴影相机的 left/right/top/bottom 都改成 ±3,打开 shadow camera 辅助线,看看哪些阴影被截掉了。
  2. 2把 sun.shadow.bias 设为 0,靠近观察物体表面是否出现条纹(阴影痤疮)。
  3. 3关掉除 Spot 以外的所有灯,调整 angle 和 penumbra,做一个舞台追光效果。
  4. 4把 shadowType 切到 Basic,对比 PCF 的边缘和帧率。
运行中