关于 3d-wood-material
面向 Three.js 场景制作的程序化木材材质技能,通过共享噪声场在着色器中生成木纹、孔隙、纤维、射线和工具痕迹。材质参数还能模拟不同木种与原木、油、蜡及漆面效果。
主要功能
- 01程序化生成木纹与年轮
- 02呈现孔隙、纤维和木射线
- 03随纹理变化的粗糙度与凹凸
- 04参数化木种和表面处理
- 05依据屏幕细节淡化纹理
适用场景
- 01为木制模型制作程序化表面
- 02呈现木板端面与不同纹理方向
- 03为模型添加油、蜡或漆面效果
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mengto/ skills --skill 3d-wood-material安装后在 Claude Code 中输入/3d-wood-material确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
demo.htmlPROMPT.mdagents/openai.yaml详细介绍
3D 木材材质
**机制:**片元着色器会在不同拉伸程度和尺度下读取同一个经过 MIP 过滤的小型周期性噪声场,因此环纹位置、晚材、孔隙、纤维、射线和刀痕都来自同一片蜿蜒的纹理,并共同影响颜色、粗糙度和浮雕效果,各自按照对应的屏幕占用范围逐渐淡出。
适用范围。本技能仅涉及木材表面。要处理整场景光照、射线和木材渲染评分,请使用 3d-wood-lighting-scorecard。对于基于图像的 PBR 贴图集(下载的贴图、纹素预算、KTX2 交付),请使用 3d-high-resolution-textures;需要照片或扫描的木材种类时,也应使用它。要处理轮廓、倒角和 LOD 几何体,请使用 3d-high-poly-models;本技能只需要圆钝的棱边(见下文)。布料、金属和纸张各有对应的同类技能。
先运行 demo.html(Kibori 工作台、四种木材、四种表面处理、宏观视图,以及可切换为失效效果的开关)。PROMPT.md 可重现该演示。
配方
- 修补,不要替换。 构建
MeshPhysicalMaterial({color:0xffffff, roughness:max(0.43,r), ior:1.43, specularIntensity:0.72}),并在onBeforeCompile中编辑:#include <map_fragment>将diffuseColor乘以木材颜色,#include <roughnessmap_fragment>设置roughnessFactor=clamp(roughness*W.rough,0.35,1),#include <normal_fragment_maps>将法线替换为木材高度W.h的屏幕空间凹凸效果。光照、阴影、IBL 和色调映射保持默认。顶点阶段只传递物体空间位置vOP和物体法线。 - 烘焙一个场。 将周期梯度噪声渲染到一个 1024² 的
RepeatWrapping、LinearMipmapLinear、NoColorSpace渲染目标中(周期为 64,三个八度:.r为基础值,.g为 fbm 0.60/0.27/0.13,.b为偏移副本)。读取时使用texture(p/64),只需一次采样。所有木材共用它;木板间的差异通过种子偏移实现,而不是使用不同纹理。 - 木纹轴。
uAxis的 0/1/2 分别选择木轴;along是该坐标,cross2是另外两个坐标。endgrain = pow(|n·axis|, 6)会让导管从条纹翻转为开放细胞,并使端面颜色变暗。 - 年轮。 用两个缓变场让髓心漂移,
radius=|(cross2+(-drift, offAxis+0.48))*(1,0.56)|,growth=radius*ringFreq加上 fbm 摆动(±1.25圈),ring=floor(growth),phase=fract。每一圈都从annual噪声中取自己的宽度:lateWidth=0.065+annual*0.21。晚材使用陡峭的smoothstep(0.94-w, 0.97-w, phase),并由1-smoothstep(0.965,1,phase)截断。较小的offAxis会产生拱形纹理;较大的offAxis会产生笔直的径切纹理。 - 细节层,每层都根据自身的覆盖范围淡出(对 growth 使用
fwidth,对导管、纤维和木射线坐标使用length(dFdx,dFdy)):
| 层 | 坐标 | 强度 |
|---|---|---|
| 导管(管孔) | (fiberX*96, along*7.5),端面处的细胞为 cross2*88,smoothstep(0.59,0.75) | 色调 +0.25,粗糙度 +0.19,高度 -0.42 |
| 纤维 | (fiberX*230, along*2.4) | 色调 -0.16,高度 +0.09,端面处乘以 0.25 |
| 木射线 | (across*13, along*115),smoothstep(0.64,0.78) | 色调向浅色偏移 +0.26,粗糙度 -0.075 |
| 裂纹 | curl.b smoothstep(0.70,0.82) 乘以 uChecks | 色调向 dark*0.68 偏移,高度 -0.20 |
| 节疤 | 哈希单元尺寸为 1.85 x 4.6,占比 29%,影响在单元边缘处消失 | 核心色调 +0.44,使纤维偏折 |
| 工具痕迹 | (along*17, across*0.4) | 高度 +0.045 乘以 uTool |
- 色调:
tone=0.075+late*0.40+early*0.070+pores*0.25-fibres*0.16+(broad.g-0.5)*0.23+knotCore*0.44,颜色为mix(pale,dark,clamp(tone,0.035,0.83)),再乘以*(0.93+annual*0.095+…)。粗糙度为0.91+late*0.13+pores*0.19+(broad.b-0.5)*0.20-rays*0.075+endgrain*0.14。 - 使用凹凸,不用法线贴图。
bumpNormal使用基于导数的 Mikkelsen 凹凸方法,并将梯度限制为0.38*|det|,因此陡峭的阶跃不会翻转法线。uBump=bump*0.020。 - 表面处理使用参数,而不是纹理。 原木:
clearcoat 0。油饰:pow(rgb,1.16)和rough*0.88,clearcoat 0.10 / 0.55。蜡饰:clearcoat 0.22 / 0.38。漆饰:亮度曲线pow(l,0.5),端面变暗*(1-eg*0.55),添加暖色调,将磨损的棱边擦回浅色,clearcoat 0.42 / 0.40。 - 倒圆棱边。 对每块木板使用
chamferBox,半径为min(w,h,d)*0.055(最多为任一边长的 0.24 倍),分段数为 3 到 5,并根据倒圆后的角设置法线。锐利的方盒边缘没有高光,看起来像被剪出来的。 - 为每块木板设置独立种子,并在更改木种或表面处理时保持稳定(在构建前后保存并恢复
woodMaterialSerial,种子设为n*7.113)。通过场偏移几何体(woodBox(..., ox,oy,oz)),让合并或共用材质的木板仍然彼此不同。
木种常量(来自工作坊)
| 木种 | 浅色 / 深色 | 粗糙度 | 纹理颗粒 | ringFreq | offAxis | 备注 |
|---|---|---|---|---|---|---|
| keyaki | #8a5f38 / #3d2412 | 0.62 | 1.5 | 20 to 34 | 0.75 | 木射线 0.35,凹凸 0.10 |
| sugi | #c8a579 / #9b774d | 0.58 | 1.8 | 8 to 30 | 2.8 | 晚材清晰,工具 0.30 |
| hinoki | #d8c096 / #8a6b40 | 0.44 to 0.50 | 2.2 | 6 to 42 | 1.6 | 纹理细密、对比度低 |
| kuri | #6f4d2c / #2c1a0b | 0.55 | 3.0 | 5 to 22 | 1.4 | 木射线 0.5,干裂 0.10 |
| 炭化木板 | #1a1511 / #0e0b08 | 0.97 | 0.8 | 9 | 0.55 | 木射线 0,干裂 0.30 |
ringFreq 的单位是每模型单位的数量,因此应根据实际年轮间距设置(在建模比例下约为 2 到 5 mm),而不是在不同场景间照搬数值:工作坊中的 7 到 8 在演示比例下看起来像粗条纹,直到提高到 20 到 42 才合适。
常见问题及解决方案
- 第二块木板上出现重复的纹理图块。 使用
repeat的画布图块会在每块木板上绘制相同的年轮,并在掠射光下显出接缝。采样物体空间中的位置,为每种材质设置不同种子,并通过纹理场偏移几何体。 - 平坦的粗糙度看起来像塑料。 粗糙度必须随木纹变化:导管更粗糙(+0.19),晚材略粗糙(+0.13),木射线更光滑(-0.075)。固定为 0.3 会产生均匀明亮的光泽,年轮上也不会出现变化。
- 只有颜色,没有凹凸。 只在反照率中绘制的年轮,在掠射光下会显得平坦。将相同的
late、pores和fibres输入高度并添加凹凸;同时限制梯度,否则年轮边缘过硬会导致法线翻转。 - 木纹没有顺着形体延伸。 从构件的实际轴线获取
along,不要从 UV 获取。在带倒角的方盒上使用 UV,会使圆角处的导管拉伸,并让木板变成条纹测试图。使用物体空间采样时,木纹会直穿角部,端面也会自动将导管切换为细胞。 - 细节在远处和掠射面上闪烁或爬动。 每个高频层都必须根据自身的屏幕覆盖范围淡出:
x *= 1 - smoothstep(a, b, fwidth-of-its-coordinate)。对纹理场生成 mipmap;当fwidth(growth)超过0.16..0.72时,将late和early混合到各自的平均值。否则,年轮在 3 m 处会在木板表面产生摩尔纹。 - 大尺度纹理看起来模糊、团块状,或凹凸上出现淡淡的方格网格。 当
grain 1.0时,1024² 纹理场被放大到每单位约 2,500 到 4,000 px 以上。双线性纹素边缘会渗入凹凸导数,形成网格;导管细胞会变软,年轮边缘也会在边界处呈点状。提高uGrainScale以缩小纤维尺寸,或将烘焙分辨率提高到 2048,以用于重点表面;切勿通过缩放网格来解决。 - 色彩空间错误。 纹理场是数据,应使用
NoColorSpace,而非 sRGB。色调映射只在最后应用一次(工作坊会在手写的最终渲染阶段执行;演示使用ACESFilmicToneMapping)。 - 油饰面材质却使用了原始饰面着色。 只在
extra片段上不同的材质会共用一个程序缓存键(onBeforeCompile.toString()),因此第二种材质会悄悄复用第一种材质的程序。为每种饰面设置不同的customProgramCacheKey;Urushi 包装器已这样处理。 - 环境光没有呈现粗糙度变化。 仅设置
scene.environment时,envMapIntensity会被忽略(r163+);请使用scene.environmentIntensity。木材需要在 PMREM 中加入明亮的窗户卡片,才能显示粗糙度贴图;灰色穹顶会将其隐藏。 - 切面看起来和顶面一样。 将切面乘以
1 - endgrain*(0.045+pores*0.10),并将其粗糙度提高+0.14:端纹会吸收饰面并保持哑光,这是最快判断材料为实木块的线索。 - 锐利的木板看起来像浮着。 没有倒棱且没有接触阴影的方盒看起来像是贴上去的。让每个部件准确放在支撑物上(
y = h/2),烘焙一次阴影贴图(shadowMap.autoUpdate=false),并检查特写视图中是否存在间隙。
性能预算
- 烘焙一次,使用带 mipmap 的 1024² RGBA8(约占用 5.6 MB GPU 显存),供所有木材共用。
- 在这块 Apple GPU 上使用无头 Chrome 测得:开启 MSAA 时,13 次绘制调用、约 2,000 个三角形(倒角方块、长凳、墙面),在 1440 × 900 分辨率下每帧耗时 1.0 至 1.5 ms,在 2880 × 1800 下耗时 3.4 至 4.5 ms;而普通平铺
MeshStandardMaterial分别耗时 0.65 ms 和 4.2 ms。在此场景中,程序化着色器在 1x 下约耗时 0.4 ms,到了 2x 时开销则被填充成本淹没。影响因素是填充率(DPR、MSAA),而非噪声。 - 将 DPR 上限设为 2。木板静止时只烘焙一次阴影。
document.hidden时暂停并重置时钟。将dt限制在 1/30 s。 - 对于
prefers-reduced-motion,跳过缓慢环绕并让摄像机移动时直接跳转;静止画面就是构图完成的主视觉。控件仍可使用。
本材质的自评分(0 至 10,基于以下标准)
标准:2 分,平铺照片,粗糙度均一。4 分,程序化条纹,仅有反照率。6 分,带年轮、浮雕和变化的粗糙度,近距离观察效果良好。8 分,孔隙、射线和端面木纹在 5 cm 处仍清晰,涂层和磨损效果可信,且无闪烁。10 分,任何距离下都像扫描得到的树种照片。
| 维度 | 评分 | 原因 |
|---|---|---|
| 近距离的木纹结构 | 7.5 | 年轮宽度、拱形纹理和节疤各不相同;默认静止画面中的 keyaki 仍略显规则 |
| 微观细节(3 至 5 cm) | 6.5 | 孔隙、纤维和工具痕迹都清晰可见;当每单位超过 4,000 px 时,1024² 纹理会变模糊 |
| 粗糙度和涂层 | 7.5 | 油、蜡和 urushi 会随年轮和孔隙呈现不同效果;没有各向异性高光 |
| 端面木纹和边缘 | 7 | 开放的细胞结构和哑光切面;倒角圆润,但没有真实的边缘磨损 |
| 闪烁和掠射角表现 | 8 | 足迹淡出效果干净,掠射角和远距离观察效果也很干净 |
| 总分 | 7.3 |
来源
提取自 Kibori 木彫工坊页面,其中一个 woodMat() 木材着色器用于墙壁、长凳、工具手柄、kumiko 格栅和漆器箱;demo.html 中的生成器原样复制自该文件。木材针对近距离观察摄像机进行了调校,因此以上所有常量均为工坊原有设置。