购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

3.2 如何使用基本光源

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

3.2.1 THREE.AmbientLight

当你创建一个THREE.AmbientLight对象后,其指定的颜色将全局应用于场景中的所有对象。THREE.AmbientLight没有一个特定的方向,也不会产生任何阴影效果。通常情况下,你不会将THREE.AmbientLight作为场景中唯一的光源,因为它以相同的方式将其颜色应用于场景中的所有对象,而不会考虑网格的形状。你通常会与其他光源(如THREE.SpotLight或THREE.DirectionalLight)一起使用它,以减轻阴影或向场景中添加一些额外的颜色。最简单的理解THREE.AmbientLight效果的方式是查看chapter-03文件夹中的ambient-light.html示例。该示例提供了一个简单的用户界面,你可用它来修改场景中的THREE.AmbientLight对象。

在下面的截图中,你可以看到我们使用了一个简单的瀑布模型,并且所使用的THREE.AmbientLight对象的颜色和强度属性是可配置的。在图3.1中,你可以看到当我们将光线的颜色设置为红色时会发生什么。

图3.1 环境光设为红色

如你所见,我们场景中的每个元素现在都添加了红色到它们原来的颜色上。如果我们将颜色改为蓝色,我们会得到如图3.2所示的结果。

如你所见,蓝色被应用到所有对象上,并在整个场景中投射出一种微光。在使用这种光线时,你应该非常谨慎地指定颜色。如果指定的颜色过亮,那么你会得到一个完全过饱和的图像。除了颜色,我们还可以设置光线的强度属性。这个属性决定了THREE.AmbientLight对场景中颜色的影响程度。如果降低它,那么场景中的对象只会添加少量的颜色;如果增加它,那么我们的场景会变得非常亮,如图3.3所示。

图3.2 环境光设为蓝色

图3.3 环境光设置为高强度的红色

现在我们已经看到了THREE.AmbientLight的作用,接下来我们来看一下如何创建和使用它。以下代码展示了如何创建一个THREE.AmbientLight:

创建一个THREE.AmbientLight非常简单,只需要几个步骤。THREE.Ambient-Light没有位置属性,它是全局应用的,因此我们只需要指定颜色并将它添加到场景中。另外我们可以在它的构造函数中提供一个额外的值,用于指定这个光源的强度。由于我们没有在这里指定强度值,因此它将使用默认强度值1。

注意,我们可以向THREE.AmbientLight构造函数传递一个THREE.Color对象(如前面代码所示)。我们也可以将颜色作为字符串传递——例如,"rgb(255, 0, 0)"或"hsl(0, 100%, 50%)"——或作为一个数字,就像我们在之前章节所做的那样:0xff0000。有关这方面的更多信息,可以在3.2.5节中找到。

在我们讨论THREE.PointLight、THREE.SpotLight和THREE.Directional-Light之前,让我们先强调它们之间的主要区别,即它们如何是发射光线的。图3.4展示了这三种光源是如何发射光线的。

图3.4 不同光源是如何发射光线的

从图3.4中可以看出:

❑ THREE.PointLight从某个点向各个方向发射光线。

❑ THREE.SpotLight从某个点以圆锥形发射光线。

❑ THREE.DirectionalLight不是从某个点发射光线,而是从一个二维平面发射平行的光线。

我们将在接下来的几节更详细地介绍这些光源。我们先从THREE.SpotLight开始。

3.2.2 THREE.SpotLight

THREE.SpotLight是你经常使用的一种光源(尤其是如果你想使用阴影效果)。THREE.SpotLight的光线具有圆锥形的光照效果。具体类似于手电筒或灯笼。这个光源具有一个产生光的方向和角度。图3.5是THREE.SpotLight的光照效果(spotlight.html)。

图3.5 SpotLight照亮的场景

表3.1列出了可以用来微调THREE.SpotLight的所有属性。首先我们讨论与THREE.SpotLight光效特性相关的属性。

表3.1 THREE.SpotLight对象的属性

(续)

当你对THREE.SpotLight对象开启阴影后,可以控制阴影的渲染方式。你可以通过THREE.SpotLight的shadow属性进行如表3.2所示的控制。

表3.2 THREE.SpotLight对象用于控制阴影渲染的属性

创建THREE.SpotLight非常容易。只需指定颜色,设置其他所需的属性并将其添加到场景中:

以上代码我们创建了一个THREE.SpotLight实例,并设置了各种属性来配置光源。我们还明确将castShadow属性设置为true,因为我们想要阴影。我们还需要将THREE.SpotLight指向某个地方,这通过使用target属性来实现。在使用target属性之前,我们首先需要将光源的默认target添加到场景中:

默认情况下,THREE.SpotLight的target会被设置为(0, 0, 0)。你可以在图3.6展示的示例中更改target属性并马上看到光源的变化效果。

图3.6 使用target属性将THREE.SpotLight指向特定目标的效果

注意,你还可以将光源的目标设置为场景中的对象。在这种情况下,光源会始终指向它。如果光源所指向的对象移动,那么光源也会跟着移动继续指向该对象。

在表3.1中,我们列出了可以用来控制THREE.SpotLight所发出光线的几个属性。distance和angle属性定义了光锥形状。angle属性定义了光锥的宽度,而distance属性设置了光锥的长度。图3.7直观地展示了distance和angle属性如何定义THREE.SpotLight的光照范围。

图3.7 SpotLight的distance和angle属性

通常,你不需要设置这些值,因为它们的默认值都很合理,但是你可以使用这些属性创建具有非常窄的光束或光强度快速下降的THREE.SpotLight实例。最后一个可以用来改变THREE.SpotLight产生光线的方式的属性是penumbra属性。通过这个属性,你可以设置光线在光锥边缘处的强度从什么位置开始下降。你可以在图3.8中看到penumbra属性的实际效果。我们获得了这么一个光源,开始非常明亮(高亮度),当光线到达边缘时,其亮度迅速下降。

图3.8 SpotLight penumbra属性应用效果

有时候,仅仅通过观察渲染出的场景很难确定光源的正确设置。例如你可能出于性能原因希望对照射区域进行微调,或者尝试将光源移动到非常具体的位置。你可以使用THREE.SpotLightHelper来实现以上目的:

使用上述代码,你将获得显示SpotLight的详细信息以帮助调试和正确定位、配置光源,如图3.9所示。

图3.9 启用了辅助线的SpotLight

在介绍下一个光源之前,我们将快速介绍一下可用于THREE.SpotLight对象的阴影相关属性。你已经知道了,通过将THREE.SpotLight实例的castShadow属性设置为true可以获得阴影效果。你还知道THREE.Mesh对象有两个与阴影相关的属性。你可以为需要投射阴影的对象设置castShadow属性,并为需要显示阴影的对象使用receiveShadow属性。你还可以在Three.js中通过设置阴影相关属性,精细地控制阴影的渲染效果。表3.2解释了一些属性。通过设置shadow.camera.near、shadow.camera.far和shadow.camera.fov,你可以控制光源的位置以及如何投射阴影。对于THREE.SpotLight实例,你无法直接设置shadow.camera.fov。该属性是根据THREE.SpotLight的angle属性计算出来的。这与透视相机的视野的工作方式相同(我们在第2章解释过)。要观察这个行为(shadow.camera.fov与angle属性的关系),最简单的方法是添加一个THREE.CameraHelper;你可以通过勾选菜单中的shadow-helper复选框并调整相机设置来实现这一点。如图3.10所示,勾选这个复选框会显示用于确定这个光源阴影的区域。

图3.10 启用了阴影辅助线的SpotLight

当调试阴影问题时,添加THREE.CameraHelper很有用。你只需添加以下行即可添加THREE.CameraHelper:

在结束本节之前,我想提供一些你在处理阴影问题时可能需要的建议。

如果阴影看起来呈块状,则可以增加shadow.mapSize.width和shadow.mapS i z e.height属性,以确保用于计算阴影的区域紧密包裹你的对象。你可以使用shadow.camera.near、shadow.camera.far和shadow.camera.fov属性来配置这个区域。

记住,你不仅必须告诉光源要去投射阴影,还必须通过设置castShadow和receiveShadow属性告诉每个几何体它是否将接收或投射阴影。

阴影偏移

场景中非常薄的对象在渲染阴影时可能会出现奇怪的伪影。你可以使用shadow.bias属性来稍微偏移阴影,这通常可以解决这个问题。

如果你希望获得更柔和的阴影效果,则可以在THREE.WebGLRenderer上设置不同的shadowMapType值。该属性默认设置为THREE.PCFShadowMap。如果将该属性设置为PCFSoftShadowMap,那么你将获得柔和的阴影。

现在我们介绍下一个光源:THREE.PointLight。

3.2.3 THREE.PointLight

THREE.PointLight是一种从某个点向所有方向发出光的光源。关于这个光源有一个很好的例子:夜间发射到天空中的信号弹或篝火。和其他光源一样,对于THREE.PointLight,我们也有一个示例供你实验。该示例是位于chapter-03目录的point-light.html,如图3.11所示。

图3.11 启用了辅助工具的PointLight

从图3.11中可以看出,这种光源向所有方向发射光线。就像我们之前介绍的SpotLight一样,这种光源也有一个辅助工具,你可以用同样的方式使用它。在启用了这个辅助工具之后,你可以在场景中心看到它:

THREE.PointLight与THREE.SpotLight有一些同样的属性可以用来配置这种光源的行为方式,如表3.3所示。

表3.3 THREE.PointLight对象的属性

除了这些属性之外,THREE.PointLight对象的阴影也可以像THREE.SpotLight的阴影一样进行配置。在接下来的几个示例和截图中,我们将展示这些属性在THREE.PointLight中的具体表现和效果。首先我们看一下如何创建一个THREE.PointLight:

这里没有特别之处——我们只是定义了光源并将其添加到场景中。当然,你也可以设置我们刚刚展示的属性。THREE.PointLight对象的两个主要属性是distance和intensity。使用distance属性,你可以指定光线在多少距离之前不会衰减为0。例如,在图3.12中,我们将distance属性设置为较低值,并将intensity属性增加一点,以模拟树林间的篝火。

图3.12 具有较低distance和较高intensity的PointLight

在这个示例中,你无法设置power和decay属性。然而,如果你想要模拟现实世界场景,这些属性是非常有用的。对此Three.js网站上有一个很好的例子:https://threejs.org/examples/#webgl_lights_physical。

THREE.PointLight还使用相机来确定绘制阴影的位置,因此你可以使用THREE.CameraHelper显示由相机所覆盖的部分。此外,THREE.PointLight还提供了一个助手THREE.PointLightHelper,用于显示THREE.PointLight的光源位置。当启用了THREE.CameraHelper和THREE.PointLightHelper之后,可以获得非常有用的调试信息,如图3.13所示。

不过如果你仔细观察图3.13,你可能会注意到阴影是在阴影相机所显示区域之外创建的。这是因为阴影辅助工具只显示了从点光源位置向下投射的阴影。你可以将THREE.PointLight想象成一个立方体,其中每个面都会发出光线并产生阴影。在这种情况下,THREE.ShadowCameraHelper只显示从上方投射到下方的阴影。

我们将要讨论的最后一个基本光源类型是THREE.DirectionalLight。

图3.13 启用辅助工具的PointLight

3.2.4 THREE.DirectionalLight

这种光源可以被看作来自非常远距离的光源。它发出的所有光线彼此平行。一个很好的例子就是太阳。太阳离我们很远,我们在地球上接收到的光线几乎是平行的。THREE.DirectionalLight和我们之前见过的THREE.SpotLight的主要区别是,这种光源不会随着离光源距离的增加而减弱。THREE.DirectionalLight所照亮的整个区域都会接收到相同的光线强度。要观察这一效果的实际效果,请查看图3.14中directionalLight.html示例。

正如你所看到的,使用THREE.DirectionalLight模拟日落非常容易。和THREE.SpotLight一样,你可以在这种光源上设置一些属性。例如,你可以设置光源的intensity属性以及光源产生阴影的方式。THREE.DirectionalLight有很多与THREE.SpotLight相同的属性:position、target、intensity、castShadow、shadow.camera.near、shadow.camera.far、shadow.mapSize.width、shadow.mapSize.height和shadow.bias。有关这些属性的更多信息,可以参考前面关于THREE.SpotLight的介绍。如果你回顾THREE.SpotLight的示例,你会看到我们必须定义应用阴影的光锥。由于THREE.DirectionalLight的所有光线彼此平行,我们不需要应用阴影的光锥;相反,我们有一个立方体区域(参考前面讲过的正交相机THREE.OrthographicCamera),如图3.15所示(这里我们启用了阴影辅助工具)。

图3.14 使用THREE.DirectionalLight模拟日落的示例

图3.15 THREE.DirectionalLight的阴影区域

所有落在该立方体内的对象都可以从该光源投射和接收阴影。和THREE.SpotLight一样,阴影区域定义得越小,阴影效果会更好。你可以通过以下属性来定义这个立方体阴影区域:

你可以将以上配置方式与我们在第2章配置正交相机的方式进行比较。

正如我们本节讨论Three.js不同类型光源时看到的那样,所有光源都需要指定颜色。目前我们只是使用十六进制字符串来配置颜色,但是THREE.Color对象提供了更多创建初始颜色对象的方式。接下来我们将探索THREE.Color对象提供的各种属性和方法。

3.2.5 使用THREE.Color对象

在Three.js中,当你需要为材质、光源等设置颜色时,可以直接传递一个THREE.Color对象,也可以传递一个字符串表示的颜色值(如#ff0000),不过Three.js最终还是用这个传入的字符串值创建一个THREE.Color对象。THREE.Color构造函数可以接收多种不同格式的颜色输入。你可以通过以下方式创建一个THREE.Color对象:

十六进制字符串 :new THREE.Color("#ababab")将根据传入的CSS颜色字符串创建一个颜色。

十六进制值 :new THREE.Color(0xababab)将根据传入的十六进制值创建颜色。如果你已经知道颜色的十六进制值,那么使用十六进制值来创建THREE.Color对象通常是最佳的方法。

RGB字符串 :new THREE.Color("rgb(255, 0, 0)")或new THREE.Color("rgb(100%, 0%, 0%)")。

颜色名称 :你也可以使用颜色名称来创建THREE.Color对象,例如,new THREE.Color('skyblue')。

HSL字符串 :如果你喜欢使用HSL而不是RGB,则可以通过new THREE.Color("hsl(0, 100%, 50%)")传入HSL值来创建颜色。

分离的RGB值 :你可以分别指定每个RGB颜色分量(值范围在0到1之间):new THREE.Color(1, 0, 0)。

如果你需要在创建THREE.Color对象后更改颜色,那么你可以选择创建一个新的THREE.Color对象,或者直接修改当前THREE.Color对象的内部属性。THREE.Color对象提供了大量的属性和函数。我们首先介绍第一组——可以设置THREE.Color对象的颜色:

❑ set(value):将颜色的值设置为所提供的值。这里的值可以是字符串、数字或现有的THREE.Color实例。

❑ setHex(value):将颜色的值设置为所提供的十六进制值。

❑ setRGB(r, g, b):将颜色的值设置为所提供的RGB值。颜色分量的值范围在0到1之间。

❑ setHSL(h, s, l):将颜色的值设置为所提供的HSL值。颜色分量的值范围在0到1之间。关于如何使用HSL配置颜色的详细解释,可参照http://en.wikibooks.org/wiki/Color_Models:_RGB,_HSV,_HSL。

❑ setStyle(style):将颜色的值设置为所提供的CSS颜色值。例如,你可以使用rgb(255, 0, 0)、#ff0000、#f00甚至red。

如果你想从现有的THREE.Color实例复制它的颜色值,则可以使用以下函数:

❑ copy(color):从提供的THREE.Color实例中复制颜色值到当前颜色对象。

❑ copySRGBToLinear(color):将提供的THREE.Color实例的颜色值从sRGB颜色空间转换为线性颜色空间,并将结果赋给当前颜色对象。sRGB颜色空间使用指数比例而不是线性比例。关于sRGB颜色空间的更多信息可以参阅:https://www.w3.org/Graphics/Color/sRGB.html。

❑ copyLinearToSRGB(color):将提供的THREE.Color实例的颜色值从线性颜色空间转换为sRGB颜色空间,并将结果赋给当前颜色对象。

❑ convertSRGBToLinear():将当前颜色从sRGB颜色空间转换为线性颜色空间。

❑ convertLinearToSRGB():将当前颜色从线性颜色空间转换为sRGB颜色空间。

如果你想要获取当前配置的颜色信息,THREE.Color对象还提供一些辅助函数:

❑ getHex():将该颜色对象的值以数字形式返回:435241。

❑ getHexString():将该颜色对象的值以十六进制字符串返回:0c0c0c。

❑ getStyle():将该颜色对象的值以CSS的形式返回:rgb(112, 0, 0)。

❑ getHSL(target):将该颜色对象的值以HSL的形式返回:{h: 0, s: 0, l:0}。当调用颜色对象的getHSL(target)函数时,如果提供了可选的target对象,则Three.js会直接将HSL值设置在target对象上。

Three.js还提供了通过更改THREE.Color对象的各个颜色分量来更改最终颜色的函数。

具体包括:

❑ offsetHSL(h, s, l):将提供的h、s和l值添加到当前颜色的h、s和l值中。

❑ add(color):将提供颜色的r、g和b值加到当前颜色对象的r、g、b值上。

❑ addColors(color1, color2):将color1和color2相加,并将结果设置到当前颜色对象上。

❑ addScalar(s):将s添加到当前颜色对象的RGB各个分量上。记住,颜色对象的内部表示使用的是0到1之间的浮点数,而不是常见的0到255的整数。

❑ multiply(color):将当前颜色对象的RGB值与color的RGB值相乘。

❑ multiplyScalar(s):将当前颜色对象的RGB值与s相乘。记住,颜色对象的内部表示使用的是0到1之间的浮点数,而不是常见的0到255的整数。

❑ lerp(color, alpha):根据alpha参数计算出一个介于当前颜色和color参数之间的插值颜色,并将结果设置到当前颜色对象。alpha属性定义了当前颜色和提供的颜色之间的插值位置。

除此之外,还有以下辅助函数:

❑ equals(color):如果提供的THREE.Color实例的RGB值与当前颜色的值匹配,则返回true。

❑ fromArray(array):具有与setRGB相同的功能,只不过输入从RGB值变为数字数组。

❑ toArray:返回一个包含三个元素的数组:[r, g, b]。

❑ clone:创建一个与当前对象具有完全相同颜色值的新颜色对象。

以上函数中,你可以看到有许多可以更改当前颜色的方式。这些函数大多数是Three.js内部使用的,但也提供了一种简便的方法来轻松更改光源和材质的颜色,而无须创建和分配新的THREE.Color对象。

到目前为止,我们已经了解了Three.js的基本光源类型以及如何配置阴影。你将以上这些光源组合使用已经可以满足大多数情况了。不过Three.js还是提供了一些用于非常特殊用途的光源。接下来我们将介绍这些光源。 ODd5wvjDO7shCRjb+FUPuxWZ1TfAeEpi1scY7efGX2919vMQep3uu2v0/cwGPkdu

点击中间区域
呼出菜单
上一章
目录
下一章
×