本章主要学习知识点
- 了解聚光源概念
- 了解什么是平行光阴影计算
- 学习使用关于阴影的一些常用属性
聚光源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)
适用场景
- 舞台灯光:聚焦照亮角色或道具
- 车灯/手电筒:第一人称视角的移动光源
- 建筑可视化:模拟射灯对建筑立面的照明效果
- 恐怖游戏:狭窄光束营造紧张氛围
平行光阴影计算
平行光阴影你可以想象自己拿着一张白纸(投影面)和一个手电筒(平行光),当物体挡住光线时,白纸上会留下影子。
搭建一个平面,其上方有一个球体
// 创建一个平面
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
是用来创建平行光,同样需要设置其castShadow
为true
才能投射阴影
const directionalLight = new THREE.DirectionalLight(0xffffff,1)
directionalLight.castShadow = true;
// 光源位置
directionalLight.position.set(5,5,5)
scene.add(directionalLight)
需要注意的是,要在整个场景中呈现阴影,需要在渲染器中开启,是否允许阴影
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)
控制阴影范围的四大参数
- 长方体视景体
通过
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
属性主要用于控制阴影边缘的模糊效果
看一个例子
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
的值来观察阴影的变化