第三章在Three.js中使用光源

在第1章,使用Three.js创建第一个3D场景中,您了解了Three.js的基础知识,在第2章,组成Three.js应用程序的基本组件中,我们更深入地了解了场景中最重要的部分:几何图形、网格和摄像机。您可能已经注意到,我们在那一章中跳过了探索灯光的细节,尽管它们构成了每3.js场景的重要组成部分。如果没有灯光,我们将不会看到任何被渲染的东西(除非我们使用基本的或线框材料)。由于Three.js包含几个不同的光源,每个光源都有特定的用途,因此我们将使用本章来解释光源的各种细节,并为接下来关于材料使用的章节做好准备。在本章结束时,您将知道可用灯光之间的差异,并能够为您的场景选择和配置正确的灯光。

注意,WebGL本身并没有对照明的固有支持。如果没有Three.js,您就必须编写特定的WebGL着色器程序来模拟这类灯光,这是相当困难的。在WebGL中模拟照明的一个很好的介绍可以在https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Lighting_in_WebGL上找到

在本章中,我们将介绍以下主题:

  1. 不同类型的照明在Three.js
  2. 工作与基本的灯
  3. 工作与特殊的灯

和所有的章节一样,我们有很多例子,你可以用它们来实验光的行为。本章示例可在提供来源的第03章文件夹中找到。

在 Three.js 中提供了什么照明类型?

在Three.js中有几种不同的灯,它们都有特定的行为和用法。在本章中,我们将讨论以下组灯:

  • THREE.AmbientLight:这是一个基本的灯光,其颜色将被添加到场景中对象的当前颜色中。
  • THREE.PointLight: 这是空间中的一个单点,光从它向各个方向扩散。此灯光可用于创建阴影。
  • THREE.SpotLight:这种光源有一种圆锥状的效果,比如台灯、天花板上的聚光灯或手电筒。这种光可以投射阴影。
  • THREE.DirectionalLight:这也被称为无限的光。来自这种光的光线可以被看作是平行的,类似于来自太阳的光。此灯光也可用于创建阴影。
  • THREE.HemisphereLight:这是一种特殊的光,可以通过模拟反射表面和微弱明亮的照明天空来创造更自然的户外照明。此灯也不提供任何与阴影相关的功能
  • THREE.RectAreaLight: 使用此光源,您可以指定光发出的区域,而不是空间中的单个点。三种。记录的光线不会投射任何阴影。
  • THREE.LightProbe: 这是一种特殊的光源,根据所使用的环境贴图,创建一个动态的环境光源来照亮场景。
  • THREE.LensFlare: 这不是一个光源,而是有三个光源。镜头闪光效果,您可以为场景中的灯光添加镜头闪光效果。

本章主要分为两个部分。首先,我们将看看基本的灯:THREE.AmbientLight, THREE.PointLight, THREE.SpotLight, 和THREE.DirectionalLight 所有这些灯都扩展了基本 THREE.Light 的对象。它提供了共享的功能。这里提到的灯是简单的灯,需要很少的设置,可以用于重新创建大多数所需的照明场景。在第二部分中,我们将看到一些特殊用途的灯和效果:THREE.HemisphereLight, THREE.RectAreaLight, THREE.LightProbe, 和THREE.LensFlare.你可能只需要在非常特殊的情况下才会有这些灯。

使用基本灯

我们将从最基本的灯开始:THREE.AmbientLight.

THREE.AmbientLight

当你创建一个 THREE.AmbientLight,颜色是全局应用的。这种光没有特定的方向,THREE.AmbientLight 不会造成任何阴影。你通常不会使用 THREE.AmbientLight 作为场景中的单一光源,因为它以相同的方式将其颜色应用于场景中的所有对象,而不管网格的形状如何。你可以把它和其他照明光源一起使用,比如 THREE.SpotLight 或 THREE.DirectionalLight,,软化阴影或添加一些额外的颜色。理解这个问题的最简单的方法是查看 chapter-03 文件夹中的 ambient-light.html 示例。在本例中,您将得到一个简单的用户界面,它可以用于修改 THREE.AmbientLight对象。在此场景中可用的环境灯光对象。

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

image-20230507163704262

图3.1-环境光设置为红色

正如您所看到的,我们场景中的每个元素现在都在其原始颜色中添加了一个红色。如果我们把颜色变成蓝色,我们会得到这样的东西:

image-20230507163737208

图3.2-环境光设置为蓝色

如此屏幕截图所示,蓝色将应用于所有对象,并在整个场景上投射发光。当你使用这个灯时,你应该记住的是,你应该对你指定的颜色非常保守。如果您指定的颜色太亮,您将很快得到一个完全过饱和的图像。除了颜色之外,我们还可以设置光的强度特性。这个属性决定了有多少个 THREE.AmbientLight 会影响场景中的颜色。如果我们拒绝使用它,则只有少量的颜色被应用于场景中的对象。如果我们把它打开,我们的场景就会变得非常明亮:

image-20230507163849521

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

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

const color = new THREE.Color(0xffffff);
const light = new THREE.AmbientLight(color);
scene.add(light);

创建一个T HREE.AmbientLight 非常简单,只需要几步。THREE.AmbientLight 没有位置,而是全局应用的,所以我们只需要指定颜色并将此光添加到场景中。此外,我们还可以在这个构造函数中为这个光的强度提供一个额外的值。因为我们没有指定,所以它使用默认强度1。

注意,在前面的代码片段中,我们传递了一个显式的 THREE.Color 对象的构造函数。 THREE.AmbientLight .我们也可以将颜色以字符串的形式传递——例如,“rgb(255,0,0)”或“hsl(0,100%,50%)”——或者作为一个数字传递,就像我们在前几章中所做的那样: 0xff0000。关于这方面的更多信息可以在使用这三个工具中找到。颜色对象的部分。

在我们讨论 THREE.PointLight, THREE.SpotLight, 和 THREE.DirectionalLight,首先,让我们来强调它们的主要区别——也就是它们发光的方式。下图显示了这三个光源的发光方式:

image-20230507164203699

图3.4-不同的光源如何发光

从此图中,您可以看到以下内容:

  • THREE.PointLight 从一个特定的点向各个方向发出光
  • THREE.SpotLight 从一个圆锥状的特定点发出光
  • THREE.DirectionalLight 不从单个点发光,而是从二维平面发光,其中光线相互平行

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

THREE.SpotLight

THREE.SpotLight 是你会经常使用的灯之一(特别是如果你想使用阴影)。

THREE.SpotLight 是一种具有圆锥状效果的光源。你可以把它与手电筒或灯笼进行比较。这个光源有一个它产生光的方向和一个角度。下面的屏幕截图显示了什么是 THREE.SpotLight 看起来像(spotlight.html):

image-20230507165140998

图3.5-聚光灯照明了一个场景 下表列出了可用于微调 THRE.SpotLight 的所有属性。首先,我们将查看特定于光的行为的属性:

名称描述
Angle确定从光中产生的光束的宽度。宽度以弧度表示,默认为数学。PI/3。
castShadow如果设置为true,则应用该属性的灯光将创建阴影。有关如何配置阴影,请参见下表
Color指示灯光的颜色。
decay表示您离光源越远,光源强度减小的量。衰减为2会产生更真实的光,默认值为1。此属性仅在WebGL渲染器上设置物理修正灯光属性时有效。
distance当此属性设置为非0值时,光强度将从光位置处的设置强度线性减小到指定距离处的0。
intensity指示光线照射的强度。该属性的默认值为1。
penumbra表示聚光灯硬币边缘的百分比,使其平滑(模糊)为0。它取一个介于0和1之间的值,其中默认值为0。
power表示在物理正确模式下渲染时灯光的功率(通过在WebGL渲染器上设置“physicallyCorrectLights”属性来启用此功能)。此属性以流明为单位进行测量,默认值为 4*Math.PI.
position指示灯在 THREE.Scene 中的位置
target有THREE.SpotLight,光指向的方向很重要。使用目标属性,您可以指 THREE.SpotLight 来查看场景中的特定物体或位置。请注意,此属性需要一个 THREE.Object3D 对象(如一个THREE.Mesh)。这与我们在第二章中看到的摄像头形成了鲜明对比,后者使用了 THREE.Vector3 在其查找函数中的作用。
visible如果此属性设置为true(默认),则灯将打开,如果设置为false,则灯将关闭。

图3.6- THREE.SpotLight 对象的特性

当您启用 THREE.SpotLight 时,您可以控制阴影的渲染方式。您可以通过 THREE.SpotLight 阴影属性来控制这一点。聚光灯,可包括以下内容:

名称描述
shadow.bias将投射的阴影移开或朝向投射阴影的对象。当您使用非常薄的对象时,您可以使用它来解决一些奇怪的效果。如果您在模型上看到了奇怪的阴影效果,那么这个属性的小值(例如,0.01)通常可以解决这个问题。此属性的默认值为0。
shadow.camera.far确定应创建的距离灯光阴影的距离。默认值为5000。请注意,您还可以设置为THREE.PerspectiveCamera 提供的所有其他属性。我们在第二章中展示过。
shadow.camera.fov确定用于创建阴影的视场的大小(请参见第2章中的“对不同的场景使用不同的摄像机”部分)。默认值为50。
shadow.camera.near确定应创建的距离灯光阴影的距离。默认值为50。
shadow.mapSize.width and shadow.mapSize.height确定使用了多少个像素来创建阴影。当阴影有锯齿状的边或看起来不平滑时,增加这些值。这在场景被渲染后就不能被更改了。两者的默认值都是512。
shadow.radius当该值设置为高于1时,阴影的边缘将变得模糊。如果将THREE.WebGlRenderer的shadowMap.type属性设置为THRE.BasicShadowMap,则不会有任何效果。

图3.7-THREE.SpotLight 对象的阴影特性

创建 THREE.SpotLight 非常简单。只需指定颜色,设置您所需的属性,并将其添加到场景中,如下所示:

const spotLight = new THREE.SpotLight("#ffffff")
spotLight.penumbra = 0.4;
spotLight.position.set(10, 14, 5);
spotLight.castShadow = true;
spotLight.intensity = 1;
spotLight.shadow.camera.near = 10;
spotLight.shadow.camera.far = 25;
spotLight.shadow.mapSize.width = 2048;
spotLight.shadow.mapSize.height = 2048;
spotLight.shadow.bias = -0.01;
scene.add(spotLight.target);

在这里,我们创建了 THREE.SpotLight 的一个实例,并设置了各种属性来配置光我们还明确地将castShadow属性设置为true,因为我们想要阴影。我们也需要将THREE.SpotLight指向某个地方,这是我们对目标物业所做的。在我们之前 可以使用此属性,我们首先需要将灯光的默认目标添加到场景中,如下所示:

scene.add(spotLight.target);

默认情况下,目标将设置为(0、0、0)。在本节的示例中,您可以更改目标属性的位置,并查看灯光是否跟随该对象的位置:

image-20230507171223384

图3.8-聚光灯指向一个目标

请注意,您还可以将灯光的目标设置为场景中的对象。在这种情况下,光的方向将被指向那个物体。如果光指向的对象四处移动,则光将继续指向该对象。

在本节开头的表格中,我们展示了一些属性,这些属性可用于控制THRE.SpotLight发出的光的方式。距离和角度属性定义了光锥的形状。角度属性定义圆锥体的宽度,使用距离属性设置圆锥体的长度。下图解释了这两个 值定义将从THRE.SpotLight接收光线的区域:

image-20230507171724236

图3.9-聚光灯的角度和距离

通常,您不需要设置这些值,因为它们具有合理的默认值,但您可以使用这些属性,例如,创建一个光束非常窄或光强度迅速降低的HREE.SpotLight实例。您可以使用的最后一个特性是半影特性来更改THRE.SpotLight产生灯光的方式。使用此属性,可以设置灯光强度在灯光圆锥体边缘的降低位置。在下面的屏幕截图中,您可以看到半影属性的作用结果。我们有一种非常明亮的光(高强度),当它到达锥体边缘时,强度会迅速减弱:

image-20230507172026681

图3.10-带有硬半暗带的聚光灯

有时,仅通过查看渲染场景就很难确定灯光的正确设置。出于性能原因,您可能需要微调照明区域,或者尝试将灯光移动到非常特定的位置。这可以通过使用THRE.SpotLightHelper来实现:

const spotLightHelper = new THREE.SpotLightHelper
 (spotLight);
scene.add(spotLightHelper)
// in the render loop
spotLightHelper.update();

通过前面的代码,您可以得到一个显示聚光灯细节的大纲,并可以帮助调试和正确定位和配置您的光线:

image-20230507172522657

图3.11-启用了助手的聚光灯

在转到下一个光源之前,我们将快速查看THREE.SpotLight对象的阴影相关属性。您已经了解到,我们可以通过将THREE.SpotLight实例的castShadow属性设置为true来获得阴影。您还知道,THREE.Mesh对象有两个与阴影相关的属性。为应该投射阴影的对象设置castShadow属性,并为应该显示 阴影Three.js还允许对阴影的渲染方式进行非常精细的控制。这是通过我们在本节开头的表中解释的几个属性来完成的。使用shadow.camera.near、shadow.caera.far和shadow.camela.fov,您可以控制此灯光投射阴影的方式和位置。对于THREE.SpotLight实例,不能直接设置shadow.camera.fov。此属性基于THRE.SpotLight的角度属性。此 其工作方式与我们在第2章中解释的透视相机的视场相同。看到这一点的最简单方法是添加一个THREE.CameraHelper;您可以通过选中菜单的阴影辅助复选框并使用相机设置来实现这一点。如您在以下屏幕截图中所见,选中此复选框将显示用于确定此灯光阴影的区域:

image-20230507172638704

图3.12-启用了阴影辅助器的聚光灯

当调试带有阴影的问题时,请添加 THREE.CameraHelper 很有用。要做到这一点,只需添加以下几行:

const shadowCameraHelper = new THREE.CameraHelper
 (spotLight.shadow.camera);
scene.add(shadowCameraHelper);
// in the render loop
shadowCameraHelper.update();

我将以几个指针结束这部分,以防您遇到阴影的问题。

如果阴影看起来是块状的,可以增加shadow.mapSize.width和shadow.mapSize.Height属性,并确保用于计算阴影的区域紧密包裹对象。您可以使用shadow.camera.near、shadow.caera.far和shadow.caera.fov属性来配置此区域。

请记住,您不仅必须告诉灯光投射阴影,还必须通过设置castShadow和receiveShadow属性来告诉每个几何体它是否会接收和/或投射阴影。

阴影偏差

如果在场景中使用薄对象,渲染阴影时可能会看到奇怪的工影。您可以使用阴影。偏差属性来略微偏移阴影,这通常会解决这些问题。

如果您想要更柔和的阴影,可以在THRE.WebGLRenderer上设置不同的shadowMapType值。默认情况下,此属性设置为THRE.PCFShadowMap;如果将此属性设置为PCFSoftShadowMap,则会得到较柔和的阴影。

现在,让我们来看看列表中的下一个光源:THREE.PointLight.

THREE.PointLight

THRE.PointLight是一种从单个点向所有方向照射光线的光源。点光源的一个很好的例子是向夜空或篝火发射信号弹。就像所有的灯一样,我们有一个特定的例子,你可以用来玩THRE.PointLight。如果你看 chapter-03 文件夹中的point-light.html,你可以在这里找到一个例子,THRE.PpointLight 正在我们也用于其他灯的同一场景中使用:

image-20230507173733826

图3.13-启用了助手的指针灯

正如您从前面的屏幕截图中所看到的,此光将发射到各个方面。就像我们之前看到的聚光灯一样,这盏灯也有一个助手,你也可以用同样的方式使用它。您可以将其看作是场景中心的线框:

const pointLightHelper = new THREE.PointLightHelper
 (pointLight);
scene.add(pointLightHelper)
// in the render loop
pointLightHelper.update();

THRE.PointLight与THRE.SpotLight共享多个属性,您可以使用这些属性来配置此灯光的行为:

名称描述
color这个光源发出的光的颜色。
distance指示光线照射到的距离。默认值为0,这意味着光的强度不会根据距离而降低。
intensity指示光线照射的强度。默认为1。
position指示灯光在THRE.Scene中的位置。
visible确定指示灯是关闭还是点亮。如果此属性设置为true(默认),则此灯将打开,如果设置为false,则该灯将关闭。
decay指示离光源越远,光强度减小的量。衰减为2会产生更逼真的灯光,默认值为1。只有当physicallyCorrectLights属性是在WebGLRenderer上设置的。
power指在物理正确模式下渲染时灯光的功率(通过将physicalyCorrectLights属性设置为打开来启用此功能WebGLRenderer)。此特性以流明和默认值为单位测量是 4*Math.PI.。功率也与强度特性直接相关((power = intensity * 4π)

图3.14-THREE.PointLight 对象的特性

除了这些属性外,THRE.PointLight对象的阴影可以以与THRE.SpotLight的阴影相同的方式进行配置。在接下来的几个示例和屏幕截图中,我们将展示这些属性是如何为THRE.PPointLight工作的。首先,让我们看看如何创建THRE.PpointLight:

const pointLight = new THREE.PointLight();
scene.add(pointLight);

这里没有什么特别的-我们只是定义灯光并将其添加到场景中;当然,您也可以设置我们刚刚展示的任何属性。THRE.SpotLight对象的两个主要特性是距离和强度。通过距离,可以指定灯光在衰减到0之前发射的距离。例如,在下面的屏幕截图中,我们将distance属性设置为 低值,并稍微增加了强度属性以模拟树木之间的篝火:

image-20230507202730768

图3.15:低距离和高强度的点灯

在本例中,您无法设置功率和衰减属性;如果您想模拟真实场景,这些属性非常有用。一个很好的例子可以在Three.js网站上找到: https://threejs.org/examples/#webgl_lights_physical.

THREE.PointLight还使用相机来确定在哪里绘制阴影,因此您可以使用THREE.CameraHelper来显示该相机覆盖的部分。此外,THRE.PointLight提供了一个辅助对象THRE.PPointLightHelper,用于显示THRE.PpointLight的灯光照射位置。启用两者后,您将获得以下非常有用的调试信息:

image-20230507203314029

图3.16-启用了助手的指针灯

如果您仔细查看前面的屏幕截图(图3.16),您可能会注意到阴影是在阴影相机显示的区域之外创建的。这是因为阴影辅助对象仅显示从点光源的位置向下投射的阴影。您可以将THREE.PointLight可视化为立方体,其中每一侧都会发光并可以投射阴影。在这种情况下,THRE.ShadowCameraHelper仅显示正在投射的阴影。

我们将讨论的最后一个基本要点是 THREE.DirectionalLight.

THREE.DirectionalLight

这种类型的光源可以被认为是一种非常遥远的光。它发出的所有光线都是相互平行的。太阳就是一个很好的例子。太阳离我们太远了我们在地球上接收到的光线(几乎)是相互平行的。THRE.DirectionalLight和THRE.SpotLight(我们之前看到过)之间的主要区别是,这种光不会它离光源越远就减少,就像使用THRE.SpotLight一样(可以使用距离和指数参数对此进行微调)。由THREE.DirectionalLight照亮的整个区域接收相同强度的光。要查看此操作,请查看以下directional-light.html示例:

image-20230509231119271

图3.17-模拟日落的方向性光线

正如您所看到的,使用THRE.DirectionalLight可以很容易地模拟日落。就像THRE.SpotLight一样,您可以在该灯光上设置几个属性。例如,可以设置灯光的强度特性及其投射阴影的方式。THRE.DirectionalLight有很多与THRE.SpotLight相同的属性:position, target, intensity, castShadow, shadow.camera.near, shadow.camera.far, shadow.mapSize.width, shadow.mapSize.width,和shadowBias。了解更多信息关于这些属性的信息,您可以在THRE.SpotLight上查看前面的部分。

如果你回头看THREE.SpotLight的例子,你会发现我们必须定义应用阴影的光锥。由于THRE.DirectionalLight的所有光线都是平行的,因此我们没有需要应用阴影的圆锥体;相反,我们有一个长方体区域(内部用THREE.OrthographicCamera表示),正如您在下面的屏幕截图中看到的那样,我们在其中启用了阴影助手:

image-20230509231119271

图3.18-显示长方体阴影区域的定向光

位于这个立方体内的所有东西都可以投射和接收来自光线的阴影。就像 THREE.SpotLight,你定义对象周围的区域越紧密,你的阴影就越好。请使用以下属性来定义此多维数据集:

directionalLight.castShadow = true;
directionalLight.shadow.camera.near = 2;
directionalLight.shadow.camera.far = 80;
directionalLight.shadow.camera.left = -30;
directionalLight.shadow.camera.right = 30;
directionalLight.shadow.camera.top = 30;
directionalLight.shadow.camera.bottom = -30;

您可以将其与我们在第2章中使用不同场景的不同摄像机部分中配置正交法摄像机的方式进行比较。

正如我们在本节中已经看到的,光源使用颜色。目前,我们刚刚使用十六进制字符串配置了颜色,但THREE.Color对象为创建初始颜色对象提供了许多不同的选项。在下一节中,我们将探讨THREE.Color对象所提供的功能。

使用 THREE.Color 对象

在Three.js中,当需要提供颜色(例如,材质、灯光等)时,可以传入一个Three.color对象;否则,Three.js将从传入的字符串值中创建一个,就像我们在THRE.AmbientLight中看到的那样。Three.js在解析Three.Color构造函数的输入时非常灵活。您可以通过以下方式创建THREE.Color对象:

  • Hex string:new THREE.Color("#ababab") 将根据传入的CSS颜色字符串创建一个颜色。
  • Hex value: new THREE.Color(0xababab) 将根据传入的十六进制值创建颜色。如果你知道十六进制的值,这通常是最好的方法。
  • RGB string: new THREE.Color("rgb(255, 0, 0)") 或 new THREE.Color("rgb(100%, 0%, 0%)"。
  • Color name:您也可以使用命名的颜色—例如,, new THREE.Color( 'skyblue' )。
  • HSL string:如果您喜欢在HSL域而不是RGB域中工作,您可以用HSL 传值。new THREE.Color("hsl(0, 100%, 50%)")。
  • 单独的RGB值:您可以按从0到1的比例指定各个RGB组件:new THREE.Color( 1, 0, 0 )。

如果你想在构造后更改颜色,你必须创建一个新的THREE.color对象或修改THREE.Coller对象的内部属性。THREE.Color对象带有一大组属性和函数。第一组功能允许您设置THREE的颜色。颜色对象:

  • 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颜色空间。
  • convertSGRBToLinear():将当前颜色从sRGB颜色空间转换为线性颜色空间。
  • convertLinearToSGRB():将当前颜色从线性颜色空间转换为sRGB颜色空间。

如果您想要关于当前配置的颜色的信息,这 THREE.Color 对象还提供了一些辅助函数:

  • getHex():返回这个颜色对象的值为一个数值: 435241。
  • getHexString():将此颜色对象的值返回为十六进制字符串: 0c0c0c。
  • getStyle():将此颜色对象的值返回为基于css的值:rgb(112、0、0)。
  • getHSL(target):将此颜色对象的值返回为HSL值({ h: 0,s: 0、l: 0 })。如果提供可选的目标对象,Three.js将在该对象上的h、s和l属性。

Three.js还提供了通过修改各个颜色组件来更改当前颜色的功能。如下所示:

  • offsetHSL(h, s, l):将提供的h、s和l值添加到当前颜色的h、s和l值中。
  • add(color): 添加提供给当前颜色的颜色的r、g和b值。
  • addColors(color1, color2):添加颜色1和颜色2,并将当前颜色的值设置为结果。
  • addScalar(s):向当前颜色的RGB组件添加一个值。请记住,内部值使用的范围是从0到1。
  • multiply(color):将当前RGB值与THREE.Color. 中的RGB值相乘。
  • multiplyScalar(s):将当前的RGB值乘以所提供的值。请记住,内部值的范围在0到1之间。
  • lerp(color, alpha):查找介于此对象的颜色与所提供的颜色属性之间的颜色。alpha属性定义了当前颜色和提供的颜色之间的距离。

最后,有几个基本的辅助方法可用:

  • equals(color): 如果这三个的RGB值,则返回true。所提供的颜色实例与当前颜色的值相匹配
  • fromArray(array):具有与setRGB相同的功能,但是现在,RGB值可以作为一个数字数组提供
  • toArray:返回一个包含三个元素的数组
  • clone:创建一个颜色的精确副本

在前面的列表中,您可以看到有多种方法可以更改当前颜色。Three.js内部使用了许多这些函数,但它们也提供了一种很好的方法来轻松更改灯光和材质的颜色,而无需创建和分配新的Three.color对象。

到目前为止,我们已经研究了Three.js提供的基本灯光以及阴影是如何工作的。在大多数情况下,您将在场景中使用这些灯光的组合。Three.js还为非常特殊的用例提供了一些特殊的灯。我们将在下一节中这些。

使用特殊灯

在关于特殊灯光的这一节中,我们将讨论three.js提供的三种额外灯光。首先,我们将介绍three.HemisphereLight,它有助于为户外场景创造更自然的照明。然后,我们将看到THREE.RectAreaLight,它从大面积而不是单个点发射光。接下来,我们将研究如何使用LightProbe基于立方体贴图应用光线,最后,我们将向您展示如何将镜头放大效果添加到场景中。

我们要看到的第一个特殊的灯是 THREE.HemisphereLight.

THREE.HemisphereLight

半球灯光

有了THRE.HemisphereLight,我们可以创造出更自然的户外照明。如果没有这种光,我们可以通过创建THREE.DirectionalLight来模拟户外太阳,也许再添加一个THREE.AmbientLight,为场景然而,这样做看起来并不自然。当你在户外时,并不是所有的光线都直接照射进来从上面看:大部分被大气散射,并被地面和其他物体反射。 THREE.js中的THREE.HemisphereLight就是为这个场景创建的。这是一个简单的方法更自然的户外照明。要查看一个示例,请查看 hemisphere-light.html 如下图所示:

image-20230509234134866

图3.19-半球灯

如果你仔细看这个屏幕截图,你会看到半球光的底色更多地显示在底部,而天空的颜色(通过颜色属性设置)在场景的顶部可见。在本例中,您可以设置这些颜色及其强度。创建一个半球光和创建其他任何灯一样简单:

const hemiLight = new THREE.HemisphereLight(0x0000ff,
 0x00ff00, 0.6); hemiLight.position.set(0, 500, 0);
scene.add(hemiLight);

您只需指定从天空接收到的颜色、从地面接收到的颜色以及这些灯光的强度。如果您以后要更改这些值,您可以通过以下属性访问它们:

属性描述
groundColor指示从地面发出的颜色
color指示从天空发出出来的颜色
intensity指示着光所照射的强度

图3.20-THREE.HemisphereLight 对象属性

由于HemisphereLight的作用类似于THREE.AmbientLight对象,只会为场景中的所有对象添加颜色,因此它无法投射阴影。到目前为止,我们看到的灯光更加传统。下一个属性允许您模拟来自矩形光源的光,例如,窗口或计算机屏幕。

THREE.RectAreaLight

使用THRE.RectAreaLight,我们可以定义一个发光的矩形区域。在我们看细节之前,让我们先看看我们的目标结果(rectarea-light.html打开了这个例子);以下屏幕截图显示了几个THREE.RectAreaLight对象:

image-20230509235126006

图3.21-整个表面的发光

您在这个屏幕截图中看到的是,我们定义了三个three.RectAreaLight对象,每个对象都有自己的颜色。您可以看到这些灯光是如何影响整个区域的,当您移动它们或更改它们的位置时,您可以看到场景中的不同对象是如何受到影响的。

我们还没有探索不同的材料以及光是如何影响它们的。我们将在下一章第4章“使用Three.js材料”中进行此操作。THRE.RectAreaLight仅适用于THRE.MeshStandardMaterial或THRE.MashPhysicalMaterial。有关这些材料的更多信息将在第4章中介绍。

要使用THREE.RectAreaLight,我们需要采取一些额外的小步骤。首先,我们需要加载并初始化RectAreaLightUniformsLib;以下是该灯所需的一组附加的低级WebGL脚本:

import { RectAreaLightUniformsLib } from "three/examples/jsm/lights/RectAreaLightUniformsLib.js";
...
RectAreaLightUniformsLib.init();
const rectLight1 = new THREE.RectAreaLight
 (0xff0000, 5, 2, 5);
rectLight1.position.set(-3, 0, 5);
scene.add(rectLight1);

如果你看一下这个对象的构造函数,你会发现它有四个属性。第一个是光的颜色,第二个是强度,最后两个定义了光的面积有多大。请注意,如果你想像我们在示例中所做的那样可视化这些光,你必须自己创建一个矩形,其位置、旋转和大小与THRE.RectAreaLight相同。

这种灯可以用来创造一些不错的效果,但它可能需要一些实验来达到你想要的效果。同样,在这个例子中,你在右边有一个菜单,你可以用它来处理各种设置。

在Three.js的最新版本中,添加了一种新的灯,名为THRE.LightProbe。这种灯类似于THRE.AmbientLight,但考虑了WebGLRenderer的立方体映射。这是我们将在本章中讨论的最后一个光源。

THREE.LightProbe

在前一章中,我们谈了一下什么是立体式地图。使用立体图,您可以在一个环境中显示您的模型。在上一章中,我们使用立体图创建一个随相机视图旋转的背景:

image-20230511211347322

图3.22-第2章的曲线示例

正如我们将在下一章中看到的,我们可以使用立方体贴图中的信息来显示对材料的反射。不过,通常情况下,这些环境贴图不会为场景提供任何光线。然而,使用THREE.LightProbe,我们可以从立方体贴图中提取照明级别信息,并使用它来照亮我们的模型。因此,您将得到的看起来有点像THREE.AmbientLight,但它会根据对象在场景中的位置和立方体贴图中的信息来影响对象

最简单的解释方法是看一个例子。在浏览器中打开light-probe.html;您将看到下面的场景:

image-20230511211616513

图3.23-洞穴模型的光探测器

在前面的示例中,我们有一个在类似洞穴的环境中建立的模型。你可以看到,如果你旋转相机的是,基于环境的光线,我们的模型的光线略有不同。在前面的截图中,我们看到的是物体的后面,它在洞穴的更深处,所以模型的颜色更暗。如果我们完全旋转相机,并将洞穴的入口设置在我们的背部,我们会看到模型更亮,接收到更多的光:

image-20230511211740806

图3.24-洞穴中的模型接收更多的光线

这是一个非常巧妙的技巧,可以让你的物体看起来更像生命,更不平坦,还有一个THREE.LightProbe,你的模型将接收光不均匀,这看起来更好。

设置一个 THREE.LightProbe 是一个更多的工作,但只需要做一次时,你创建你的场景。只要您不改变环境,您就不需要重新计算这 THREE.LightProbe对象:

Import { LightProbeGenerator } from "three/examples/jsm/lights//LightProbeGenerator";
...
const loadCubeMap = (renderer, scene) => {
 const base = "drachenfels";
 const ext = "png";
 const urls = [
 "/assets/panorama/" + base + "/posx." + ext,
 "/assets/panorama/" + base + "/negx." + ext,
 "/assets/panorama/" + base + "/posy." + ext,
 "/assets/panorama/" + base + "/negy." + ext,
 "/assets/panorama/" + base + "/posz." + ext,
 "/assets/panorama/" + base + "/negz." + ext,
 ];
 new THREE.CubeTextureLoader().load(urls, function
 (cubeTexture) {
 cubeTexture.encoding = THREE.sRGBEncoding;
 scene.background = cubeTexture;
 const lp = LightProbeGenerator.fromCubeTexture
 (cubeTexture);
 lp.intensity = 15;
 scene.add(lp);
 });
};

在前面的代码片段中,我们做了两件主要的事情。首先,我们使用THREE.CubeTextureLoader加载一个立方体映射。正如我们将在下一章中看到的那样,立方体地图由六个图像组成,代表立方体的六个面,它们共同构成了我们的环境。加载后,我们将其设置为场景的背景(请注意,THRE.LightProbe不需要这样做)。

现在我们有了这个cubemap,我们可以从中生成一个THREE.LightProbe。这是通过将cubeTexture传递给LightProbeGenerator来完成的。结果是一个THREE.LightProbe,我们将其添加到场景中,就像任何其他灯光一样。就像使用THREE.AmbientLight一样,可以通过设置强度属性来控制该灯光对网格照明的贡献程度

注意

Three.js还提供了另一种LightProbe:THRE.HemisphereLightProbe。这一种与普通的THRE.HimisphereLight工作原理基本相同,但内部使用LightProbe

本章的最后一个对象不是光源,而是在电影中经常看到的镜头中使用的技巧:THREE.LensFlare

THREE.LensFlare

你可能已经很熟悉镜头耀斑了。例如,当你直接拍摄太阳或其他明亮的光源时,它们就会出现。在大多数情况下,你想要避免这种情况,但对于游戏和3d生成的图像,它提供了一个很好的效果,使场景看起来更真实一些。Three.js还支持镜头照明弹,并且可以很容易地将它们添加到你的场景中。在最后一节中,我们将向场景添加一个镜头,并创建如下截图所示的输出;你可以通过打开lens-flare.html自己看到这一点:

image-20230511212325156

图3.25-当你观察光线时,会出现一个镜头闪光

我们可以通过实例化镜头耀斑对象和添加来创建一个镜头耀斑

import {
 Lensflare,
 LensflareElement,
} from "three/examples/jsm/objects/Lensflare";
const textureLoader = new THREE.TextureLoader()
const textureFlare0 = textureLoader.load
 ('/assets/textures/lens-flares/lensflare0.png')
const textureFlare1 = textureLoader.load
 ('/assets/textures/lens-flares/lensflare3.png')
const lensFlare = new LensFlare();
lensFlare.addElement(new LensflareElement
 (textureFlare0, 512, 0));
lensFlare.addElement(new LensflareElement
 (textureFlare1, 60, 0.6));
lensFlare.addElement(new LensflareElement
 (textureFlare1, 70, 0.7));
lensFlare.addElement(new LensflareElement
 (textureFlare1, 120, 0.9));
lensFlare.addElement(new LensflareElement
 (textureFlare1, 70, 1.0));
pointLight.add(lensFlare);

LensFlare元素只是LensFlareElement对象的一个容器,而LensFlareNode是您在查看光源时看到的工件。然后,我们将LensFlare添加到光源中,就完成了。如果您查看代码,您会看到我们为每个LensFlareElement传递了几个属性。这些属性决定LensFlareElement的外观以及它在屏幕上的渲染位置。要使用此元素,我们可以应用以下构造函数参数:

属性描述
texture纹理是决定耀斑形状的图像。
size我们可以指定耀斑应该有多大。大小表示以像素为单位的大小。如果指定-1,则将使用纹理本身的大小。
distance表示从光源(0)到照相机(1)的距离。使用此方法将镜头耀斑放在正确的位置。
color表示耀斑的颜色。

图3.26–THREE.LensFlareElement对象的属性

首先,让我们仔细看看第一个LensFlareElement :

const textureLoader = new THREE.TextureLoader();
const textureFlare0 = textureLoader.load( "/assets/textures/lens-flares/lensflare0.png");
lensFlare.addElement(new LensflareElement(textureFlare0, 512, 0));

第一个参数,纹理,是一个显示耀斑的形状和一些基本着色的图像。我们用一个 THREE.TextureLoader ,其中我们可以简单地添加纹理的位置:

image-20230511212720193

图3.27-示例中使用的镜头闪光

第二个参数是这个耀斑的大小。因为这是我们在光源本身看到的耀斑,我们将把它变得相当大:在这种情况下是512像素。接下来,我们需要设置这个耀斑的距离属性。你在这里设置的是光源和相机中心之间的相对距离。如果我们将距离设置为0,纹理将显示在光的位置,如果我们将它设置为1,它将显示在相机的位置。在这种情况下,我们将它直接把它放在光源上。

现在,如果您回顾其他光片元素对象的位置,您会看到我们将它们以0到1的间隔定位,这将导致您打开lens-flare.html示例时看到的效果:

const textureFlare1 = textureLoader.load( "/assets/textures/lens-flares/lensflare3.png");
lensFlare.addElement(new LensflareElement(textureFlare1, 60, 0.6));
lensFlare.addElement(new LensflareElement(textureFlare1, 70, 0.7));
lensFlare.addElement(new LensflareElement(textureFlare1, 120, 0.9));
lensFlare.addElement(new LensflareElement(textureFlare1, 70, 1.0));

据此,我们讨论了Three.js

总结

在本章中,我们介绍了许多关于Three.js中可用的不同类型的灯的信息。您了解到,配置灯光、颜色和阴影并不是一门精确的科学。为了得到正确的结果,您应该尝试使用不同的设置,并使用一个lil。使用GUI控件来调整您的配置。不同的光以不同的方式表现,正如我们将在第四章中看到的,材料对光的反应也有所不同。

THREE.AmbientLight颜色会添加到场景中的每种颜色中,通常用于平滑硬颜色和阴影。THRE.PointLight向所有方向发射光线,并可以投射阴影。THREE.SpotLight 是一种类似手电筒的灯。它具有圆锥形,可以配置随着距离的推移而褪色,并且可以投射阴影。我们还研究了THREE.DirectionalLight。这种光可以比作遥远的光,比如太阳,太阳的光线相互平行另一种,其强度不会随着距离配置目标越远而降低,以及这也可以投射阴影。

除了标准灯,我们还研究了一些更专业的灯。为了更自然户外效果,您可以使用THRE.HemisphereLight,它将地面和天空考虑在内反思。THREE.RectAreaLight不是从一个点发光,而是从一个大的点发光地区我们还通过使用HRE.LightProbe展示了一种更先进的环境照明,其使用来自环境地图的信息来确定物体是如何被照明的。最后,我们向您展示了如何使用THREE.LenseFlare对象添加摄影镜头光斑。

在到目前为止的章节中,我们已经介绍了几种不同的材料,在本章中,您看到并不是所有的材料都以相同的方式响应可用的灯。在第4章中,我们将概述在Three.js中可用的材料。