概述:
阅读完本文,你将学会如何使用 Threejs 平行光源创建阴影以及如何避免阴影渲染过程中的一些坑;
基本原理:
Threejs 阴影的渲染有三个关键的条件:
- Render 对象开启阴影渲染能力;
- 光源或阴影原物体开启阴影投射;
- 显示阴影的物体开启阴影接收;
渲染过程关键代码:
根据上面的原理,以下代码片段演示在实际 threejs 开发中如何进行配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| const renderer: THREE.WebGLRenderer = new THREE.WebGLRenderer({ antialias: true, }) renderer.shadowMap.enabled = true renderer.shadowMap.type = THREE.VSMShadowMap
const light = new THREE.DirectionalLight(0xffffff, item.intensity) const helper = new THREE.DirectionalLightHelper(light, 5) light.position.set(10, 10, 10)
light.castShadow = true light.shadow.bias = -0.00005 light.shadow.camera.left = -5 * 10 light.shadow.camera.right = 5 * 10 light.shadow.camera.top = 5 * 10 light.shadow.camera.bottom = -5 * 10 light.shadow.mapSize.width = 2048 light.shadow.mapSize.height = 2048
const cubeGeometry = new THREE.BoxGeometry(2, 2, 2) const cubeMaterial = new THREE.MeshLambertMaterial() const cube = new THREE.Mesh(cubeGeometry, cubeMaterial) cube.castShadow = true cube.position.set(2, 2, 2)
const planeGeometry = new THREE.PlaneGeometry(20, 20, 32, 32) const plane = new THREE.Mesh(planeGeometry, new THREE.MeshLambertMaterial()) ground.rotation.set(-Math.PI / 2, 0, 0) ground.receiveShadow = true
|
要点及坑点总结:
1.渲染模型的阴影需要同时开启阴影投射和阴影接收,这是因为复杂的模型在光源下可能会接收到自身产生的阴影
1 2
| mesh.castShadow = true mesh.receiveShadow = true
|
2.需要确保平行光的阴影相机的投射范围覆盖需要产生阴影的范围
如果没有覆盖,就会出现这种只产生一小块阴影的情况:
正确覆盖:
3.材质的金属度为 1 会导致模型无法漫反射,呈现为纯黑色,这一特性会导致渲染某些材质异常的模型时,模型为纯黑色无法被环境光照亮
这种情况下需要降低模型的 metalness,比如设置为 0.5
1 2 3 4 5 6 7 8 9 10
| const reflectBallGeometry = new THREE.SphereGeometry(1, 32, 32) const reflectBallMaterial = new THREE.MeshStandardMaterial({ roughness: 0.0, metalness: 1, }) const reflectBall = new THREE.Mesh(reflectBallGeometry, reflectBallMaterial) reflectBall.position.set(3, 3, 3) reflectBall.castShadow = true this.scene.add(reflectBall)
|
镜面球体没有环境贴图时为纯黑:
4.未产生阴影的地方出现条纹,需要设置 bias 参数,具体原理我也不清楚,感兴趣可自行查阅研究:
未设置 bias:
设置了 bias 为很小的数:
light.shadow.bias = -0.00001
5.设置 mapSize 的宽高可以提高阴影质量
1 2
| light.shadow.mapSize.width = 2048 light.shadow.mapSize.height = 2048
|