带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

点击查看第一章
点击查看第二章

第3章

学习使用Three.js中的光源
在第1章中,我们学习了Three.js的基础知识,而在上一章,我们对场景中最重要的部分进行了一些深入的了解,包括几何体、网格和摄像机。你可能已经注意到,尽管灯光也是场景中十分重要的一部分,但是在之前的章节中却略过了。没有光源,渲染的场景将不可见(除非你使用基础材质或线框材质)。Three.js中包含大量的光源,每一个光源都有特别的用法,所以我们会用一整章来阐述不同光源的详情,并为下一章材质的使用做准备。
WebGL本身并不支持光源。如果不使用Three.js,则需要自己写WebGL着色程序来模拟光源。查阅使用WebGL从头开始模拟光源的推荐资料请访问如下网址:https://developer.mozilla. org/en-US/docs/Web/WebGL/Lighting_in_WebGL。
在本章中你将学到以下几个主题:

  • Three.js中可用的光源。
  • 特定光源使用的时机。
  • 如何调整和配置所有光源的行为。
  • 简单地介绍如何创建镜头光晕。

在本书所有的章节中,有大量的示例可以用来试验光源的行为。本章的示例代码可以在提供的源码的chapter-03文件夹中找到。

3.1 Three.js中不同种类的光源

Three.js中有许多不同种类的光源,每种光源都有特别的行为和用法。在本章中,将讨论表3.1中所列光源。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

本章主要分为两部分内容。首先,我们先看一下基础光源:THREE.AmbientLight、 THREE.PointLight、THREE.SpotLight和THREE.DirectionalLight。所有这些光源都是基于THREE.Light 对象扩展的,这个对象提供公用的功能。以上提到的光源都是简单光源,只需一些简单的配置即可,而且可用于创建大多数场景的光源。在第二部分,我们将会看到一些特殊用途的光源和效果:THREE.HemisphereLight、THREE.AreaLight和THREE.LensFlare。只有在十分特殊的情况下才会用到这些光源。

3.2 基础光源

我们将从最基本的THREE.AmbientLight光源开始。

3.2.1 THREE.AmbientLight

在创建THREE.AmbientLight时,颜色将会应用到全局。该光源并没有特别的来源方向,并且THREE.AmbientLight不会生成阴影。通常,不能将THREE.AmbientLight作为场景中唯一的光源,因为它会将场景中的所有物体渲染为相同的颜色,而不管是什么形状。在使用其他光源(如THREE.SpotLight或THREE.DirectionalLight)的同时使用它,目的是弱化阴影或给场景添加一些额外的颜色。理解这点的最简单方式就是查看chapter-03文件夹下的例子01-ambient-light.html。在这个例子里,可以使用一个简单的用户界面来修改添加到场景中的THREE.AmbientLight光源。请注意,在这个场景中,也使用了THREE.SpotLight光源来照亮物体并生成阴影。
从如图3.1所示的截图里,你可以看到我们使用了第1章中的场景,并且THREE.AmbientLight的颜色和强度是可调的。在这个例子中,可以关闭聚光灯来查看只有THREE.AmbientLight光源的效果。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

我们在这个场景中使用的标准颜色是#606008。这是该颜色的十六进制表示形式。前两个值表示颜色的红色部分,紧接着的两个值表示绿色部分,而最后两个值表示蓝色部分。在该例的用户界面中显示的是颜色的十进制值。
在这个例子里,我们使用一个非常暗淡的灰色,用来弱化网格对象在地面上生硬的投影。通过右上角的菜单,你可以将这个颜色改成比较明显的黄橙色:rgb(190,190,41),这样所有对象就会笼罩在类似阳光的光辉下,如图3.2所示。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

正如图3.2所示,这个黄橙色应用到了所有的对象,并在整个场景中投下了一片橙色的光辉。使用这种光源时要记住:用色应该尽量保守。如果你指定的颜色过于明亮,那么你很快就会发现画面的颜色过于饱和了。除了颜色之外,还可以为环境光设置强度值。这一参数决定了光源THREE.AmbientLight对场景中物体颜色的影响程度。如果将该参数调小,则光源对颜色的影响会很微弱。如果将该值调大,则整个场景会变得过于明亮。实际效果如图3.3所示。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

既然我们已经知道了THREE.AmbientLight光源能做什么,接下来学习如何创建和使用THREE.AmbientLight光源。下面几行代码展示了如何创建THREE.AmbientLight光源,以及如何将该光源与我们前几章已见过的GUI控制菜单关联起来。
带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

创建THREE.AmbientLight光源非常简单。由于THREE.AmbientLight光源不需要指定位置并且会应用到全局,所以只需使用new THREE.AmbientLight("#606008")来指定颜色(十六进制),并用scene.add(ambientLight)将此光源应用到整个场景。环境光类的构造函数还有一个可选参数intensity,用于指定光的强度。上面的代码并没有指定强度值,则该值使用默认值1。在这个例子里,将THREE.AmbientLight光源的颜色和强度绑定到控制菜单。为此,可以使用与前面章节相同的配置方法。唯一需要改变的是调用gui.addColor(…)函数而不是gui.add(…)函数。该方法会在控制菜单里添加一个选项,在这个选项里可以直接改变传入的颜色变量。在代码中,你可以看到我们使用了dat.GUI控制菜单的onChange功能:gui.addColor(…).onChange(function(e){…})。通过这个函数,我们告诉dat.GUI控制菜单在每次颜色改变的时候调用传入的函数。对于本例来讲,我们会在这个函数里将THREE.AmbientLight光源的颜色设置为一个新值。最后我们通过类似方法确保控制菜单中intensity选项的任何修改都会作用于场景中的环境光对象。
使用THREE.Color对象
在讲述下一个光源之前,我们先简单介绍一下THREE.Color对象。在Three.js中需要(例如为材质、灯光等)指定颜色时,可以使用THREE.Color对象,也可以像我们在设置环境光时所做的那样,以一个字符串指定颜色。此时Three.js将基于该字符串自动创建一个THREE.Color对象。实际上Three,js在构造THREE.Color对象时非常灵活,它可以基于下面所列的任何一种方式来完成:

  • 无参数构造:new THREE.Color()这种构造形式会创建一个代表白颜色的对象。
  • 十六进制数值:new THREE.Color(0xababab)这种构造形式会将十六进制值转换为颜色分量值并基于此构造颜色对象。这是最佳的颜色对象构造形式。
  • 十六进制字符串:new THREE.Color("#ababab"),此时Three.js会将字符串当作CSS颜色字符串去解释,并构造颜色对象。
  • RGB字符串:顾名思义,这种构造形式需要为每个RGB分量指定亮度值,其具体形式可以是new THREE.Color("rgb(255, 0, 0)")或者new THREE.Color("rgb(100%, 0%, 0%)")。
  • 颜色名称:可以使用Three.js能够识别的颜色名称字符串,例如new THREE.Color("skyblue")。
  • HSL字符串:如果相比RGB,你更熟悉HSL色域,也可以使用HSL值来构造颜色对象,例如new THREE.Color("hsl(0%, 100%, 50%)")。
  • 分离的RGB值:最后也可以直接使用RGB颜色分量来构造颜色对象。这三个值的范围都是0到1。形式例如new THREE.Color(1, 0, 0)。

如果需要修改一个现有颜色对象的颜色,可以用新颜色值构造一个临时颜色对象,并将其复制给现有对象。另一种修改颜色的方式是使用THREE.Color类携带的方法来读取和修改其内部颜色值,如表3.2所列。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

从这张表中可以看出,要改变当前颜色有很多方法。其中很多是Three.js库内部使用的,但同样也提供了一些方法轻松修改光源和材质的颜色。
在进入对THREE.PointLight、THREE.SpotLight和THREE.DirectionalLight的讨论之前,我们先看一下它们之间最主要的区别,那就是它们发射光线的方式。图3.4展示了这三种光源如何发射光线。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

从这个图中可以看到如下信息:

  • THREE.PointLight从特定的一点向所有方向发射光线。
  • THREE.SpotLight从特定的一点以锥形发射光线。
  • THREE.DirectionalLight不是从单个点发射光线,而是从二维平面发射光线,光线彼此平行。

在接下来的几节里,我们将更详细地介绍这些光源。

3.2.2 THREE.SpotLight

THREE.SpotLight(聚光灯光源)是最常使用的光源之一(特别是如果你想要使用阴影的话)。THREE.SpotLight是一种具有锥形效果的光源。你可以把它与手电筒或灯塔产生的光进行对比。该光源产生的光具有方向和角度。图3.5展示了聚光灯光源的效果(02-spot-light.html)。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

表3.3列出了适用于THREE.SpotLight的所有属性。我们会先研究那些与光照直接相关的属性,之后再看一看与渲染阴影有关的属性。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

当THREE.SpotLight的shadow属性为enable时,可以通过表3.4中的属性来调节阴影特性。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

创建聚光灯光源非常简单。只要指定颜色、设置想要的属性并将其添加到场景中即可,如下代码所示:
带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

在上面代码中,我们创建了THREE.SpotLight对象实例,并且将castShadow属性设置为true,因为我们想要阴影。此外,由于需要让这个光源照向指定的方向,因此我们通过设置target属性来实现。在本例中,我们将其指向名为plane的对象。当运行示例(02-spot-light.html)时,你将看到如图3.6所示的场景。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

在这个例子里,可以设置一些THREE.SpotLight对象独有的属性。其中之一就是target属性。如果我们对蓝色球体(sphere对象)设置此属性,那么这个光源会一直瞄准球体的中心,即使它在绕场景移动。我们创建这个光源时,瞄准的是地面(plane)对象,而在我们的例子中,也可以将光源瞄准另外两个物体。但是如果你不想把光源瞄准一个特定的对象,而是空间中的任意一点呢?可以通过创建一个THREE.Object3D()对象来实现,如下代码所示:
带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

然后,设置THREE.SpotLight对象的target属性:
带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

在表3.3中列出了几个适用于THREE.SpotLight的属性,这些属性可以控制光线如何从THREE.SpotLight对象发出。distance属性和angle属性定义了光锥的形状。angle属性定义了光锥的角度,而distance属性则可以用来设置光锥的长度。图3.7解释了这两个值如何一起定义了从THREE.SpotLight对象发出光线的区域。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

通常情况是不需要设置这些值的,因为它们的默认值比较合适,但是也可以使用这些属性,例如创建一个光柱很窄或光强递减很快的THREE.SpotLight对象。此外,还有最后一个可以更改THREE.SpotLight光源渲染方式的属性—penumbra属性。通过这个属性,可以设置光强从光锥中心向锥形边缘递减的速度。在图3.8中,可以看到penumbra属性的运行结果—一束非常明亮的光(intensity值很高),离中心越远光强衰减得越快(penumbra值很高)。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

在开始学习下一个光源之前,我们先简要介绍一下THREE.SpotLight光源提供的几个与阴影相关的属性。我们已经学过,将THREE.SpotLight对象的castShadow属性设置为true可以生成阴影。(当然,在场景中渲染THREE.Mesh对象时,要确保为要投射阴影的对象设置castShadow属性,为要显示阴影的对象设置receiveShadow属性。)Three.js库也允许对阴影渲染的方式进行微调。这些已经在表3.3中进行了介绍。通过shadow.camara.near、shadow.camera.far和shadow.camera.fov,可以控制光线如何投射阴影和在哪里投射阴影。其工作原理与我们前面章节中讲的透视摄像机的工作原理是一致的。想看看这些是如何起作用的,最简单的方法添加THREE.CameraHelper。在示例程序中可以通过勾选菜单上的shadowDebug(阴影调试)复选框来设置。这样可以把用来决定阴影的光照区域显示出来,如图3.9所示。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

当实际阴影效果与所希望的不一致时,使用THREE.CameraHelper可以非常方便地帮助我们发现问题所在。下面代码展示了如何使用THREE.CameraHelper。
带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

与调试阴影类似,如果你需要调试聚光灯光源本身存在的问题,可以使用Three,js提供的THREE.SpotLightHelper,并通过下面代码所示的方法使用该类。
带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

在THREE.SpotLightHelper的帮助下,我们可以直观地看到聚光灯的形状和朝向,如图3.10所示。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

下面针对使用阴影的过程中可能遇到的问题给出几个提示:

  • 如果阴影看上去有点粗糙(如阴影形状的边缘呈块状),可以增加shadow.mapSize.width和shadow.mapSize.height属性的值,或者保证用于计算阴影的区域紧密包围在对象周围。可以通过shadow.camera.near、shadow.camera.far和shadow.camera.fov属性来配置这个区域。
  • 记住,不仅要告诉光源生成阴影,而且还必须通过配置每个几何体的castShadow和receiveShadow属性来告诉几何体对象是否接收或投射阴影。
  • 如果你在场景中使用薄对象,在渲染阴影时,可能会出现奇怪的渲染失真现象。通常可以使用shadow.bias属性轻微偏移阴影来修复这些问题。
  • 如果想要阴影更柔和,可以在THREE.WebGLRenderer对象上设置不同的shadowMap- Type属性值。默认情况下,此属性的值为THREE.PCFShadowMap;如果将此属性设置为PCFSoftShadowMap,则会得到更柔和的阴影。

3.2.3 THREE.PointLight

Three.js库中的THREE.PointLight(点光源)是一种单点发光、照射所有方向的光源。夜空中的照明弹就是一个很好的点光源的例子。与所有光源一样,我们有一个专门的例子,你可以通过这个例子来试验THREE.PointLight。打开chapter-03文件夹下的03-point-light.html,你会看到一个点光源绕场景移动的例子。如图3.11所示。
本例中的场景还是第1章的那个场景,只是这次有一个点光源绕场景移动。为了更清楚地看到这个点光源在哪里,我们让一个橙色的小球(sphere对象)沿着相同的轨迹移动。随着光源的移动,你将看到红色的方块和蓝色的球被这个光源从不同的侧面照亮。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

如果你使用过旧版Three.js便会知道点光源(THREE.PointLight)不会产生阴影,然后在新版Three.js中,点光源也可以像聚光灯(THREE.SpotLight)和平行光(THREE.DirectionalLight)一样产生阴影了。
用THREE.PointLight可以对光源设置很多额外的属性,具体见表3.5。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

点光源可以像聚光灯光源一样启用阴影并设置其属性。在接下来的几个例子和截图中,我们将解释这些属性。首先,我们先看看如何创建THREE带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

我们使用指定的颜色创建了一个光源(这里使用了一个字符串值,也可以使用一个数字或THREE.Color对象),设置了它的position(位置)和distance(距离)属性,并将它添加到场景中。在介绍聚光灯光源时,我们曾在示例代码中设置了intensity和distance属性,这些属性对点光源同样有效。效果如图3.12所示。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

示例代码中没有设置power(功率)和decay(衰减)这两个属性,但它们对于模拟真实世界很有意义。下面网站为这两个属性的使用提供了很好的示例程序:https://threejs.org/ examples/#webgl_lights_physical。在前面介绍聚光灯光源时,已经展示了使用intensity属性的效果,该属性对点光源同样适用,并能产生类似效果,如图3.13所示。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

此外,聚光灯光源的distance属性在点光源上也能产生相似效果。下面的图3.14演示了当光的intensity值很高而distance值却很小时所产生的光源效果。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

聚光灯光源中的distance属性决定了在光线强度变为0之前光线的传播距离。在图3.14中,光线强度在距离为14的地方慢慢地减少为0。这就是为什么在这个例子中你仍然可以看到一个被照亮的明亮区域,但光却不会把更远的地方照亮。distance属性的默认值为0,这意味着光线强度不会随着距离的增加而减弱。
THREE.PointLight同样使用摄像机来决定如何绘制阴影,所以也可以使用辅助类THREE.CameraHelper来展示场景中哪些部分被光源的摄像机所覆盖,以及使用辅助类THREE.PointLightHelper来展示点光源的光线所照射的位置。两个辅助类一起使用时,我们 便可以获得非常直观的调试信息,如图3.15所示。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

3.2.4 THREE.DirectionalLight

我们要看的最后一个基本光源是THREE.DirectionalLight(平行光)。这种类型的光可以看作是距离很远的光。它发出的所有光线都是相互平行的。平行光的一个范例就是太阳光。太阳是如此遥远,以至于到达地球时所有的光线(几乎)都是相互平行的。THREE.DirectionalLight和我们之前看过的THREE.SpotLight之间的主要区别是:平行光不像聚光灯(可以通过distance和exponent属性来微调)那样离目标越远越暗淡。被平行光照亮的整个区域接收到的光强是一样的。
可以在示例04-directional-light.html中看到实际效果,如图3.16所示。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

从上图可以看到,场景里没有那种锥形效果的光线。所有对象接收的都是相同光强的光。只有光源的方向(direction)、颜色(color)和强度(intensity)属性用来计算颜色和阴影。
与THREE.SpotLight一样,可以设置一些属性来控制光照的强度和投射阴影的方式。THREE.DirectionalLight对象和THREE.SpotLight对象有许多属性相同,例如position、target、intensity、castShadow、shadow.camera.near、shadow.camera.far、shadow.mapSize.width、shadow.mapSize.height和shadow.bias。关于这些属性更多的信息,可以查看3.2.3节。下面只讨论平行光光源特有的几个属性。
如果你研究一下THREE.SpotLight的例子,会发现我们必须定义生成阴影的光锥。然而,对于THREE.DirectionalLight,由于所有的光线都是平行的,所以不会有光锥,而是一个立方体区域,如图3.17所示(如果想看到它,可以移动摄像机远离场景并勾选debug复选框)。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

在这个立方体范围内的所有对象都可以投影和接收阴影。与THREE.SpotLight一样,包围对象的空间定义得越紧密,投影的效果越好。可以使用下面几个属性来定义这个立方体范围:
带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

可以把这个与第2章中配置正交投影摄像机的方法比较一下。

3.3 特殊光源

这一节讲述的是特殊光源,我们将讨论Three.js提供的两个特殊光源。首先要讨论的是THREE.HemisphereLight(半球光光源),这种光源可以为户外场景创建更加自然的光照效果。然后我们会看一看THREE.AreaLight(区域光光源),它可以从一个很大的区域发射光线,而不是从单个点。最后,会展示一下如何在场景中添加镜头光晕的效果。

3.3.1 THREE.HemisphereLight

第一个特殊光源是THREE.HemisphereLight。使用THREE.Hemisphere Light,可以创建出更加贴近自然的户外光照效果。如果不使用这个灯光,要模拟户外光照,可以创建一个THREE.DirectionalLight来模拟太阳光,并且可能再添加一个THREE.AmbientLight来为场景提供基础色。但是,这样的光照效果看起来并不怎么自然。在户外,并不是所有的光照都来自上方:很多是来自于大气的散射和地面以及其他物体的反射。Three.js中的THREE.HemisphereLight光源就是为这种情形创建的。它为获得更自然的户外光照效果提供了一种简单的方式。关于它的示例,可以查看示例05-hemisphere-light.html,截图如图3.18所示。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

注意这是第一个需要加载额外的资源,并且不能从本地的文件系统直接运行的例子。因此,如果你还没有这样做,可以参考第1章,了解如何创建一个本地的Web服务器,或者禁用浏览器中的安全设置,使之可以加载外部资源。
仔细观察蓝色球体可以发现,该球体表面的底部有接近草地的绿色,而顶部有接近天空的蓝色(通过设置color属性获得)。在这个示例中,可以打开或关闭THREE.HemisphereLight,也可以设置颜色和光强。创建一个半球光光源就像创建其他光源一样简单:
带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

你只需要给它指定接收来自天空的颜色,接收来自地面的颜色,以及这些光线的光照强度。之后如果想修改这些属性值,可以使用表3.6所列出的属性。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

3.3.2 THREE.AreaLight

我们最后要看的光源是THREE.AreaLight。使用THREE.AreaLight,可以定义一个长方形的发光区域。在旧版Three.js中,THREE.AreaLight并不在标准的Three.js库中,而是在它的扩展库中,所以在使用之前我们要完成几个额外的步骤。而在新版Three.js中则可以直接使用THREE.AreaLight。在深入细节之前先来看一下我们追求的结果(打开06-area-light.html示例),如图3.19所示。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

从截图中可以看到,我们定义了三个THREE.AreaLight对象,每个都有自己的颜色,你也可以看到这些光源是如何影响整个区域的。要使用THREE.AreaLight光源,需要先在HTML文件的head标签中添加如下导入库:
带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

添加了上述导入库后,便可以像添加其他光源一样来添加THREE.AreaLight光源:
带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

在这个示例里,创建了一个新的THREE.AreaLight对象。这个光源的颜色为0xff0000,光强的值为500,width就4,height是10。与其他光源一样,可以使用position属性设置该光源在场景中的位置。在创建THREE.AreaLight时,会创建出一个垂直平面。在这个示例中,创建了三个THREE.AreaLight对象,有不同的颜色。当你第一次尝试该光源的时候,可能会觉得奇怪:为什么在你放置光源的地方什么都看不到?这是因为你不能看到光源本身,而只能看到它发射出的光,而且只有当这些光照射到某个物体上时才能看到。如果你想创建出例子中所展示的场景,可以在相同的位置(areaLight1.position)增加THREE.PlaneGeometry或THREE.BoxGeometry对象来模拟光线照射的区域,代码如下所示:
带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

通过THREE.AreaLight可以创建出非常漂亮的效果,但是可能要多试验才能获得想要的效果。拉下右上角的控制面板,会找到一些控件来设置场景中三个光源的颜色和光强,并立即看到设置后的效果,如图3.20所示。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

3.3.3 镜头光晕

本章将要讨论的最后一个主题是镜头光晕(lens flare)。你可能已经对镜头光晕很熟悉了。例如,当你直接朝着太阳或另一个非常明亮的光源拍照时就会出现镜头光晕效果。在大多数情况下,需要避免出现这种情形,但是对于游戏和三维图像来说,它提供了一种很好的效果,让场景看上去更加真实。
Three.js库也支持镜头光晕,而且在场景中添加它非常简单。在最后这一节中,我们将在场景中添加一个镜头光晕,并创建出如图3.21所示的效果。可以打开示例文件07-lensflares.html来查看这个效果。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

可以通过实例化THREE.LensFlare对象来创建镜头光晕。首先要做的是创建这个对象。THREE.LensFlare对象接受如下参数:
带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

这些参数的含义在表3.7中列出。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

我们看看创建这个对象的代码(请见示例07-lensflares.html):
带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

首先需要加载一个纹理。在这个示例里,我使用的是Three.js示例库中的镜头光晕纹理,如图3.22所示。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

如果将这张图与图3.21展示的截图相比较,会发现它定义了镜头光晕的样子。接下来,使用“new THREE.Color(0xffacc);”定义镜头光晕的颜色,这将使镜头光晕泛着红光。有了这两个对象之后,就可以创建THREE.LensFlare对象了。在这个示例里,把光晕的尺寸设置为350,距离设置为0.0(就在光源处)。
创建完LensFlare对象之后,将它放在光源处,添加到场景中,如图3.23所示。

带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

这看起来已经很好了,但是如果把这张截图与图3.21相比较,你会发现在页面*少了一些小的圆形失真图形。
我们会使用与创建主光晕相同的方法来创建它们,如下代码所示:
带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之三:学习使用Three.js中的光源

但是这次并没有创建一个新的THREE.LensFlare,而是使用了刚创建的THREE.LensFlare对象的add方法。在这个方法中,只需指定纹理(texture)、尺寸(size)、距离(distance)和混合(blending)模式。
注意add方法可以接受两个额外的参数。在add方法中,你还可以给新光晕设置颜色(color)和不透明度(opacity)属性。这些新光晕使用的纹理是一个颜色很淡的圆,在目录assets/textures/flares/下可以找到本示例所使用的光晕图片。
如果你再来看这个场景,就会发现失真图形出现在用distance参数指定的位置。

3.4 总结

本章涵盖了Three.js库中提供的各种不同灯源,信息量非常大。在本章中,我们学习了配置光源、颜色和阴影,并且知道了它们不是严谨的科学。要获得正确的结果,需要不断试验,使用dat.GUI控件可以微调配置。不同的光源以不同的方式表现,正如第4章将介绍的,材质也会对光源有不同的反应。THREE.AmbientLight光源的颜色可以附加到场景中的每一种颜色上,通常用来柔化生硬的颜色和阴影。THREE.PointLight光源会朝所有方向发射光线,不能被用来创建阴影。THREE.SpotLight光源类似于手电筒。它有一个锥形的光束,可以配置它随着距离的增大而逐渐变弱,并且可以生成阴影。我们还学习了THREE.DirectionalLight光源。这个光源相当于远光的效果,比如太阳光。它的光线彼此平行,其光强并不会随着与目标对象距离的增大而减弱。除了这些标准光源之外,我们还学习了几个更加特殊的光源。如果想要一个更加自然的户外效果,可以使用THREE.HemisphereLight光源,它考虑了天空和地面的反射。THREE.AreaLight不从单个点发射光线,而是从一个很大的区域发射光线。我们还展示了如何通过THREE.LensFlare对象添加图像化的镜头光晕。
到本章为止,我们已经介绍了几种不同的材质。在本章,你也看到了各种材质对于光照的反应各不相同。下一章将会概述Three.js库中的各种材质。

上一篇:云计算与钉钉相结合——钉钉成功案例分析


下一篇:学生笔记3 ECS云服务器新手上路