
three.js TSL 中的 BasicEnvironmentNode为非 PBR 材质注入 IBL 环境光照的原理与用法【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.jsthree.js 的节点系统TSLThree Shading Language中BasicEnvironmentNode是面向非 PBR 材质如MeshBasicNodeMaterial、MeshPhongNodeMaterial的基于图像的照明IBLImage-based Lighting节点。本文以官方 API 文档 BasicEnvironmentNode 为骨架结合仓库源码深入讲解它的继承关系、构造参数、envNode属性、内部的setup编译流程以及它与BasicLightingModel之间环境贴图如何最终混合进片元颜色的完整链路帮助读者理解非 PBR 材质在节点系统中获得环境映射的底层机制。类定义与继承体系官方文档对该类的定位是表示基于图像的照明IBL基础模型环境通过等距柱状equirectangular或立方体贴图cube map格式的环境贴图定义并且明确说明它面向MeshBasicNodeMaterial、MeshPhongNodeMaterial等非 PBR 材质。文档给出的继承链为EventDispatcher → Node → LightingNode → BasicEnvironmentNode从源码看这条继承链与仓库实现完全对应基类 LightingNode 继承自Node构造时声明输出类型为vec3并设置isLightingNode true标志用于类型测试——这决定了它能否被材质识别为灯光节点并加入灯光列表BasicEnvironmentNode 继承LightingNodestatic type为BasicEnvironmentNode并通过 Nodes.js 统一导出可在three/tsl命名空间中使用。值得注意的是它与同目录下的EnvironmentNode分工不同BasicEnvironmentNode只做把一张环境贴图作为查找来源这一件事PBR 材质Standard/Physical Node Material所需的辐照度、预滤波等完整 IBL 流程则由EnvironmentNode等更复杂的节点实现。构造函数与 envNode 属性文档定义的构造函数与属性如下// new BasicEnvironmentNode( envNode : Node ) // 构造一个新的 basic environment 节点。 // envNode表示环境的节点默认值为 null属性属性类型默认值说明.envNodeNodenull表示环境的节点通常是纹理节点或materialReference节点源码实现src/nodes/lighting/BasicEnvironmentNode.js与文档一致class BasicEnvironmentNode extends LightingNode { static get type() { return BasicEnvironmentNode; } /** * Constructs a new basic environment node. * * param {Node} [envNodenull] - A node representing the environment. */ constructor( envNode null ) { super(); this.envNode envNode; } setup( builder ) { // environment property is used in the finish() method of BasicLightingModel builder.context.environment cubeMapNode( this.envNode ); } }构造函数本身非常轻量核心逻辑全部在setup( builder )方法中见下一节。envNode传入null是合法状态——它意味着环境映射暂不可用编译期会安全地走无环境分支。setup自动把环境贴图编译为立方体查找节点setup是节点编译管线中被NodeBuilder调用的钩子。BasicEnvironmentNode的setup只有一行关键代码builder.context.environment cubeMapNode( this.envNode );它做两件事归一化环境格式cubeMapNode来自 CubeMapNode这是一个TempNode子类职责是自动把等距柱状格式的环境贴图转换为立方体贴图格式。其updateBefore逻辑为若纹理的mapping是EquirectangularReflectionMapping/EquirectangularRefractionMapping则通过CubeRenderTarget.fromEquirectangularTexture现场转换并用模块级WeakMap缓存结果避免重复转换原贴图dispose()时会连带清理缓存的 render target若纹理尚未加载完成image.height 0不成立则使用一个占位的默认CubeTexture兜底保证渲染不中断若本来就是立方体贴图则直接把envNode透传同时mapTextureMapping会把生成纹理的mapping修正为对应的CubeReflectionMapping/CubeRefractionMapping。写入编译上下文结果存入builder.context.environment。注释明确指出这个属性随后会被BasicLightingModel的finish()方法消费——这正是BasicEnvironmentNode 的完整数据流闭环。因此对使用者而言envNode既可以是cubeTexture( ... )纹理节点也可以是materialReference( envMap, cubeTexture )这类材质属性引用节点两者都会被cubeMapNode统一处理。谁在创建 BasicEnvironmentNode三个非 PBR Node 材质文档说该节点面向非 PBR 材质在源码中体现为三个 Node 材质重写了setupEnvironment( builder )在存在环境节点时统一包装成BasicEnvironmentNode// MeshBasicNodeMaterial.js setupEnvironment( builder ) { const envNode super.setupEnvironment( builder ); return envNode ? new BasicEnvironmentNode( envNode ) : null; }MeshBasicNodeMaterial无光照材质虽然定义上不受光照影响但其lights仍设为true借助BasicLightingModel计算出射光MeshPhongNodeMaterialPhong 光照模型Blinn-Phong BRDF环境映射与直接光照并存MeshLambertNodeMaterialPhongLightingModel( false )强制无高光同样走BasicEnvironmentNode路径。父类 NodeMaterial.setupEnvironment 的取值优先级是优先使用显式设置的this.envNode否则若设置了this.envMap纹理则按纹理类型构造materialReference( envMap, cubeTexture )或materialReference( envMap, texture )。也就是说用户只需给材质赋一个envMap纹理或 TSL 风格的envNode材质编译时就会自动产出BasicEnvironmentNode无需手动 new。随后 NodeMaterial.setupMaterialLightings 会检查返回节点是否满足envNode.isLightingNode是则推入materialLightsNode数组参与灯光求值——LightingNode基类提供的isLightingNode标志在此处起到关键作用。下游消费BasicLightingModel.finish() 中的混合运算BasicEnvironmentNode写入的builder.context.environment最终在 BasicLightingModel 的finish阶段被读取并参与颜色混合finish( builder ) { const { material, context } builder; const outgoingLight context.outgoingLight; const envNode builder.context.environment; if ( envNode ) { switch ( material.combine ) { case MultiplyOperation: outgoingLight.rgb.assign( mix( outgoingLight.rgb, outgoingLight.rgb.mul( envNode.rgb ), materialSpecularStrength.mul( materialReflectivity ) ) ); break; case MixOperation: outgoingLight.rgb.assign( mix( outgoingLight.rgb, envNode.rgb, materialSpecularStrength.mul( materialReflectivity ) ) ); break; case AddOperation: outgoingLight.rgb.addAssign( envNode.rgb.mul( materialSpecularStrength.mul( materialReflectivity ) ) ); break; default: warn( BasicLightingModel: Unsupported .combine value:, material.combine ); } } }要点环境采样结果与出射光按材质的combine模式混合支持AddOperation加法叠加MeshBasicMaterial的默认 combine 即加法、MultiplyOperation乘法、MixOperation线性插值三种混合权重由materialSpecularStrength * materialReflectivity对应材质的envMapIntensity与反射率决定PhongLightingModel继承自BasicLightingModel见 PhongLightingModel只在direct/indirect中追加 Blinn-Phong 直接光照与 Lambert 间接光照finish的环境混合逻辑原样复用。典型使用方式结合示例 webgl_materials_envmaps.html其中对立方体/等距柱状环境贴图做了切换演示非 PBR 材质接入BasicEnvironmentNode的典型代码形态为import * as THREE from three; import { CubeTextureLoader, TextureLoader } from three; const cubeTexture new THREE.CubeTextureLoader().setPath( textures/ ).load( [ px.jpg, nx.jpg, py.jpg, ny.jpg, pz.jpg, nz.jpg ] ); // 方式一直接使用 envMap 纹理材质内部自动包装为 BasicEnvironmentNode const material new THREE.MeshBasicNodeMaterial( { envMap: cubeTexture, envMapIntensity: 1.0 } ); // 方式二TSL 风格显式给出 envNode import { cubeTexture as tslCubeTexture } from three/tsl; material.envNode tslCubeTexture( cubeTexture );无论哪种方式编译时都会走到setupEnvironment → new BasicEnvironmentNode( envNode ) → setup → cubeMapNode( envNode )这条链路等距柱状贴图EquirectangularReflectionMapping也会被CubeMapNode自动转换为立方体无需预处理。小结BasicEnvironmentNode是一个继承自LightingNode的轻量 IBL 节点唯一状态是envNode默认null唯一行为是setup时把环境编译为cubeMapNode并写入builder.context.environment它的Basic体现在不做 PBR 级辐照度/预滤波处理而是把环境贴图当作可直接查表的vec3颜色来源交由BasicLightingModel.finish()按combine模式混合进出射光三个非 PBR Node 材质Basic/Phong/Lambert Node Material通过重写setupEnvironment自动创建它使用者通常只需设置envMap或envNode无需显式实例化官方文档页位于 BasicEnvironmentNode.html.md实现源码位于 BasicEnvironmentNode.js格式转换细节可参考 CubeMapNode.js。【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考