WebGL+Three.js—第十一章 Threejs光源

328 阅读22分钟

11.1 光源类型

11.1.1 基础光源

        1、环境光AmbientLight

            THREE.AmbientLight灯光全局应用,该光源没有特定的方向,THREE.AmbientLight不会产生阴影。一般不会使用THREE.AmbientLight作为单个光源,该光源以相同的颜色为所有对象着色。可以与THREE.SpotLight或THREE.DirectionalLight柔化阴影或添加一些额外的颜色场景。

image.png

        2、点光源PointLight

            点光源是一个从一个点发出,向各个方向发光的光源。点光源的一个很好的例子是发射信号弹在夜空中。

image.png

        3、聚光灯光源SpotLight

            聚光灯是您最常使用的灯之一(尤其是如果您想要使用阴影),它是一种具有锥形效果的光源,你可以将其与手电筒或灯笼进行比较。这种光有方向和角度。

image.png

        4、平行光DirectionalLight

            我们将看到的最后一个基本光是平行光。这类光可以认为是很远的光。它发出的所有光线彼此平行。太阳就是一个很好的例子。太阳那么远我们在地球上接收到的光线(几乎)彼此平行。平行光和聚光灯的区别是这种光不会随着距离越远而减弱。

image.png

11.1.2 特殊光源

        1、半球光HemisphereLight

            我们可以创造更自然的户外照明。没有这个光,我们可以通过创建THREE.DirectionalLight来模拟户外,它模拟太阳,并且可能添加额外的平行光来提供给场景一些一般的颜色。然而,这看起来并不自然,因为不是所有的光都直接来自上方,大部分都是由大气并被地面和其他物体反射,半球光可以让外观颜色更加自然。

image.png

            其实threejs的半球光有点类似于WebGL的反射光,关于反射光的原理可以参考# WebGL+Three.js—第六章 WebGL光照 ### 6.1.3 反射

        2、面光源AreaLight

            我们可以定义一个发光的矩形区域,它散发光线是一个平面,不是一个点。

image.png

11.1.3 光源特殊效果

        1、镜面眩光LensFlare

            镜头光晕它们会在您拍照时出现直接进入太阳或其他明亮的光源。在大多数情况下,您希望避免这个,但对于游戏和3D生成的图像,它提供了一个很好的效果,使得场景看起来更真实一些。

image.png

11.2 SpotLight聚光灯光源

        聚光灯光源是最常用的光源之一,是一种具有锥形效果的光源,和手电筒类似。可以配置它随着距离的增大而逐渐减弱,并且可以产生阴影效果。

11.2.1 聚光灯使用

        在使用聚光灯之前,先选择好材质,因为不是所有的材质都对灯光有效的,像MeshBasicMaterial这个基础材质是不受光照影响的,它只根据自己设置的color参数显示。因此我们采用MeshLambertMaterial这个材质进行测试。

        关于three.js的材质,可以在WebGL+Three.js—第十二章 Threejs材质进行详细了解。

        1、初始化场景、相机、渲染器

            建议在初学阶段把世界坐标辅助器和轨道控制器都添加上,这样可以比较直观看到物体所在的位置。

// 初始化场景
initScene() {
  this.scene = new THREE.Scene();
},
// 初始化相机
initCamera() {
  // 创建一个相机 视点
  this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
  // 设置相机的位置
  this.camera.position.x = -30;
  this.camera.position.y = 45;
  this.camera.position.z = 35;
  this.camera.lookAt(0, 0, 0);
},
// 初始化渲染器
initRenderer() {
  // 创建一个渲染器
  this.renderer = new THREE.WebGLRenderer();
  // 设置渲染器尺寸
  this.renderer.setSize(window.innerWidth, window.innerHeight);
  this.renderer.shadowMap.enabled = true;
  document.body.appendChild(this.renderer.domElement);
},
// 添加世界坐标辅助器
addAxesHelper() {
  const axesHelper = new THREE.AxesHelper(50);
  this.scene.add(axesHelper);
},
// 添加轨道控制器
addOrbitControls() {
  this.orbitControls = new OrbitControls(this.camera, this.renderer.domElement);
  this.orbitControls.enableDamping = true;
  this.orbitControls.dampingFactor = 0.05;
},

image.png

        2、添加立方体

            在添加聚光灯之前,先使用基础网格材质MeshBasicMaterial把立方体显示出来,确保立方体能正常的显示在场景对应的位置中。

// 添加一个立方体
addCube() {
  const cubeGeometry = new THREE.BoxGeometry(8, 8, 8);
  const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xff2288 });
  this.cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
  this.cube.position.set(0, 8, 0)

  // 添加父元素到场景里
  this.scene.add(this.cube);
},

image.png

        3、添加聚光灯

            聚光灯的构造函数是:SpotLight(color: 颜色, intensity: 强度, distance: 距离, angle: 角度, penumbra: 边缘衰减度, decay: 光线衰减度)。添加了聚光灯之后,记得要把物体的材质换回MeshLambertMaterial。

// 添加一个立方体
addCube() {
  const cubeGeometry = new THREE.BoxGeometry(8, 8, 8);
  const cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xff2288 });
  this.cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
  this.cube.position.set(0, 8, 0)
  this.scene.add(this.cube);
},
// 添加聚光灯光源
addSpotLight() {
  const spotLight = new THREE.SpotLight(0xFFFFFF, 50);
  spotLight.position.set(-60, 40, -65);
  spotLight.decay = 0.5;
  this.scene.add(spotLight)
},

image.png

            此时聚光灯已然生效,现在聚光灯在物体的左上方,因此物体的上面和正面是光亮的,而右面由于背对着聚光灯,因此是黑暗的。

            注意:这里有一个常见的问题,在初始化聚光灯的类,必须要传给它前两个参数,这两个参数分别是聚光灯的颜色color和光照强度intensity。

const spotLight = new THREE.SpotLight(0xFFFFFF, 50);

image.png

            我们发现明明给它设置了颜色和光线强度,但还是没有效果,这是因为three.js给它的decay属性默认值有点大,decay属性是控制聚光灯根据距离的衰减度,值越大就越暗,后续会详细描述。我们在这里可以适当把decay值调小一些。

const spotLight = new THREE.SpotLight(0xFFFFFF, 50);
spotLight.decay = 0.5;

image.png

11.2.2 添加阴影效果

        聚光灯是可以让物体产生阴影的,聚光灯对象里有一个shadow属性是专门针对阴影进行设置。想体验阴影效果,需要做一些准备工作:

        1、添加一个平面

            添加平面是用来接收阴影的,它同样也需要使用MeshLambertMaterial材质。

addPlane() {
  const planeGeometry = new THREE.PlaneGeometry(100, 100);
  const planeMaterial = new THREE.MeshLambertMaterial({color: 0xcccccc});
  const plane = new THREE.Mesh(planeGeometry, planeMaterial);
  plane.rotation.x = -0.5 * Math.PI;
  plane.position.set(15, 0, 0);
  this.scene.add(plane);
}

image.png

        2、设置聚光灯的shadow属性

// 添加聚光灯光源
addSpotLight() {
  const spotLight = new THREE.SpotLight(0xFFFFFF, 50);
  spotLight.position.set(-60, 60, -65);
  spotLight.decay = 0.5;
  spotLight.shadow.mapSize = new THREE.Vector2(1024, 1024);
  spotLight.shadow.camera.far = 130;
  spotLight.shadow.camera.near = 40;
  this.scene.add(spotLight)
},

        3、设置各模块的阴影属性

            我们看到一个物体的阴影效果,不是单独配置某个物体的阴影属性就能生效,而是需要各个模块都要开启阴影属性才能生效,以下是设置阴影的各个环节:

            (1)渲染器开启阴影效果

                设置渲染器对象的shadowMap.enabled为true。

// 初始化渲染器
initRenderer() {
  this.renderer = new THREE.WebGLRenderer();
  this.renderer.setSize(window.innerWidth, window.innerHeight);
  this.renderer.shadowMap.enabled = true;
  document.body.appendChild(this.renderer.domElement);
},

            (2)聚光灯开启阴影效果

                聚光灯默认是不会产生阴影的,如有需要,手动设置它的castShadow属性为true。

// 添加聚光灯光源
addSpotLight() {
  const spotLight = new THREE.SpotLight(0xFFFFFF, 50);
  ......
  spotLight.castShadow = true;
  this.scene.add(spotLight)
},

            (3)物体开启阴影效果

                物体默认也是不会产生阴影的,哪个物体需要阴影,就设置对应物体的castShadow属性为true。

// 添加一个立方体
addCube() {
  const cubeGeometry = new THREE.BoxGeometry(8, 8, 8);
  const cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xff2288 });
  this.cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
  this.cube.position.set(4, 10, 20)
  this.cube.castShadow = true;
  this.scene.add(this.cube);
},

            (4)设置平面接收阴影

                把各个模块的阴影属性都开启了之后,最终阴影肯定会落在某一个地方展示出来。这里我们通常会用一个平面去接收阴影,设置它的receiveShadow属性为true。

// 添加一个平面,用来接收阴影
addPlane() {
  const planeGeometry = new THREE.PlaneGeometry(100, 100);
  const planeMaterial = new THREE.MeshLambertMaterial({color: 0xcccccc});
  const plane = new THREE.Mesh(planeGeometry, planeMaterial);
  plane.rotation.x = -0.5 * Math.PI;
  plane.position.set(15, 0, 0);
  plane.receiveShadow = true;
  this.scene.add(plane);
},

image.png

        注意:上述各个环节缺一不可,漏了某一个环节都会无法显示阴影效果。

11.2.3 添加聚光灯辅助类

        这个聚光灯辅助对象很有必要,因为聚光灯的位置以及它与物体的距离,是对物体显示的光亮度产生直接的影响,有了辅助器非常方便调试聚光灯的位置。

        three.js添加聚光灯辅助器十分简单,它借助SpotLightHelper类实现,只需要把聚光灯的对象传进去,然后添加到场景中即可。添加完之后记得在动画函数里调用一下它的update()方法,凡是这种辅助类都需要在动画函数update一下,否则修改或移动场景中的属性,辅助类不会发生变化。

// 添加聚光灯光源
addSpotLight() {
  const spotLight = new THREE.SpotLight(0xFFFFFF, 50);
  spotLight.position.set(-60, 60, -65);
  spotLight.decay = 0.5;
  spotLight.distance = 150;
  this.scene.add(spotLight)

  const lightHelper = new THREE.SpotLightHelper( spotLight );
  this.scene.add( lightHelper );
},
// 动画函数
animation() {
  this.lightHelper.update();
  // 渲染
  this.renderer.render(this.scene, this.camera);
  requestAnimationFrame(this.animation);
},

image.png

        为了将辅助类看得更清楚一些,可以稍微把相机的位置调远一点,设置一下它的y坐标,同时旋转一下角度。

image.png

        我们看到添加了辅助类之后,它会给我们添加了一个锥形的线条,这些线条就是模拟聚光灯所发出的光线,而锥形的顶点就是聚光灯的所在位置。锥形的底部是一个圆,从顶点到圆代表的是聚光灯可以照耀的最远距离。

11.2.4 聚光灯参数

属性介绍版本号
color颜色所有
intensity强度所有
distance距离所有
angle角度所有
exponent光源模型中,衰减的一个参数,越大衰减越快。0.73及以下
decay光线随着距离增加变暗的衰减量0.74+
penumbra照明区域在边缘附近的平滑衰减速度,取值范围在0到1之间0.74+

        1、color-颜色

fdec0eec-fac9-464a-b380-55209b376183.gif

        2、intensity-强度

            这个光照强度属性在旧版本的时候,对聚光灯初始化是不强调设置的,它会默认给你设置好一定的强度。但在最新版本则必须得自己手动设置好,因为它的默认值设置为1,那相当于没有任何强度,看不出灯光效果。

249befc1-406f-4233-bdcc-5695a7689f10.gif

        3、distance-距离

            该属性控制的是聚光灯的照射距离。

e29611a5-b7ad-44e6-a4d9-a40ddac0106b.gif

        4、angle-角度

            该属性控制的是聚光灯的光照散射角度,最大范围是180°。

38bd486c-794c-4083-b4b5-d2f07404ffc8.gif

        5、penumbra-边缘衰减度

            该属性控制的是照明区域在边缘附近的平滑衰减速度。

33357844-ddfa-48c5-b549-4d08374542b3.gif

        6、decay-光线衰减度

            聚光灯的亮度随着距离的远近而变化,距离越远就越暗,越近就越亮。而decay属性控制的是它的衰减度,它的值越大衰减得越快,越小就衰减得越慢,如果设为0则不受距离控制,亮度不变。

6a045ee8-ba6e-4b9f-92aa-9927d64fbb56.gif

11.2.5 示例代码

11.3 AmbientLight环境光

        环境光会均匀的照亮场景中的所有物体,由于它是没有方向的,因此它不能产生阴影。通常不会将AmbientLight光源作为场景中唯一的光源,一般会配合SpotLight聚光灯或者SpotLight点光源共同使用,它主要的作用是柔化生硬的颜色和阴影。

11.3.1 环境光使用

        使用环境光跟聚光灯类似,物体的材质同样要采用MeshLambertMaterial进行测试。

        至于初始化场景、相机、渲染器和添加物体等这些步骤,跟前面聚光灯的步骤是雷同的,可以参考,这里不再赘述。

// 添加ambientLight环境光
addAmbientLight() {
  this.ambientLight = new THREE.AmbientLight(0xAAAAAA, 2)
  this.scene.add(this.ambientLight)
}

11.3.2 环境光参数

属性介绍版本号
color颜色所有
intensity强度所有

        1、color-颜色

c4aa6078-4ff5-4f86-ba2a-993e35d95ef9.gif

        2、intensity-强度

            环境光初始化的时候不强制要求设置光线强度,它会默认设为1,是比较暗的,建议还是给它一个光线强度值。

fbb3ef7b-265a-455a-8a2e-34fa4552501a.gif

11.3.3 结合聚光灯一起使用

        通常作为主要光源基本上是聚光灯或者点光源,但如果只有主光源,物体的阴暗面的颜色就比较生硬,如果配合环境光就相对比较柔和。

        1、只有聚光灯光源

            聚光灯是符合我们日常生活的光照原理,但是物体的阴暗面由于聚光灯无法照射就完全是暗黑色,这显然不太合理,因为在正常情况下,即使灯光照射不到的地方,也会有最基础的亮度,这就是环境光的作用。

image.png

        2、聚光灯搭配环境光

            有了环境光,阴暗面的区域也显得比较柔和,看起来会比较协调。

image.png

11.3.4 示例代码

        温馨提示:此示例是环境光与聚光灯相结合,如果想单独看环境光效果,可以在聚光灯的"是否显示"选项去掉勾选即可。

11.4 PointLight点光源

        点光源跟聚光灯是有些类似的,它们都是从单点发光,但区别在于聚光灯是发射锥形形状的光线,而点光源则是向所有方向发射光线。聚光灯类似于手电筒,而点光源类似于灯泡。

11.4.1 点光源使用

        关于初始化场景、相机、渲染器等步骤,请参考前面的10.2聚光灯模块。

        1、添加立方体和平面

            在添加点光源之前,先使用MeshLambertMaterial材质把立方体和平面添加到场景中。

// 添加一个立方体
addCube() {
  const cubeGeometry = new THREE.BoxGeometry(8, 8, 8);
  const cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xff2288 });
  this.cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
  this.cube.position.set(0, 8, 0)
  // 添加父元素到场景里
  this.scene.add(this.cube);
},
// 添加一个平面
addPlane() {
  const planeGeometry = new THREE.PlaneGeometry(100, 100);
  const planeMaterial = new THREE.MeshLambertMaterial({color: 0xcccccc});
  const plane = new THREE.Mesh(planeGeometry, planeMaterial);
  plane.rotation.x = -0.5 * Math.PI;
  plane.position.set(15, 0, 0);
  this.scene.add(plane);
},

            此时没有添加点光源,虽然立方体和平面在场景里,但还是一片漆黑。

image.png

        2、添加点光源

            点光源的构造函数是PointLight(color: Color, intensity: Float, distance: Number, decay: Float),这4个属性分别是颜色、光线强度,距离和衰减度,在下面会对它们详细介绍。

// 添加点光源
addPointLight() {
  this.pointLight = new THREE.PointLight(0xFFFFFF, 6, 100);
  this.pointLight.position.set(0, 10, 5);
  this.scene.add(this.pointLight)
},

image.png

            这里初始化的时候给它设置了颜色、光线强度和距离这3个参数,但是发现依然还是非常暗淡,除了光线强度以外,它默认设置的decay衰减度是挺大的,值越大就越暗。因此在使用点光源的时候,可以适当把decay的值调小一点。例如它默认值是2,我们可以把它设置成0.5。

this.pointLight = new THREE.PointLight(0xFFFFFF, 6, 100, 0.5);

image.png

11.4.2 添加阴影效果

        在10.2聚光灯模块已经详细讲解了设置阴影的步骤,在点光源设置阴影跟聚光灯的步骤是一致的,在这里简单回顾一下:

        1、渲染器开启阴影效果

            设置渲染器对象的shadowMap.enabled为true。

// 初始化渲染器
initRenderer() {
  ......
  this.renderer.shadowMap.enabled = true;
},

        2、点光源开启阴影效果

            点光源默认是不会产生阴影的,如有需要,手动设置它的castShadow属性为true,同时设置点光源的shadow阴影属性。

// 添加点光源
addPointLight() {
  this.pointLight = new THREE.PointLight(0xFFFFFF, 60, 150, 0.5);
  this.pointLight.position.set(50, 50, 50);
  this.pointLight.castShadow = true;
  this.pointLight.shadow.mapSize = new THREE.Vector2(1024, 1024);
  this.pointLight.shadow.camera.far = 130;
  this.pointLight.shadow.camera.near = 40;
  this.scene.add(this.pointLight)
},

        3、物体开启阴影效果

            物体默认也是不会产生阴影的,哪个物体需要阴影,就设置对应物体的castShadow属性为true。

// 添加一个立方体
addCube() {
  ......
  this.cube.castShadow = true;
  this.scene.add(this.cube);
},

        4、设置平面接收阴影

            把各个模块的阴影属性都开启了之后,最终阴影肯定会落在某一个地方展示出来。这里我们通常会用一个平面去接收阴影,设置它的receiveShadow属性为true。

// 添加一个平面,用来接收阴影
addPlane() {
  const planeGeometry = new THREE.PlaneGeometry(100, 100);
  const planeMaterial = new THREE.MeshLambertMaterial({color: 0xcccccc});
  const plane = new THREE.Mesh(planeGeometry, planeMaterial);
  plane.rotation.x = -0.5 * Math.PI;
  plane.position.set(15, 0, 0);
  plane.receiveShadow = true;
  this.scene.add(plane);
},

image.png

11.4.3 添加点光源辅助类

        这个点光源辅助类添加之后,会出现一个小图标,表示点光源的位置。

        添加聚光灯辅助器的方法,跟聚光灯的SpotLightHelper辅助类是一样的,点光源的辅助类名叫PointLightHelper,也是把点光源的对象传进去,然后添加到场景中即可。添加完之后记得在动画函数里调用一下它的update()方法。

// 添加点光源
addPointLight() {
  this.pointLight = new THREE.PointLight(0xFFFFFF, 60, 150, 0.5);
  this.pointLight.position.set(50, 50, 50);
  this.pointLight.castShadow = true;
  this.pointLight.shadow.mapSize = new THREE.Vector2(1024, 1024);
  this.pointLight.shadow.camera.far = 130;
  this.pointLight.shadow.camera.near = 40;
  this.scene.add(this.pointLight)

  this.lightHelper = new THREE.PointLightHelper( this.pointLight );
  this.scene.add( this.lightHelper );
},
// 动画函数
animation() {
  this.orbitControls.update();
  this.lightHelper.update();
  // 渲染
  this.renderer.render(this.scene, this.camera);
  requestAnimationFrame(this.animation);
},

        为了能看到辅助类的小图标,可以稍微把相机的位置调远一点,将相机的y坐标调大一些。

// 初始化相机
initCamera() {
  // 创建一个相机 视点
  this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
  // 设置相机的位置
  this.camera.position.x = -30;
  // this.camera.position.y = 40;
  this.camera.position.y = 80;
  this.camera.position.z = 30;
  this.camera.lookAt(0, 0, 0);
},

image.png

11.4.4 点光源参数

属性介绍
color颜色
intensity光线强度
distance距离
decay光线随着距离增加变暗的衰减量

        1、color-颜色

d1dfad53-435c-4f67-9fd2-6d36e2ee8a22.gif

        2、intensity-强度

            这个光照强度属性在上面简单介绍了一下,这个属性默认值是挺小的,不设置它光线非常的暗淡,基本上在初始化的时候就需要给它设置一下强度。

e1a4c4f7-51f7-424a-839a-d8102a21af87.gif

        3、distance-距离

            该属性控制的是点光源的照射距离。

18b67b85-d478-4e09-a6a5-d20d443c8bf2.gif

        4、decay-光线衰减度

            点光源的亮度随着距离的远近而变化,距离越远就越暗,越近就越亮。而decay属性控制的是它的衰减度,它的值越大衰减得越快,越小就衰减得越慢,如果设为0则不受距离控制,亮度不变。

56815d09-25be-4ef0-9f57-6971c062a9a3.gif

11.4.4 示例代码

11.5 DirectionalLight平行光

        平行光可以看作是距离很远的光,它所发出的所有光线都是相互平行的,类似于太阳光。

11.5.1 平行光使用

        关于初始化场景、相机、渲染器、添加立方体和平面等步骤,请参考前面的10.4点光源模块,这里把点光源的对象换成平行光的对象。

        平行光的构造函数是DirectionalLight(color: Color, intensity: Float),这2个属性分别是颜色、光线强度,在下面会对它们详细介绍。

// 添加平行光
addDirectionalLight() {
  this.directionalLight = new THREE.DirectionalLight(0xFFFFFF);
  this.directionalLight.position.set(30, 30, 30);
  this.scene.add(this.directionalLight);
},

image.png

            这里初始化的时候如果没有设置它的光线强度属性,效果是比较暗淡的,因为它的intensity属性默认值为1,因此最好还是稍微调整一下。

this.directionalLight = new THREE.DirectionalLight(0xFFFFFF, 4);

image.png

11.5.2 添加阴影效果

        在10.2聚光灯和10.4点光源已经详细讲解了设置阴影的步骤,平行光的步骤跟它们也是一致的,在这里就不再阐述。

        平行光开启阴影效果:手动设置它的castShadow属性为true,同时设置它的shadow阴影属性。

// 添加平行光
addDirectionalLight() {
  this.directionalLight = new THREE.DirectionalLight(0xFFFFFF, 4);
  this.directionalLight.position.set(30, 30, 30);
  this.directionalLight.castShadow = true;
  this.directionalLight.shadow.mapSize = new THREE.Vector2(1024, 1024);
  this.scene.add(this.directionalLight);
},

image.png

11.5.3 添加平行光辅助类

        这个点光源辅助类添加之后,会出现一个小正方形和一条线,表示平行光的位置和它的光线。

        添加聚光灯辅助器的方法,跟聚光灯的SpotLightHelper辅助类是一样的,点光源的辅助类名叫PointLightHelper,也是把点光源的对象传进去,然后添加到场景中即可。添加完之后记得在动画函数里调用一下它的update()方法。

// 添加点光源
addPointLight() {
  this.pointLight = new THREE.PointLight(0xFFFFFF, 60, 150, 0.5);
  this.pointLight.position.set(50, 50, 50);
  this.pointLight.castShadow = true;
  this.pointLight.shadow.mapSize = new THREE.Vector2(1024, 1024);
  this.pointLight.shadow.camera.far = 130;
  this.pointLight.shadow.camera.near = 40;
  this.scene.add(this.pointLight)

  this.lightHelper = new THREE.PointLightHelper( this.pointLight );
  this.scene.add( this.lightHelper );
},
// 动画函数
animation() {
  this.orbitControls.update();
  this.lightHelper.update();
  // 渲染
  this.renderer.render(this.scene, this.camera);
  requestAnimationFrame(this.animation);
},

image.png

11.5.4 平行光参数

属性介绍
color颜色
intensity光线强度

        1、color-颜色

be50dd3a-2f0f-432c-88f1-4b2619c49196.gif

        2、intensity-强度

            这个光照强度属性在上面简单介绍了一下,这个属性默认值是挺小的,不设置它光线非常的暗淡,基本上在初始化的时候就需要给它设置一下强度。

5bbfced0-7e32-425f-a78e-f6ecb47abafc.gif

11.5.5 target属性

        平行光跟其它光源有一个区别,它有一个target属性,它指的是灯光从它的位置指向目标位置,默认的目标位置为(0, 0, 0)。

        为了更好的了解target属性,在这里再添加一个球体:

// 添加一个球体
addSphere() {
  const sphereGeometry = new THREE.SphereGeometry(3,10,10);
  const sphereMaterial = new THREE.MeshLambertMaterial({ color: 0x00ff00 });
  this.sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
  this.sphere.castShadow = true;
  this.sphere.position.set(0, 8, 20);
  this.scene.add(this.sphere)
},

image.png

        此时我们发现,虽然球体也同样设置了castShadow属性为true,也就是接受阴影,但只有立方体有阴影,而球体是没有阴影的。

        我们在这里可以添加一个相机辅助器,来查看一下平行光的指向的位置。

// 添加平行光的相机辅助器
addCameraHelper() {
  const cameraHelper = new THREE.CameraHelper(this.directionalLight.shadow.camera);
  this.scene.add(cameraHelper);
},

image.png

        这样就非常明确了,平行光在默认的情况下是指向原点(0,0,0),而立方体的位置恰好在原点的位置,位于平行光的照射范围内,因此它才能产生阴影。如果想改变平行光的指向位置,此时target属性就派上用场了,例如这里把平行光指向球体,那么把target设置为球体即可:

image.png

        结论:平行光的阴影是有一定的局限性的,如果想所有物体都产生阴影,还得借助聚光灯或者点光源。

11.5.6 示例代码

11.6 HemisphereLight半球光

        半球光光源可以为室外场景创建更加自然的光照。

11.6.1 半球光使用

        关于初始化场景、相机、渲染器、添加立方体和平面等步骤,请参考前面的10.4点光源模块,这里把点光源的对象换成平行光的对象。

        半球光的构造函数是HemisphereLight(skyColor: Integer, groundColor: Color, intensity: Float),这3个属性分别是天空中发出光线的颜色、地面发出光线颜色、光线强度,在下面会对它们详细介绍。

        1、添加半球光

addHemisphereLight() {
  this.hemisphereLight = new THREE.HemisphereLight(0xFFFFFF, 0x00ff00, 1);
  this.scene.add( this.hemisphereLight );
},

image.png

        2、搭配平行光

            在一般情况下,半球光不会作为主要的光源,它多数是作为一个辅助的角色,搭配点光源、聚光灯或者平行光做一些美化的效果,以下例子与平行光进行搭配使用。

// 添加平行光
addDirectionalLight() {
  this.directionalLight = new THREE.DirectionalLight(0xFFFFFF, 4);
  this.directionalLight.position.set(30, 30, 30);
  this.directionalLight.castShadow = true;
  this.directionalLight.shadow.mapSize = new THREE.Vector2(1024, 1024);
  this.scene.add(this.directionalLight);
},

image.png

        3、观察半球光的效果

            这里可以做一个对比,就是当一个场景只有平行光,与平行光+半球光结合的效果进行比较:

4b3130b7-c286-4b71-86aa-1a3b069879d2.gif

            很明显只有一种主光源,会显得比较生硬的,而加上半球光之后,光照的颜色则显得比较自然。

11.6.2 半球光参数

属性介绍
color天空发出光线颜色
groundColor地面发出光线颜色
intensity光线强度

        1、color-天空发出光线颜色

7d60e5a1-16a7-4c17-8a2e-89cc306319e4.gif

        2、groundColor-地面发出光线颜色

            设置该属性之前,最好先把光线强度intensity调大一些,这样可以更好的观察效果。

f374cf1d-c3ec-447f-affe-bd4a25815d26.gif

            实际上该属性在光线高强度的情况下,是可以改变物体的颜色,尤其是在模型下更容易看出效果:

93b79b94-52aa-4aff-a8b3-663faab1b877.gif

        3、intensity-强度

7d60e5a1-16a7-4c17-8a2e-89cc306319e4.gif

11.6.3 示例代码

11.7 RectAreaLight平面光光源

        平面光光源从一个矩形平面上均匀地发射光线,这种光源的主要应用场景是模拟明亮的窗户或者条状灯光光源,实际在开发家具建模项目中会有广泛应用。

        使用平面光光源有3个注意事项:

        1、不支持阴影

        2、只支持MeshStandardMaterial和MeshPhysicalMaterial两种材质

        3、必须在场景中加入RectAreaLightUniformsLib,并调用init()

11.7.1 平面光使用

        平面光的构造函数是RectAreaLight(color: Color, intensity: Float, width: Float, height: Float),这4个属性分别是颜色、光线强度、宽度、高度,在下面会对它们详细介绍。

        1、引入RectAreaLightUniformsLib库

import { RectAreaLightUniformsLib } from 'three/examples/jsm/lights/RectAreaLightUniformsLib'

        2、调用RectAreaLightUniformsLib的init方法

RectAreaLightUniformsLib.init();

        3、添加平面光

addRectAreaLight() {
  RectAreaLightUniformsLib.init();
  this.rectLight = new THREE.RectAreaLight(0xff0000, 5, 4, 10);
  this.rectLight.position.set(0, 0, 0);
  this.scene.add(this.rectLight);
},

        4、添加平面来观看平面光效果

            注意:平面光只支持MeshStandardMaterial和MeshPhysicalMaterial两种材质,这里先使用MeshStandardMaterial。关于材质里的参数,在后续的材质文章中会详细讲解。

// 添加一个平面
addPlane() {
  const planeGeometry = new THREE.BoxGeometry(2000, 0.1, 2000);
  const planeMaterial = new THREE.MeshStandardMaterial({color: 0xffffff, roughness: 0.2, metal: 0});
  const plane = new THREE.Mesh(planeGeometry, planeMaterial);
  this.scene.add(plane);
},

image.png

11.7.2 添加平面光辅助类

        添加了平面光之后,虽然已经看到效果了,但是它并没有把发射光源的矩形平面显示出来。此时可以借助平面光辅助类,让它把平面显示。

        注意:这个平面光辅助类RectAreaLightHelper是需要独立引入的,它并不在three.js核心库内。

        1、引入RectAreaLightHelper库

import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper'

        2、添加平面光辅助类

addRectAreaLight() {
  RectAreaLightUniformsLib.init();
  this.rectLight = new THREE.RectAreaLight(0xff0000, 5, 4, 10);
  this.rectLight.position.set(0, 0, 0);
  this.scene.add(this.rectLight);

  // 添加辅助类
  const rectAreaLightHelper = new RectAreaLightHelper(this.rectLight);
  this.scene.add(rectAreaLightHelper)
},

image.png

11.7.3 平面光参数

属性介绍
color颜色
intensity光线强度
width矩形宽度
height矩形高度

        1、color-颜色

74835c83-ac02-458a-a6da-dd561c75da0d.gif

        2、intensity-强度

dcd144ba-5fb0-446f-a193-d0aef4f5118d.gif

        3、width-矩形宽度

b7a29cd5-b9c4-4b70-985e-4b741ae1b63f.gif

        4、height-矩形高度

94c7b997-e023-48cc-a024-69f4a5c66641.gif

11.7.4 示例代码

11.8 Lensflare镜头光晕

        Lensflare镜头光晕并不是一种光源。当我们直接朝着太阳或者另一个非常明亮的光源拍照时会出现镜头光晕效果,在大多数的情况下需要避免该效果,但是为了让三维场景看起来更加的真实我们需要使用到Lensflare镜头光晕。

image.png

11.8.1 镜头光晕使用

        1、搭建场景

            因为镜头光晕它不属于一个光源,因此在使用它之前先把场景、物体准备好,这里参照10.6半球光搭建一个一模一样的场景、光源和物体。(代码忽略,可参考10.6,调整了一下角度)

image.png

        2、引入Lensflare, LensflareElement两个库

import { Lensflare, LensflareElement } from 'three/examples/jsm/objects/Lensflare'

        3、加载纹理贴图

            镜头光晕是需要纹理贴图的,这里先加载两个贴图,一个是太阳的贴图,一个是光晕的贴图。关于纹理的知识在后续的文章会有详细的讲解。

// 加载纹理贴图
loadTexture() {
const textureLoader = new THREE.TextureLoader();
this.textureFlare0 = textureLoader.load('太阳.png');
this.textureFlare1 = textureLoader.load('光晕.png');
}

        4、添加镜头光晕

            创建一个Lensflare镜头光晕对象,每个光晕的效果都是通过一个个LensflareElement对象组成的。LensflareElement的构造函数是LensflareElement(texture: Texture, size: Float, distance: Float, color: Color),这4个属性分别是纹理、光晕尺寸、距离、颜色,在下面会对它们详细介绍。

addLensflare() {
  const lensflare = new Lensflare();
  lensflare.addElement(new LensflareElement(this.textureFlare0, 500, 0))
  lensflare.addElement(new LensflareElement(this.textureFlare1, 60, 0.1))
  lensflare.addElement(new LensflareElement(this.textureFlare1, 30, 0.2))
  this.hemisphereLight.add(lensflare);
}

            这里添加了3个LensflareElement对象,一个是太阳,两个是光晕。注意添加完之后,要将这个Lensflare镜头光晕对象添加到一个光源里,这里把它添加到半球光中。

image.png

11.8.2 镜头光晕参数

属性介绍
texture纹理贴图
size光晕尺寸(单位为像素)
distance和光源的距离值在0到1之间(值为0时在光源的位置)
color光晕颜色

        上面的例子里使用了两个光晕效果,在这里使用dat.gui控件的时候,也同样分别控制两个光晕来观看:

        1、size-光晕尺寸

17ec2f2b-27f3-4018-b117-bb963755af27.gif

        2、distance-与光源距离

306ed9c4-cde4-4542-99aa-e530ebc3a635.gif

        3、color-光晕颜色

c0dcf247-4e80-4fde-a7ee-46373f2d2e25.gif

11.8.3 示例代码