
Three.js 灯光给你的 3D 场景打上第一束光原文出处Three.js Manual – Lights本文基于官方手册 Lights 章节整理用通俗方式带你看懂 three.js 里各种灯该怎么用、什么时候该用哪种。写在前面前面几篇我们陆续搞定了场景、几何体、材质模型摆好了、颜色也有了。但如果你刚建好一个场景、加上材质结果画面是一片惨白、或者黑乎乎的完全没有立体感。原因很简单没有光。之前我们用MeshBasicMaterial不受光照影响的材质时不用管灯光也能看见东西。但一旦换成MeshPhongMaterial、MeshStandardMaterial这类会受光影响的材质灯光就成了刚需。这篇就带你看一遍 three.js 里的六种灯环境光、半球光、平行光、点光、聚光灯和区域光。为了方便演示我们先准备一个标准场景一块带棋盘格纹理的地面、一个立方体、一个球相机放在斜上方再挂上OrbitControls确保能拖动观察。constfov45;constaspect2;// 画布默认宽高比constnear0.1;constfar100;constcameranewTHREE.PerspectiveCamera(fov,aspect,near,far);camera.position.set(0,10,20);import{OrbitControls}fromthree/addons/controls/OrbitControls.js;constcontrolsnewOrbitControls(camera,canvas);controls.target.set(0,5,0);controls.update();地面、立方体、球都用MeshPhongMaterial这样灯光一上去就能立刻看出区别。一、AmbientLight环境光均匀但没立体感环境光是最简单的一种光——它没有方向只是把整个场景的颜色乘上去。constcolor0xFFFFFF;constintensity1;constlightnewTHREE.AmbientLight(color,intensity);scene.add(light);你可以把它理解成大晴天把所有东西都均匀照亮。它的工作原理其实就是一道公式最终颜色 材质颜色 × 灯光颜色 × 强度划重点环境光其实不太像光。因为它 100% 均匀所以物体没有任何明暗交界、没有立体感看起来是平的。二、HemisphereLight半球光模拟天光 地面反光半球光可以理解为环境光的升级版它有两种颜色一种从上方天空照下来一种从下方地面反射上来。constskyColor0xB1E1FF;// 天蓝constgroundColor0xB97A20;// 土黄橙constintensity1;constlightnewTHREE.HemisphereLight(skyColor,groundColor,intensity);scene.add(light);它依然不会有强烈的明暗对比但物体朝上的一面会偏冷色、朝下的一面会偏暖色比纯环境光自然得多。三、DirectionalLight平行光平行光模拟的是无限远处的光源比如太阳。它的特点是所有光线方向一致、互相平行所以没有具体的发光点只关心光从哪个方向来。constcolor0xFFFFFF;constintensity1;constlightnewTHREE.DirectionalLight(color,intensity);light.position.set(0,10,0);light.target.position.set(-5,0,0);scene.add(light);scene.add(light.target);常见坑平行光是靠position和target两个点来决定方向的——光从position射向target。所以target也要加进场景scene.add(light.target)否则它可能不生效。调试时可以挂一个DirectionalLightHelper用一个线框小飞机帮你直观看到光的方向consthelpernewTHREE.DirectionalLightHelper(light);scene.add(helper);注意每次改了position或target都要调一下light.target.updateMatrixWorld()和helper.update()辅助箭头才会跟着动。四、PointLight点光点光就是一个会发光的点光线从它向四面八方散射类似现实里的灯泡、蜡烛。constcolor0xFFFFFF;constintensity150;// 注意点光强度通常要调大很多constlightnewTHREE.PointLight(color,intensity);light.position.set(0,10,0);scene.add(light);两个关键点点光的intensity默认偏小手册里给了 150比方向光的 1 大得多别奇怪。它有个distance属性设为 0 表示照到无穷远设成大于 0 的数光会在distance范围内从满强度逐渐衰减到 0——你拖动distance就能看到光照范围收缩。五、SpotLight聚光灯聚光灯 点光 一个锥形光束只照亮锥体内部像手电筒、舞台灯。constcolor0xFFFFFF;constintensity150;constlightnewTHREE.SpotLight(color,intensity);scene.add(light);scene.add(light.target);// 同样需要 target 决定锥体朝向它比点光多了两个核心参数angle弧度锥体张角大小。注意是弧度不是角度所以手册里用DegRadHelper把角度和弧度互相转换。penumbra0~1内外锥之间的柔化过渡带。0表示边缘锐利1表示光从锥体中心就开始渐隐到边缘。想做柔和的舞台光就把penumbra往 1 调。坑聚光灯的锥体默认开口朝下如果它埋在地面以下你可能根本看不到光锥。把distance调小一点比如 5就能看到张开的锥口了。六、RectAreaLight区域光区域光就是一块矩形发光面像天花板上的长条灯、磨砂天窗。它最特别只支持MeshStandardMaterial和MeshPhysicalMaterial所以得先把所有材质换成标准材质。使用前必须初始化RectAreaLightUniformsLib否则灯能亮但效果会很怪。它不用 target而是用自身的rotation决定朝向。它的 Helper 必须是光的子节点light.add(helper)不能像别的 helper 那样直接加进场景。import{RectAreaLightUniformsLib}fromthree/addons/lights/RectAreaLightUniformsLib.js;import{RectAreaLightHelper}fromthree/addons/helpers/RectAreaLightHelper.js;RectAreaLightUniformsLib.init();// 别忘了这步constcolor0xFFFFFF;constintensity5;constwidth12;constheight4;constlightnewTHREE.RectAreaLight(color,intensity,width,height);light.position.set(0,10,0);light.rotation.xTHREE.MathUtils.degToRad(-90);scene.add(light);consthelpernewRectAreaLightHelper(light);light.add(helper);七、性能提醒最后说一个很现实的点每往场景里多加一盏灯three.js 的渲染就会变慢一点。所以实战里要养成习惯——用尽可能少的灯达到你要的效果。总结灯光类型像什么有方向吗典型用途AmbientLight均匀打底无防止暗部太黑垫底HemisphereLight天光地反上/下两向自然户外补光DirectionalLight太阳有平行主光源、阴影PointLight灯泡四面八方局部点光源SpotLight射灯锥形舞台、手电RectAreaLight灯管/天窗矩形面室内写实照明延伸阅读Light – three.js docsDirectionalLightPointLightSpotLightRectAreaLight下一篇我们聊 Cameras相机