在three.js基础学习之光源的学习中,我们已经学习和知道了如何在three.js中通过构造函数创建光源,并且设置光的颜色和强度。但是,我们在案例中并没有直接使用THREE.Light
进行构造,而是使用THREE.DirectionalLight
。这是因为Light
只是three.js中众多光源中的基类,并不能直接构造光源,构造光源还是需要具体的光源构造函数,比如我们用到的DirectionalLight
。那么,现在就开始学习探索DirectionalLight
,了解它的用法和使用场景。
在正式开始之前,复制three.js基础学习之光源的demo代码并创建一个新的html文件learnThree16.mtml
DirectionalLight
平行光可以发射到无限远,在three.js中用来模拟太阳光。因此,在使用到太阳光的场景中,我们都可以考虑使用它。创建平行光时只需要使用THREE.DirectionalLight
构造器,并传入光照颜色和强度即可。如下:1
2
3
4
5
6
7{
const lightColor = 0xffffff; // 灯光颜色
const intensity = 1; // 灯光强度
const light = new THREE.DirectionalLight(lightColor, intensity);
light.position.set(10,10,20);
scene.add(light);
}
这样,我一使用DirectionalLight
平行光的three.js应用便创建了出来,但是如果仅仅是如此,就没必要单独拿出来讲了。接下来我们开始进一步探索DirectionalLight
。
让three.js中DirectionalLight
平行光显示阴影,设置castShadow 属性
前面我们说了,three.js中DirectionalLight
平行光是用来模仿太阳光的,但是现在我们做出来的应用中并没有阴影的存在。这是three.js为了减少对内存的消耗,提升资源的利用效率,默认情况下关闭了阴影渲染,因此需要我们去手动打开阴影渲染。
- 首先,告诉渲染器我们需要渲染阴影
1
2const renderer = new THREE.WebGLRenderer({canvas})
renderer.shadowMap.enabled = true; // 新增这行代码,告诉渲染器要渲染阴影了 设置具体需要投射阴影的物体
虽然我们已经告诉渲染器接下来要开始投射阴影了,但这还不够。我们还需通过将对应物体的castShadow
属性值设置为true
来告诉渲染器具体是哪些物体需要投射阴影。在我们已有的代码中,我们将立方体的
castShadow
属性值设置为true。1
2const box = new THREE.Mesh(boxGeometry, material)
box.castShadow = true // 告诉渲染器需要为这个box渲染阴影决定那些地方可以接收阴影
现在,我们的渲染器已经会渲染阴影了,也已经知道了具体哪个物体需要渲染阴影,就缺阴影投放在哪了。这个时候,我们还需要告诉渲染引擎具体哪些地方可以接收阴影。我们需要将能接收阴影物体的receiveShadow
属性值设置为true
。在我们的示例代码中,我们可以把平面设置为可以接收阴影。代码如下:
1
2const plane = new THREE.Mesh(planeGeometry, material)
plane.receiveShadow = true; // 新增代码,让plane接收阴影- 最后,同意光源投射隐隐
走完以上步骤后,我们还需要让光线自身可以投身阴影,需要将light
的castShadow
属性值设置为true。现在,刷新你的代码看一下,是不是能看到像下面这样的阴影了呢?1
2
3const light = new THREE.DirectionalLight(lightColor, intensity);
light.position.set(10,10,20);
light.castShadow = true;
设置three.js中DirectionalLight
平行光的照射位置target
我们已经知道了如何设置光源发出的位置,现在,就来学习如何设置光源照射位置。默认情况下,无论光从哪个位置发出,最终都会照射到点(0,0,0)的位置。要想改变光照的位置,就需要设置light.target.position
属性。
为了能方便的看出我们光照位置的变化,在开始之前我们先将demo中的动画停止。如下修改render函数代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24function render (time) {
if (resizeRenderSizeToDisplaySize()) {
const pixelRatio = window.devicePixelRatio;
const width = canvas.clientWidth * pixelRatio
const height = canvas.clientHeight * pixelRatio
renderer.setSize(width, height, false)
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
<!-- time *= 0.001
group['children'].forEach((each, index) => {
if (index !== 1) {
each.rotation.x = -time
each.rotation.y = -time
}
})
这部分代码全部注释
-->
renderer.render(scene, camera)
// requestAnimationFrame(render)注释
}
// requestAnimationFrame(render) 注释掉这行
render() // 放开注释
现在,我们得到了一帧静止画面
现在,我们设置光照目标的位置,如下:1
2light.target.position.set(5,4,2)
scene.add(light.target)
这里需要注意的是,一定要把light.target
放到scene
中,否则设置不生效
下面三个是我分别把光照目标位置设置为(1,1,1),(3,3,3),(5,5,5)后的光照阴影变化图,同时对比默认情况下的光照阴影变化,我们可以明显的看出随着光照目标变化,阴影也在不停的变化。
three.jsDirectionalLight
平行光的照射位置target
之让光追着目标走
three.js中DirectionalLight
平行光的照射位置target
不仅可以设置光照的具体位置,还可以让光照位置随着目标位置的移动而移动,只要这个对应的目标对象拥有position属性即可。
现在,我们对render
函数再次进行改造,让立方体在白色平面上来回移动。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25let positionx = 0 // 新增
let direction = 'add' // 新增
function render (time) {
···
time *= 0.001
group['children'].forEach((each, index) => {
if (index !== 1) {
each.rotation.x = -time
each.rotation.y = -time
}
})
// 新增代码
if (positionx < 10 && direction === 'add') {
positionx = positionx + 0.1
} else {
direction = 'reduce'
positionx = positionx - 0.1
if (positionx < -10) {
direction = 'add'
}
}
// 新增到此为止
renderer.render(scene, camera)
requestAnimationFrame(render)
}
现在,立方体盒子就会左右滑动。
可以看到,盒子在来回的走动,影子也在变化,只是在某些地方消失了。
现在,我们修改一下代码,将光源target指向box。1
2light.target.position.set(5,4,2)
scene.add(light.target)
改为1
light.target = box
需要注意,这里如果是将一个目标对象赋值给target,是不需要将light.target
添加到scene中的,只需要将目标对象自身添加到scene中即可。在咱们的demo中,咱们已经通过group将box添加到scene中,因此不需要额外动手。
接下来看一下修改后的结果,可以看到随着盒子滑动,影子大小虽然在变化,但是影子一直存在,这说明咱们的光线确实一直在跟着box走。
关于three.js中平行光源DirectionalLight我们就学习到这里,以下是今天学习的所有内容的源代码,也可以点击链接https://www.91yqz.com/learnThree/learnThree16.html后右键查看
1 | <script> |