ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

three.js SSSLightingModel 深度解析:为 MeshSSSNodeMaterial 注入次表面散射的直接光照项

three.js SSSLightingModel 深度解析:为 MeshSSSNodeMaterial 注入次表面散射的直接光照项 three.js SSSLightingModel 深度解析为 MeshSSSNodeMaterial 注入次表面散射的直接光照项【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.jsSSSLightingModel是 three.js 节点材质体系WebGPURenderer TSL中的一个实验性光照模型它继承PhysicalLightingModel并在其direct()方法前叠加一个廉价的次表面散射Subsurface ScatteringSSS近似项使MeshSSSNodeMaterial材质能够呈现皮肤、蜡、玉石等透光材质在光照下的半透明质感。读完本文你将掌握SSSLightingModel的完整构造参数与useSSS开关机制、SSS 直接光照项的逐行公式与物理含义、MeshSSSNodeMaterial六个厚度参数的默认值与调参范围并能基于官方示例 examples/webgpu_materials_sss.html 在自己的场景中启用快速次表面散射效果。继承链LightingModel → PhysicalLightingModel → SSSLightingModel从 API 文档 docs/pages/SSSLightingModel.html.md 的继承声明和源码结构看SSSLightingModel位于 three.js 光照模型体系的末端LightingModel抽象基类 └── PhysicalLightingModelPBR 物理光照模型 └── SSSLightingModel实验性追加 SSS 项抽象基类 src/nodes/core/LightingModel.js 定义了光照求值过程中各钩子方法的契约start(builder)初始化上下文并触发间接光照、direct(lightData, builder)逐光源执行直接光照项、directRectArea(...)矩形面光的 LTC 直接光照项、indirect(builder)间接光照项、ambientOcclusion(builder)环境遮蔽项与finish(builder)对出射光的最终修正。SSSLightingModel只重写了其中一个钩子direct()。父类 src/nodes/functions/PhysicalLightingModel.js 实现了完整的 Cook-Torrance PBR 直接/间接光照GGX 高光、Lambert 漫反射、FresnelSchlick、多次散射能量补偿computeMultiscattering以及 clearcoat、sheen、iridescence、anisotropy、transmission、dispersion、retroreflection 等可选特性。SSSLightingModel原样复用这套 PBR 管线仅在直接光照阶段追加一个 SSS 项。SSSLightingModel与MeshSSSNodeMaterial定义在同一个源文件 src/materials/nodes/MeshSSSNodeMaterial.js 中并在 src/materials/nodes/NodeMaterials.js 中随MeshSSSNodeMaterial一起导出。源码注释明确说明该材质是MeshPhysicalNodeMaterial的实验性扩展experimental extension。构造函数7 个特性开关new SSSLightingModel( clearcoat, sheen, iridescence, anisotropy, transmission, dispersion, sss )构造参数摘自 API 文档与 MeshSSSNodeMaterial.js#L14-L24 的 JSDoc参数含义默认值clearcoat是否启用清漆层falsesheen是否启用织物绒毛光泽falseiridescence是否启用薄膜虹彩falseanisotropy是否启用各向异性高光falsetransmission是否启用量体透射falsedispersion是否启用色散falsesss是否启用 SSS 项false构造器实现MeshSSSNodeMaterial.js#L25-L37constructor( clearcoat false, sheen false, iridescence false, anisotropy false, transmission false, dispersion false, sss false ) { super( clearcoat, sheen, iridescence, anisotropy, transmission, dispersion ); /** * Whether the lighting model should use SSS or not. * type {boolean} * default false */ this.useSSS sss; }要点前六个开关通过super()原样透传给PhysicalLightingModel其构造器签名为 PhysicalLightingModel.js#L352只有sss是子类新增的能力。这些布尔标志决定光照模型在着色器中编译哪些代码路径——未启用的特性不会进入生成的 TSL 节点图从而控制着色器体积与运行开销。属性.useSSSSSS 项的总开关.useSSS : booleanWhether the lighting model should use SSS or not. Default isfalse.它是direct()中 SSS 代码分支的唯一判据见下节。需要区分两个同名的useSSS光照模型侧SSSLightingModel.useSSS是普通属性由构造参数sss写入MeshSSSNodeMaterial.js#L35。材质侧MeshSSSNodeMaterial上定义了一个只读 getterMeshSSSNodeMaterial.js#L137-L147/** * Whether the lighting model should use SSS or not. * type {boolean} * default true */ get useSSS() { return this.thicknessColorNode ! null; }也就是说材质的useSSS由thicknessColorNode是否被赋值决定只要把厚度/透光色节点thickness color node赋上任意 TSL 节点SSS 效果即被激活为null时则退化为普通物理材质。材质的setupLightingModel()正是把该 getter 的结果传给光照模型构造器的第 7 个参数MeshSSSNodeMaterial.js#L154-L158setupLightingModel( /*builder*/ ) { return new SSSLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useAnisotropy, this.useTransmission, this.useDispersion, this.useSSS ); }父类MeshPhysicalNodeMaterial中的useClearcoat、useSheen等 getter 遵循同一模式属性值 0 || 对应 xxxNode ! null见 MeshPhysicalNodeMaterial.js#L286-L368各特性开关最终都会体现在光照模型的构造标志上。方法.direct()在 PBR 直接光照前叠加 SSS 项方法签名.direct( input : Object, builder : NodeBuilder )input当前光源的数据。在SSSLightingModel中解构为{ lightDirection, lightColor, reflectedLight }即光源方向、光源颜色、以及待累加的反射光输出对象reflectedLight.directDiffuse/directSpecular。builder当前节点构建器NodeBuilder通过builder.material拿到正在求值的材质实例。OverridesPhysicalLightingModel#direct见 PhysicalLightingModel.js#L624-L677。API 文档给出的学术参考是 Colin Barrebrisebois 2011 年 GDC 分享的Approximating Translucency for a Fast, Cheap and Convincing Subsurface Scattering Look——该算法用光线穿过物体后从背面散射出来的近似视角以极低的代价模拟半透明质感正是本方法的实现基础。逐行解析实现完整实现MeshSSSNodeMaterial.js#L47-L65direct( { lightDirection, lightColor, reflectedLight }, builder ) { if ( this.useSSS true ) { const material builder.material; const { thicknessColorNode, thicknessDistortionNode, thicknessAmbientNode, thicknessAttenuationNode, thicknessPowerNode, thicknessScaleNode } material; // 1. 散射半向量光线方向 被扭曲的法线归一化 const scatteringHalf lightDirection.add( normalView.mul( thicknessDistortionNode ) ).normalize(); // 2. 散射强度视线与反半向量的点积saturate 后按 power 取幂再乘 scale const scatteringDot float( positionViewDirection.dot( scatteringHalf.negate() ) .saturate() .pow( thicknessPowerNode ) .mul( thicknessScaleNode ) ); // 3. 散射照度(散射强度 环境项) × 厚度颜色 const scatteringIllu vec3( scatteringDot.add( thicknessAmbientNode ).mul( thicknessColorNode ) ); // 4. 按衰减系数与光源颜色累加到直接漫反射 reflectedLight.directDiffuse.addAssign( scatteringIllu.mul( thicknessAttenuationNode.mul( lightColor ) ) ); } super.direct( { lightDirection, lightColor, reflectedLight }, builder ); }结合源码可以归纳出该近似的计算语义散射半向量scatteringHalfnormalView.mul( thicknessDistortionNode )用扭曲系数缩放视图空间法线再加到光源方向上相当于模拟光穿入物体后出射方向的偏折thicknessDistortionNode越大出射光偏离镜面半角越多。scatteringDot取视线方向positionViewDirection与反向半向量的点积——这度量的是背侧散射可见性视线越接近光线穿过的背面点积越大。saturate()钳制到 [0,1] 后pow( thicknessPowerNode )控制高光衰减的陡峭程度power 越大散射区越聚拢mul( thicknessScaleNode )则是整体强度增益。scatteringIlluscatteringDot thicknessAmbientNode表明该近似还包含一个与光源位置无关的环境透光分量thicknessAmbientNode再统一乘以厚度颜色thicknessColorNode通常是 vec3 颜色节点或纹理定义光透过物体后的颜色。累加目标结果经thicknessAttenuationNode衰减系数与光源颜色缩放后写入reflectedLight.directDiffuse——即 SSS 项被当作漫反射的一部分参与后续能量分配而不是独立于 PBR 管线的新层。调用顺序SSS 项先累加随后super.direct(...)执行完整的 PBR 直接光照Lambert GGX 可选 clearcoat/sheen/retroreflection见 PhysicalLightingModel.js#L624-L677两者叠加得到最终直接光照输出。值得注意的是SSS 项对每个直接光源方向光、点光源、聚光灯都会执行一次——它挂载在LightingModel抽象基类定义的逐光源求值钩子上LightingModel.js#L37-L45 的注释说明direct在方向光、点光、聚光节点构建过程中被调用。MeshSSSNodeMaterial驱动 SSS 项的 6 个厚度参数SSSLightingModel的每一项数值都来自材质MeshSSSNodeMaterial上的 TSL 节点属性MeshSSSNodeMaterial.js#L88-L135材质属性类型默认值在 SSS 项中的作用thicknessColorNodeNodevec3null厚度颜色同时是 SSS 的激活开关getteruseSSS判空thicknessDistortionNodeNodefloatfloat( 0.1 )法线扭曲系数控制散射出射方向偏折程度thicknessAmbientNodeNodefloatfloat( 0.0 )环境透光分量与光源方向无关的常数项thicknessAttenuationNodeNodefloatfloat( .1 )SSS 项整体衰减/强度缩放thicknessPowerNodeNodefloatfloat( 2.0 )散射衰减幂指数越大散射区越窄thicknessScaleNodeNodefloatfloat( 10.0 )散射强度总增益所有参数都是 Node而非标量因此可以用uniform()、纹理采样、或其他 TSL 表达式逐像素驱动。例如官方示例中thicknessColorNode就是一张厚度贴图乘以颜色缩放texture( thicknessTexture ).mul( vec3( 0.5, 0.3, 0.0 ) )。调用链从 NodeMaterial 到 SSSLightingModel从源码结构看光照模型并非由用户手动实例化而是在材质构建build阶段由节点构建器装配NodeMaterial基类的setupLighting( builder )在判断场景有光且lights开启后调用子类的setupLightingModel( builder )并用lightingContext( lightsNode, lightingModel, ... )把光照模型包进出射光节点src/materials/nodes/NodeMaterial.js#L1089-L1093MeshSSSNodeMaterial重写的setupLightingModel()返回new SSSLightingModel( ... )六个 PBR 开关与useSSS一并提供之后每个光源节点求值时回调lightingModel.direct( lightData, builder )SSSLightingModel在此处先累加 SSS 项再委托父类完成 PBR 直接光照。因此使用者只需把MeshSSSNodeMaterial赋给 Mesh 并设置厚度节点无需也不应直接 newSSSLightingModel。实战跑通 examples/webgpu_materials_sss.html仓库自带完整可运行的示例 examples/webgpu_materials_sss.html配套截图见 examples/screenshots/webgpu_materials_sss.jpg其核心流程使用WebGPURenderer加载斯坦福兔子 examples/models/fbx/stanford-bunny.fbx 作为承载几何体场景布置一个环境光、一个方向光和两个点光源一个暖色、一个冷色用于展示多光源下的散射叠加创建材质并注入 SSS 参数示例代码 examples/webgpu_materials_sss.html#L121-L129const material new THREE.MeshSSSNodeMaterial(); material.color new THREE.Color( 1.0, 0.2, 0.2 ); material.roughness 0.3; material.thicknessColorNode texture( thicknessTexture ).mul( vec3( 0.5, 0.3, 0.0 ) ); material.thicknessDistortionNode uniform( 0.1 ); material.thicknessAmbientNode uniform( 0.4 ); material.thicknessAttenuationNode uniform( 0.8 ); material.thicknessPowerNode uniform( 2.0 ); material.thicknessScaleNode uniform( 16.0 );注意thicknessColorNode一经赋值useSSSgetter 即返回trueSSSLightingModel的 SSS 分支随之后端生效。示例还通过 Inspector GUI 暴露了五个实时调参滑块examples/webgpu_materials_sss.html#L148-L194其推荐取值区间对调参很有参考价值参数GUI 取值范围步长distortionthicknessDistortionNode0.01 – 10.01ambientthicknessAmbientNode0.01 – 5.00.05attenuationthicknessAttenuationNode0.01 – 5.00.05powerthicknessPowerNode0.01 – 16.00.1scalethicknessScaleNode0.01 – 50.00.1本地运行方式在仓库根目录启动开发服务器如npx serve或仓库提供的 utils/server.js然后访问examples/webgpu_materials_sss.html页面示例的 importmap 指向../build/three.webgpu.js与../build/three.tsl.js因此需要仓库已构建出build/产物。适用前提与限制该材质属于实验性experimental扩展仅在 WebGPU 渲染管线three/webgpu入口 WebGPURenderer下以节点材质方式工作与 WebGL 渲染器无关该 SSS 是近似算法它不依赖厚度网格数据如硬件厚度图仅用穿过物体的半向量模型模拟背侧透光适合皮肤、蜡、玉石等薄壁物体的快速视觉近似不能替代基于辐射传输的真实 SSS特性开关是构建期标志thicknessColorNode未赋值时useSSS为false生成的着色器不含 SSS 分支SSSLightingModel行为退化为PhysicalLightingModel。参考路径汇总内容路径API 文档本文主体docs/pages/SSSLightingModel.html.md光源模型与材质实现src/materials/nodes/MeshSSSNodeMaterial.js父类物理光照模型src/nodes/functions/PhysicalLightingModel.js抽象光照模型基类src/nodes/core/LightingModel.js材质 → 光照模型装配src/materials/nodes/NodeMaterial.js可运行示例examples/webgpu_materials_sss.html【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进