Three.js-硬要自学系列22 (聚光源、平行光阴影计算、阴影范围、阴影属性)

178 阅读4分钟

本章主要学习知识点

  • 了解聚光源概念
  • 了解什么是平行光阴影计算
  • 学习使用关于阴影的一些常用属性

聚光源SpotLight

聚光源(SpotLight)可以理解为「虚拟手电筒」,它能产生类似舞台聚光灯的锥形光束效果。

聚光源具有以下特性

  • 方向性
    聚光灯有明确的照射方向,通过设置 target 属性控制光束指向(如让光线聚焦到某个物体上)
  • 锥形光区
    光线呈圆锥形扩散,可通过 angle 参数调节光锥角度(默认约60度),角度越大,覆盖范围越广
  • 衰减效果
    光线强度随距离衰减,通过 distance(最大照射距离)和 exponent(衰减速度)参数控制。例如,exponent 值越大,光束边缘越锐利

查看效果

创建一个球体

const geometry = new THREE.SphereGeometry(1, 32, 32);
// 添加高光材质
const material = new THREE.MeshPhongMaterial({ color: 'deepskyblue' });
cube = new THREE.Mesh(geometry, material);
scene.add(cube);

创建聚光源

const spotLight = new THREE.SpotLight(0xffffff, 1);
// 设置聚光灯的位置
spotLight.position.set(4, 4, 4);
// 设置聚光灯的角度
spotLight.angle = Math.PI / 6;
// 设置聚光灯的半影
spotLight.penumbra = 0.05;
// 设置聚光灯的衰减
spotLight.decay = 0;

scene.add(spotLight);

这里创建了个一个白色的聚光灯,并设置了一些相关参数,为了方便我们调整聚光灯,three.js 提供了SpotLightHelper辅助器

const spotLightHelper = new THREE.SpotLightHelper(spotLight, '#fff')   
spotLight.target.position.set(0, 0, 0); // 设置聚光灯的目标位置
scene.add(spotLight.target);
scene.add(spotLightHelper)

image.png

适用场景

  • 舞台灯光:聚焦照亮角色或道具
  • 车灯/手电筒:第一人称视角的移动光源
  • 建筑可视化:模拟射灯对建筑立面的照明效果
  • 恐怖游戏:狭窄光束营造紧张氛围

平行光阴影计算

平行光阴影你可以想象自己拿着一张白纸(投影面)和一个手电筒(平行光),当物体挡住光线时,白纸上会留下影子。

搭建一个平面,其上方有一个球体

// 创建一个平面
const planeGeometry = new THREE.PlaneGeometry( 8,8 );
const planeMaterial = new THREE.MeshStandardMaterial( {color: '#737373', roughness: 0.7} );
const plane = new THREE.Mesh( planeGeometry, planeMaterial );
plane.rotation.x = -Math.PI / 2;
// 设置接收阴影
plane.receiveShadow = true;
scene.add( plane );

// 添加球体
const sphereGeometry = new THREE.SphereGeometry( 0.5, 32, 32 );
const sphereMaterial = new THREE.MeshStandardMaterial( {color: 'deeppink'} );
const sphere = new THREE.Mesh( sphereGeometry, sphereMaterial );
sphere.position.set(1,1,1)
sphere.castShadow = true;  // 设置投射阴影
scene.add( sphere );

这里创建了一个平面,设置平面的receiveShadow是为了接收阴影,我们为球体添加sphere.castShadow = true开启了允许投射阴影

DirectionalLight是用来创建平行光,同样需要设置其castShadowtrue才能投射阴影

const directionalLight = new THREE.DirectionalLight(0xffffff,1)
directionalLight.castShadow = true;
// 光源位置
directionalLight.position.set(5,5,5)
scene.add(directionalLight)

453.gif

需要注意的是,要在整个场景中呈现阴影,需要在渲染器中开启,是否允许阴影

renderer.shadowMap.enabled = true; // 开启阴影

阴影范围

影范围可以理解为「虚拟探照灯的有效照射区域」,只有这个区域内的物体会参与阴影计算。

想象我们在夜晚用手电筒照射地面,阴影范围由以下因素决定:

  • 手电筒的照射角度和距离(对应光源的 shadow.camera 参数)
  • 灯光强度(阴影贴图分辨率 shadow.mapSize 影响清晰度)
  • 遮挡物的位置(物体必须在光源和投影面之间)

为了更好的观察光源阴影,three.js提供了CameraHelper辅助器, 我们来添加一个平行光

const light = new THREE.DirectionalLight( 0xffffff, 1 );
light.position.set( 5, 5, 5 );
light.castShadow = true; // 开启阴影
// 设置阴影相机的左边界
light.shadow.camera.left = -5;
// 设置阴影相机的右边界
light.shadow.camera.right = 5;
// 设置阴影相机的上边界
light.shadow.camera.top = 5;
// 设置阴影相机的下边界
light.shadow.camera.bottom = -5;
light.shadow.camera.far = 200;
scene.add( light );

const lightHelper = new THREE.CameraHelper(light.shadow.camera)
scene.add(lightHelper)

image.png

控制阴影范围的四大参数

  • 长方体视景体 通过 shadow.camera 的6个参数定义阴影计算区域,只有在此长方体范围内的物体才会产生阴影
light.shadow.camera.left = -100; // 左边界
light.shadow.camera.right = 100; // 右边界
light.shadow.camera.top = 100; // 上边界 
light.shadow.camera.bottom = -100; // 下边界 
light.shadow.camera.near = 0.1; // 近裁面 
light.shadow.camera.far = 1000; // 远裁面
  • 分辨率与清晰度 阴影贴图(类似一张黑白纹理)的分辨率决定清晰度,分辨率越高,锯齿越少,但同时性能消耗也大
light.shadow.mapSize.width = 2048; // 宽度像素 
light.shadow.mapSize.height = 2048; // 高度像素
  • 光源位置与方向 平行光的位置和照射方向影响阴影投射范围
light.position.set(100, 100, 100); // 光源位置 
light.target.position.set(0, 0, 0); // 照射目标点
  • 动态适配场景 通过包围盒自动计算场景物体的边界,动态调整阴影范围
const box = new THREE.Box3().expandByObject(scene); // 计算场景包围盒 
light.shadow.camera.left = box.min.x;
light.shadow.camera.right = box.max.x;

阴影属性radius

阴影的 radius 属性主要用于控制阴影边缘的模糊效果

看一个例子

64.gif

const light = new THREE.DirectionalLight( 0xffffff, 1 );
light.position.set( 15, 15, 15 );
light.castShadow = true; // 开启阴影
light.shadow.mapSize.width = 2048; // 阴影mapSize
light.shadow.mapSize.height = 2048; // 阴影mapSize
light.shadow.radius = 5; // 阴影radius

你可以通过修改radius的值来观察阴影的变化

以上案例均可在案例中心查看体验

THREE 案例中心

image.png