Three.js 里有个很反直觉的事:你放了一个物体,加了材质,但打开页面------黑的。不是代码写错了,是没打光。就像你买了一盏很贵的灯,结果没插电。这节就是把电插上,把六种光源一个一个试过去。从环境光到聚光灯,看它们各自能把场景照亮成什么样。看完你就知道,光不是乱打的,每种光都有自己的脾气。
无光情况:

很多光线:
我们依旧准备之前材质篇用到的基础代码。
1. 先搭个展示台
在讲光源之前,先放了四个物体在场景里:球体、立方体、圆环、平面。材质统一用 MeshStandardMaterial,粗糙度 0.4。这样每种光源照上去的效果可以直观对比。
ini
const material = new THREE.MeshStandardMaterial()
material.roughness = 0.4
2. 六种光源详解
1. AmbientLight(环境光)------ 基础照明
csharp
js
// 实例化一个环境光对象
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
// ↑ ↑
// 颜色 强度
// (白色光) (0.5,中等亮度)
scene.add(ambientLight)
参数:
0xffffff:白色光0.5:强度,亮度中等
作用:可以均匀的照亮所有面,没有固定的方向,没有阴影,就像把一个透明的玻璃杯放在光线充足的室内。环境光能让杯子整体亮起来,你能透过它看到杯壁的另一面,但你看不出光是从哪个方向打过来的------因为它无处不在,又好像哪里都不在。这就是环境光:照亮物体,但不制造层次感。
可以看到我放置的gif图中,设置了淡粉色的环境光,舞台上的物体被某种淡粉色光线照亮了,并且甜甜圈物体的圈内壁也是一样的颜色,证明环境光真的很均匀。
② DirectionalLight(平行光)------ 模拟太阳
它是什么: 从一个方向平行照射,所有光线方向一致。物体受光面亮、背光面暗,立体感强,日常生活中太阳光就是最典型的平行光。早晨太阳从东边照过来,人的影子朝西;傍晚太阳在西边,影子朝东;正午太阳在头顶,影子最短。不同时间段,光照方向不同,人脸上的受光面和暗面也有明确的明暗对比。这就是平行光的特点------方向决定一切。
csharp
js
const directionalLight = new THREE.DirectionalLight(0x00fffc, 0.9)
// ↑ ↑
// 颜色 强度
// (青蓝色) (0.9,较亮)
directionalLight.position.set(1, 0.25, 0)
// ↑ ↑ ↑
// x y z
// (右) (上) (前)
scene.add(directionalLight)
参数:
0x00fffc:青蓝色(偏冷的光)0.9:强度,接近满亮position.set(1, 0.25, 0):光从右上方来(x正方向偏上)

我们可以借助平行光辅助器来查看光线从里过来,可以看到我们设置的光线位置是从x轴的正方向偏上,右侧微微上方打过来的,未受光的面完全黑色。
③ HemisphereLight(半球光)------ 天空+地面漫反射
js
const hemisphereLight = new THREE.HemisphereLight(0xff0000, 0x0000ff, 0.9)
// ↑ ↑ ↑
// 天空颜色 地面颜色 强度
// (红) (蓝) (0.9)
scene.add(hemisphereLight)
它是什么: 从上方和下方分别发出不同颜色的光。上方颜色照到物体的顶面,下方颜色照到底面,日出或日落的时候,太阳把天空染成暖色(红/橙),地面反射的光却是偏冷的(蓝/紫)。物体处在中间,顶部被暖光照亮,底部被冷光包围,中间区域两种光自然过渡,形成一种很柔和的氛围感。这就是半球光------它不是从一个方向打光,而是从"天"和"地"两个方向同时给颜色。
参数:
0xff0000(红色):天空颜色,照到物体的上面0x0000ff(蓝色):地面颜色,照到物体的下面0.9:强度

可以看到,我用了下方为蓝色,上方为红色,通过半圆光辅助器能看出光线进行了分割,可以看到场景中物体中段有种过渡的效果营造氛围感,此光线大有用处。
④ PointLight(点光源)------ 像灯泡
csharp
js
const pointLight = new THREE.PointLight(0xff9000, 1.5, 0, 2)
// ↑ ↑ ↑ ↑
// 颜色 强度 距离 衰减
// (橙色) (1.5) (0=无限远)(2=较快衰减)
pointLight.position.set(1, -0.5, 1)
// ↑ ↑ ↑
// x y z
// (右) (下) (前)
scene.add(pointLight)
它是什么: 实际上就是像灯泡一样的光源,向四面八方散发光芒,具体项目中可以用来当作火把或者蜡烛的微弱聚集光线,我们来看看它吧!
参数:
0xff9000:橙色1.5:强度0:距离(0 表示无限远,光不会消失)2:衰减速度(值越大,光随距离变暗得越快)

当我只给点光源,可以营造一种一开始很黑暗,然后点了一根蜡烛,烛光照射看到物体的感觉,我想如果在黑暗的环境中,人物举着火把或打火机前进,光源跟着人物走,越靠近物体,物体就越清晰。这种"靠近才看清"的真实感,就是点光源的拿手好戏。虽然点光源不能像DirectionalLight那样模拟全局太阳光,但在局部照明上,它非常实用。
⑤ RectAreaLight(矩形区域光)------ 柔光箱效果
csharp
js
const rectAeaLight = new THREE.RectAreaLight(0x4e00ff, 6, 1, 1)
// ↑ ↑ ↑ ↑
// 颜色 强度 宽 高
// (紫色) (6) (1)(1)
rectAeaLight.position.set(-1.5, 0, 1.5)
// ↑ ↑ ↑
// x y z
// (左) (中)(前)
rectAeaLight.lookAt(new THREE.Vector3())
// ↑
// 照射方向(默认指向原点 0,0,0)
scene.add(rectAeaLight)
它是什么: 从一个矩形区域向外发光,光线柔和,不是从一个点发出的。就好像摄影棚里的柔光箱------光从一大块区域均匀照出来,不刺眼,阴影很柔和,我想它可以模仿窗户打进来的光,还可以通过强度控制光线强度。
参数:
0x4e00ff:紫色6:强度(区域光需要较高的强度才明显)1, 1:矩形区域的宽度和高度
特点: 需要用 lookAt() 指定照射方向。只支持 MeshStandardMaterial 和 MeshPhysicalMaterial。

看我的gif,可以把球体想象成舞台模特,此刻相当于,摄影棚的柔光箱正对着球体。
⑥ SpotLight(聚光灯)------ 舞台追光灯
csharp
js
const spotLight = new THREE.SpotLight(0x78ff00, 4.5, 10, Math.PI * 0.1, 0.25, 1)
// ↑ ↑ ↑ ↑ ↑ ↑
// 颜色 强度 距离 角度 边缘 衰减
// (亮绿) (4.5)(10) (约18°) (0.25)(1)
spotLight.position.set(0, 2, 3)
// ↑ ↑ ↑
// x y z
// (中)(上)(前)
spotLight.target.position.x = -0.75
// ↑
// 目标X偏移(聚光灯指向偏左)
scene.add(spotLight)
scene.add(spotLight.target)
它是什么: 从一个点向一个方向发射锥形光束,光集中在特定区域,像我们日常去的一些漂亮饭餐厅都会使用暖色柔光聚光灯打向桌面,显得菜品颜色很漂亮鲜艳,体现氛围感和精致度。
**参数(按顺序):**z
0x78ff00(亮绿色):颜色4.5:强度(很强)10:距离(最远照 10 个单位)Math.PI * 0.1(约 18°):光束的锥角,越小越集中0.25:边缘衰减(0=边缘清晰,1=边缘完全模糊)1:距离衰减速度
特点: 必须设置 target 指定照射目标。

看到我gif中的聚光灯辅助器了嘛,就是绿色镂空锥体,没错它就是让我们观察光从哪里照向哪里,可以看到物体上有一个黄色的光照圈,这就是聚集光线,旁边白色的矩形是柔光箱效果的辅助器,这很酷,我觉得可以去用来锁定焦点。
2. 光线辅助器(Helpers)简要讲解
光源本身在场景中是看不见的,只能看到它照在物体上的效果。辅助器的作用是把光源的位置和方向可视化,方便调试。
csharp
js
// 半球光辅助
const hemisphereLightHelper = new THREE.HemisphereLightHelper(hemisphereLight, 0.2)
scene.add(hemisphereLightHelper)
// 平行光辅助
const directionalLightHelper = new THREE.DirectionalLightHelper(directionalLight, 0.2)
scene.add(directionalLightHelper)
// 点光源辅助
const pointLightHelper = new THREE.PointLightHelper(pointLight, 0.2)
scene.add(pointLightHelper)
// 聚光灯辅助
const spotLightHelper = new THREE.SpotLightHelper(spotLight)
scene.add(spotLightHelper)
// 聚光灯辅助需要每帧更新
window.requestAnimationFrame(() => {
spotLightHelper.update()
})
// 矩形区域光辅助(需要单独导入)
import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js'
const rectAreaLightHelper = new RectAreaLightHelper(rectAeaLight)
scene.add(rectAreaLightHelper)
各辅助器长什么样:
| 辅助器 | 显示内容 |
|---|---|
| HemisphereLightHelper | 一个球体,显示上下两种颜色 |
| DirectionalLightHelper | 一个箭头,显示方向 |
| PointLightHelper | 一个小球,显示光源位置 |
| SpotLightHelper | 一个锥体,显示光束范围和方向 |
| RectAreaLightHelper | 一个矩形框,显示发光区域 |
辅助器帮你"看见"光源的位置和方向,调试的时候很有用,项目做完就可以关掉了。
实际项目里不会六种光一起上------就像做饭不会把厨房里所有调料都倒进去。通常就是环境光打底,再加一两个主光源就够了。但每种光都试过之后,以后做项目时,看到场景你大概就能判断出:这里该用平行光模拟太阳,那里该用点光源做烛光,想突出某个物体就用聚光灯。光不是乱打的,每种光都有自己的脾气,知道它们各自擅长什么,场景就能亮得刚刚好。
最后我们来看看调整了聚光灯的位置,让我们的正方体成为焦点吧。

📚 本文是学习 Three.js Journey(Bruno Simon 的付费课程)的学习笔记,代码为个人练习所写,概念讲解融入了个人的理解和比喻。