2.1 灯具谱系:五类光源的分工 本节摘要:Three.js 的灯光分五类,各有一张岗位说明书:环境光铺底、方向光当太阳、点光源做灯泡、聚光灯造射灯、半球光补天地色差。本节承接第 1 章的素坯场景,讲清每类灯的照明模型与选用依据,并用五灯同台的沙盘案例演示一次完整布光。 从"为什么是黑的"开始 上一章换上了 MeshStandardMaterial,场景却黑成一团——这不是故障,是材质在如实汇报:没有光照输入,物理材质就无光可反。灯光与受光材质是配套件,装一必须装二。而一旦开始加灯,真正的难题随之而来:同样一个"照亮",环境光一个构造函数就能铺满,方向光也能照满全场,该用谁?答案藏在每类灯的照明模型里:光从哪里来、照到哪些地方、衰减不衰减、有没有方向。四问过后,灯具岗位自然清晰。
本节摘要:Three.js 的灯光分五类,各有一张岗位说明书:环境光铺底、方向光当太阳、点光源做灯泡、聚光灯造射灯、半球光补天地色差。本节承接第 1 章的素坯场景,讲清每类灯的照明模型与选用依据,并用五灯同台的沙盘案例演示一次完整布光。
上一章换上了 MeshStandardMaterial,场景却黑成一团——这不是故障,是材质在如实汇报:没有光照输入,物理材质就无光可反。灯光与受光材质是配套件,装一必须装二。而一旦开始加灯,真正的难题随之而来:同样一个"照亮",环境光一个构造函数就能铺满,方向光也能照满全场,该用谁?答案藏在每类灯的照明模型里:光从哪里来、照到哪些地方、衰减不衰减、有没有方向。四问过后,灯具岗位自然清晰。

环境光(AmbientLight)没有位置、没有方向,把指定颜色均匀撒到所有受光面上。它照不出任何明暗对比——每个面收到的光一模一样——因此永远不能当主光,它的岗位是抬底色:给阴影面留一口"活气",避免背光面死黑。经验值是拿主光强度的十分之一到五分之一当底。
方向光(DirectionalLight)模拟无限远的光源,所有光线彼此平行,只由 position 指向 target 的方向决定照明——位置远近不影响亮度,方向才是唯一变量。太阳、月光、整面天窗,都是它的戏份。它同时是默认的阴影担当,2.3 节的阴影相机就挂在它身上。
半球光(HemisphereLight)可以理解为"两色环境光":天空色从上往下照、地面反光色从下往上补,中间平滑过渡。户外场景用它替代环境光,物件的顶面与底面立刻有了环境依据——蓝天配土黄地面,物件底面微微泛暖,这是环境光一辈子做不出的效果。
点光源(PointLight)从一点向所有方向发光,亮度随距离衰减,是灯泡、火把、烛光的正身。衰减让它在近距离内很有戏剧感,也注定它照不远——大面积铺光用它是给自己挖坑。
聚光灯(SpotLight)在点光源基础上加了锥角:只有落在锥形范围内的物件被照亮,angle 控锥角、penumbra 控边缘软硬,射灯、车头灯、舞台追光全靠它点题。锥角小、距离近的聚光灯光影对比最锋利,是"展厅高级感"的头号功臣。
背景:货箱沙盘需要从"能看清"升级到"有氛围":客户给的参考图是冷调展厅——主光从左上打下,地面有淡淡反光,右后方有一束射灯打在最高的货箱上。
操作:按"先底、后形、再点戏"的顺序派灯,每盏灯一行注释说明岗位。
// 1. 底:半球光代替环境光,冷天光配灰地面反光 const hemi = new THREE.HemisphereLight(0xbfd8ff, 0x8a7f70, 0.5); stage.scene.add(hemi); // 2. 形:方向光当主光,从左上往右下打,让货箱产生体积 const sun = new THREE.DirectionalLight(0xffffff, 1.2); sun.position.set(-6, 10, 4); // 方向由位置指向原点决定 stage.scene.add(sun); // 3. 戏:聚光灯点题,锁定最高的那只货箱 const spot = new THREE.SpotLight(0xffe6c0, 30, 25, Math.PI / 9, 0.4, 1.5); // 颜色 强度 距离 锥角 半影 衰减 spot.position.set(4, 7, -3); spot.target.copy(tallestBox.position); // 锥体指向目标货箱 stage.scene.add(spot, spot.target); // target 也必须进场景才生效
结果:货箱迎光面明亮、背光面保有半球光的底色,最高货箱被一束暖光罩住,冷调场景里多了一处暖点——参考图的氛围基本复刻。
解读:两处最容易踩的坑都在这段代码里。第一,SpotLight 的 target 是独立对象,只设置 position 的灯会朝着默认目标(原点)照——想让锥体跟着走,必须把 target 一并 add 进场景并同步它的位置,这是聚光灯报障榜第一名。第二,强度数字与衰减模式绑定:上面聚光灯强度给了 30,是因为默认物理衰减下亮度随距离平方跌落,远处的灯必须给大数字;而方向光没有衰减,1.2 就已经很亮。把方向光也照抄成 30,画面立刻过曝——这也是 2.2 节要把衰减讲透的原因。
变式:把方向光的颜色换成 0xffd9b0(暖橙)、位置压低到 y 等于 2,沙盘瞬间变成黄昏仓库;再给聚光灯加一个每帧摆动的小动画(第 6 章的属性动画),射灯就扫成了仓库巡检灯。灯具就这五类,戏却能排出几十种,排练成本只是改两个数字。
事故一,"加了灯还是黑"。逐项排查:材质是否受光型号、灯是否 add 进了场景、强度是否给了物理模式下的合理量级——三点全对仍黑,查场景里是否存在一个强度为零的环境光把底色锁死,或贴图本身是纯黑。事故二,"画面像褪色旧照片"。典型原因是多灯色温互相拉扯:暖主光叠暖补光再叠暖点光,色相全挤在一个区间,画面失去对比;处置是保留一盏中性白或冷色灯当"锚",其余灯围绕它调温。事故三,"灯光一多帧率腰斩"。回看 2.2 的账:每盏灯都加重全部受光材质的着色负担,而三个点光源照同一区域在视觉上远不如一盏聚光加适度衰减;先合并岗位再谈加灯,是布光工位的节能守则。
补一条岗位交接的实务:灯具对象是可复用的——场景主题切换时,优先改既有灯的参数而不是删除重造,因为每次增删灯都会触发材质的着色程序重新编译,画面会顿一下;提前把可能上场的灯建好、用 visible 控制出勤,切换主题就只是改参数的轻量动作。这与 2.2 的登记表模式是同一思想的两个侧面:灯要少而稳,戏全靠参数。
灯已派到岗,但三颗旋钮还没校。下一节谈调光:强度单位为什么反直觉、色温区间怎么选、衰减曲线如何决定一盏灯像灯泡还是像手电。