携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第18天,点击查看活动详情 >>
今天我们来讨论聚光灯阴影与点光源阴影,以及烘焙阴影。
聚光灯阴影
创建聚光灯
// Spot Light
const spotLight = new THREE.SpotLight(0xffffff, 0.3, 10, Math.PI * 0.3);
spotLight.castShadow = true;
spotLight.position.set(0, 2, 2);
scene.add(spotLight);
// 如果要使聚光灯看向某处记得把target添加场景中
scene.add(spotLight.target);
创建相机助手
const spotLightCameraHelper = new THREE.CameraHelper(
spotLight.shadow.camera
);
scene.add(spotLightCameraHelper);
优化聚光灯阴影
因为它是聚光灯,使用的是透视相机PerspectiveCamera,所以可以通过fov属性改变摄像机视锥体垂直视野角度
spotLight.shadow.mapSize.width = 1024;
spotLight.shadow.mapSize.height = 1024;
spotLight.shadow.camera.fov = 30;
spotLight.shadow.camera.near = 1;
spotLight.shadow.camera.far = 6;
下图中,我们可以看到聚光灯的阴影,以及聚光灯相机助手:
点光源阴影
创建点光源
// Point light
const poingtLight = new THREE.PointLight(0xffffff, 0.3);
poingtLight.castShadow = true;
poingtLight.position.set(-1, 1, 0);
scene.add(poingtLight);
创建相机助手
const poingtLightHelper = new THREE.CameraHelper(
poingtLight.shadow.camera
);
// poingtLightHelper.visible = false;
scene.add(poingtLightHelper);
优化点光源阴影
点光源摄像机使用的也是透视相机,但最好不要去改变它的视锥体垂直视野角度fov属性
poingtLight.shadow.mapSize.width = 1024;
poingtLight.shadow.mapSize.height = 1024;
poingtLight.shadow.camera.near = 0.1;
poingtLight.shadow.camera.far = 5;
下图中,我们可以看到点光源的阴影,以及点光源相机助手:
烘焙阴影
烘培阴影是Three.js阴影的一个很好的替代品。我们可以将阴影集成到纹理中,并将其应用到材质上。 我们先关闭渲染器的阴影贴图渲染,这样就看不到场景中的阴影了。
renderer.shadowMap.enabled = false;
设置平面 plane 的材质纹理为烘焙阴影贴图:
const textureLoader = new THREE.TextureLoader();
const backedShadow = textureLoader.load("./img/bakedShadow.jpg");
const plane = new THREE.Mesh(
new THREE.PlaneBufferGeometry(5, 5),
new THREE.MeshBasicMaterial({ map: backedShadow })
);
这种情况只适合于静态物体,当物体运动起来,阴影并不会跟随物体移动。
备选方案
我们可以使用更简单的烘焙阴影贴图并移动它,使其一直保持在球体下方。
const simpleShadow = textureLoader.load("./img/simpleShadow.jpg");
创建一个略高于地板的平面,将它的材质的 alphaMap 属性设置为简单阴影纹理贴图:
const sphereShadow = new THREE.Mesh(
new THREE.PlaneBufferGeometry(1.5, 1.5),
new THREE.MeshBasicMaterial({
color: 0x000000,
transparent: true,
alphaMap: simpleShadow,
})
);
sphereShadow.rotation.x = -Math.PI * 0.5;
sphereShadow.position.y = plane.position.y + 0.01;
scene.add(sphereShadow);
给球体 sphere 添加动画:
// Update the sphere
// 圆周运动
sphere.position.x = Math.cos(elapsedTime) * 1.5;
sphere.position.z = Math.sin(elapsedTime) * 1.5;
// 触底弹跳
sphere.position.y = Math.abs(Math.sin(elapsedTime * 3));
更新平面 sphereShadow 的位置:
// Update the shadow
sphereShadow.position.x = sphere.position.x;
sphereShadow.position.z = sphere.position.z;
sphereShadow.material.opacity = (1 - sphere.position.y) * 0.5;
最终效果: