8.5 阴影
明暗是相对的,阴影的形成也就是因为比周围获得的光照更少。因此,要形成阴影,光源必不可少。
在Three.js中,能形成阴影的光源只有THREE.DirectionalLight
与THREE.SpotLight
;而相对地,能表现阴影效果的材质只有THREE.LambertMaterial
与THREE.PhongMaterial
。因而在设置光源和材质的时候,一定要注意这一点。
下面,我们以聚光灯为例,在例8.4.1的基础上增加阴影效果。
首先,我们需要在初始化时,告诉渲染器渲染阴影:
renderer.shadowMapEnabled = true;
然后,对于光源以及所有要产生阴影的物体调用:
xxx.castShadow = true;
对于接收阴影的物体调用:
xxx.receiveShadow = true;
比如场景中一个平面上有一个正方体,想要让聚光灯照射在正方体上,产生的阴影投射在平面上,那么就需要对聚光灯和正方体调用castShadow = true
,对于平面调用receiveShadow = true
。
以上就是产生阴影效果的必要步骤了,不过通常还需要设置光源的阴影相关属性,才能正确显示出阴影效果。
对于聚光灯,需要设置shadowCameraNear
、shadowCameraFar
、shadowCameraFov
三个值,类比我们在第二章学到的透视投影照相机,只有介于shadowCameraNear
与shadowCameraFar
之间的物体将产生阴影,shadowCameraFov
表示张角。
对于平行光,需要设置shadowCameraNear
、shadowCameraFar
、shadowCameraLeft
、shadowCameraRight
、shadowCameraTop
以及shadowCameraBottom
六个值,相当于正交投影照相机的六个面。同样,只有在这六个面围成的长方体内的物体才会产生阴影效果。
为了看到阴影照相机的位置,通常可以在调试时开启light.shadowCameraVisible = true
。
至此,阴影效果已经能正常显示了:
如果想要修改阴影的深浅,可以通过设置shadowDarkness
,该值的范围是0
到1
,越小越浅。
另外,这里实现阴影效果的方法是Shadow Mapping,即阴影是作为渲染前计算好的贴图贴上去的,因而会受到贴图像素大小的限制。所以可以通过设置shadowMapWidth
与shadowMapHeight
值控制贴图的大小,来改变阴影的精确度。
而如果想实现软阴影的效果,可以通过renderer.shadowMapSoft = true;
方便地实现。
设置阴影完整的代码是:
renderer = new THREE.WebGLRenderer();
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;
var plane = new THREE.Mesh(new THREE.PlaneGeometry(8, 8, 16, 16),
new THREE.MeshLambertMaterial({color: 0xcccccc}));
plane.rotation.x = -Math.PI / 2;
plane.position.y = -1;
plane.receiveShadow = true;
scene.add(plane);
cube = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1),
new THREE.MeshLambertMaterial({color: 0x00ff00}));
cube.position.x = 2;
cube.castShadow = true;
scene.add(cube);
var light = new THREE.SpotLight(0xffff00, 1, 100, Math.PI / 6, 25);
light.position.set(2, 5, 3);
light.target = cube;
light.castShadow = true;
light.shadowCameraNear = 2;
light.shadowCameraFar = 10;
light.shadowCameraFov = 30;
light.shadowCameraVisible = true;
light.shadowMapWidth = 1024;
light.shadowMapHeight = 1024;
light.shadowDarkness = 0.3;
scene.add(light);