首页
/ three.js Node 材质解析:MeshBasicNodeMaterial 无光照材质与着色器节点构建原理

three.js Node 材质解析:MeshBasicNodeMaterial 无光照材质与着色器节点构建原理

2026-09-07 13:17:03作者:翟江哲Frasier

MeshBasicNodeMaterial 是 three.js 新一代 Node 材质体系中 MeshBasicMaterial 的节点化实现:它把“不受光照影响的纯色/贴图材质”以 TSL(Three Shading Language)节点图的形式接入渲染管线,最终在 WebGL/WebGPU 后端编译成对应的着色器。本文以 MeshBasicNodeMaterial.html 官方文档 为骨架,结合其 源码实现 与若干配套节点源码,讲解它的继承关系、构造方式、特殊属性,以及五个被重写的着色器构建钩子方法——读完即可理解“无光照材质在节点化管线中如何被表述、如何接入烘焙光照与环境贴图”,并能在自己的 WebGPU 项目中直接使用。

一、类在继承体系中的位置

MeshBasicNodeMaterial 的完整继承链为:

EventDispatcher → Material → NodeMaterial → MeshBasicNodeMaterial

文档开头的 *Inheritance: EventDispatcher → Material → NodeMaterial →* 说明它是 NodeMaterial 基类 的直接子类。它位于节点材质家族中,与 MeshLambertNodeMaterialMeshStandardNodeMaterial 等并列,全部从 NodeMaterials.js 统一导出:

export { default as MeshBasicNodeMaterial } from './MeshBasicNodeMaterial.js';
// ... 以及其他十几种 Node 材质

Three.WebGPU.Nodes.js 又通过 export * from './materials/nodes/NodeMaterials.js' 将整组材质暴露出去,因此在实际项目里可以直接从 'three/webgpu' 导入:

import { MeshBasicNodeMaterial } from 'three/webgpu';

从类的 static get type() 可看到其类型标识为字符串 'MeshBasicNodeMaterial'(源码 MeshBasicNodeMaterial.js),用于材质序列化/克隆时的类型还原。

二、构造器与参数语义

文档定义:

new MeshBasicNodeMaterial( parameters : Object ) —— 传入一个包含材质属性的配置对象,构造一个新的网格基础节点材质。

构造实现(源码 MeshBasicNodeMaterial.js)做了三件事:

super();
this.isMeshBasicNodeMaterial = true;
this.lights = true;
this.setDefaultValues( _defaultValues ); // 用 pristine 的 MeshBasicMaterial 实例补全默认值
this.setValues( parameters );            // 应用用户传入参数

其中 _defaultValues 是一个模块级缓存的 new MeshBasicMaterial() 实例(源码 MeshBasicMaterial.js),setDefaultValues() 会把这套“经典材质默认值”批量搬进节点材质。这意味着 MeshBasicMaterial 的全部外观属性都天然可用,主要包括:

参数 类型/默认值 说明
color Color,默认 0xffffff 漫反射(材质本体)颜色
map Texture,默认 null 颜色贴图,与 color 相乘,建议 SRGBColorSpace
lightMap / lightMapIntensity Texture / 1.0 烘焙光照贴图(需第二套 UV,通常 float 格式/LinearSRGBColorSpace
aoMap / aoMapIntensity Texture / 1.0 环境光遮蔽贴图(取红通道,非颜色数据)
specularMap Texture,默认 null 高光贴图(本材质中用于控制环境贴图强度)
alphaMap Texture,默认 null 灰度透明贴图
envMap / envMapRotation Texture / Euler(0,0,0) 环境贴图及其旋转
combine MultiplyOperation(默认)/MixOperation/AddOperation 表面色与环境贴图的混合方式
reflectivity number,默认 1 环境贴图影响强度(与 specularMap 相乘)
refractionRatio number,默认 0.98 折射率比值(折射类 envMap 使用)
wireframe boolean,默认 false 是否以线框渲染
fog boolean,默认 true 是否受雾影响

因此使用方式与经典材质几乎一致:

const material = new MeshBasicNodeMaterial( {
	color: 0x049ef4,
	map: colorTexture,
	wireframe: false
} );

三、两个关键属性

.isMeshBasicNodeMaterial : boolean(只读)

类型测试标志,默认 true。由于 ES6 的 instanceof 跨副本/多版本场景可能失效,three.js 统一采用这种鸭子类型判断。例如 examples/jsm/inspector/extensions/tsl-graph/TSLGraphEditor.js 中用它判断材质种类并返回 'material/basic' 分类:

if ( material.isMeshBasicNodeMaterial ) return 'material/basic';

.lights : boolean

默认 true,文档强调:基础材质按定义是不受光照的(unlit),但这里仍置为 true,因为节点化实现要用一套照明模型去计算片元着色器的出射光。它与普通属性布尔开关不同——它直接决定 NodeMaterial 基类 setupLighting() 内部是否走“照明上下文”分支:当 lights === true 且渲染器启用了 lighting 时,会调用 setupMaterialLightings() 收集环境、光照贴图、AO 节点,并经过 lightingContext 与材质自己的照明模型共同计算出射光。该属性覆写自 NodeMaterial#lights(默认 false)。

四、五个被覆写的构建钩子方法

NodeMaterial 的着色器不是手写 GLSL,而是通过 setup* 系列方法在构建期动态组装 TSL 节点。MeshBasicNodeMaterial 精准覆写了以下五个方法,正好对应它“unlit 但有环境/烘焙光参与”的特殊身份:

1. setupNormal() : Node<vec3>

返回法线节点。因为基础材质不受法线贴图与凹凸贴图影响,它直接返回默认的 normalViewGeometry(视图空间几何法线)。源码 MeshBasicNodeMaterial.js 额外用 negateOnBackSide() 包裹,并注释引用了 issue #28839(背面剔除几何的法线修正):

setupNormal() {
	return negateOnBackSide( normalViewGeometry ); // see #28839
}

对比基类默认实现 this.normalNode ? vec3( this.normalNode ) : materialNormalNodeMaterial.js),可见基础材质“跳过法线贴图采样”这一语义是刻意为之。

2. setupEnvironment( builder : NodeBuilder ) : BasicEnvironmentNode.<vec3>

实现默认的环境映射。它先调用 super.setupEnvironment( builder )(基类逻辑会检查用户是否显式传入 envNode,否则回退到 envMap 引用,见 NodeMaterial.js),再把结果包进 BasicEnvironmentNode

setupEnvironment( builder ) {
	const envNode = super.setupEnvironment( builder );
	return envNode ? new BasicEnvironmentNode( envNode ) : null;
}

BasicEnvironmentNode 是非 PBR 材质(如 MeshBasicNodeMaterial、MeshPhongNodeMaterial)专用的 IBL 环境节点:cubeMapNode() 把立方体/等距柱状环境贴图转成采样节点,并写入 builder.context.environment,供照明模型的 finish() 阶段消费。若没有 envMap,则返回 null(环境节点是可选的)。

3. setupLightMap( builder : NodeBuilder ) : BasicLightMapNode.<vec3>

光照贴图(烘焙的间接光照)必须以特殊缩放因子参与计算,因此要覆写。实现与基类差异一目了然:

// MeshBasicNodeMaterial(子类)
setupLightMap( builder ) {
	let node = null;
	if ( builder.material.lightMap ) {
		node = new BasicLightMapNode( materialLightMap );
	}
	return node;
}

基类版本返回的是 IrradianceNodeNodeMaterial.js),而这里换成 BasicLightMapNode。两者的核心差异在 BasicLightMapNode 的 setup() 中:它会乘以 1 / Math.PIRECIPROCAL_PI)后再写入 builder.context.irradianceLightMap,这是因为基础材质用 Lambert 式的漫反射辐射度语义评估烘焙贴图。

4. setupLightingModel() : BasicLightingModel

返回本材质的照明模型。覆写自基类的抽象接口方法(NodeMaterial.js):

setupLightingModel() {
	return new BasicLightingModel();
}

BasicLightingModel 对应“无光照材质”的照明模型,核心逻辑分为两段:

  • indirect()源码 L32-L58):只累积烘焙间接光——存在 irradianceLightMap(即上面的光照贴图)则累加它,否则以 vec4(1,1,1,0) 兜底;随后用环境光遮蔽 AO 与 diffuseColor.rgb 调制。
  • finish()源码 L65-L96):执行环境映射。按 material.combine 取值分派三种算法——MultiplyOperationmaterialSpecularStrength * materialReflectivity 作为强度做乘法混合、MixOperation 做线性插值混合、AddOperation 做加法叠加;未知取值时输出 warn() 警告。

这也解释了 setupNormal()/setupEnvironment() 为何都要配套改造:基础材质的 IBL 路径与常规 PBR 材质的辐照度/镜面反射两条链路完全不同。

5. setupOutgoingLight() : Node.<vec3>

这是文档中“最绕”的一点:因为 lights 被置为 true,基类默认的 setupOutgoingLight() 会返回 vec3(0)NodeMaterial.jslights === true 分支意味着“由照明模型计算出射光”),但基础材质不应该因照明而变暗,所以此处直接返回漫反射颜色本身:

setupOutgoingLight() {
	return diffuseColor.rgb;
}

即:无论如何走照明上下文,出射光都等于材质的漫反射色 color × map;照明模型(环境、光照贴图、AO)只在此基础上做乘法/加法调制,而不是产生新的光源方向性贡献。

五、构建期调用链小结

把 NodeMaterial 的 setupLighting() 主流程(NodeMaterial.js)与上述覆写对照,可得到 MeshBasicNodeMaterial 的着色器构建骨架:

setupLighting()
 ├─ setupOutgoingLight()          → diffuseColor.rgb          (覆写)
 ├─ setupMaterialLightings()
 │    ├─ setupEnvironment()       → BasicEnvironmentNode      (覆写,包装基类 envNode)
 │    └─ setupLightMap()          → BasicLightMapNode         (覆写,烘焙光照×1/π)
 │    └─ (AO) ambientOcclusion
 ├─ setupLightingModel()          → BasicLightingModel        (覆写)
 └─ lightingContext( lightsNode, BasicLightingModel, ... )
      └─ BasicLightingModel.indirect()  累积调制烘焙光 + AO
      └─ BasicLightingModel.finish()    按 combine 混合环境贴图
setupNormal()                       → negateOnBackSide( normalViewGeometry ) (覆写)

由于 mesh 的基础几何与材质属性(UV、map 等)由 NodeMaterial 基类统一定义,MeshBasicNodeMaterial 只需在“法线 / 环境 / 光照贴图 / 照明模型 / 出射光”五个接缝上做最小化覆写,就能复用整条节点化渲染管线——这正是该实现"小而清晰"的原因。

六、实际项目中的应用证据

MeshBasicNodeMaterial 在仓库中被广泛用于需要“经典基础材质语义 + Node/WebGPU 管线”的场景,可作参考范例:

自行快速验证的方式:在任意基于 'three/webgpu' 的示例(WebGPURenderer)中把 new MeshBasicMaterial(...) 替换为 new MeshBasicNodeMaterial( { color, map, envMap, combine: THREE.MixOperation } ),即可观察它在节点化管线中产出等价且可编程的着色器图。若要在着色器层面进一步定制其颜色,可在 TSL 中借助 material.colordiffuseColor 等节点继续组合,相关 TSLLanguage 语法见 docs/TSL.md

综上:MeshBasicNodeMaterial 是理解 three.js 节点材质“用照明模型表达无光照材质”这一设计的关键入口——它用五个精准的方法覆写,把经典 MeshBasicMaterial 的视觉语义无损迁移到可编程的节点化着色器管线中,是 WebGPU 后端材质迁移与 TSL 二次开发的常用底座。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388