首页
/ Three.js 节点材质完全解析:MeshLambertNodeMaterial 的 Lambert 光照实现与 WebGPU 使用指南

Three.js 节点材质完全解析:MeshLambertNodeMaterial 的 Lambert 光照实现与 WebGPU 使用指南

2026-09-07 17:31:36作者:尤辰城Agatha

本文围绕 Three.js 的 MeshLambertNodeMaterial 展开,它是经典 MeshLambertMaterial 在**节点材质体系(Node Material / TSL)**下的对等实现,用于在无高光的非光泽表面(如未上漆的木材、石材)上提供性能友好的 Lambert 漫反射光照。读完本文,你将掌握它的继承结构、构造函数参数、两个只读/行为属性的含义、setupEnvironmentsetupLightingModel 的底层原理,以及它如何被 WebGPURendererStandardNodeLibrary 自动接管渲染。

概览:什么是 MeshLambertNodeMaterial

MeshLambertNodeMaterial 是文档页 MeshLambertNodeMaterial.html.md 所描述的对象,官方用一句话定位它:

Node material version of MeshLambertMaterial.

它位于节点材质文件族 NodeMaterials.js 中,与 MeshBasicNodeMaterialMeshPhongNodeMaterial 等并列导出。其核心实现只有约 80 行,位于 MeshLambertNodeMaterial.js,整套逻辑建立在基类 NodeMaterial(约 1368 行)的通用节点材质框架之上。

继承链

按文档定义,其继承关系为:

EventDispatcher → Material → NodeMaterial → MeshLambertNodeMaterial

关键点在于中间层 NodeMaterial。基类把材质从"一组固定 uniform 的着色器模板"升级为"可编程的节点图":漫反射、自发光、法线、环境等都可以用 TSL 节点接管。MeshLambertNodeMaterial 只负责两件事——覆盖光照模型覆盖环境映射策略,其余外观属性全部复用自 MeshLambertMaterial 的默认值。

为何 Lambert:无高光非光泽材质的取舍

要理解这个节点材质,先要理解它的"经典版"兄弟 MeshLambertMaterial.js。源码头部注释清晰说明了设计意图:

  • 使用非物理的 Lambertian(朗伯)反射模型计算反射率;
  • 适合模拟未上漆木材、石材等表面,无法模拟带镜面高光的光泽表面(如清漆木材);
  • 采用逐片元(per-fragment)着色
  • 由于反射与光照模型简单,性能通常优于 MeshPhongMaterialMeshStandardMaterialMeshPhysicalMaterial,代价是图形精度略低。

因此 MeshLambertNodeMaterial.lights 必须为 true——它依赖场景光源做漫反射计算,这与 NodeMaterial 基类默认的 lights = false 恰好相反(见 NodeMaterial.js 附近注释),这一点在下文属性一节会再次印证。

构造与实例化

构造函数签名

new MeshLambertNodeMaterial( parameters : Object )

parameters 为可选配置对象,其中可包含该材质(含继承来的)任意属性。颜色类属性接受 Color.set 支持的所有写法(十六进制、CSS 字符串、THREE.Color 实例等)。

使用方式

由于源码 MeshLambertNodeMaterial.js 的构造函数逻辑是 super() → 设置自有标记 → setDefaultValues( _defaultValues )setValues( parameters ),所以传参方式与经典材质完全一致:

import { WebGPURenderer, Mesh, BoxGeometry, MeshLambertNodeMaterial } from 'three/webgpu';

const material = new MeshLambertNodeMaterial( {
	color: 0xddbb99,          // 漫反射颜色,默认 0xffffff
	emissive: 0x000000,       // 自发光颜色,默认黑色
	flatShading: true,        // 平直着色
} );

const mesh = new Mesh( new BoxGeometry( 1, 1, 1 ), material );

值得注意的一行关键源码在模块顶部:

const _defaultValues = /*@__PURE__*/ new MeshLambertMaterial();

这意味着默认值并非逐一手写,而是直接实例化一个经典 MeshLambertMaterial,再将其全部自有属性拷入节点材质实例。基类 NodeMaterial#setDefaultValues(见 NodeMaterial.js)遍历传入材质实例的属性并赋值。这一"复用刷新逻辑"的设计,使得经典材质的全部外观参数在节点材质上开箱即用。

自动转换:WebGPU 下的经典材质无缝升级

当你不显式使用 MeshLambertNodeMaterial,而只是把一个普通 new MeshLambertMaterial(...) 交给 WebGPURenderer 渲染时,渲染器会通过材质映射库 StandardNodeLibrary.js 自动把 MeshLambertMaterial 适配为 MeshLambertNodeMaterial

this.addMaterial( MeshBasicNodeMaterial, 'MeshBasicMaterial' );
this.addMaterial( MeshLambertNodeMaterial, 'MeshLambertMaterial' );

因此熟悉经典 API 的用户在迁移到 WebGPU 后端时几乎不需要改业务代码——升级在渲染管线内部透明完成。

属性详解

.isMeshLambertNodeMaterial : boolean(只读)

类型测试标志,用于在代码中判断某个材质是否为 Lambert 节点材质:

if ( material.isMeshLambertNodeMaterial ) { /* ... */ }

默认恒为 true,在构造函数中写入(见 MeshLambertNodeMaterial.js)。注意它与经典版的 isMeshLambertMaterial 是不同的标志,两者分别标记两条材质家族。

.lights : boolean

Lambert 材质依赖光照,故该属性为 true。这是对基类 NodeMaterial#lights(基类默认 false)的显式覆盖(Overrides)。在基类中,节点材质通过 lights = true 表明"受场景全部灯光影响";如需"选择性光照",可在基类提供的 lightsNode 属性上挂一个由 lights( [ light1, light2 ] ) 构造的自定义灯光节点(见 NodeMaterial.js 附近说明),该能力对 Lambert 节点材质同样生效。

外观属性全集:继承自 MeshLambertMaterial 的默认值

由于 setDefaultValues( new MeshLambertMaterial() ) 的存在,以下出自 MeshLambertMaterial.js 的属性在 MeshLambertNodeMaterial 上全部可用。整理如下(未注明时括号内为默认值):

类别 属性(默认值) 说明
漫反射 color (0xffffff) 漫反射基色,与 map 相乘
贴图 map (null) 颜色贴图,需设 SRGBColorSpace
烘焙光照 lightMap (null) / lightMapIntensity (1) 预烘焙光照贴图,需第二套 UV,多为 LinearSRGBColorSpace.exr/.hdr
环境光遮蔽 aoMap (null) / aoMapIntensity (1) 使用红色通道,强度范围 [0,1],需第二套 UV,无颜色空间
自发光 emissive (0x000000) / emissiveIntensity (1) / emissiveMap (null) 不受其他光源影响的自发光;有 emissiveMap 时请把 emissive 设成非黑色
凹凸 bumpMap (null) / bumpScale (1) 黑白深度感知,仅影响光照;定义了法线贴图时被忽略
法线 normalMap (null) / normalMapType (TangentSpaceNormalMap) / normalScale ((1,1)) 左手系法线贴图需将 y 取负以修正
位移 displacementMap (null) / displacementScale (1) / displacementBias (0) 真正移动顶点,可投射阴影;需配套法线贴图
高光贴图 specularMap (null) Lambert 模型本身无高光,但保留该贴图槽位与经典版对齐
Alpha alphaMap (null) 灰度透明度(黑透明白不透明),仅用绿色通道采样
环境 envMap (null) / envMapRotation (Euler) / combine (MultiplyOperation) / reflectivity (1) / envMapIntensity (1) / refractionRatio (0.98) 环境映射;MixOperation 时用 reflectivity 混合
线框 wireframe (false) / wireframeLinewidth (1) / wireframeLinecap ('round') / wireframeLinejoin ('round') 线框渲染(仅 SVGRenderer 支持线宽/端点样式)
着色/雾 flatShading (false) / fog (true) 平直着色与雾效开关

映射到节点材质后,颜色与贴图仍受同一套 ColorSpace 约定约束;alpha 通道配合 Material#transparentalphaTest 生效。这些属性都会在实例化后通过 setValues( parameters ) 被覆盖为传入值,行为与经典 MeshLambertMaterial 完全一致。

方法深度剖析

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

Lambert 材质使用 BasicEnvironmentNode(而非 PBR 的 PMREM/辐照度环境模型)实现默认环境映射。源码实现非常简短(MeshLambertNodeMaterial.js):

setupEnvironment( builder ) {

    const envNode = super.setupEnvironment( builder );

    return envNode ? new BasicEnvironmentNode( envNode ) : null;

}

含义是:先让基类 NodeMaterial#setupEnvironment 解析环境来源(例如 envNode 或材质自身的 envMap),若解析到环境节点,就把它包装成 BasicEnvironmentNode;否则返回 null。包装后的节点在 BasicEnvironmentNode.jssetup() 中执行关键动作:

builder.context.environment = cubeMapNode( this.envNode );

即把环境写入 builder 上下文,供 BasicLightingModel.finish() 消费。注释明确指出:BasicEnvironmentNode 面向非 PBR 材质(如 MeshBasicNodeMaterialMeshPhongNodeMaterial),立方体/经纬环境贴图在这里走 cubeMapNode 采样路径。

值得区分:基类若没有可用环境节点会返回 null,此时 Lambert 节点材质的环境通道整体关闭,环境贴图不会产生任何效果。

.setupLightingModel() : PhongLightingModel

这是"Lambert"语义真正落地的地方(MeshLambertNodeMaterial.js):

setupLightingModel( /*builder*/ ) {

    return new PhongLightingModel( false ); // ( specular ) -> force lambert

}

MeshLambertNodeMaterial 复用了 Phong 光照模型类 PhongLightingModel.js,但传入构造参数 specular = false,用源码注释的话说就是 "force lambert"——强制关闭镜面分量,只保留漫反射。

PhongLightingModel 内部结构印证了这一机制:

  • 构造函数默认 specular = truePhongLightingModel.js),注释指明:要得到"无高光、非光泽表面"的 Lambert 式材质,应置为 false
  • direct() 直接光部分(第 67-80 行)先计算 dotNL(法线与光线方向的点积,经 clamp())得到辐照度 irradiance,再乘以 BRDF_Lambert( diffuseColor.rgb ) 累加进 reflectedLight.directDiffuse;只有 this.specular === true 时才追加 BRDF_BlinnPhong 高光计算与 materialSpecularStrength
  • indirect() 间接光部分(第 87-95 行)把辐照度(IBL)同样经 BRDF_Lambert 累加,再乘环境光遮蔽。

结论specular = false 意味着即使 specularMap 有值,Blinn-Phong 高光分支也完全不会进入着色器图。这正是 Lambert 材质"没有镜面高光"的本质来源,也是它与 MeshPhongNodeMaterial(使用 new PhongLightingModel( true ))在代码层面的唯一分水岭。如果读者想要高光,应改用 MeshPhongNodeMaterial;想要基于物理的高光/粗糙度,则应选用 PBR 的 MeshStandardNodeMaterial

从底层到实战:一个完整的渲染链路

综合上述源码,一次渲染经历的数据流可以概括为:

  1. 场景灯光 → 由 NodeMaterial 组装为 LightsNode(或经 lightsNode 选择性裁剪);
  2. MeshLambertNodeMaterial.setupLightingModel() 注入 PhongLightingModel(false),剔除高光分支;
  3. setupEnvironment()BasicEnvironmentNode 包装环境贴图,走 cubeMapNode 快速采样;
  4. 节点图编译后生成 WebGPU/WebGL 着色器,逐片元计算 BRDF_Lambert 漫反射并叠加 AO 与雾效。

如果只想快速验证其行为,可参照本文档阅读 源文件 及其被引用处:模块出口在 NodeMaterials.js,WebGPU 材质映射在 StandardNodeLibrary.js,光照模型细节见 PhongLightingModel.js,环境节点见 BasicEnvironmentNode.js

常见疑问速查

  • 问:为什么它在三套(Basic/Lambert/Phong)节点材质里"复用 Phong 模型"? 答:因为 Lambert 本质是 Phong 模型去掉镜面分量的退化形态。通过 PhongLightingModel(false) 统一实现,代码复用度最高,代价仅是一个布尔分支。
  • 问:lights 明明默认被覆盖为 true,基类却默认 false 答:这是刻意为之——大部分纯 TSL 节点材质(如 Basic)不需要动态光源;Lambert 需要。覆盖行为正是文档标注 "Overrides: NodeMaterial#lights" 的原因。
  • 问:要不要手动给每个网格 new 一个 Lambert 节点材质? 答:不需要。WebGPU 后端已通过 StandardNodeLibrary 将经典 MeshLambertMaterial 自动替换为节点版本;手动实例化仅在需要精确控制节点级属性(如自定义 envNodelightsNode)时才有意义。
  • 问:想在 WebGL 后端用 TSL 场景怎么办? 答:仓库 package.jsonexports 提供了 ./webgpu(WebGPU 全量)与 ./tsl(TSL 管线)两个入口;本材质位于 WebGPU 全量构建所导出的 NodeMaterials.js,应结合你实际使用的渲染后端选择对应入口。

需要再次强调的是:选用 Lambert 系材质,意味着你已接受"无高光、非物理、追求性能"的定位。若场景以 PBR 质感的金属、玻璃、清漆表面为主,Lambert 节点材质并非合适的载体——这正是本项目同时维护 Phong、Standard、Physical 等多套节点材质的原因。

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

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 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
531
594
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
916
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
516
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388