Three.js 入门系列(8):六种光源全解析 —— 关灯了,开光!

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() 指定照射方向。只支持 MeshStandardMaterialMeshPhysicalMaterial

看我的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 的付费课程)的学习笔记,代码为个人练习所写,概念讲解融入了个人的理解和比喻。

相关推荐
属于自己的天空2 小时前
每天省去重复 Prompt:我用 Skills 把 CRUD 生成标准化了
前端·后端
卡卡罗特AI2 小时前
GitHub怎么用?零基础,保姆级使用教程-上!建议收藏
前端·后端·github
自然 醒2 小时前
v-tooltip自定义指令封装
前端·javascript·vue.js
因_崔斯汀2 小时前
Three.js 3D 热力云图效果实现
前端·three.js
爱勇宝3 小时前
人到了一定年纪,才会看懂这些人性真相
前端·后端
梓䈑3 小时前
【用 Vibe Coding 实现的 C++17 在线判题系统】前端开发 + Web 自动化测试
前端·c++·ai编程
程序员黑豆4 小时前
鸿蒙应用开发 @BuilderParam 使用教程:实现灵活的 UI 插槽
前端·harmonyos
万少4 小时前
用 TraeWork 给小孩做一个家庭工作台
前端·人工智能·后端