携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第17天,点击查看活动详情 >>
激活阴影
想要激活并使用阴影,就得先在渲染器 renderer 的 .shadowMap.enabled 属性中设置开启,允许在场景中使用阴影贴图。
renderer.shadowMap.enabled = true;
检查每个对象,确定它是否可以使用castshadow投射阴影,以及是否可以使用receiveshadow接收阴影。
现在我们的场景里有一个球体和一块平面,光源有环境光 AmbientLight 和平行光 DirectionalLight。
场景中存在一球体与一平面。
// 创建球体
const sphere = new THREE.Mesh(
new THREE.SphereBufferGeometry(0.5, 32, 32),
material
);
// 为sphere开启投射阴影
sphere.castShadow = true;
// 创建一平面
const plane = new THREE.Mesh(
new THREE.PlaneBufferGeometry(5, 5),
material
);
plane.rotation.x = -Math.PI * 0.5;
plane.position.y = -0.5;
// plane接收投射阴影
plane.receiveShadow = true;
scene.add(sphere, plane);
注意:只有平行光、点光源和聚光灯支持阴影
平行光阴影
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.3);
// 改变光的方向
directionalLight.position.set(2, 2, -1);
// 使用castShadow激活directionalLight灯光上的阴影
directionalLight.castShadow = true;
此时,平行光下的阴影还是比较模糊,不够清晰,我们可以设置贴图尺寸为2的n次幂,我们会发现当数值越高,阴影就拥有月清晰的细节,数值越低,阴影就越模糊。
directionalLight.shadow.mapSize.width = 1024;
directionalLight.shadow.mapSize.height = 1024;
directionalLight.shadow.camera.top = 2;
directionalLight.shadow.camera.right = 2;
directionalLight.shadow.camera.bottom = -2;
directionalLight.shadow.camera.left = -2;
directionalLight.shadow.camera.near = 1;
// 灯光相机的可视范围越小,阴影越精确,当然如果设置得实在太小,阴影将会被裁剪掉
directionalLight.shadow.camera.far = 6;
// 我们可以通过radius属性控制阴影模糊程度,它不会改变灯光相机与物体的距离
directionalLight.shadow.radius = 10;
// 用于模拟相机视锥体的辅助对象:CameraHelper
const directionalLightCameraHelper = new THREE.CameraHelper(
// 参数为:被模拟的相机
directionalLight.shadow.camera
);
directionalLightCameraHelper.visible = false;
scene.add(directionalLightCameraHelper);
此时效果为:
阴影贴图
有不同类型的算法可以应用于阴影贴图:
| 种类 | 特点 |
|---|---|
| THREE.BasicShadowMap | 性能非常好但是质量很差 |
| THREE.PCFShadowMap | 性能较差但边缘更平滑(默认) |
| THREE.PCFSoftShadowMap | 性能较差但边缘更柔和 |
| THREE.VSMShadowMap | 性能差,约束多,但能够产生意想不到的效果 |
PCF柔软阴影贴图
注意点:renderer.shadowMap 的 type 为 PCFSoftShadowMap 时,shadow.radius 不生效,阴影不存在模糊程度。
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
此时效果为下图所示:
关于聚光灯阴影和点光源阴影,我们下一篇再来讨论(≖ᴗ≖)✧