three.js Light 光照抽象基类解析:继承体系、核心属性与资源释放机制
2026/9/8 21:41:52 网站建设 项目流程

three.js Light 光照抽象基类解析:继承体系、核心属性与资源释放机制

【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js

Light是 three.js 中所有光源的抽象基类,AmbientLightDirectionalLightPointLightSpotLight等一切具体光源类型都继承自它。本文以 docs/pages/Light.html.md 文档为骨架,结合 src/lights/Light.js 及其实子类的源码实现,系统讲解 Light 的类继承关系、构造参数语义、color/intensity/isLight 等核心属性的底层实现,以及 dispose() 沿继承链级联释放 GPU 资源的真实机制,帮助你建立“从抽象基类到具体光源”的完整认知。

Light 是什么:位于事件体系顶端的光照抽象层

three.js 的光照系统从Light抽象类开始。它定义了两条最基本的信息——颜色(color)强度(intensity),具体光源类型只需在此基础上添加方向、衰减范围、阴影等自身特征即可。

从文档页开头给出的继承链可以看到 Light 在整个对象模型中的位置:

EventDispatcher → Object3D → Light

也就是说Light继承自 src/core/Object3D.js,因此每个光源实例天然具备三维空间中positionrotationscaleparent/children等变换与场景图能力(光源可以作为节点加入场景并参与层级变换)。而 Object3D 继承自EventDispatcher,意味着光源上也可以派发与监听事件(例如 Object3D 的dispose事件)。

在实际源码中,Light类定义于 src/lights/Light.js,其中src/lights目录下直接派生出的具体光源包括:AmbientLight(环境光)、DirectionalLight(平行光/方向光)、HemisphereLight(半球光)、PointLight(点光源)、RectAreaLight(矩形面光源)、SpotLight(聚光灯)以及LightProbe(光照探针),另有webgpu子目录存放 WebGPU 后端的光照相关实现。

需要特别说明:Light是抽象基类,不应直接实例化。文档将其构造函数标注为 abstract,实际使用中应实例化其具体子类,例如new THREE.AmbientLight()new THREE.PointLight()

构造函数与参数语义

new Light( color : number | Color | string, intensity : number ) // 抽象,请勿直接调用

从 src/lights/Light.js 的构造函数实现可以看到两个参数的完整语义:

参数类型默认值语义
colornumber \| Color \| string0xffffff(白色)光源颜色,支持十六进制数值、THREE.Color实例或 CSS 颜色字符串
intensitynumber1光源强度/亮度数值

源码中颜色参数通过this.color = new Color( color )统一转换为THREE.Color实例存储(这就是.color属性类型为 Color 的原因,同时也解释了为何构造与属性都接受三种格式的输入);强度则直接原样保存为.intensity

AmbientLight为例,它在 src/lights/AmbientLight.js 中的构造函数只是简单透传这两个参数给父类,再补上自己的类型标记:

constructor( color, intensity ) { super( color, intensity ); this.isAmbientLight = true; this.type = 'AmbientLight'; }

可见具体光源类型普遍遵循“先 super(color, intensity) 完成基类初始化,再登记自身 isXxxLight 标记与 type”的模板,这与Light基类自身在构造时执行的this.isLight = true; this.type = 'Light';一脉相承。

核心属性详解

.color : Color

光源颜色。默认0xffffff,构造时被包装为Color实例。

在源码中通过new Color( color )创建,因此可直接调用Color的全部方法操作颜色,例如light.color.setHSL( ... )light.color.copy( otherColor )等。颜色是影响最终渲染表现最直接的属性:例如冷暖光源的区分、氛围色、乃至借助彩色光源制造特殊材质反光效果,都建立在其之上。

.intensity : number

光源强度,默认1

需要特别注意的是,不同光源类型的 intensity 单位并不统一。以 src/lights/PointLight.js 为例,其构造注释明确写明 intensity 以坎德拉(candela, cd)计量;而同一个文件里提供的power存取器则基于“各向同性点光源:光通量(lm) = 4π × 光强(cd)”的物理关系,在瓦特级物理光效语义下换算流明:

get power() { // 光通量 (lm) = 4 π × 光强 (cd) return this.intensity * 4 * Math.PI; } set power( power ) { this.intensity = power / ( 4 * Math.PI ); }

因此,当你在调光时把某类型光源强度设为1,其真实视觉亮度可能与其他类型光源完全不同——这正是“为什么 0.5 的 PointLight 看起来比 0.5 的 AmbientLight 亮得多”的根源。光源的物理光效还涉及衰减:PointLight默认distance = 0(不限距离)、decay = 2(平方反比衰减),源码注释明确指出在物理正确渲染语境下不应改动decay的默认值。

.isLight : boolean(只读)

类型测试标记,恒为true。源码中在构造器内直接赋值this.isLight = true;

isXxx系列布尔标记是 three.js 全库统一的鸭子类型判断手段(isMeshisCameraisPointLight等同理)。你可以在自己的代码里用light.isLight === true判断某个对象是否为光源,而无需instanceof;子类则各自额外带出isAmbientLightisPointLight等更细粒度的标记,与.type字符串(如'Light''PointLight')形成互补:标记面向程序逻辑判断,type面向序列化与工具链识别。

dispose():资源释放的级联链路

文档在方法部分给出的dispose()说明为:“释放该实例占用的 GPU 相关资源;当实例不再使用时务必调用”。

深入源码会发现一个值得澄清的实现细节:抽象基类 Light 自身并没有覆盖 dispose()。src/lights/Light.js 只实现了构造、copytoJSONLight上可调用的dispose()实际继承自 src/core/Object3D.js:

dispose() { // @fires Object3D#dispose this.dispatchEvent( { type: 'dispose' } ); }

即基类层面的dispose只是派发一个'dispose'事件,让外部监听者(例如场景管理逻辑或渲染器)得以感知对象生命周期。

真正会占用 GPU 资源的,是具体光源的阴影子系统,因此其子类通过重写 dispose() 完成级联释放

  • PointLight.dispose():super.dispose()(向上级联触发基类事件)后调用this.shadow.dispose()
  • DirectionalLight.dispose() 与 SpotLight.dispose() 结构完全相同;
  • LightShadow.dispose() 则负责真正释放阴影贴图相关资源——分别对this.map(阴影深度渲染目标)与this.mapPass(PCF 软阴影二次处理通道)调用各自的dispose()

由此可以总结出三条实用结论:

  1. 无阴影的光源(如 AmbientLight、HemisphereLight)几乎没有需要手动释放的 GPU 资源,因为它们不持有阴影贴图渲染目标;
  2. 启用castShadow的 PointLight/DirectionalLight/SpotLight 会持有阴影贴图 RenderTarget,在大量动态创建与销毁场景中应记得调用光源的dispose()来回收;
  3. dispose()事件沿继承链向上逐级派发,意味着你可以在Object3D层面统一监听'dispose'事件做资源记账或调试,光源释放时会触发该事件。

补充说明:dispose()只负责光源自身(及其阴影)占用的资源。光源关联的几何体、材质与纹理若与其他对象共享,仍需按 src/materials/Material.js 等各自的规则分别释放,这与 Object3D 中“几何体/材质/纹理可能被多个 3D 对象共享,必须单独释放”的注释是一致的。

copy 与 toJSON:克隆与序列化

虽然文档正文没有展开,但 src/lights/Light.js 中的两个方法补齐了基类能力的完整拼图,值得一并理解:

.copy( source, recursive )—— 先调用super.copy()复制 Object3D 的变换、层级等状态,再复制光源特有的两个核心字段:

this.color.copy( source.color ); this.intensity = source.intensity;

也就是说克隆一个光源时,color(对象引用深拷贝)与 intensity(值拷贝)是基类保证被继承的语义,而distancedecayshadow等则由各子类在自身的copy()中追加处理(见 PointLight.copy())。

.toJSON( meta )—— 在 Object3D 序列化结果之上补写光源字段:

data.object.color = this.color.getHex(); data.object.intensity = this.intensity;

序列化时颜色以 16 进制数值形式输出。这也解释了color属性为何同时接受 number 输入——JSON 格式本身就以数字表达颜色。整套toJSON输出可供ObjectLoader/ 编辑器 editor/index.html 场景持久化使用。

具体光源速览与选型参考

作为全文收束,下表汇总 src/lights 下各直接子类的核心特征(均基于对应源码实现),供选型参考:

光源类核心文件特征可否投阴影
AmbientLightsrc/lights/AmbientLight.js全局均匀照亮所有物体,无方向无位置概念否(源码注释明确说明)
DirectionalLightsrc/lights/DirectionalLight.js平行光,从无穷远照射,自带DirectionalLightShadow
PointLightsrc/lights/PointLight.js单点向四周发射(模拟裸灯泡),带distance/decay/power,自带PointLightShadow
SpotLightsrc/lights/SpotLight.js锥形光束(聚光灯光斑效果)
HemisphereLightsrc/lights/HemisphereLight.js天空-地面双色半球光,常用于模拟环境渐变光照
RectAreaLightsrc/lights/RectAreaLight.js矩形面光源,适合柔光/影棚光
LightProbesrc/lights/LightProbe.js光照探针,记录空间光照信息

一个典型的入门组合是“环境光 + 主光源”:

// 场景级均匀补光(无方向、不投阴影) const ambient = new THREE.AmbientLight( 0x404040 ); // 柔和白光补暗部 scene.add( ambient ); // 点光源:带颜色、强度与位置 const light = new THREE.PointLight( 0xff0000, 1, 100 ); light.position.set( 50, 50, 50 ); scene.add( light );

示例同时展示了 Light 的两个核心参数(color、intensity)与继承自 Object3D 的position配合使用的典型形态。若需要阴影,记得额外设置light.castShadow = true,并在释放资源时调用light.dispose()

小结

Light作为 three.js 全部光源的共同祖先,用最精简的两个字段(color + intensity)定义了光照的本质,并通过isLight标记、copy/toJSON、级联的dispose()协议,把通用行为固化在了继承链上。理解这个抽象基类,就能以“每类光源 = 基础颜色强度 + 各自的分布与衰减 + 各自的阴影配置”的统一视角去把握整个 three.js 光照体系。更细的用法差异(如距离衰减曲线、阴影 mapSize 配置、物理光照单位换算),建议进一步阅读 AmbientLight、PointLight、DirectionalLight、SpotLight 等各具体光源文档页与对应源码。

【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

立即咨询