3d-cloth-material

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

3D Cloth Material

3D 布料材质

Mechanism: hang the cloth as rows whose tangent angle is the fold signal, so arc length equals the rest coordinate
s
and the weave never stretches. Then let a thread-level weave, sheen, hem thickness and light through the gaps do the reading of "fabric".
Nearest neighbours:
3d-high-resolution-textures
chooses texel density, mipmaps and delivery for any material; use it for the budget and stay here for what makes cloth different (weave interlacement, folds, sheen, hems).
3d-wood-material
,
3d-paper-material
and
3d-metal-material
cover their own surfaces; this skill owns woven and sewn fabric only. It is not a cloth simulation: for a character's flowing cape or a flag that collides, simulate (Verlet or Blender cloth) and bake, then keep the material rules below.
Extracted from KIBORI 木彫, a dark WebGL workshop where a roll of indigo canvas (the dōgu-maki) lies under a warm key light and had to survive a macro close-up. Ported from there: the weave bake, the stitch shader, half-circle hem turn-under, wear on thread tops, the sheen constants. Newly built for this skill (Kibori has one indigo canvas, not three fabrics): the tangent-angle fold curve, satin and twill interlacements, silk/wool/linen tables, tabs on the rod, raw-edge fray, fold AO, backlit transmission, wind.
demo.html
is the reference.
Demo: Three.js r169 · WebGL · GLSL (
MeshPhysicalMaterial
+
onBeforeCompile
), vanilla JavaScript, no post chain.
原理: 将布料悬挂为逐行结构,并以切线角表示褶皱信号,使弧长等于静止坐标
s
,因此织纹永不拉伸。随后借助线级织纹、Sheen、折边厚度以及穿过缝隙的光线来呈现“织物”质感。
最相关的 skill:
3d-high-resolution-textures
负责任何材质的纹素密度、Mipmap 和资源交付方式;用它来控制预算,并留在本 skill 中处理布料特有的部分(编织交错、褶皱、Sheen、折边)。
3d-wood-material
、
3d-paper-material
和
3d-metal-material
负责各自的表面;本 skill 仅负责编织和缝制织物。它不是布料模拟:若需角色飘逸的披风或会与物体碰撞的旗帜,应先进行模拟(Verlet 或 Blender cloth)并烘焙,然后继续遵循以下材质规则。
提取自 KIBORI 木彫——一个深色 WebGL 工坊,暖色主光下放着一卷靛蓝色帆布(dōgu-maki),并且必须经得住微距特写。由此移植了:织纹烘焙、针脚着色器、半圆形折边内翻、线顶磨损以及 Sheen 常量。为本 skill 新建(Kibori 只有一种靛蓝帆布,而不是三种布料):切线角褶皱曲线、缎纹与斜纹交错、丝绸/羊毛/亚麻参数表、挂杆上的挂袢、毛边流苏、褶皱 AO、背光透射以及风动。
demo.html
为参考实现。
演示:Three.js r169 · WebGL · GLSL(
MeshPhysicalMaterial
+
onBeforeCompile
),原生 JavaScript,无后处理链。

The rules, each with the failure it prevents

各项规则及其所防止的问题

  1. Integrate folds from an angle, not a height.
    α(s) = a·(sinθ + 0.16 sin(2θ+0.8)) + …
    , then
    x += ds·cos α
    ,
    z += ds·sin α
    . Failure: a height field
    z = A·sin(kx)
    gives arc length 1 + slope², so the weave swims and stretches 30–80% on every fold. With the angle form
    uv = (s, v)
    in metres is exact. Keep
    |α| < 1.45
    rad; past that it clamps into flat plateaus and folds become tubes with black seams.
  2. Uv is material metres, never re-fitted per frame. Do not recompute uv from the moving surface. Failure: weave shimmers and crawls in wind. Set
    texture.repeat = 1/(threads × pitch)
    so one texel tile is
    NT
    threads; linen 1.6 mm, silk 0.7 mm, wool 2.6 mm pitch.
  3. Bake interlacement, not noise. Each thread has its own width (0.80–0.97), tone and a slub (Gaussian thickening up to 0.34). Warp height blends over/under across cell borders by
    0.5·smoothstep(0.05, 0.5, |t|)
    . Plain =
    (A+B)&1
    , twill 2/1 =
    (A+B)%3 < 2
    , 5-harness satin =
    (2A+B)%5 != 0
    warp-over.
    NT
    must be a multiple of the repeat (32, 24, 40) or the tile shows a seam. Failure: a tiled noise normal map reads as stucco or leather.
  4. Spun yarn gets a twist. Add
    0.22·twist·sin(2π(5·along + 1.3·across))
    to each thread height (twist 0.10–0.14 for linen and wool, 0 for silk). Failure: linen looks like wire mesh.
  5. Two dyes, per-thread tone. Colour
    mix(warpDye, weftDye, weftOnTop·shot)
    ; silk uses shot 1.0 (madder red warp, gold weft), the rest 0. Tone
    mix(0.86, 1.14, threadTone)
    , cavity
    mix(0.5, 1, smoothstep(0.05, 0.85, height))
    , blotch + warp-direction streaks
    1 + var·((blot−0.5)·0.62 + (streak−0.5)·0.22)
    . Failure: one flat albedo on a woven map looks printed.
  6. Sheen is the fabric, and it must be small.
    sheen 0.5–1.0
    ,
    sheenRoughness 0.28 (silk) – 0.82 (wool)
    , and
    sheenColor = dye lightened × 0.62
    . Failure: near-white
    sheenColor
    blows out to a milky rim under a warm key. Never set
    sheen
    to exactly 0 at runtime (0.0001); crossing zero recompiles the program and hitches 200+ ms.
  7. Silk gets anisotropy, wool gets fuzz. Silk
    anisotropy 0.85, roughness 0.36
    ; linen
    0.90
    rough with sheen 0.55; wool
    0.96
    rough with sheen 1.0. Keep
    anisotropy
    above 0 at creation (0.0001) so the define never flips.
  8. Fold occlusion is not optional. Cast and receive the key's shadow map (
    normalBias 0.012
    ,
    bias −0.0004
    ,
    DoubleSide
    shadows) and add a vertex AO from the fold depth
    0.62 + 0.38·smoothstep(−0.075, 0.035, zFold)
    on indirect light. Failure: without both, valleys light up like the crests and the folds look painted.
  9. Edges have thickness. Turn every free edge under on a half circle,
    P = edge + out·r·sinφ − N·r(1−cosφ)
    ,
    φ ∈ [0, 0.94π]
    ,
    r
    = 1.1 mm silk, 2.2 mm linen, 4.6 mm wool. Return the bottom hem up the back at
    2r + 0.2 mm
    with flipped normals. Failure: a zero-thickness cut edge is the loudest tell for CG cloth in a close-up.
  10. Stitch in the shader, in cloth metres. Thread arches between holes (
    4·x(1−x)
    over 74% of the pitch), the needle groove and pucker feed the normal by finite difference, faded by
    fwidth
    . Hem 3 cm up, sides 2.2 cm in, seam
    ±7 mm
    with a proud ridge that puckers every 4 pitches. Failure: geometry stitches z-fight and alias; texture-painted ones do not follow the folds.
  11. Raw edge: draw out the weft. Beyond the cut, discard fragments except the warp threads (
    |fract(u/pitch)−0.5| < 0.36
    ), each with a random length
    F·(0.3+0.7·hash)
    . Failure: an alpha fringe texture has no thread structure.
  12. Thin cloth passes light.
    emissive += trans · lightColour · dye·(1.7,1.2,0.85) · pow(max(0, −N·L), 1.15) · gap · thin
    with
    gap = mix(1, 0.42, height)
    so threads block and gaps pass. Silk 1.05, linen 0.6, wool 0.06. Failure: without it a lit window behind a curtain does nothing.
  13. Wear where cloth is touched.
    wear = clamp(aWear·(0.25+height) + (fbm−0.5)·0.3, 0, 1)
    → mix dye toward a pale colour by
    wear·threadTop
    . Hems +0.4, crests +0.3. Failure: uniform dye reads brand new.
  1. 从角度而非高度积分褶皱。
    α(s) = a·(sinθ + 0.16 sin(2θ+0.8)) + …
    ,然后
    x += ds·cos α
    、
    z += ds·sin α
    。失败:高度场
    z = A·sin(kx)
    的弧长为 1 + slope²,因此每个褶皱处的织纹都会游移并拉伸 30–80%。采用角度形式后,
    uv = (s, v)
    以米为单位可精确对应。保持
    |α| < 1.45
    rad;超过后会钳制为平坦平台,褶皱会变成带黑缝的管状。
  2. UV 是材质米制坐标,绝不逐帧重新拟合。 不要根据移动中的表面重新计算 UV。失败:织纹在风中会闪烁并爬行。设置
    texture.repeat = 1/(threads × pitch)
    ,使每个贴图周期包含
    NT
    根纱线;亚麻间距为 1.6 mm,丝绸为 0.7 mm,羊毛为 2.6 mm。
  3. 烘焙交错结构,而不是噪声。 每根纱线都有自己的宽度(0.80–0.97)、色调和粗节(高斯增粗最高 0.34)。经纱高度通过
    0.5·smoothstep(0.05, 0.5, |t|)
    在单元边界处混合上下关系。平纹 =
    (A+B)&1
    ,斜纹 2/1 =
    (A+B)%3 < 2
    ,5 枚缎纹 =
    (2A+B)%5 != 0
    表示经纱在上。
    NT
    必须是 repeat 的倍数(32、24 或 40),否则图块会显示接缝。失败:平铺噪声法线贴图看起来像灰泥或皮革。
  4. 短纤纱线需要捻度。 将
    0.22·twist·sin(2π(5·along + 1.3·across))
    添加到每根纱线的高度中(亚麻和羊毛的 twist 为 0.10–0.14,丝绸为 0)。失败:亚麻会看起来像金属网。
  5. 使用两种染料和逐纱线色调。 颜色为
    mix(warpDye, weftDye, weftOnTop·shot)
    ;丝绸使用 shot 1.0(茜红经线、金色纬线),其余为 0。色调为
    mix(0.86, 1.14, threadTone)
    ,凹陷区域为
    mix(0.5, 1, smoothstep(0.05, 0.85, height))
    ,斑块与经向条纹为
    1 + var·((blot−0.5)·0.62 + (streak−0.5)·0.22)
    。失败:在编织贴图上使用单一平坦的 albedo 会显得像印花。
  6. Sheen 才体现织物感,而且必须很弱。
    sheen 0.5–1.0
    ,
    sheenRoughness 0.28(丝绸)– 0.82(羊毛)
    ,并且
    sheenColor = 染料提亮值 × 0.62
    。失败:接近白色的
    sheenColor
    在暖色主光下会过曝成乳白色边缘。运行时绝不要将
    sheen
    精确设为 0(应设为 0.0001);跨过零点会重新编译程序,并造成超过 200 ms 的卡顿。
  7. 丝绸使用各向异性,羊毛使用绒毛。 丝绸为
    anisotropy 0.85, roughness 0.36
    ;亚麻为
    0.90
    roughness、sheen 0.55;羊毛为
    0.96
    roughness、sheen 1.0。创建时保持
    anisotropy
    大于 0(0.0001),确保 define 不会发生翻转。
  8. 褶皱遮蔽不可省略。 投射并接收主光的 shadow map(
    normalBias 0.012
    、
    bias −0.0004
    、
    DoubleSide
    阴影),并根据褶皱深度
    0.62 + 0.38·smoothstep(−0.075, 0.035, zFold)
    在间接光上添加 vertex AO。失败:如果缺少两者,褶皱谷底会像峰顶一样明亮,褶皱看起来像是画上去的。
  9. 边缘必须具有厚度。 每条自由边都沿半圆向内翻折,
    P = edge + out·r·sinφ − N·r(1−cosφ)
    ,
    φ ∈ [0, 0.94π]
    ,
    r
    = 丝绸 1.1 mm、亚麻 2.2 mm、羊毛 4.6 mm。将底部折边沿背面回折到
    2r + 0.2 mm
    ,并翻转法线。失败:零厚度切边是 CG 布料特写中最明显的破绽。
  10. 在着色器中以布料米制坐标缝制。 纱线在针孔之间形成拱形(
    4·x(1−x)
    ,覆盖间距的 74%),针槽和褶皱通过有限差分影响法线,并由
    fwidth
    淡出。折边向上 3 cm,侧边向内 2.2 cm,接缝位于 ±7 mm,并带有一道凸起脊线,每 4 个间距产生一次褶皱。失败:几何针脚会发生 Z-fighting 和 alias;贴图绘制的针脚则无法跟随褶皱。
  11. 毛边:抽出纬纱。 在切口之外,除经纱线程(
    |fract(u/pitch)−0.5| < 0.36
    )外丢弃所有片元,每根经纱的长度为随机值
    F·(0.3+0.7·hash)
    。失败:alpha 边缘贴图没有真实的纱线结构。
  12. 薄布可以透光。
    emissive += trans · lightColour · dye·(1.7,1.2,0.85) · pow(max(0, −N·L), 1.15) · gap · thin
    ,其中
    gap = mix(1, 0.42, height)
    ,让纱线阻挡光线、缝隙透过光线。丝绸为 1.05,亚麻为 0.6,羊毛为 0.06。失败:没有该效果时,窗帘后方被照亮的窗户不会产生任何透光效果。
  13. 布料被接触的位置产生磨损。
    wear = clamp(aWear·(0.25+height) + (fbm−0.5)·0.3, 0, 1)
    ,然后通过
    wear·threadTop
    将染料混合为浅色。折边增加 0.4,褶皱峰顶增加 0.3。失败:均匀的染色会显得全新。

Constants

常量

linensilkwool
weave / NT / pitchplain / 32 / 1.6 mm5-harness satin / 40 / 0.7 mmtwill / 24 / 2.6 mm
normal strength S · normalScale2.6 · 1.151.5 · 0.62.9 · 1.45
roughness · sheen · sheenR0.90 · 0.55 · 0.550.36 · 0.5 · 0.280.96 · 1.0 · 0.82
fold λ · amax · wind gain0.34 m · 0.98 · 1.00.40 · 1.02 · 1.90.32 · 0.86 · 0.55
edgeraw fray 3 cmhem 3.5 cmhem 5 cm
Cloth 2.0 × 1.95 m, grid 160 × 120 (≈ 21k verts, 45k tris). Key SpotLight 0xffd0a0 × 3.0, angle 0.44, decay 0; cool fill 1.0; window back light 0.2–1.8; environment intensity 0.42; ACES, exposure 1.0.
亚麻丝绸羊毛
编织方式 / NT / 间距平纹 / 32 / 1.6 mm5 枚缎纹 / 40 / 0.7 mm斜纹 / 24 / 2.6 mm
法线强度 S · normalScale2.6 · 1.151.5 · 0.62.9 · 1.45
roughness · sheen · sheenR0.90 · 0.55 · 0.550.36 · 0.5 · 0.280.96 · 1.0 · 0.82
褶皱 λ · amax · 风增益0.34 m · 0.98 · 1.00.40 · 1.02 · 1.90.32 · 0.86 · 0.55
边缘3 cm 毛边3.5 cm 折边5 cm 折边
布料尺寸 2.0 × 1.95 m,网格 160 × 120(≈ 21k 个顶点,45k 个三角形)。主 SpotLight 为 0xffd0a0 × 3.0,angle 0.44,decay 0;冷色补光为 1.0;窗户背光为 0.2–1.8;环境强度为 0.42;ACES,exposure 1.0。

Gotchas, symptom first

常见问题:先看症状

  • Weave crawls or shimmers when it moves → uv was rebuilt from arc length or scrolled; keep it as the rest metres.
  • Horizontal moire stripes at wide view → bump/crease term uses
    dFdx
    of a high-frequency noise; keep crease octaves below 17 cycles/m and scale by 0.016. Mipmaps + 16× anisotropy handle the weave itself.
  • Folds are flat panels with black slits →
    |α|
    clamped. Lower
    amax
    so
    a·env·1.28 < 1.45
    , do not add more darkness.
  • Everything glows orange when backlit → transmission colour multiplied by a warm light and a warm dye. Tint by
    (1.7,1.2,0.85)
    , not
    (2.1,1.35,0.72)
    .
  • envMapIntensity does nothing → in r163+ it only applies with
    material.envMap
    ; with
    scene.environment
    use
    scene.environmentIntensity
    .
  • onBeforeCompile
    shader is shared between two meshes with different uniforms
    → set
    customProgramCacheKey
    , and put uniforms on the material, not the mesh.
  • Winding wrong on a hem strip (lit inside-out) → pick each strip's index order from the sign of its first triangle normal against the attribute normal, once, after the first update.
  • Turn-under leaves a dark gap → the return strip must sit at
    2r + 0.2 mm
    , not
    r
    .
  • Shadow acne on a double-sided sheet →
    normalBias
    , not a bigger
    bias
    ; a large bias detaches the fold shadows.
  • 织纹在移动时爬行或闪烁 → UV 是根据弧长重建或被滚动的;应保持为静止状态下的米制坐标。
  • 远景出现水平摩尔条纹 → bump/crease 项使用了高频噪声的
    dFdx
    ;折痕倍频应保持在每米 17 个周期以下,并按 0.016 缩放。织纹本身由 Mipmap + 16× anisotropy 处理。
  • 褶皱变成带黑缝的平板 →
    |α|
    被钳制。降低
    amax
    ,使
    a·env·1.28 < 1.45
    ,不要继续增加暗度。
  • 逆光时一切发橙 → transmission 颜色同时乘以暖色光和暖色染料。按
    (1.7,1.2,0.85)
    着色,不要使用
    (2.1,1.35,0.72)
    。
  • envMapIntensity
    无效
    → 在 r163+ 中,它仅在存在
    material.envMap
    时生效;使用
    scene.environment
    时应设置
    scene.environmentIntensity
    。
  • onBeforeCompile
    着色器被两个具有不同 uniforms 的 mesh 共享
    → 设置
    customProgramCacheKey
    ,并将 uniforms 放在 material 上,而不是 mesh 上。
  • 折边条带绕序错误,内部受光反了 → 在首次更新后,依据第一个三角形法线相对于属性法线的符号,为每条带选择索引顺序,并且只执行一次。
  • 向内翻折留下黑色缝隙 → 回折条带必须位于
    2r + 0.2 mm
    ,而不是
    r
    。
  • 双面薄片出现 shadow acne → 使用
    normalBias
    ,不要增大
    bias
    ;过大的 bias 会让褶皱阴影脱离物体。

Lifecycle

生命周期

prefers-reduced-motion
: render one designed still at
t = 7.3
(gust mid-swell), stop the loop, keep every control live and re-render on change. Pause on
document.hidden
; reset
last
on resume. Clamp
dt
to 1/30 s, cap DPR at 2 and step it down by 0.25 when a 60-frame average exceeds 26 ms. Size from a
ResizeObserver
. Expose no per-frame allocation in the cloth loop: reuse typed arrays and update
position
/
normal
only.
prefers-reduced-motion
:在
t = 7.3
(阵风起伏的中段)渲染一幅经过设计的静态画面,停止循环,保留所有控件的交互能力,并在变更时重新渲染。
document.hidden
时暂停;恢复时重置
last
。将
dt
钳制在 1/30 s,DPR 上限为 2;60 帧平均值超过 26 ms 时,每次下调 0.25。通过
ResizeObserver
调整尺寸。布料循环中不得产生逐帧分配:复用 typed arrays,只更新
position
/
normal
。

Cost (measured, headless Chrome for Testing, Apple GPU, 1440×900 at DPR 2)

成本(实测,无头 Chrome for Testing,Apple GPU,1440×900,DPR 2)

  • Cloth CPU (folds + normals + hems + tabs + fringe): 3.7–4.9 ms at 160×120. Halving the row count (190 → 120) bought −40%, and no fold was lost, because folds vary slowly down the drop.
  • Whole frame: 10–11 ms wide, 15 ms macro. The macro's extra 4 ms is the fragment shader (weave + stitch + fbm) over the whole screen, not geometry.
  • Boot: 0.8 s to first frame including three 512² weave bakes. Fabric switch 25 ms. Layer toggles 14 ms.
  • Not the bottleneck: triangle count, the 2048 shadow map, tabs, fringe (520 strands).
  • 布料 CPU(褶皱 + 法线 + 折边 + 挂袢 + 流苏):在 160×120 下为 3.7–4.9 ms。将行数减半(190 → 120)带来了 −40% 的提升,且没有丢失任何褶皱,因为褶皱沿垂落方向变化缓慢。
  • 整帧:广角为 10–11 ms,微距为 15 ms。微距额外增加的 4 ms 来自覆盖整个屏幕的片元着色器(织纹 + 针脚 + fbm),而非几何体。
  • 启动:0.8 s 到达首帧,包括三次 512² 织纹烘焙。布料切换为 25 ms。图层开关为 14 ms。
  • 并非瓶颈:三角形数量、2048 shadow map、挂袢、流苏(520 根)。

Score against the rubric (0 = flat coloured plane, 5 = convincing at arm's length, 10 = photographic macro)

评分标准得分(0 = 平坦着色平面,5 = 手臂长度距离下具有说服力,10 = 照片级微距)

Weave structure 7 · Sheen and dye 6.5 · Fold shape and drape 6 (a hanging curtain, not free cloth with self-contact) · Edges, stitches, seams 7.5 · Light transmission 6 · Wear 5.5 · Motion 5.5 (wind is analytic, no collision) · Performance 8. Overall 6.5. What would lift it: real self-collision folds (simulate and bake), fibre halo geometry on wool, a second normal scale for creases.
织纹结构 7 · Sheen 与染色 6.5 · 褶皱形态与垂坠 6(悬挂窗帘,而非带自接触的自由布料)· 边缘、针脚、接缝 7.5 · 光线透射 6 · 磨损 5.5 · 运动 5.5(风为解析式,无碰撞)· 性能 8。总分 6.5。可提升之处:真实的自碰撞褶皱(模拟并烘焙)、羊毛的纤维光晕几何体,以及用于折痕的第二组法线缩放。