十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

three.js TSL 中 SpotLightNode 的 API 详解:WebGPU 管线里聚光灯的节点化实现与参数原理

three.js TSL 中 SpotLightNode 的 API 详解:WebGPU 管线里聚光灯的节点化实现与参数原理 three.js TSL 中 SpotLightNode 的 API 详解WebGPU 管线里聚光灯的节点化实现与参数原理【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.jsSpotLightNode 是 three.js 节点着色语言TSLThree Shading Language中用于表示聚光灯的光照节点是 WebGPU 渲染管线将传统SpotLight光源对象转换为可编程节点图的关键一环。阅读本文你将掌握 SpotLightNode 的完整 API构造函数、5 个 Uniform 属性、getSpotAttenuation与update方法、锥角/半影余弦的数学含义以及它如何被渲染器自动注册、逐帧更新并参与直接光照与阴影计算。定位SpotLightNode 在 three.js 架构中的位置官方文档页 SpotLightNode API 给出的继承链为EventDispatcher → Node → LightingNode → AnalyticLightNode → SpotLightNode从源码结构看这条链路逐层承担不同职责AnalyticLightNode 是所有解析式光源节点的基类持有light引用、color/colorNode、阴影节点并定义了setupDirect等抽象接口LightingNode 负责把光源接入当前光照上下文LightingContextNode/LightingModelNode基类提供update、setup、dispose等节点生命周期方法。SpotLightNode 本身并不需要在用户代码中显式创建。StandardNodeLibrary 在构造时通过this.addLight( SpotLightNode, SpotLight )建立SpotLight光源类型 →SpotLightNode节点类的映射WebGPURenderer在构建场景节点图时会自动按此映射转换BasicNodeLibrary 也做了同样的注册。因此实践中你只需向场景添加普通SpotLight对象即可节点化由渲染器透明完成。同时SpotLightNode 也是两个专用光源节点的基类从源码结构看二者都复用了它的锥体衰减逻辑IESSpotLightNode用 IES 光度学贴图采样替代默认的smoothstep衰减ProjectorLightNode在聚光灯基础上叠加投影贴图能力。构造函数new SpotLightNode( light )文档定义new SpotLightNode( light : SpotLight )—— Constructs a new spot light node.lightThe spot light source. Default isnull.对应 SpotLightNode.js 第 27 行 的实现light参数默认值为null透传给AnalyticLightNode构造函数。构造函数随后创建了 5 个 Uniform 节点并统一调用.setGroup( renderGroup )把它们归入渲染器级别的 uniform 组以便按组批量上传 GPU 数据this.coneCosNode uniform( 0 ).setGroup( renderGroup ); this.penumbraCosNode uniform( 0 ).setGroup( renderGroup ); this.cutoffDistanceNode uniform( 0 ).setGroup( renderGroup ); this.decayExponentNode uniform( 0 ).setGroup( renderGroup ); this.colorNode uniform( this.color ).setGroup( renderGroup );注意colorNode在这里被 SpotLightNode 覆盖Override了父类AnalyticLightNode#colorNode父类初始化逻辑 会优先使用光源自带的light.colorNode如果设置过否则基于this.color创建 uniform而 SpotLightNode 无条件以自身color为准重建该节点。被封装的光源是经典的 SpotLight 类其构造参数与默认值可直接作为 SpotLightNode 各 uniform 的取值参照见 SpotLight.js 构造函数SpotLight 参数默认值含义color0xffffff光色intensity1强度单位 candela (cd)distance0最大作用距离0表示无限制对应cutoffDistanceNodeangleMath.PI/3锥体最大半角上界Math.PI/2决定coneCosNodepenumbra0边缘衰减占比取值[0,1]决定penumbraCosNodedecay2距离衰减指数物理正确渲染下不建议修改对应decayExponentNodeProperties五个 Uniform 属性文档列出的全部属性及其在 源码中的定义行属性类型含义每帧更新来源见下文 update.colorNodeUniformNodeColor灯光颜色节点覆盖父类同名属性light.color * light.intensity.coneCosNodeUniformNodefloat锥角余弦cos(angle)Math.cos( light.angle ).penumbraCosNodeUniformNodefloat半影内边界余弦Math.cos( light.angle * ( 1 - light.penumbra ) ).cutoffDistanceNodeUniformNodefloat截断距离light.distance.decayExponentNodeUniformNodefloat衰减指数light.decay每帧更新.update( frame )文档定义.update( frame : NodeFrame )—— Overwritten to updated spot light specific uniforms.frameA reference to the current node frame. Overrides: AnalyticLightNode#updateSpotLightNode.update 的实现 先调用super.update( frame )再同步聚光灯特有 uniformupdate( frame ) { super.update( frame ); const { light } this; this.coneCosNode.value Math.cos( light.angle ); this.penumbraCosNode.value Math.cos( light.angle * ( 1 - light.penumbra ) ); this.cutoffDistanceNode.value light.distance; this.decayExponentNode.value light.decay; }这里的父类 AnalyticLightNode.update 负责颜色与强度的合并this.color.copy( light.color ).multiplyScalar( light.intensity )即colorNode最终承载的是颜色 × 强度。由于 AnalyticLightNode 构造函数 将updateType设置为NodeUpdateType.FRAME这套 uniform 同步是逐帧执行的——即使angle、penumbra、distance等属性在运行时被动态修改渲染结果下一帧即生效。锥体衰减.getSpotAttenuation( builder, angleCosine )文档定义.getSpotAttenuation( builder : NodeBuilder, angleCosine : Node.float ) : Node.float—— Computes the spot attenuation for the given angle. 参数builder为节点构建器angleCosine为待计算衰减的角度余弦值返回值ReturnsThe spot attenuation.实现只有两行getSpotAttenuation( builder, angleCosine ) { const { coneCosNode, penumbraCosNode } this; return smoothstep( coneCosNode, penumbraCosNode, angleCosine ); }它利用smoothstep对余弦值做平滑插值物理含义是angleCosine是片段方向与光束方向的点积余弦值。余弦函数在[0, π]上单调递减因此越靠近光束中心方向余弦值越大锥体外边界coneCosNode cos(angle)最小smoothstep在该处输出0完全暗半影内边界penumbraCosNode cos(angle * (1 - penumbra))更大smoothstep在该处输出1完全亮两者之间按penumbra控制的宽度平滑过渡——penumbra 0时两个余弦相等衰减退化为硬边锥体。这正是SpotLight文档中penumbraPercent of the spotlight cone that is attenuated 的节点级落地。子类IESSpotLightNode则重写了此方法当iesMap存在时改为用角度查 IES 贴图的 R 通道IESSpotLightNode.js无贴图时回退到super.getSpotAttenuation。直接光照组装setupDirect 与距离衰减文档 API 表未直接列出setupDirect但它是 SpotLightNode 的核心私有链路值得从源码层面拆解SpotLightNode.js求光矢量与夹角余弦lightVector由父类 getLightVector 返回光的世界/视空间位置减去片段位置归一化后与lightTargetDirection( light )点积得到angleCos锥体衰减调用getSpotAttenuation( builder, angleCos )得到spotAttenuation距离衰减调用 getDistanceAttenuation传入lightDistance实际距离、cutoffDistanceNode与decayExponentNode。该 TSL 函数基于 Frostbite 3 PBR 文档的窗口函数公式const distanceFalloff lightDistance.pow( decayExponent ).max( 0.01 ).reciprocal(); return cutoffDistance.greaterThan( 0 ).select( distanceFalloff.mul( lightDistance.div( cutoffDistance ).pow4().oneMinus().clamp().pow2() ), distanceFalloff );可见decayExponentNode作为指数参与倒数幂衰减默认decay 2即平方反比而cutoffDistanceNode只有在大于 0distance非零时才叠加四次方窗口函数使光强在截断距离处平滑归零——对应文档中cutoffDistanceNode的语义合成光色lightColor colorNode * spotAttenuation * lightAttenuation投影贴图map若光源设置了colorNode或mapSpotLight.map用于调制光色的cookie贴图见 SpotLight.js则通过 getLightCoord 取得lightProjectionUV采样贴图并用lightCoord.mul(2).sub(1).abs().lessThan(1).all()判断采样点是否落在锥体投影范围内范围外保持未调制的lightColor。最终setupDirect返回{ lightColor, lightDirection }由父类 AnalyticLightNode.setup 交给builder.lightsNode.setupDirectLight并入当前LightingModel的直接光累加。阴影接入父类机制如何作用在 SpotLightNode 上文档提到update覆盖自AnalyticLightNode#update阴影行为同样继承自 AnalyticLightNodesetup( builder )中当light.castShadow且接收对象receiveShadow时调用setupShadow( builder )setupShadow要求renderer.shadowMap.enabled为真随后通过setupShadowNode()默认shadow( this.light )创建阴影节点并把colorNode替换为colorNode.mul( shadowNode )——即阴影采样直接乘进光色原始色节点保存在baseColorNode中disposeShadow()时恢复若光源注册过自定义light.shadow.shadowNodeTSL 节点会优先通过nodeObject包装使用。因此 SpotLightNode 无需自己实现阴影聚光灯阴影SpotLightShadow透视阴影相机由shadow( light )节点自动承接。使用方式与参考在WebGPURenderer下标准用法就是创建SpotLight并加入场景节点转换、uniform 逐帧同步、锥体/距离衰减与阴影全部由管线自动完成import * as THREE from three; import { WebGPURenderer } from three/webgpu; const spotLight new THREE.SpotLight( 0xffffff, 100 ); // intensity 单位 cd spotLight.position.set( 100, 1000, 100 ); spotLight.angle Math.PI / 4; // 锥体半角上界 PI/2 spotLight.penumbra 0.3; // 边缘半影占比 [0,1] spotLight.distance 2000; // 0 表示无距离截断 spotLight.decay 2; // 物理正确渲染建议保持 2 scene.add( spotLight ); scene.add( spotLight.target ); // 需要移动照射方向时必须把 target 加入场景若需要 IES 光度学分布则改用IESSpotLight对应IESSpotLightNode聚光灯投影贴图能力对应ProjectorLight。可运行的聚光灯效果可参考仓库示例页 webgpu_lights_spotlight.html。小结SpotLightNode 的设计要点可以归纳为五个 uniform 属性颜色、锥角余弦、半影余弦、截断距离、衰减指数通过update( frame )逐帧镜像SpotLight的运行时参数锥体边缘平滑度由getSpotAttenuation中的smoothstep( coneCos, penumbraCos, angleCos )决定距离衰减复用 Frostbite 窗口函数阴影与光照模型接入则完全继承自AnalyticLightNode。理解这条光源对象 → 节点类 → uniform 同步 → 直接光组装的链路即可在 three.js 的 TSL 体系中正确配置、扩展如自定义getSpotAttenuation行为聚光灯。主要参考文件src/nodes/lighting/SpotLightNode.js、src/nodes/lighting/AnalyticLightNode.js、src/nodes/lighting/LightUtils.js、src/renderers/webgpu/nodes/StandardNodeLibrary.js、src/lights/SpotLight.js、docs/pages/SpotLightNode.html.md。【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表