【three.js教程】Three.js 灯光:给你的 3D 场景打上第一束光
2026/8/31 6:42:04 网站建设 项目流程

Three.js 灯光:给你的 3D 场景打上第一束光

原文出处:Three.js Manual – Lights
本文基于官方手册 Lights 章节整理,用通俗方式带你看懂 three.js 里各种"灯"该怎么用、什么时候该用哪种。

写在前面

前面几篇我们陆续搞定了场景、几何体、材质,模型摆好了、颜色也有了。但如果你刚建好一个场景、加上材质,结果画面是一片惨白、或者黑乎乎的,完全没有立体感。

原因很简单:没有光

之前我们用MeshBasicMaterial(不受光照影响的材质)时,不用管灯光也能看见东西。但一旦换成MeshPhongMaterialMeshStandardMaterial这类"会受光影响"的材质,灯光就成了刚需。这篇就带你看一遍 three.js 里的六种灯,环境光、半球光、平行光、点光、聚光灯和区域光。

为了方便演示,我们先准备一个标准场景:一块带棋盘格纹理的地面、一个立方体、一个球,相机放在斜上方,再挂上OrbitControls确保能拖动观察。

constfov=45;constaspect=2;// 画布默认宽高比constnear=0.1;constfar=100;constcamera=newTHREE.PerspectiveCamera(fov,aspect,near,far);camera.position.set(0,10,20);import{OrbitControls}from'three/addons/controls/OrbitControls.js';constcontrols=newOrbitControls(camera,canvas);controls.target.set(0,5,0);controls.update();

地面、立方体、球都用MeshPhongMaterial,这样灯光一上去就能立刻看出区别。

一、AmbientLight:环境光,均匀但"没立体感"

环境光是最简单的一种光——它没有方向,只是把整个场景的颜色乘上去

constcolor=0xFFFFFF;constintensity=1;constlight=newTHREE.AmbientLight(color,intensity);scene.add(light);

你可以把它理解成"大晴天把所有东西都均匀照亮"。它的工作原理其实就是一道公式:

最终颜色 = 材质颜色 × 灯光颜色 × 强度

划重点:环境光其实"不太像光"。因为它 100% 均匀,所以物体没有任何明暗交界、没有立体感,看起来是平的。

二、HemisphereLight:半球光,模拟"天光 + 地面反光"

半球光可以理解为环境光的升级版:它有两种颜色,一种从上方(天空)照下来,一种从下方(地面)反射上来。

constskyColor=0xB1E1FF;// 天蓝constgroundColor=0xB97A20;// 土黄橙constintensity=1;constlight=newTHREE.HemisphereLight(skyColor,groundColor,intensity);scene.add(light);

它依然不会有强烈的明暗对比,但物体朝上的一面会偏冷色、朝下的一面会偏暖色,比纯环境光自然得多。

三、DirectionalLight:平行光

平行光模拟的是"无限远处的光源",比如太阳。它的特点是:所有光线方向一致、互相平行,所以没有具体的发光点,只关心光从哪个方向来。

constcolor=0xFFFFFF;constintensity=1;constlight=newTHREE.DirectionalLight(color,intensity);light.position.set(0,10,0);light.target.position.set(-5,0,0);scene.add(light);scene.add(light.target);

常见坑:平行光是靠positiontarget两个点来决定方向的——光从position射向target。所以target也要加进场景scene.add(light.target)),否则它可能不生效。

调试时可以挂一个DirectionalLightHelper,用一个线框小飞机帮你直观看到光的方向:

consthelper=newTHREE.DirectionalLightHelper(light);scene.add(helper);

注意:每次改了positiontarget,都要调一下light.target.updateMatrixWorld()helper.update(),辅助箭头才会跟着动。

四、PointLight:点光

点光就是一个"会发光的点",光线从它向四面八方散射,类似现实里的灯泡、蜡烛。

constcolor=0xFFFFFF;constintensity=150;// 注意:点光强度通常要调大很多constlight=newTHREE.PointLight(color,intensity);light.position.set(0,10,0);scene.add(light);

两个关键点

  1. 点光的intensity默认偏小,手册里给了 150,比方向光的 1 大得多,别奇怪。
  2. 它有个distance属性:设为 0 表示照到无穷远;设成大于 0 的数,光会在distance范围内从满强度逐渐衰减到 0——你拖动distance就能看到光照范围收缩。

五、SpotLight:聚光灯

聚光灯 = 点光 + 一个锥形光束,只照亮锥体内部,像手电筒、舞台灯。

constcolor=0xFFFFFF;constintensity=150;constlight=newTHREE.SpotLight(color,intensity);scene.add(light);scene.add(light.target);// 同样需要 target 决定锥体朝向

它比点光多了两个核心参数:

  • angle(弧度):锥体张角大小。注意是弧度不是角度,所以手册里用DegRadHelper把角度和弧度互相转换。
  • penumbra(0~1):内外锥之间的"柔化过渡带"。0表示边缘锐利,1表示光从锥体中心就开始渐隐到边缘。想做柔和的舞台光,就把penumbra往 1 调。

:聚光灯的锥体默认"开口朝下",如果它埋在地面以下你可能根本看不到光锥。把distance调小一点(比如 5),就能看到张开的锥口了。

六、RectAreaLight:区域光

区域光就是一块"矩形发光面",像天花板上的长条灯、磨砂天窗。它最特别:

  • 只支持MeshStandardMaterialMeshPhysicalMaterial,所以得先把所有材质换成标准材质。
  • 使用前必须初始化RectAreaLightUniformsLib,否则灯能亮但效果会很怪。
  • 不用 target,而是用自身的rotation决定朝向。
  • 它的 Helper 必须是光的子节点(light.add(helper)),不能像别的 helper 那样直接加进场景。
import{RectAreaLightUniformsLib}from'three/addons/lights/RectAreaLightUniformsLib.js';import{RectAreaLightHelper}from'three/addons/helpers/RectAreaLightHelper.js';RectAreaLightUniformsLib.init();// 别忘了这步constcolor=0xFFFFFF;constintensity=5;constwidth=12;constheight=4;constlight=newTHREE.RectAreaLight(color,intensity,width,height);light.position.set(0,10,0);light.rotation.x=THREE.MathUtils.degToRad(-90);scene.add(light);consthelper=newRectAreaLightHelper(light);light.add(helper);

七、性能提醒

最后说一个很现实的点:每往场景里多加一盏灯,three.js 的渲染就会变慢一点。所以实战里要养成习惯——用尽可能少的灯达到你要的效果。

总结

灯光类型像什么有方向吗典型用途
AmbientLight均匀打底防止暗部太黑(垫底)
HemisphereLight天光+地反上/下两向自然户外补光
DirectionalLight太阳有(平行)主光源、阴影
PointLight灯泡四面八方局部点光源
SpotLight射灯锥形舞台、手电
RectAreaLight灯管/天窗矩形面室内写实照明

延伸阅读

  • Light – three.js docs
  • DirectionalLight
  • PointLight
  • SpotLight
  • RectAreaLight
  • 下一篇我们聊 Cameras(相机)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询