Skip to content

光源和阴影

聚光源

沿着特定方向会逐渐发散的光源,照射范围在三维空间中构成一个圆锥体光源

js
const spotLight = new THREE.SpotLight(0xffffff, 0.8);
// 设置聚光光源位置
spotLight.position.set(0, 50, 0);
scene.add(spotLight); //光源添加到场景中
spotLight.intensity = 1.0; //修改光照强度

聚光源位置.position

js
spotLight.position.set(0, 50, 0);

聚光源发散角度.angle

js
spotLight.angle = Math.PI / 6; //光锥角度的二分之一

聚光源目标对象.target

js
// spotLight.target 默认是坐标原点
spotLight.target.position.set(50, 0, 0);
scene.add(spotLight.target);

注意

spotLight.target添加到场景中, .target.position 才会起作用

聚光源辅助对象SpotLightHelper

js
// 聚光源辅助对象,可视化聚光源
const spotLightHelper = new THREE.SpotLightHelper(spotLight, 0xffffff);
scene.add(spotLightHelper);

平行光阴影计算

点光源、聚光源、平行光等都可以产生阴影, 需要开启一些配置才会显现

1. 模型阴影投射.castShadow

js
// 设置产生投影的网格模型
mesh.castShadow = true;

2. 光源阴影投射属性.castShadow

光源默认不产生阴影,需要代码开启阴影投射属性

js
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
// 平行光设置产生阴影的光源对象,开启光源阴影的计算功能
directionalLight.castShadow = true;

3. 模型阴影接收属性.receiveShadow

js
// 设置接收阴影的投影面
planeMesh.receiveShadow = true;

4. .shadowMap.enabled 允许渲染器渲染阴影

开启 WebGL 的渲染器的阴影贴图属性

js
// 设置渲染器,允许光源阴影渲染
renderer.shadowMap.enabled = true;

5. 平行光阴影相机属性.shadow.camera(阴影渲染范围)

该属性的属性值是一个正投影相机对象OrthographicCamera

js
// 平行光阴影相机属性
directionalLight.shadow.camera;
  • CameraHelper可视化.shadow.camera
js
// 可视化平行光阴影对应的正投影相机对象
const cameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera);
scene.add(cameraHelper);

阴影

TIP

  • 平行光阴影相机的位置.shadow.camera.position, 默认就是平行光的位置属性 directionalLight.position
  • .shadow.camera属性值是正投影相机OrthographicCamera, 属性配置可以完全参考

阴影.mapSize.radius

这两个属性主要影响阴影的渲染质量

light.shadow.mapSize阴影贴图尺寸属性

调节阴影边缘不够清晰、模糊感或锯齿感,值越大阴影渲染质量越好

js
// 默认值为 512x512, 尺寸一般2的n次方
directionalLight.shadow.mapSize.set(128, 128);

阴影半径.shadow.radius属性

通过该属性调节阴影边缘非阴影区域渐变过渡, 阴影边缘逐渐弱化或模糊化

js
directionalLight.shadow.radius = 3;

平行光模拟太阳光

1. 平行光辅助对象DirectionalLightHelper

可视化平行光.position 和照射方向

js
// 参数2表示平行光.position附近方框的尺寸
const dirHelper = new THREE.DirectionalLightHelper(directionalLight, 5);
scene.add(dirHelper);

阴影可视化

2. 平行光位置和方向 GUI 可视化控制

  • 添加高度控制

    js
    gui.add(directionalLight.position, "y", 0, 300);
  • 添加绕 Y 轴的旋转控制

    通过三角函数、指定半径还有角度计算出 x、z 坐标

    js
    const obj = { R: 100, angle: 0 };
    //控制旋转半径
    gui.add(obj, "R", 0, 300).onChange(function (value) {
      directionalLight.position.x = value * Math.cos(obj.angle);
      directionalLight.position.z = value * Math.sin(obj.angle);
    });
    //控制旋转角度
    gui.add(obj, "angle", 0, Math.PI * 2).onChange(function (value) {
      directionalLight.position.x = obj.R * Math.cos(value);
      directionalLight.position.z = obj.R * Math.sin(value);
    });

3. 更新平行光辅助对象 DirectionalLightHelper

当平行光位置变化时,执行helper.update()更新平行光辅助对象DirectionalLightHelper的姿态同步变化

js
gui.add(directionalLight.position, "y", 0, 300).onChange(function (value) {
  dirHelper.update();
});
js
gui.add(obj, "R", 0, 300).onChange(function (value) {
  directionalLight.position.x = value * Math.cos(obj.angle);
  directionalLight.position.z = value * Math.sin(obj.angle);
  dirHelper.update();
});
gui.add(obj, "angle", 0, Math.PI * 2).onChange(function (value) {
  directionalLight.position.x = obj.R * Math.cos(value);
  directionalLight.position.z = obj.R * Math.sin(value);
  dirHelper.update();
});

模拟太阳光阴影

1. 允许光源和渲染器光源投影计算

js
directionalLight.castShadow = true;
renderer.shadowMap.enabled = true;

2. 设置模型产生和接收阴影

所有模型既可以产生阴影, 也能够接收阴影, 给外部 gltf 模型批量配置

js
//递归遍历场景,允许所有Mesh产生投影、接收投影
gltf.scene.traverse(function (obj) {
  if (obj.isMesh) {
    // 批量设置所有Mesh都可以产生阴影和接收阴影
    obj.castShadow = true;
    obj.receiveShadow = true;
  }
});

3. 调节阴影范围

通过 CameraHelper 辅助调试参数, 让平行光源覆盖要产生阴影的外部模型区域

js
//设置三维场景 directionalLight.shadow.camera 计算阴影的范围
//...
// 可视化平行光阴影对应的正投影相机对象
const cameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera);
scene.add(cameraHelper);

4. 阴影条纹问题解决.shadowMap.type

js
// 模型表面产生条纹影响渲染效果,可以改变.shadowMap.type默认值优化
renderer.shadowMap.type = THREE.VSMShadowMap;

5. 优化阴影效果

js
// 如果阴影边缘锯齿感的时候,可以适当提升像素
directionalLight.shadow.mapSize.set(1024, 1024);
// 模糊弱化阴影边缘
directionalLight.shadow.radius = 3;

gui 辅助调节光源阴影

js
// 阴影子菜单
const shadowFolder = gui.addFolder("平行光阴影");
const cam = directionalLight.shadow.camera;
js
// 相机left、right等属性变化执行.updateProjectionMatrix();
// 相机变化了,执行CameraHelper的更新方法.update();
shadowFolder.add(cam, "right", 0, 500).onChange(function (v) {
  cam.updateProjectionMatrix();
  cameraHelper.update();
});
shadowFolder.add(cam, "far", 0, 1000).onChange(function (v) {
  cam.updateProjectionMatrix();
  cameraHelper.update();
});
//...

注意

directionalLight.shadow.camera 参数改变后,注意执行 cameraHelper.update();