一、光照原理和常见光源类型
three.ts
虚拟光源是对自然界光照的模拟,three.ts
搭建虚拟场景的时候, 为了更好的渲染场景,往往需要设置不同的光源,设置不同的光照强度,就像摄影师给你拍照要设置各种辅助灯光一样。
three.ts
场景对象Scene
主要是由模型对象和光源对象Light
构成, 在实际开发过程中,多数三维场景往往需要设置光源对象,通过不同的光源对象模型生活中的光照效果, 尤其是为了提高three.ts
的渲染效果更需要设置好光源,就像职业摄影师拍照要打灯一样。
1. 环境光AmbientLight
- 环境光是没有特定方向的光源,主要是均匀整体改变
three.ts
物体表面的明暗效果, 这一点和具有方向的光源不同,比如点光源可以让物体表面不同区域明暗程度不同。javascript// 环境光:环境光颜色RGB成分分别和物体材质颜色RGB成分分别相乘 const ambient = new THREE.AmbientLight(0x444444); scene.add(ambient); // 环境光对象添加到scene场景中
2. 点光源PointLight
- 点光源就像生活中的白炽灯,光线沿着发光核心向外发散,同一平面的不同位置与点光源光线入射角是不同的, 点光源照射下,同一个平面不同区域是呈现出不同的明暗效果。
- 和环境光不同,环境光不需要设置光源位置,而点光源需要设置位置属性
.position
,光源位置不同, 物体表面被照亮的面不同,远近不同因为衰减明暗程度不同。 - 可以把点光源位置从
(400, 200, 300)
位置改变到(-400, -200, -300)
,会发现网格模型被照亮的位置从前面变到了后面, 这很正常,光源只能照亮面对着光源的面,背对着光源的无法照射到,颜色会比较暗。javascript// 点光源 const point = new THREE.PointLight(0xffffff); //设置点光源位置,改变光源的位置 point.position.set(400, 200, 300); scene.add(point);
3. 平行光DirectionalLight
- 平行光顾名思义光线平行,对于一个平面而言,平面不同区域接收到平行光的入射角一样。
- 点光源因为是向四周发散,所以设置好位置属性
.position
就可以确定光线和物体表面的夹角, 对于平行光而言,主要是确定光线的方向,光线方向设定好了,光线的与物体表面入射角就确定了, 仅仅设置光线位置是不起作用的。 - 在三维空间中为了确定一条直线的方向只需要确定直线上两个点的坐标即可,所以
three.ts
平行光提供了位置.position
和 目标.target
两个属性来一起确定平行光方向。目标.target
的属性值可以是three.ts
场景中任何一个三维模型对象, 比如一个网格模型Mesh
,这样three.ts
计算平行光照射方向的时候,会通过自身位置属性.position
和.target
表示的物体的位置属性.position
计算出来。javascript// 平行光 const directionalLight = new THREE.DirectionalLight(0xffffff, 1); // 设置光源的方向:通过光源position属性和目标指向对象的position属性计算 directionalLight.position.set(80, 100, 50); // 方向光指向对象网格模型mesh2,可以不设置,默认的位置是0,0,0 directionalLight.target = mesh2; scene.add(directionalLight);
- 平行光如果不设置
.position
和.target
属性,光线默认从上往下照射,也就是可以认为(0,1,0)
和(0,0,0)
两个坐标确定的光线方向。 - 注意一点平行光光源的位置属性
.position
并不表示平行光从这个位置向远处照射,.position
属性只是用来确定平行光的照射方向, 平行光你可以理解为太阳光,从无限远处照射过来。
4. 聚光源SpotLight
- 聚光源可以认为是一个沿着特定方会逐渐发散的光源,照射范围在三维空间中构成一个圆锥体。 通过属性
.angle
可以设置聚光源发散角度,聚光源照射方向设置和平行光光源一样是通过位置.position
和目标.target
两个属性来实现。javascript// 聚光光源 const spotLight = new THREE.SpotLight(0xffffff); // 设置聚光光源位置 spotLight.position.set(200, 200, 200); // 聚光灯光源指向网格模型mesh2 spotLight.target = mesh2; // 设置聚光光源发散角度 spotLight.angle = Math.PI / 6 scene.add(spotLight);//光对象添加到scene场景中
5. 光源辅助对象
three.ts
提供了一些光源辅助对象,就像AxesHelper
可视化显示三维坐标轴一样显示光源对象, 通过这些辅助对象可以方便调试代码,查看位置、方向。
6. 光照计算算法
three.ts
在渲染的时候网格模型材质的颜色值mesh.material.color
和光源的颜色值light.color
会进行相乘,简单说就是RGB
三个分量分别相乘。- 平行光漫反射简单数学模型:
漫反射光的颜色 = 网格模型材质颜色值 x 光线颜色 x 光线入射角余弦值
。 - 漫反射数学模型RGB分量表示:
(R2,G2,B2) = (R1,G1,B1) x (R0,G0,B0) x cosθ
javascriptR2 = R1 * R0 * cosθ G2 = G1 * G0 * cosθ B2 = B1 * B0 * cosθ
7. 颜色相乘测试
- 通过下面代码验证上面颜色相乘的算法,比如把网格模型的颜色设置为白色
0xffffff
,也就意味着可以反射任意光照颜色, 然后把环境光和点光源只保留红色成分,绿色和蓝色成分都设置为0
。可以看到网格模型会把渲染为红色。javascript// 网格模型材质设置为白色 const geometry = new THREE.BoxGeometry(100, 100, 100); // const material = new THREE.MeshLambertMaterial({ color: 0xffffff }); const mesh = new THREE.Mesh(geometry, material); scene.add(mesh); //环境光 环境光颜色RGB成分分别和物体材质颜色RGB成分分别相乘 const ambient = new THREE.AmbientLight(0x440000); scene.add(ambient);//环境光对象添加到scene场景中 //点光源 const point = new THREE.PointLight(0xff0000); //设置点光源位置 光源对象和模型对象的position属性一样是Vector3对象 //PointLight的基类是Light Light的基类是Object3D 点光源对象继承Object3D对象的位置属性position point.position.set(400, 200, 300); scene.add(point);
- 可以把网格模型设置为纯蓝色
0x0000ff
,光源颜色只保留红色成分不变,可以看到网格模型的渲染效果是黑色,因为这两个颜色相乘总有一个RGB
分量为0
, 相乘的结果是0x00000
,也就是黑色。这也符合实际的物理规律,蓝色的物体不会反射红色的光线,熙然就是黑色效果。 - 模拟一个舞台的各种颜色灯光效果,可以用这种思路设置
RGB
各个分量值来实现特定颜色光源,不过一般渲染的时候RGB
三个分量是相同的, 也就是表示白色光源,0xffffff
表示最高强度的白色光源,0x000000
相当于没有光照。