
three.js Light 光照抽象基类解析继承体系、核心属性与资源释放机制【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.jsLight是 three.js 中所有光源的抽象基类AmbientLight、DirectionalLight、PointLight、SpotLight等一切具体光源类型都继承自它。本文以 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因此每个光源实例天然具备三维空间中position、rotation、scale、parent/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 全库统一的鸭子类型判断手段isMesh、isCamera、isPointLight等同理。你可以在自己的代码里用light.isLight true判断某个对象是否为光源而无需instanceof子类则各自额外带出isAmbientLight、isPointLight等更细粒度的标记与.type字符串如Light、PointLight形成互补标记面向程序逻辑判断type面向序列化与工具链识别。dispose()资源释放的级联链路文档在方法部分给出的dispose()说明为“释放该实例占用的 GPU 相关资源当实例不再使用时务必调用”。深入源码会发现一个值得澄清的实现细节抽象基类 Light 自身并没有覆盖 dispose()。src/lights/Light.js 只实现了构造、copy与toJSONLight上可调用的dispose()实际继承自 src/core/Object3D.jsdispose() { // 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.mapPassPCF 软阴影二次处理通道调用各自的dispose()。由此可以总结出三条实用结论无阴影的光源如 AmbientLight、HemisphereLight几乎没有需要手动释放的 GPU 资源因为它们不持有阴影贴图渲染目标启用castShadow的 PointLight/DirectionalLight/SpotLight 会持有阴影贴图 RenderTarget在大量动态创建与销毁场景中应记得调用光源的dispose()来回收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值拷贝是基类保证被继承的语义而distance、decay、shadow等则由各子类在自身的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),仅供参考