three-simplecloth 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -66,7 +66,7 @@ type ClothConfig = {
66
66
  declare function setupClothOnSkinnedMesh(mesh: SkinnedMesh, renderer: WebGPURenderer, config?: Partial<ClothConfig>): {
67
67
  stiffnessUniform: import('three/webgpu').UniformNode<number | undefined>;
68
68
  dampeningUniform: import('three/webgpu').UniformNode<number | undefined>;
69
- gravityUniform: import('three/webgpu').UniformNode<Vector3 | undefined>;
69
+ gravityUniform: import('three/webgpu').UniformNode<Vector3>;
70
70
  windUniform: import('three/webgpu').UniformNode<Vector3 | undefined>;
71
71
  colliders: Collider[];
72
72
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"SimpleCloth.d.ts","sourceRoot":"","sources":["../src/SimpleCloth.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,QAAQ,EAGR,QAAQ,EAGR,OAAO,EACP,KAAK,WAAW,EACnB,MAAM,OAAO,CAAC;AAyBf,OAAO,EAEH,IAAI,EACJ,YAAY,EAEZ,KAAK,cAAc,EACtB,MAAM,cAAc,CAAC;AAItB,KAAK,QAAQ,GAAG;IACf,MAAM,EAAC,MAAM,CAAC;IACd,QAAQ,EAAC,QAAQ,GAAC,OAAO,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACvB;;OAEG;IACH,MAAM,EAAC,YAAY,CAAA;IAEnB;;OAEG;IACH,cAAc,EAAC,CAAC,CAAC,EAAC,MAAM,EAAE,CAAC,EAAC,MAAM,EAAE,CAAC,EAAC,MAAM,KAAK,IAAI,CAAA;IAErD;;OAEG;IACH,UAAU,EAAC,YAAY,CAAA;CACvB,CAAA;AAiLD,KAAK,WAAW,GAAG;IAElB;;OAEG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,QAAQ,CAAC;IAEzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAElC;;OAEG;IACH,aAAa,CAAC,EAAC,OAAO,CAAA;IAEtB;;OAEG;IACH,gBAAgB,CAAC,EAAC,OAAO,CAAA;IAEzB;;OAEG;IACH,OAAO,EAAC,MAAM,CAAC;IAEf;;;;;;;OAOG;IACH,cAAc,EAAE,CAAE,IAAI,EAAC,QAAQ,EAAE,YAAY,EAAC,IAAI,EAAE,UAAU,EAAC,IAAI,KAAM,YAAY,CAAA;CACrF,CAAA;AAiHD,iBAAS,uBAAuB,CAC5B,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,cAAc,EAC3B,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC;;;;;;IAof5B;;;;;OAKG;oBACmB,MAAM;IAuB5B;;;;;;;;;OASG;kCAC2B,MAAM,YAAW,OAAO,GAAC,QAAQ;;4BAkB9B,MAAM,KAAI,MAAM,KAAI,MAAM;;;EAiC5D;AAGD;;;;GAIG;AACH,qBAAa,WAAW;IAEvB;;;;;;;;;OASG;IACH,MAAM,CAAC,aAAa,iCAA2B;CAC/C"}
1
+ {"version":3,"file":"SimpleCloth.d.ts","sourceRoot":"","sources":["../src/SimpleCloth.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,QAAQ,EAGR,QAAQ,EAGR,OAAO,EACP,KAAK,WAAW,EACnB,MAAM,OAAO,CAAC;AAyBf,OAAO,EAEH,IAAI,EACJ,YAAY,EAEZ,KAAK,cAAc,EACtB,MAAM,cAAc,CAAC;AAItB,KAAK,QAAQ,GAAG;IACf,MAAM,EAAC,MAAM,CAAC;IACd,QAAQ,EAAC,QAAQ,GAAC,OAAO,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACvB;;OAEG;IACH,MAAM,EAAC,YAAY,CAAA;IAEnB;;OAEG;IACH,cAAc,EAAC,CAAC,CAAC,EAAC,MAAM,EAAE,CAAC,EAAC,MAAM,EAAE,CAAC,EAAC,MAAM,KAAK,IAAI,CAAA;IAErD;;OAEG;IACH,UAAU,EAAC,YAAY,CAAA;CACvB,CAAA;AAiLD,KAAK,WAAW,GAAG;IAElB;;OAEG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,QAAQ,CAAC;IAEzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAElC;;OAEG;IACH,aAAa,CAAC,EAAC,OAAO,CAAA;IAEtB;;OAEG;IACH,gBAAgB,CAAC,EAAC,OAAO,CAAA;IAEzB;;OAEG;IACH,OAAO,EAAC,MAAM,CAAC;IAEf;;;;;;;OAOG;IACH,cAAc,EAAE,CAAE,IAAI,EAAC,QAAQ,EAAE,YAAY,EAAC,IAAI,EAAE,UAAU,EAAC,IAAI,KAAM,YAAY,CAAA;CACrF,CAAA;AAiHD,iBAAS,uBAAuB,CAC5B,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,cAAc,EAC3B,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC;;;;;;IAwf5B;;;;;OAKG;oBACmB,MAAM;IAgC5B;;;;;;;;;OASG;kCAC2B,MAAM,YAAW,OAAO,GAAC,QAAQ;;4BAkB9B,MAAM,KAAI,MAAM,KAAI,MAAM;;;EAiC5D;AAGD;;;;GAIG;AACH,qBAAa,WAAW;IAEvB;;;;;;;;;OASG;IACH,MAAM,CAAC,aAAa,iCAA2B;CAC/C"}
package/dist/index.js CHANGED
@@ -1,85 +1,85 @@
1
- var Tt = Object.defineProperty;
2
- var Wt = (t, i, l) => i in t ? Tt(t, i, { enumerable: !0, configurable: !0, writable: !0, value: l }) : t[i] = l;
3
- var ut = (t, i, l) => Wt(t, typeof i != "symbol" ? i + "" : i, l);
4
- import { Vector3 as z, BufferAttribute as dt, Matrix4 as Ut, DoubleSide as kt, Scene as Dt } from "three";
5
- import { uniform as U, instancedArray as F, objectWorldMatrix as qt, computeSkinning as Ct, storage as Et, Fn as T, If as S, instanceIndex as f, Return as tt, mix as Rt, Loop as gt, bitcast as mt, select as pt, triNoise3D as bt, time as Bt, float as ft, uint as Lt, attribute as xt, cross as Yt, transformNormalToView as $t, frontFacing as jt } from "three/tsl";
1
+ var It = Object.defineProperty;
2
+ var Wt = (t, a, d) => a in t ? It(t, a, { enumerable: !0, configurable: !0, writable: !0, value: d }) : t[a] = d;
3
+ var ct = (t, a, d) => Wt(t, typeof a != "symbol" ? a + "" : a, d);
4
+ import { Vector3 as T, BufferAttribute as lt, Matrix4 as Ut, DoubleSide as kt, Scene as qt } from "three";
5
+ import { uniform as U, instancedArray as F, objectWorldMatrix as Dt, computeSkinning as Et, storage as Ct, Fn as N, If as w, instanceIndex as p, Return as O, mix as Rt, uint as ut, bitcast as dt, Loop as mt, select as gt, triNoise3D as Bt, time as Lt, float as bt, attribute as pt, cross as Yt, transformNormalToView as $t, frontFacing as jt } from "three/tsl";
6
6
  import { StorageInstancedBufferAttribute as Xt, MeshPhysicalNodeMaterial as Zt } from "three/webgpu";
7
- const Y = new z();
8
- function Gt(t, i = "color") {
9
- const l = t.geometry, o = l.attributes.position, d = l.getAttribute(i), g = o.count, a = /* @__PURE__ */ new Map(), h = /* @__PURE__ */ new Map(), m = new Uint32Array(g), G = [], k = [], D = [];
7
+ const X = new T();
8
+ function Gt(t, a = "color") {
9
+ const d = t.geometry, n = d.attributes.position, m = d.getAttribute(a), f = n.count, c = /* @__PURE__ */ new Map(), A = /* @__PURE__ */ new Map(), h = new Uint32Array(f), _ = [], k = [], q = [];
10
10
  let W = 0;
11
- const N = new z();
12
- for (let s = 0; s < g; s++) {
13
- const c = o.getX(s), v = o.getY(s), x = o.getZ(s), w = d ? d.getY(s) : 0, X = `${c},${v},${x}`;
14
- a.has(X) || (a.set(X, W), N.set(c, v, x), N.applyMatrix4(t.matrixWorld), G.push(N.x, N.y, N.z, w), W++), m[s] = a.get(X);
11
+ const z = new T();
12
+ for (let o = 0; o < f; o++) {
13
+ const l = n.getX(o), x = n.getY(o), y = n.getZ(o), P = m ? m.getY(o) : 0, B = `${l},${x},${y}`;
14
+ c.has(B) || (c.set(B, W), z.set(l, x, y), z.applyMatrix4(t.matrixWorld), _.push(z.x, z.y, z.z, P), W++), h[o] = c.get(B);
15
15
  }
16
- const q = [];
17
- new z(), new z();
18
- const C = /* @__PURE__ */ new Set(), $ = (s, c) => {
19
- h.has(s) ? h.get(s).push(c) : h.set(s, [c]);
20
- }, E = (s, c) => {
21
- const v = s + "-" + c, x = c + "-" + s;
22
- if (C.has(v) || C.has(x))
16
+ const D = [];
17
+ new T(), new T();
18
+ const I = /* @__PURE__ */ new Set(), Z = (o, l) => {
19
+ A.has(o) ? A.get(o).push(l) : A.set(o, [l]);
20
+ }, E = (o, l) => {
21
+ const x = o + "-" + l, y = l + "-" + o;
22
+ if (I.has(x) || I.has(y))
23
23
  return;
24
- const w = q.length / 4;
25
- q.push(s, c, 0, 0), $(s, w), $(c, w), C.add(v);
26
- }, u = l.index.array;
27
- for (let s = 0; s < u.length; s += 3) {
28
- const c = m[u[s]], v = m[u[s + 1]], x = m[u[s + 2]];
29
- E(c, v), E(x, v), E(c, x);
30
- const w = D.length;
31
- D.push([c, v, x]), k[u[s]] = w, k[u[s + 1]] = w, k[u[s + 2]] = w;
24
+ const P = D.length / 4;
25
+ D.push(o, l, 0, 0), Z(o, P), Z(l, P), I.add(x);
26
+ }, u = d.index.array;
27
+ for (let o = 0; o < u.length; o += 3) {
28
+ const l = h[u[o]], x = h[u[o + 1]], y = h[u[o + 2]];
29
+ E(l, x), E(y, x), E(l, y);
30
+ const P = q.length;
31
+ q.push([l, x, y]), k[u[o]] = P, k[u[o + 1]] = P, k[u[o + 2]] = P;
32
32
  }
33
- const j = [], R = new Uint32Array(W);
34
- for (let s = 0; s < W; s++) {
35
- R[s] = j.length;
36
- const c = h.get(s) || [];
37
- if (c.length == 0)
33
+ const C = [], R = new Uint32Array(W);
34
+ for (let o = 0; o < W; o++) {
35
+ R[o] = C.length;
36
+ const l = A.get(o) || [];
37
+ if (l.length == 0)
38
38
  debugger;
39
- j.push(c.length, ...c);
39
+ C.push(l.length, ...l);
40
40
  }
41
41
  return {
42
- vFaces: new Uint32Array(D.flat()),
42
+ vFaces: new Uint32Array(q.flat()),
43
43
  //vec3[]
44
44
  vVertexToFace: new Uint32Array(k),
45
45
  // uint
46
46
  springsPointer: new Uint32Array(R),
47
- springsPerVertexArray: new Uint32Array(j),
47
+ springsPerVertexArray: new Uint32Array(C),
48
48
  uniqueCount: W,
49
49
  // unique vertices
50
- indices: m,
50
+ indices: h,
51
51
  // for each vertice, stores the index of the unique one in the vPos array
52
- vPos: new Float32Array(G),
52
+ vPos: new Float32Array(_),
53
53
  // 4 components, a vector 3 positions of the unique vertices ( in world space ) + the weight
54
- springs: new Uint32Array(q)
54
+ springs: new Uint32Array(D)
55
55
  // Pair of index points in vPos representing a spring
56
56
  };
57
57
  }
58
- function Ot(t, i, l = 1) {
59
- const o = [];
60
- let d;
61
- return t.traverseAncestors((g) => {
62
- g instanceof Dt && (d = g);
63
- }), t.traverse((g) => {
64
- (g.userData.stickto || g.userData.clothCollider) && o.push({
65
- position: g,
58
+ function Ot(t, a, d = 1) {
59
+ const n = [];
60
+ let m;
61
+ return t.traverseAncestors((f) => {
62
+ f instanceof qt && (m = f);
63
+ }), t.traverse((f) => {
64
+ (f.userData.stickto || f.userData.clothCollider) && n.push({
65
+ position: f,
66
66
  radius: 0
67
67
  });
68
- }), o.forEach((g) => {
69
- var m;
70
- const a = g.position;
71
- let h;
72
- if (a.userData.stickto && (h = (m = i.getBoneByName) == null ? void 0 : m.call(i, a.userData.stickto.replaceAll(/[\.\:]/g, "")), !h))
73
- throw new Error("Bone not found for collider: " + a.userData.stickto) + " ???";
74
- d.attach(a), g.radius = Math.abs(a.getWorldScale(Y).x) * l, h == null || h.attach(a);
75
- }), o;
68
+ }), n.forEach((f) => {
69
+ var h;
70
+ const c = f.position;
71
+ let A;
72
+ if (c.userData.stickto && (A = (h = a.getBoneByName) == null ? void 0 : h.call(a, c.userData.stickto.replaceAll(/[\.\:]/g, "")), !A))
73
+ throw new Error("Bone not found for collider: " + c.userData.stickto) + " ???";
74
+ m.attach(c), f.radius = Math.abs(c.getWorldScale(X).x) * d, A == null || A.attach(c);
75
+ }), n;
76
76
  }
77
- function _t(t, i, l) {
77
+ function _t(t, a, d) {
78
78
  if ("isNodeMaterial" in t) {
79
- const o = t;
80
- return o.positionNode = i, o.normalNode = l, o;
79
+ const n = t;
80
+ return n.positionNode = a, n.normalNode = d, n;
81
81
  } else {
82
- const o = new Zt({
82
+ const n = new Zt({
83
83
  side: kt,
84
84
  // wireframe:true,
85
85
  wireframe: t.wireframe,
@@ -88,151 +88,158 @@ function _t(t, i, l) {
88
88
  depthWrite: t.depthWrite,
89
89
  depthTest: t.depthTest
90
90
  });
91
- return o.positionNode = i, o.normalNode = l, o.color = t.color, o.map = t.map, o.emissive = t.emissive, o.emissiveMap = t.emissiveMap, o.emissiveIntensity = t.emissiveIntensity, o.roughness = t.roughness, o.roughnessMap = t.roughnessMap, o.metalness = t.metalness, o.metalnessMap = t.metalnessMap, o.normalMap = t.normalMap, o.normalScale = t.normalScale, o.alphaMap = t.alphaMap, o.opacity = t.opacity, o.transparent = t.transparent, o.aoMap = t.aoMap, o;
91
+ return n.positionNode = a, n.normalNode = d, n.color = t.color, n.map = t.map, n.emissive = t.emissive, n.emissiveMap = t.emissiveMap, n.emissiveIntensity = t.emissiveIntensity, n.roughness = t.roughness, n.roughnessMap = t.roughnessMap, n.metalness = t.metalness, n.metalnessMap = t.metalnessMap, n.normalMap = t.normalMap, n.normalScale = t.normalScale, n.alphaMap = t.alphaMap, n.opacity = t.opacity, n.transparent = t.transparent, n.aoMap = t.aoMap, n;
92
92
  }
93
93
  }
94
- function Ht(t, i, l) {
94
+ function Ht(t, a, d) {
95
95
  t.updateWorldMatrix(!0, !1);
96
- const o = {
96
+ const n = {
97
97
  colorAttributeName: "color",
98
98
  logStats: !1,
99
- stiffness: 0.4,
100
- dampening: 0.5,
99
+ stiffness: 0.2,
100
+ dampening: 0.96,
101
101
  colliderRadiusMultiplier: 1,
102
- windPerSecond: new z(0, 0, 0),
103
- gravityPerSecond: new z(0, -0.3, 0),
102
+ windPerSecond: new T(0, 0, 0),
103
+ gravityPerSecond: new T(0, -9.8, 0),
104
104
  updateMaterial: _t,
105
105
  magnets: 0,
106
- ...l
107
- }, d = l != null && l.collidersRoot ? Ot(l.collidersRoot, t.skeleton, o.colliderRadiusMultiplier) : [], {
108
- indices: g,
109
- uniqueCount: a,
110
- vPos: h,
111
- springs: m,
112
- springsPointer: G,
106
+ ...d
107
+ }, m = d != null && d.collidersRoot ? Ot(d.collidersRoot, t.skeleton, n.colliderRadiusMultiplier) : [], {
108
+ indices: f,
109
+ uniqueCount: c,
110
+ vPos: A,
111
+ springs: h,
112
+ springsPointer: _,
113
113
  springsPerVertexArray: k,
114
- vFaces: D,
114
+ vFaces: q,
115
115
  vVertexToFace: W
116
- } = Gt(t, o.colorAttributeName);
117
- if (o.logStats) {
118
- console.group("Stats"), console.log("vertices", a), console.log("edges", m.length / 4), console.log("faces", D.length / 3);
119
- for (let e = 0; e < a; e++) {
120
- let n = !1;
121
- for (let r = 0; r < m.length; r += 4)
122
- if (m[r] === e || m[r + 1] === e) {
123
- n = !0;
116
+ } = Gt(t, n.colorAttributeName);
117
+ if (n.logStats) {
118
+ console.group("Stats"), console.log("vertices", c), console.log("edges", h.length / 4), console.log("faces", q.length / 3);
119
+ for (let e = 0; e < c; e++) {
120
+ let s = !1;
121
+ for (let r = 0; r < h.length; r += 4)
122
+ if (h[r] === e || h[r + 1] === e) {
123
+ s = !0;
124
124
  break;
125
125
  }
126
- n || console.log("WARNING!: vertex", e, "has no strings! wtf?");
126
+ s || console.log("WARNING!: vertex", e, "has no strings! wtf?");
127
127
  }
128
128
  console.groupEnd();
129
129
  }
130
- t.geometry.setAttribute("uniqueIndex", new dt(g, 1)), t.geometry.setAttribute("faceIndex", new dt(W, 1));
131
- const N = U(o.stiffness), q = U(o.dampening), C = U(0), $ = U(o.gravityPerSecond, "vec3"), E = U(o.windPerSecond, "vec3"), u = F(h, "vec4"), j = F(a, "vec3"), R = new Uint32Array(a * 2);
132
- for (let e = 0; e < a; e++)
133
- R[e * 2] = G[e], R[e * 2 + 1] = 0;
134
- const s = F(R, "uvec2"), c = F(
130
+ t.geometry.setAttribute("uniqueIndex", new lt(f, 1)), t.geometry.setAttribute("faceIndex", new lt(W, 1));
131
+ const z = U(n.stiffness), D = U(n.dampening), I = U(0), Z = U(n.gravityPerSecond, "vec3"), E = U(n.windPerSecond, "vec3"), u = F(A, "vec4"), C = F(c, "vec3"), R = new Uint32Array(c * 2);
132
+ for (let e = 0; e < c; e++)
133
+ R[e * 2] = _[e], R[e * 2 + 1] = 0;
134
+ const o = F(R, "uvec2"), l = F(
135
135
  k,
136
136
  "uint"
137
- ), v = m.length / 4, x = g.length, w = F(m, "uvec4"), X = F(D, "uvec3"), et = F(g, "uint"), b = F(Math.max(1, o.magnets), "vec4"), B = U(0, "uint"), nt = qt(t), ot = Ct(t), yt = new Float32Array(Math.max(1, (d == null ? void 0 : d.length) ?? 0) * 4), J = new Xt(yt, 4), st = Et(J, "vec4"), O = U(new Ut()), ht = T(() => {
138
- S(f.greaterThanEqual(x), () => tt());
139
- const e = et.element(f), n = u.element(e), r = nt.mul(ot);
140
- n.xyz.assign(r);
141
- })().compute(x).setName("Initialize skinning points"), vt = T(() => {
142
- S(f.greaterThanEqual(x), () => tt());
143
- const e = et.element(f), n = u.element(e), r = n.w, p = nt.mul(ot);
144
- n.xyz.assign(Rt(n.xyz, p, r));
145
- })().compute(x).setName("Update skinning points"), Mt = T(() => {
146
- S(f.greaterThanEqual(a), () => {
147
- tt();
148
- });
149
- const e = u.element(f), n = j.element(f), r = e.w.oneMinus(), A = s.element(f).x, P = c.element(A), M = A.add(1).toVar("ptrStart"), y = M.add(P).toVar("ptrEnd");
150
- n.mulAssign(q), gt(
151
- { start: M, end: y, type: "uint", condition: "<" },
152
- ({ i: V }) => {
153
- const Z = c.element(V).toVar("springId"), I = w.element(Z).toVar(), L = mt(I.z, "float"), H = I.x, Q = I.y, Nt = pt(H.equal(f), Q, H), ct = u.element(Nt).xyz.sub(e.xyz), lt = ct.length().max(1e-6), It = ct.div(lt), Ft = lt.sub(L).mul(N).mul(0.5);
154
- n.addAssign(It.mul(Ft));
155
- }
156
- );
157
- const K = bt(e, 1, Bt).sub(0.2).mul(0.1).mul(E);
158
- if (n.addAssign(K), d)
159
- for (let V = 0; V < d.length; V++) {
160
- const Z = st.element(V).xyz, I = ft(st.element(V).w), L = e.add(n).sub(Z), H = L.length(), Q = I.sub(H).max(0).mul(L.normalize()).mul(3);
161
- n.addAssign(Q);
137
+ ), x = h.length / 4, y = f.length, P = F(h, "uvec4"), B = F(x * 3, "vec3"), ft = F(q, "uvec3"), tt = F(f, "uint"), L = F(Math.max(1, n.magnets), "vec4"), b = U(0, "uint"), et = Dt(t), nt = Et(t), ht = new Float32Array(Math.max(1, (m == null ? void 0 : m.length) ?? 0) * 4), K = new Xt(ht, 4), st = Ct(K, "vec4"), H = U(new Ut()), xt = N(() => {
138
+ w(p.greaterThanEqual(y), () => O());
139
+ const e = tt.element(p), s = u.element(e), r = et.mul(nt);
140
+ s.xyz.assign(r);
141
+ })().compute(y).setName("Initialize skinning points"), vt = N(() => {
142
+ w(p.greaterThanEqual(y), () => O());
143
+ const e = tt.element(p), s = u.element(e), r = s.w, i = et.mul(nt);
144
+ s.xyz.assign(Rt(s.xyz, i, r));
145
+ })().compute(y).setName("Update skinning points"), yt = N(() => {
146
+ w(p.greaterThanEqual(ut(x)), () => O());
147
+ const e = P.element(p), s = dt(e.z, "float"), r = u.element(e.x), g = u.element(e.y).sub(r).toVar(), M = g.length().max(1e-6).toVar(), S = M.sub(s).mul(z).mul(g).mul(0.5).div(M);
148
+ B.element(p).assign(S);
149
+ })().compute(x).setName("computeSpringForces"), Mt = N(() => {
150
+ w(p.greaterThanEqual(c), () => O());
151
+ const e = u.element(p), s = e.xyz, r = e.w.oneMinus();
152
+ w(r.equal(0), () => O());
153
+ const i = C.element(p);
154
+ i.mulAssign(D);
155
+ const { x: g, y: M } = o.element(p), S = l.element(g), v = g.add(1).toVar("ptrStart"), G = v.add(S).toVar("ptrEnd");
156
+ mt({ start: v, end: G, type: "uint", condition: "<" }, ({ i: V }) => {
157
+ const Y = l.element(V).toVar("springId"), $ = P.element(Y).toVar(), j = B.element(Y), J = gt($.x.equal(p), 1, -1);
158
+ i.addAssign(j.mul(J));
159
+ }), i.addAssign(Z.mul(I).mul(I));
160
+ const Nt = Bt(s, 1, Lt).sub(0.2).mul(0.1).mul(E);
161
+ if (i.addAssign(Nt.mul(I)), m)
162
+ for (let V = 0; V < m.length; V++) {
163
+ const Y = st.element(V).xyz, $ = st.element(V).w, j = s.add(i).sub(Y), J = j.length(), zt = $.sub(J).max(0).mul(j).div(J);
164
+ i.addAssign(zt.mul(0.5));
162
165
  }
163
- n.addAssign($.mul(r).mul(C));
164
- const at = s.element(f).y;
165
- S(at.greaterThan(0), () => {
166
- const V = b.element(at.sub(1)), Z = V.xyz, I = V.w;
167
- S(I.greaterThan(0), () => {
168
- const L = Z.sub(e.xyz).mul(I);
169
- e.xyz.addAssign(L);
166
+ i.mulAssign(r);
167
+ const Tt = i.length(), at = 0.01;
168
+ w(Tt.greaterThan(at), () => {
169
+ i.assign(i.normalize().mul(at));
170
+ }), C.element(p).assign(i), w(M.greaterThan(0), () => {
171
+ const V = L.element(M.sub(1)), Y = V.xyz, $ = V.w;
172
+ w($.greaterThan(0), () => {
173
+ const j = Y.sub(s).mul($);
174
+ s.addAssign(j);
170
175
  });
171
176
  }).Else(() => {
172
- e.xyz.addAssign(n);
177
+ s.addAssign(i);
173
178
  });
174
- })().compute(a).setName("compute Vertex Forces"), wt = T(() => {
175
- S(f.lessThan(v), () => {
176
- const e = w.element(f), n = e.z, r = e.x, p = e.y, A = u.element(r).xyz, y = u.element(p).xyz.sub(A).length().max(1e-6);
177
- n.assign(mt(y, "uint"));
179
+ })().compute(c), St = N(() => {
180
+ w(p.lessThan(x), () => {
181
+ const e = P.element(p), s = e.z, r = e.x, i = e.y, g = u.element(r).xyz, v = u.element(i).xyz.sub(g).length().max(1e-6);
182
+ s.assign(dt(v, "uint"));
178
183
  });
179
- })().compute(v).setName("calculate Rest Lengths"), At = T(() => {
180
- const e = b.element(B).xyz, n = Lt(0).toVar(), r = ft(1e4).toVar("minDist");
181
- gt(a, ({ i: p }) => {
182
- const M = u.element(p).xyz.sub(e).length(), y = s.element(p).y;
183
- S(y.equal(0).and(M.lessThan(r)), () => {
184
- r.assign(M), n.assign(p);
184
+ })().compute(x).setName("calculate Rest Lengths"), wt = N(() => {
185
+ const e = L.element(b).xyz, s = ut(0).toVar(), r = bt(1e4).toVar("minDist");
186
+ mt(c, ({ i }) => {
187
+ const S = u.element(i).xyz.sub(e).length(), v = o.element(i).y;
188
+ w(v.equal(0).and(S.lessThan(r)), () => {
189
+ r.assign(S), s.assign(i);
185
190
  });
186
- }), S(r.lessThan(1e4), () => {
187
- s.element(n).y.assign(B.add(1));
191
+ }), w(r.lessThan(1e4), () => {
192
+ o.element(s).y.assign(b.add(1));
188
193
  });
189
- })().compute(1).setName("assign Vertices To Magnet"), St = T(() => {
190
- S(f.lessThan(a), () => {
191
- const e = s.element(f);
192
- S(e.y.equal(B.toUint().add(1)), () => {
194
+ })().compute(1).setName("assign Vertices To Magnet"), At = N(() => {
195
+ w(p.lessThan(c), () => {
196
+ const e = o.element(p);
197
+ w(e.y.equal(b.toUint().add(1)), () => {
193
198
  e.y.assign(0);
194
199
  });
195
200
  });
196
- })().compute(a).setName("remove Vertices From Magnet"), Pt = T(() => {
197
- const e = xt("uniqueIndex", "uint"), n = u.element(e).xyz;
198
- return O.mul(n);
201
+ })().compute(c).setName("remove Vertices From Magnet"), Pt = N(() => {
202
+ const e = pt("uniqueIndex", "uint"), s = u.element(e).xyz;
203
+ return H.mul(s);
199
204
  })();
200
205
  t.isSkinnedMesh = !1;
201
- const rt = T(() => {
202
- const e = xt("faceIndex", "uint"), n = X.element(e), r = u.element(n.x).toVar(), p = u.element(n.y).toVar(), A = u.element(n.z).toVar(), P = p.sub(r), M = A.sub(r), y = Yt(P, M).normalize(), _ = O.transformDirection(y);
203
- return $t(_);
204
- })().toVarying(), Vt = pt(jt, rt, rt.negate()), zt = () => {
205
- if (!(d != null && d.length))
206
+ const ot = N(() => {
207
+ const e = pt("faceIndex", "uint"), s = ft.element(e), r = u.element(s.x).toVar(), i = u.element(s.y).toVar(), g = u.element(s.z).toVar(), M = i.sub(r), S = g.sub(r), v = Yt(M, S).normalize(), G = H.transformDirection(v);
208
+ return $t(G);
209
+ })().toVarying(), Vt = gt(jt, ot, ot.negate()), Ft = () => {
210
+ if (!(m != null && m.length))
206
211
  return;
207
- const e = J.array;
208
- for (let n = 0; n < d.length; n++) {
209
- const r = d[n];
210
- r.position instanceof z ? Y.copy(r.position) : (r.position.updateMatrixWorld(!0), r.position.getWorldPosition(Y)), e[n * 4] = Y.x, e[n * 4 + 1] = Y.y, e[n * 4 + 2] = Y.z, e[n * 4 + 3] = r.radius;
212
+ const e = K.array;
213
+ for (let s = 0; s < m.length; s++) {
214
+ const r = m[s];
215
+ r.position instanceof T ? X.copy(r.position) : (r.position.updateMatrixWorld(!0), r.position.getWorldPosition(X)), e[s * 4] = X.x, e[s * 4 + 1] = X.y, e[s * 4 + 2] = X.z, e[s * 4 + 3] = r.radius;
211
216
  }
212
- J.needsUpdate = !0;
217
+ K.needsUpdate = !0;
213
218
  };
214
- t.material = o.updateMaterial(t.material, Pt, Vt), O.value.copy(t.matrixWorld).invert();
215
- let it = !1;
216
- return requestAnimationFrame(() => {
217
- i.compute(ht), i.compute(wt), it = !0;
218
- }), {
219
- stiffnessUniform: N,
220
- dampeningUniform: q,
221
- gravityUniform: $,
219
+ t.material = n.updateMaterial(t.material, Pt, Vt), H.value.copy(t.matrixWorld).invert();
220
+ let rt = !1;
221
+ requestAnimationFrame(() => {
222
+ a.compute(xt), a.compute(St), rt = !0;
223
+ });
224
+ let Q = 0;
225
+ return {
226
+ stiffnessUniform: z,
227
+ dampeningUniform: D,
228
+ gravityUniform: Z,
222
229
  windUniform: E,
223
- colliders: d,
230
+ colliders: m,
224
231
  /**
225
232
  * Runs the cloth simulation...
226
233
  *
227
234
  * @param delta seconds passed since last render
228
235
  * @param steps number of steps to run the simulation ( more steps = more "stable" but slower )
229
236
  */
230
- update: (e, n = 11) => {
231
- if (it) {
232
- t.updateMatrixWorld(), O.value.copy(t.matrixWorld).invert(), i.compute(vt), zt(), C.value = e / n;
233
- for (let r = 0; r < n; r++)
234
- i.compute(Mt);
235
- }
237
+ update: (e, s = 360) => {
238
+ if (!rt) return;
239
+ t.updateMatrixWorld(), H.value.copy(t.matrixWorld).invert(), Ft();
240
+ const r = Math.min(e, 1 / 60), g = 1 / s;
241
+ for (I.value = g, Q += r, a.compute(vt); Q >= g; )
242
+ Q -= g, a.compute(yt), a.compute(Mt);
236
243
  },
237
244
  /**
238
245
  * Grab the closest vertex to the given magnet. An object to update the magnet position is returned.
@@ -244,20 +251,20 @@ function Ht(t, i, l) {
244
251
  * @param strength Strength of the magnet. Default is .5.
245
252
  * @returns An object with update and release methods.
246
253
  */
247
- activateMagnet: (e, n, r = 1) => {
248
- const p = new z(), A = () => (n instanceof z ? p.copy(n) : n.getWorldPosition(p), p), P = (y, _, K) => {
249
- b.value.setXYZW(e, y, _, K, r), b.value.needsUpdate = !0;
254
+ activateMagnet: (e, s, r = 1) => {
255
+ const i = new T(), g = () => (s instanceof T ? i.copy(s) : s.getWorldPosition(i), i), M = (v, G, it) => {
256
+ L.value.setXYZW(e, v, G, it, r), L.value.needsUpdate = !0;
250
257
  };
251
- t.updateMatrixWorld(!0), B.value = e, B.needsUpdate = !0;
252
- const M = A();
253
- return P(M.x, M.y, M.z), i.compute(At), {
258
+ t.updateMatrixWorld(!0), b.value = e, b.needsUpdate = !0;
259
+ const S = g();
260
+ return M(S.x, S.y, S.z), a.compute(wt), {
254
261
  update: () => {
255
- const y = A();
256
- P(y.x, y.y, y.z);
262
+ const v = g();
263
+ M(v.x, v.y, v.z);
257
264
  },
258
- updatePosition: P,
265
+ updatePosition: M,
259
266
  deactivate: () => {
260
- b.value.setXYZW(e, 0, 0, 0, 0), b.value.needsUpdate = !0, B.value = e, i.compute(St);
267
+ L.value.setXYZW(e, 0, 0, 0, 0), L.value.needsUpdate = !0, b.value = e, a.compute(At);
261
268
  }
262
269
  };
263
270
  }
@@ -275,7 +282,7 @@ class Jt {
275
282
  * @param options The options for the simulation.
276
283
  * @returns The cloth simulation's API.
277
284
  */
278
- ut(Jt, "onSkinnedMesh", Ht);
285
+ ct(Jt, "onSkinnedMesh", Ht);
279
286
  export {
280
287
  Jt as SimpleCloth
281
288
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/SimpleCloth.ts"],"sourcesContent":["import {\n\tBone,\n BufferAttribute,\n DoubleSide,\n Material,\n Matrix4,\n Mesh,\n Object3D,\n Scene,\n Skeleton,\n Vector3,\n type SkinnedMesh,\n} from \"three\";\nimport { ShaderCallNodeInternal } from \"three/src/nodes/TSL.js\";\nimport {\n attribute,\n computeSkinning,\n Fn,\n If,\n instancedArray,\n instanceIndex,\n Loop,\n mix,\n objectWorldMatrix,\n Return,\n select,\n storage,\n time,\n triNoise3D,\n uniform,\n float,\n\tfrontFacing,\n\tcross,\n\ttransformNormalToView,\n\tuint,\n\tbitcast,\n} from \"three/tsl\";\nimport {\n\tMeshPhysicalNodeMaterial,\n Node,\n NodeMaterial,\n StorageInstancedBufferAttribute,\n type WebGPURenderer,\n} from \"three/webgpu\";\n\nconst v = new Vector3();\n\ntype Collider = {\n\tradius:number,\n\tposition:Object3D|Vector3\n}\n\nexport type MagnetAPI = {\n\t/**\n\t * Updates the world position of the magnet by re-reading the original vector 3 passed as position\n\t */\n\tupdate:VoidFunction\n\n\t/**\n\t * Updates the world position of the magnet by setting it to these values\n\t */\n\tupdatePosition:(x:number, y:number, z:number) => void \n\n\t/**\n\t * clears every vertex from this magnet. This is the \"release\" action.\n\t */\n\tdeactivate:VoidFunction\n}\n\n// function hash3(a: number, b: number, c: number) {\n// const q = 1e6; // precision control\n// let x = (a * q) | 0;\n// let y = (b * q) | 0;\n// let z = (c * q) | 0;\n\n// let h = x * 374761393 + y * 668265263 + z * 2147483647;\n// h = (h ^ (h >> 13)) * 1274126177;\n// h = h ^ (h >> 16);\n\n// return h >>> 0;\n// } \n\n/**\n * Here we calculate the geometry of the cloth.\n * We need to know the unique vertices, the springs (edges), and the faces.\n * \n * @param mesh The mesh to calculate the geometry of.\n * @param $maskAttribute The attribute to use as a mask (default: \"color\").\n * @returns An object containing the information for the cloth\n */\nfunction calculateGeometry(mesh: Mesh, $maskAttribute = \"color\") {\n const geometry = mesh.geometry;\n const pos = geometry.attributes.position;\n\n\t/**\n\t * The vertex paint info. We assume you pain in red, and blender's default background is white. \n\t * So we will use the blue channel to determine the weight of the cloth.\n\t */\n const mask = geometry.getAttribute($maskAttribute);\n\n const count = pos.count;\n\n // Map of position string -> unique index\n const map = new Map<string, number>();\n const springPerVertex = new Map<number, number[]>();\n\n // Array to store the unique index for each vertex\n const indices = new Uint32Array(count);\n\n const vPos: number[] = [];\n \n const vVertexToFace: number[] = [];\n const vFaces: number[][] = [];\n\n let uniqueCount = 0;\n const v = new Vector3();\n\n //\n // identify unique vertices (because some may be repeated but actually the same spacial vertex)\n //\n for (let i = 0; i < count; i++) {\n const x = pos.getX(i);\n const y = pos.getY(i);\n const z = pos.getZ(i);\n // Defaults to 0 if mask is missing. \n // Logic: 1 = Pinned (Skin), 0 = Simulated (Cloth)\n const weight = mask ? mask.getY(i) : 0; \n\n // Create a unique key for the position\n const key = `${x},${y},${z}`;// hash3(x, y, z);\n\n if (!map.has(key)) {\n map.set(key, uniqueCount);\n\n //\n // convert to world space.\n //\n v.set(x, y, z); \n \n\t\t\tv.applyMatrix4(mesh.matrixWorld) \n\n vPos.push(v.x, v.y, v.z, weight);\n \n uniqueCount++;\n }\n\n indices[i] = map.get(key)!;\n }\n\n //\n // now, create the \"springs\" ( the connections between them )\n //\n const springs: number[] = []; // unique index id of a A-B vertex pair + rest length float + unused \n const vA = new Vector3();\n const vB = new Vector3();\n const springDefined = new Set<string>();\n\n const addSpringToVertex = (vertex: number, springID: number) => {\n if (springPerVertex.has(vertex)) {\n springPerVertex.get(vertex)!.push(springID);\n } else {\n springPerVertex.set(vertex, [springID]);\n }\n };\n\n const addSpring = (A: number, B: number) => {\n const hash = A + \"-\" + B; //(A * 73856093) ^ (B * 19349663);\n const hash2 = B + \"-\" + A; //(B * 73856093) ^ (A * 19349663);\n\n if (springDefined.has(hash) || springDefined.has(hash2)) {\n return;\n }\n\n const springID = springs.length/4;\n\n springs.push(A, B, 0, 0);\n\n addSpringToVertex(A, springID);\n addSpringToVertex(B, springID); \n\n springDefined.add(hash);\n };\n\n //\n // now for each triangle, create a spring from each edge...\n // \n const gIndices = geometry.index!.array;\n\n\n for (let i = 0; i < gIndices.length; i += 3) {\n const Ai = indices[gIndices[i]];\n const Bi = indices[gIndices[i + 1]];\n const Ci = indices[gIndices[i + 2]];\n\n //AB BC CA | rest length + force\n addSpring(Ai, Bi);\n addSpring( Ci, Bi,);\n addSpring( Ai , Ci, );\n\n // This is a face... make all indices point to these 3 indices...\n const faceIndex = vFaces.length;\n\n // Add the \"face\" to the face index\n vFaces.push([Ai, Bi, Ci]);\n\n\t\tvVertexToFace[gIndices[i]] = faceIndex;\n\t\tvVertexToFace[gIndices[i+1]] = faceIndex;\n\t\tvVertexToFace[gIndices[i+2]] = faceIndex;\n } \n\n //\n // build springs pointer array (adjacency list)\n // This allows O(1) lookup of springs for each vertex in the shader\n //\n const springsPerVertexArray: number[] = [];\n const springsPointer = new Uint32Array(uniqueCount);\n \n for (let i = 0; i < uniqueCount; i++) {\n springsPointer[i] = springsPerVertexArray.length;\n const springsForV = springPerVertex.get(i) || [];\n // Store count, then the spring IDs\n\t\tif( springsForV.length==0 )\n\t\t{\n\t\t\tdebugger\n\t\t}\n springsPerVertexArray.push(springsForV.length, ...springsForV);\n }\n \n\n return {\n vFaces: new Uint32Array(vFaces.flat()), //vec3[]\n vVertexToFace: new Uint32Array(vVertexToFace), // uint\n\n springsPointer: new Uint32Array(springsPointer),\n springsPerVertexArray: new Uint32Array(springsPerVertexArray),\n\n uniqueCount, // unique vertices\n indices, // for each vertice, stores the index of the unique one in the vPos array\n vPos: new Float32Array(vPos), // 4 components, a vector 3 positions of the unique vertices ( in world space ) + the weight\n\n springs: new Uint32Array(springs), // Pair of index points in vPos representing a spring \n };\n}\n\ntype ClothConfig = {\n\n\t/**\n\t * Usually it is \"color\" but sometimes it may be other like \"color_1\"\n\t */\n\tcolorAttributeName?: string;\n\n\t/**\n\t * Log stats to the console ( about the cloth mesh )\n\t */\n\tlogStats?: boolean;\n\n\t/**\n\t * The root object to search for colliders. \n\t * Colliders are expected to be empty objects with uniform scale and `userData.stickto=\"bonename\"` OR `userData.clothCollider=true` properties.\n\t * The radius of the collider will be the absolute value of `scale.x * colliderRadiusMultiplier`.\n\t */\n\tcollidersRoot?: Object3D;\n\n\tstiffness?: number;\n\tdampening?: number;\n\n\t/**\n\t * you can tweak the radius of the colliders ( which are spheres attached to bones )\n\t * \n\t * @param radius 1.0 is the default\n\t */\n\tcolliderRadiusMultiplier?: number; \n\n\t/**\n\t * Wind DIRECTION in world space (noise will be used to add variation)\n\t */\n\twindPerSecond?:Vector3\n\n\t/**\n\t * Gravity force in world space\n\t */\n\tgravityPerSecond?:Vector3 \n\n\t/**\n\t * How many magnets to use ( cloch grab manipulators )\n\t */\n\tmagnets:number;\n\n\t/**\n\t * The material used by the SkinnedMesh to turn into \"cloth\" must apply and use these TSL nodes...\n\t * By default it will try to guess the most common case when you import a model from blender...\n\t * \n\t * @param positionNode \n\t * @param normalNode \n\t * @returns \n\t */\n\tupdateMaterial: ( base:Material, positionNode:Node, normalNode:Node ) => NodeMaterial\n}\n \n\n/**\n * Looks for objects ( empty uniformlyscaled Spheres from blender ) with a userData.stickto = \"name of a bone\"\n * @param root \n * @returns \n */\nfunction getCollidersFrom( root:Object3D, skeleton:Skeleton, multiplier:number =1)\n{\n\tconst colliders:Collider[] = []; \n\tlet scene:Scene;\n\n\troot.traverseAncestors((o)=>{\n\t\tif( o instanceof Scene ){\n\t\t\tscene = o;\n\t\t}\n\t});\n\n\t//\n\t// collect colliders\n\t//\n\troot.traverse((o)=>{\n\t\tif( o.userData.stickto || o.userData.clothCollider )\n\t\t{\n\t\t\tcolliders.push({\n\t\t\t\tposition: o,\n\t\t\t\tradius: 0, \n\t\t\t});\n\t\t}\n\t}); \n\n\t//\n\t// attatch to skeleton and calculate world dimension\n\t//\n\tcolliders.forEach( col => {\n\t\tconst obj = col.position as Object3D;\n\t\tlet bone :Bone|undefined;\n\t\t\n\t\tif( obj.userData.stickto )\n\t\t{\n\t\t\tbone = skeleton.getBoneByName?.( obj.userData.stickto.replaceAll(/[\\.\\:]/g,\"\") );\n\n\t\t\tif( !bone ){\n\t\t\t\tthrow new Error(\"Bone not found for collider: \" + obj.userData.stickto)+ \" ???\";\n\t\t\t} \n\t\t} \n\t\t\n\t\tscene.attach(obj);\n\t\t\n\t\t//\n\t\t// the world scale is the radius of the collider ( uniform scale assumed!! )\n\t\t//\n\t\tcol.radius = Math.abs( obj.getWorldScale(v).x ) * multiplier ;\n\t \n\n\t\tbone?.attach( obj ); \n\n\t} );\n\n\n\treturn colliders;\n}\n\nfunction assumeTheModelCameFromBlenderAndWasTexturedNormally(base:Material, posNode:ShaderCallNodeInternal, normalNode:ShaderCallNodeInternal ) {\n\tif( \"isNodeMaterial\" in base )\n\t{\n\t\tconst m = base as NodeMaterial;\n\t\tm.positionNode = posNode;\n\t\tm.normalNode = normalNode;\n\t\treturn m;\n\t}\n\telse \n\t{\n\t\tconst m = new MeshPhysicalNodeMaterial({ \n\t\t\tside: DoubleSide,\n\t\t\t// wireframe:true, \n\t\t\twireframe: base.wireframe,\n\t\t\tflatShading: base.flatShading,\n\t\t\ttransparent: base.transparent,\n\t\t\tdepthWrite: base.depthWrite,\n\t\t\tdepthTest: base.depthTest,\n\t\t});\n\t\tm.positionNode = posNode;\n\t\tm.normalNode = normalNode;\n\n\t\tm.color = base.color;\n\t\tm.map = base.map;\n\n\t\tm.emissive = base.emissive;\n\t\tm.emissiveMap = base.emissiveMap;\n\t\tm.emissiveIntensity = base.emissiveIntensity;\n\n\t\tm.roughness = base.roughness;\n\t\tm.roughnessMap = base.roughnessMap;\n\n\t\tm.metalness = base.metalness;\n\t\tm.metalnessMap = base.metalnessMap;\n\n\t\tm.normalMap = base.normalMap;\n\t\tm.normalScale = base.normalScale;\n\n\t\tm.alphaMap = base.alphaMap;\n\t\tm.opacity = base.opacity;\n\t\tm.transparent = base.transparent;\n\n\t\tm.aoMap = base.aoMap;\n\n\n\t\treturn m; \n\t} \n}\n\nfunction setupClothOnSkinnedMesh(\n mesh: SkinnedMesh,\n renderer: WebGPURenderer,\n\tconfig?: Partial<ClothConfig>, \n) {\n\tmesh.updateWorldMatrix(true, false);\n\n\t\n\tconst $cfg : ClothConfig = {\n\t\tcolorAttributeName: \"color\",\n\t\tlogStats: false,\n\t\tstiffness: 0.4,\n\t\tdampening: 0.5,\n\t\tcolliderRadiusMultiplier:1,\n\t\twindPerSecond: new Vector3(0,0,0),\n\t\tgravityPerSecond: new Vector3(0, -0.3,0), \n\t\tupdateMaterial: assumeTheModelCameFromBlenderAndWasTexturedNormally,\n\t\tmagnets: 0,\n\t\t...config\n\t}\n\n\t//\n\t// -- Look for colliders\n\t//\n\tconst colliders:Collider[] = config?.collidersRoot ? getCollidersFrom(config.collidersRoot, mesh.skeleton, $cfg.colliderRadiusMultiplier) : []\n \n const {\n indices,\n uniqueCount,\n vPos,\n springs, \n springsPointer,\n springsPerVertexArray,\n\t\tvFaces,\n\t\tvVertexToFace\n } = calculateGeometry(mesh, $cfg.colorAttributeName!);\n\n\tif( $cfg.logStats ){\n\t\tconsole.group(\"Stats\") \n\t\tconsole.log(\"vertices\", uniqueCount); \n\t\tconsole.log(\"edges\", springs.length/4); \n\t\tconsole.log(\"faces\", vFaces.length/3); \n\t\n\n\t\tfor(let i=0; i<uniqueCount; i++){\n\t\t\tlet hasString = false;\n\t\t\tfor( let j=0; j<springs.length; j+=4){\n\t\t\t\tif(springs[j] === i || springs[j+1] === i){\n\t\t\t\t\thasString = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(!hasString){\n\t\t\t\tconsole.log(\"WARNING!: vertex\", i, \"has no strings! wtf?\");\n\t\t\t}\n\t\t} \n\n\t\tconsole.groupEnd();\n\t}\n \n\t// for each vertex position, this will help us know which unique spatial vertex on the cloth this represents.\n mesh.geometry.setAttribute(\"uniqueIndex\", new BufferAttribute(indices, 1));\n\n\t// from what face this vertex is part of.\n mesh.geometry.setAttribute(\"faceIndex\", new BufferAttribute(vVertexToFace, 1));\n\t\t \n\n const stiffnessUniform = uniform($cfg.stiffness); \n const dampeningUniform = uniform($cfg.dampening); \n \n\t/**\n\t * Delta time (updated on .update)\n\t */\n const dt = uniform(0);\n\n\t/**\n\t * Gravity ( force acting on the cloth on every compute )\n\t */\n const gravityUniform = uniform( $cfg.gravityPerSecond, \"vec3\");\n\t\n\t/**\n\t * Wind (updated on .update)\n\t */\n const windUniform = uniform( $cfg.windPerSecond, \"vec3\"); \n\n\t/**\n\t * position of each unique spatial index XYZ and the W is the value of the vertex paint mask ( 1:skinned, ..., 0:physics )\n\t */\n const vPosStore = instancedArray(vPos, \"vec4\") ;\n\n\t/**\n\t * The force vector acting on each unique spatial index.\n\t */\n const vForceStore = instancedArray(uniqueCount, \"vec3\") ; \n\n\t/**\n\t * (I know this is messy...)\n\t * For each unique vertex, this is a pointer to the location in `vSpringsPerVertexArray` where the list of springs for that vertex begins.\n\t * It starts with \"count\" followed by the IDs of each spring in the `springsStore` array\n\t * --\n\t * .x = pointer to the location in `vSpringsPerVertexArray` where the list of springs for that vertex begins.\n\t * .y = magnet index\n\t */\n\tconst vVertexIntsArray = new Uint32Array( uniqueCount * 2 );\n\tfor(let i=0; i<uniqueCount; i++){\n\t\tvVertexIntsArray[i*2] = springsPointer[i];\n\t\tvVertexIntsArray[i*2+1] = 0;\n\t}\n\n\t/**\n\t * 2 Ids packed. \n\t * .x = pointer to the location in `vSpringsPerVertexArray` where the list of springs for that vertex begins.\n\t * .y = magnet index\n\t */\n const vVertexInts = instancedArray(vVertexIntsArray, \"uvec2\");\n\n\t/**\n\t * Contains [ count, ID1, ID2, ID3, count, ID1, ID2, count, ID etc... ]\n\t * Count then a serie of IDs\n\t */\n const vSpringsPerVertexArray = instancedArray(\n springsPerVertexArray,\n \"uint\",\n );\n\n\t/**\n\t * How many springs (edges) the cloth has. It will equal the number of edges of the mesh.\n\t */\n const totalSprings = springs.length / 4; // because each spring has 2 vertices + 1 rest length + 1 unused\n\n\t/**\n\t * Total number of vertices in the mesh (not the unique vertices, the actual mesh like the one you see in Blender's stats)\n\t */\n const countOfPoints = indices.length;\n\n\t/**\n\t * Stores:\n\t * XY: a pair of A,B IDs. (id of the unique vertices that this spring will try to keep at a certain distance )\n\t * Z: rest length of the spring ( in world space )\n\t * W: unused\n\t */\n const springsStore = instancedArray(springs, \"uvec4\"); \n\n\t/**\n\t * array triplets defining a face ( a triangle )\n\t */\n\tconst vFacesStore = instancedArray(vFaces, \"uvec3\"); \n \n\t/**\n\t * basically a map from each mesh's vertex to the ID of the unique spatial vertlet. ( since many vertices may exist in the space spatial position )\n\t */\n const indicesStore = instancedArray(indices, \"uint\");\n\n\n\tconst magnet = instancedArray(Math.max(1, $cfg.magnets), \"vec4\"); \n\tconst magnetToAssign = uniform(0,\"uint\");\n\n\n const worldMatrix = objectWorldMatrix(mesh);\n\n\t/**\n\t * This puppy is the node that runs the skinning process setting the positions of the vertices to match the skeleton.\n\t */\n const skinningPosition = computeSkinning(mesh);\n\n\t/**\n\t * Position XYZ and Radius W\n\t */\n\tconst collidersArray = new Float32Array(Math.max(1, colliders?.length ?? 0) * 4);\n\tconst colliderAttr = new StorageInstancedBufferAttribute(collidersArray, 4);\n\tconst collidersStore = storage(colliderAttr, \"vec4\"); \n\n\tconst worldMatrixInverseUniform = uniform(new Matrix4());\n\n /** \n * Initial setup\n */\n const initializeSkinningPosition = Fn(() => {\n If(instanceIndex.greaterThanEqual(countOfPoints), () => Return());\n\n const uIndex = indicesStore.element(instanceIndex);\n const wPos = vPosStore.element(uIndex); \n \n const skinningWorldPosition = worldMatrix.mul(skinningPosition) ;\n wPos.xyz.assign(skinningWorldPosition) ; \n\n })()\n .compute(countOfPoints)\n .setName(\"Initialize skinning points\"); \n\n /**\n * < SYNC TO SKINNED MESH >\n * Skinning --> unique vertices\n * Runs once per frame before physics steps.\n * Updates positions of pinned vertices to match the animation.\n */\n const updateSkinningPoints = Fn(() => {\n If(instanceIndex.greaterThanEqual(countOfPoints), () => Return());\n\n const uIndex = indicesStore.element(instanceIndex);\n const wPos = vPosStore.element(uIndex); \n const factor = wPos.w;//.pow(2); // 1 = skinned (Pinned), 0 = cloth (Simulated)\n\n const skinningWorldPosition = worldMatrix.mul(skinningPosition) ;\n\n // Only update if factor > 0 (partially or fully skinned)\n // If fully cloth (0), we leave it to physics\n // mix(currentPos, skinningPos, factor). If factor=1, we force it to skinningPos.\n\t \n\t\twPos.xyz.assign(mix(wPos.xyz, skinningWorldPosition, factor)); \n\n })()\n .compute(countOfPoints)\n .setName(\"Update skinning points\"); \n\n\n\t/**\n\t * < CALCULATE SPRING FORCES > \n\t * Calculates the force of each spring.\n * This iterates per SPRING (linear with number of springs).\n\t */\n \n\n /**\n * < COMPUTE VERTEX FORCES >\n * Integrates forces and updates position.\n * Iterates per VERTEX.\n */\n\tconst computeVertexForces = Fn(()=>{\n\n\t\tIf(instanceIndex.greaterThanEqual(uniqueCount), () => {\n\t\t\tReturn();\n\t\t});\n\n\t\tconst position = vPosStore.element( instanceIndex );\n\t\tconst force = vForceStore.element( instanceIndex ) ; \n\t\tconst mask = (position.w).oneMinus(); //.pow(2); // If w=1 (pinned), mask=0. If w=0 (simulated), mask=1.\n \n\t\n\t\n\t\tconst vertexInts = vVertexInts.element(instanceIndex);\n\t\tconst springPointer = vertexInts.x;\n\t\t\n // springsPerVertexArray layout: [count, id1, id2, ...]\n const springCount = vSpringsPerVertexArray.element(springPointer);\n\n const ptrStart = springPointer.add(1).toVar(\"ptrStart\");\n const ptrEnd = ptrStart.add(springCount).toVar(\"ptrEnd\");\n\n\t\tforce.mulAssign(dampeningUniform);\n\n\t\t\tLoop(\n\t { start: ptrStart, end: ptrEnd, type: \"uint\", condition: \"<\" },\n\t ({ i }) => {\n\t const springIndex = vSpringsPerVertexArray.element(i).toVar(\"springId\"); \n\t const spring = springsStore.element(springIndex).toVar();\n\t \n\t\t\t\t\t//\n\t\t\t\t\t// Inline spring force calculation\n\t\t\t\t\t//\n\t\t\t\t\tconst restLength = bitcast(spring.z, \"float\") ;\n\t\t\t\t\tconst Ai = spring.x;\n\t\t\t\t\tconst Bi = spring.y;\n\n\t\t\t\t\t// identify neighbor\n\t\t\t\t\tconst neighborIndex = select(Ai.equal(instanceIndex), Bi, Ai);\n\n\t\t\t\t\tconst posNeighbor = vPosStore.element(neighborIndex).xyz;\n\t\t\t\t\tconst delta = posNeighbor.sub(position.xyz);\n\t\t\t\t\tconst dist = delta.length().max(0.000001);\n\t\t\t\t\tconst dir = delta.div(dist);\n\t\t\t\t\t\n\t\t\t\t\t// Force\n\t\t\t\t\tconst f = dist.sub(restLength).mul(stiffnessUniform).mul(0.5);\n\t\t\t\t\t\n\t\t\t\t\tforce.addAssign(dir.mul(f));\n\t },\n\t );\n\n\t\t// // Wind\n const noise = triNoise3D(position, 1, time).sub(0.2).mul(0.1);\n const windForce = noise.mul(windUniform);\n force.addAssign(windForce);\n\n\t\t// Sphere collisions\n\t\tif (colliders) {\n\t\t\tfor (let i = 0; i < colliders.length; i++) {\n\t\t\t\tconst cPos = collidersStore.element(i).xyz;\n const cRad = float(collidersStore.element(i).w);\n \n // Vector from collider center to vertex\n\t\t\t\tconst deltaSphere = position.add(force).sub(cPos); \n\t\t\t\tconst dist = deltaSphere.length();\n \n\t\t\t\t\n\n // If inside sphere (dist < radius)\n\t\t\t\tconst sphereForce = cRad\n\t\t\t\t\t.sub(dist)\n\t\t\t\t\t.max(0)\n\t\t\t\t\t.mul(deltaSphere.normalize())\n\t\t\t\t\t.mul(3)\n // Push out\n\t\t\t\tforce.addAssign(sphereForce);\n\t\t\t}\n\t\t}\n\n\t\t//force.mulAssign(mask);\n\n\t\tforce.addAssign(gravityUniform.mul(mask).mul(dt ) ); \n\n\t\t//\n\t\t// Magnet \"attraction\"\n\t\t//\n\t\tconst magnetIndex = vVertexInts.element(instanceIndex).y;\n\n\t\tIf( magnetIndex.greaterThan(0), ()=>{\n\n\t\t\tconst magnetData = magnet.element(magnetIndex.sub(1)) ;\n\t\t\tconst magnetPosition = magnetData.xyz;\n\t\t\tconst magnetStrength = magnetData.w;\n\n\t\t\tIf( magnetStrength.greaterThan(0), ()=>{\n\t\t\t\tconst magnetForce = magnetPosition.sub(position.xyz).mul(magnetStrength) ;\n\t\t\t\tposition.xyz.addAssign(magnetForce);\n\t\t\t}) \n\n\t\t}) \n\t\t.Else(()=>{\n\t\t\tposition.xyz.addAssign( force );\n\t\t}) \n \n\t\t\n\t \n\t \t//force.assign( vec3(0,0,0) );\n \n\t\t\n\t})().compute( uniqueCount ).setName(\"compute Vertex Forces\"); \n\n\t/**\n\t * < CALCULATE REST LENGTHS>\n\t * the leght of each spring is calculated and stored in the Z component of the spring data.\n\t */\n\tconst calculateRestLengths = Fn(()=>{\n\t\tIf(instanceIndex.lessThan(totalSprings), () => {\n\t\t\tconst vertexIds = springsStore.element( instanceIndex );\n\t\t\tconst restLength = vertexIds.z ;\n\n\t\t\tconst Ai = vertexIds.x;\n\t\t\tconst Bi = vertexIds.y; \n\n\t\t\tconst posA = vPosStore.element(Ai).xyz;\n\t\t\tconst posB = vPosStore.element(Bi).xyz;\n\n\t\t\tconst delta = posB.sub(posA);\n\t\t\tconst dist = delta.length().max(0.000001);\n\n\t\t\trestLength.assign( bitcast(dist, \"uint\") );\n \n\n\t\t});\n\t})().compute( totalSprings ).setName(\"calculate Rest Lengths\"); \n\n\t/**\n\t * Scans all vertices and assigns the nearest vertex to the magnet.\n\t * Check the length of each spring and pick the closest one, then assign that one to the magnet.\n\t */\n\tconst assignVerticesToMagnet = Fn(() => { \n\n\t const magnetPosition = magnet.element(magnetToAssign).xyz;\n\t const selectedIndex = uint(0).toVar();\n\t const minDist = float(10000).toVar(\"minDist\"); // sentinel — no special casing needed\n\n\t\tLoop( uniqueCount, ({ i })=>{\n\n\t\t\tconst vertlet = vPosStore.element(i) ; \n\t\t\tconst position = vertlet.xyz ; \n\t\t\tconst dist = position.sub(magnetPosition).length() ; \n\t\t\tconst currentMagnet = vVertexInts.element(i).y ;\n\n\t\t\t// If it already has a magnet, ignore it.\n\t\t\tIf( currentMagnet.equal(0).and( dist.lessThan(minDist) ) , ()=>{\n\t\t\t\tminDist.assign(dist);\n\t\t\t\tselectedIndex.assign(i); \n\t\t\t})\n\t\t\t\n\t\t}) ;\n\n\t\tIf( minDist.lessThan(10000), () => {\n\t\t\tconst ids = vVertexInts.element(selectedIndex);\n\t\t\tids.y.assign(magnetToAssign.add(1));\n\t\t}) \n\n\t})().compute(1).setName(\"assign Vertices To Magnet\"); \n\n\t/**\n\t * Removes vertices from the magnet.\n\t * Check the y component of the vertex data and if it is equal to the magnetToAssign uniform, \n\t * then remove the vertex from the magnet.\n\t */\n\tconst removeVerticesFromMagnet = Fn(() => {\n\n\t\tIf( instanceIndex.lessThan(uniqueCount), ()=>{\n \n\t const ids = vVertexInts.element(instanceIndex);\n\n\t If(ids.y.equal(magnetToAssign.toUint().add(1)), () => {\n\t ids.y.assign(0);\n\t });\n\t\t});\n \n\t})().compute(uniqueCount).setName(\"remove Vertices From Magnet\");\n \n\n\tconst positionNode_ = Fn(()=>{\n\t\tconst uIndex = attribute(\"uniqueIndex\", \"uint\");\n\t\tconst position = vPosStore.element(uIndex).xyz;\n\t\treturn worldMatrixInverseUniform.mul(position);\n\t})();\n\t// hack(?) to make it NOT re-skin after positionNode changes.\n\t// without this, after the positionNode runs, the skinning process will change the positions based on the skeleton.\n\t// but we already did that in the updateSkinningPoints compute node. Setting this to false apparently skips that... \n\tmesh.isSkinnedMesh = false;\n\t\n\tconst calculateNormal = Fn(() => { \n\t\tconst uIndex = attribute(\"faceIndex\", \"uint\");\n\t\tconst face = vFacesStore.element(uIndex);\n\t\tconst v0 = vPosStore.element(face.x).toVar();\n\t\tconst v1 = vPosStore.element(face.y).toVar();\n\t\tconst v2 = vPosStore.element(face.z).toVar(); \n\n\t\t// Compute edges from the actual vertices\n\t\tconst edge1 = v1.sub(v0);\n\t\tconst edge2 = v2.sub(v0);\n\t\t\n\t\t// Cross product gives the normal\n\t\tconst normal = cross(edge1, edge2).normalize();\n\t\t\n\t\tconst localNormal = worldMatrixInverseUniform.transformDirection(normal);\n\t\treturn transformNormalToView(localNormal);\n\t});\n\n\tconst vNormal = calculateNormal().toVarying();\n\tconst normalNode = select(frontFacing, vNormal, vNormal.negate());\n\n\t/**\n\t * updates the positions of the colliders in the colliderAttr array.\n\t * This is called every frame.\n\t */\n\tconst updateCollidersPositions = ()=>{\n\t\tif(!colliders?.length){\n\t\t\treturn;\n\t\t}\n\n\t\tconst collidersArray = colliderAttr.array;\n\n\t\tfor(let i = 0; i < colliders.length; i++){ \n\t\t\tconst col = colliders[i];\n\t\t\tif( col.position instanceof Vector3 )\n\t\t\t{\n\t\t\t\tv.copy(col.position)\n\t\t\t}\n\t\t\telse \n\t\t\t{\n\t\t\t\tcol.position.updateMatrixWorld(true);\n\t\t\t\tcol.position.getWorldPosition(v);\n\t\t\t}\n\n\t\t\tcollidersArray[i * 4] = v.x;\n\t\t\tcollidersArray[i * 4 + 1] = v.y;\n\t\t\tcollidersArray[i * 4 + 2] = v.z;\n\t\t\tcollidersArray[i * 4 + 3] = col.radius ;\n\t\t} \n\t\t\n\t\tcolliderAttr.needsUpdate = true;\n\t}\n\n\tmesh.material = $cfg.updateMaterial!(mesh.material as Material, positionNode_, normalNode); \n\t\n\t\n\tworldMatrixInverseUniform.value.copy(mesh.matrixWorld).invert();\n\n\tlet init = false;\n\n\t//\n\t// I do it this way because if you set the position of the rig before adding it to the scene it will calculate all wrong\n\t// and I haven't figured out how to fix that yet.\n\t//\n\trequestAnimationFrame(()=>{\n\t\trenderer.compute( initializeSkinningPosition );\n\t\trenderer.compute( calculateRestLengths ); \n\t\tinit = true;\n\t})\n\n\n return {\n\n\t\tstiffnessUniform,\n\t\tdampeningUniform,\n\t\tgravityUniform,\n\t\twindUniform,\n\t\tcolliders, \n\n\t\t/** \n\t\t * Runs the cloth simulation...\n\t\t * \n\t\t * @param delta seconds passed since last render\n\t\t * @param steps number of steps to run the simulation ( more steps = more \"stable\" but slower ) \n\t\t */\n update: (delta: number, steps=11) => {\n\n\t\t\tif( !init ) return;\n\n\t\t\tmesh.updateMatrixWorld();\n\n\t\t\tworldMatrixInverseUniform.value.copy(mesh.matrixWorld).invert();\n \n\t\t\trenderer.compute(updateSkinningPoints); \n\n\t\t\t//\n\t\t\t// extract the position of the colliders and send them to the GPU\n\t\t\t//\n\t\t\tupdateCollidersPositions(); \n\n\t\t\tdt.value = delta/steps;\n\n\t\t\tfor(let i=0; i<steps; i++ )\n\t\t\t{\n\t\t\t\trenderer.compute(computeVertexForces);\n\t\t\t} \n },\n\n\t\t/**\n\t\t * Grab the closest vertex to the given magnet. An object to update the magnet position is returned. \n\t\t * This is designed so that when you call this, it is assumed to be during a \"grab\" action. You then\n\t\t * should call the `deactivate` callback to produce the \"release\" action.\n\t\t * \t\n\t\t * @param magnetIndex Index of the magnet to use.\n\t\t * @param worldPos World position. This object now controls the position of the magnet. you can change the XYZ.\n\t\t * @param strength Strength of the magnet. Default is .5.\n\t\t * @returns An object with update and release methods.\n\t\t */\n\t\tactivateMagnet: ( magnetIndex:number, worldPos:Vector3|Object3D, strength = 1 ) => { \n \n\t\t\tconst v = new Vector3();\n\t\t\tconst getWPos = ()=>{\n\t\t\t\tif(worldPos instanceof Vector3)\n\t\t\t\t{\n\t\t\t\t\tv.copy(worldPos);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tworldPos.getWorldPosition(v);\n\t\t\t\t}\n\t\t\t\treturn v;\n\t\t\t}\n\n\t\t\t\n\n\n\t\t\tconst updateMagnetPosition = (x:number, y:number, z:number)=>{\n\t\t\t\t//\n\t\t\t\t// set the value of the magnet to use\n\t\t\t\t//\n\t\t\t\tmagnet.value.setXYZW(magnetIndex , x, y, z, strength);\n\t\t\t\tmagnet.value.needsUpdate = true; \n\t\t\t}\n\n\t\t\tmesh.updateMatrixWorld(true);\n\n\t\t\tmagnetToAssign.value = magnetIndex; \n\t\t\tmagnetToAssign.needsUpdate = true;\n\n\t\t\tconst pos = getWPos();\n\t\t\tupdateMagnetPosition(pos.x, pos.y, pos.z);\n\t\t\t\n\t\t\trenderer.compute(assignVerticesToMagnet); \n\n\t\t\treturn {\n\t\t\t\tupdate: ()=>{\n\t\t\t\t\tconst pos = getWPos();\n\t\t\t\t\tupdateMagnetPosition(pos.x, pos.y, pos.z);\n\t\t\t\t},\n\t\t\t\tupdatePosition: updateMagnetPosition,\n\t\t\t\tdeactivate: ()=>{\n\t\t\t\t\tmagnet.value.setXYZW(magnetIndex, 0, 0, 0, 0);\n\t\t\t\t\tmagnet.value.needsUpdate = true;\n\t\t\t\t\tmagnetToAssign.value = magnetIndex;\n\t\t\t\t\trenderer.compute(removeVerticesFromMagnet);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n };\n}\n\n\n/**\n * A SIMPLE cloth simulation. Goal is to have a minimal interface to just get some mesh to act kind of like a cloth. \n * Adaptation/Based on the Three's Official examples: https://github.com/mrdoob/three.js/blob/a58e9ecf225b50e4a28a934442e854878bc2a959/examples/webgpu_compute_cloth.html\n * \n */\nexport class SimpleCloth {\n \n\t/**\n\t * Turns the vertex painted parts of a skinned mesh into a cloth simulation.\n\t * Red paint is assumed to be the part of the mesh that should be simulated.\n\t * The rest is assumed to be white. \n\t * \n \t * @param mesh The skinned mesh to turn into a cloth simulation.\n\t * @param renderer The renderer ( because we need to run compute shaders )\n\t * @param options The options for the simulation.\n\t * @returns The cloth simulation's API.\n\t */\n\tstatic onSkinnedMesh = setupClothOnSkinnedMesh;\n}\n"],"names":["v","Vector3","calculateGeometry","mesh","$maskAttribute","geometry","pos","mask","count","map","springPerVertex","indices","vPos","vVertexToFace","vFaces","uniqueCount","i","x","y","z","weight","key","springs","springDefined","addSpringToVertex","vertex","springID","addSpring","A","B","hash","hash2","gIndices","Ai","Bi","Ci","faceIndex","springsPerVertexArray","springsPointer","springsForV","getCollidersFrom","root","skeleton","multiplier","colliders","scene","o","Scene","col","obj","bone","_a","assumeTheModelCameFromBlenderAndWasTexturedNormally","base","posNode","normalNode","m","MeshPhysicalNodeMaterial","DoubleSide","setupClothOnSkinnedMesh","renderer","config","$cfg","hasString","j","BufferAttribute","stiffnessUniform","uniform","dampeningUniform","dt","gravityUniform","windUniform","vPosStore","instancedArray","vForceStore","vVertexIntsArray","vVertexInts","vSpringsPerVertexArray","totalSprings","countOfPoints","springsStore","vFacesStore","indicesStore","magnet","magnetToAssign","worldMatrix","objectWorldMatrix","skinningPosition","computeSkinning","collidersArray","colliderAttr","StorageInstancedBufferAttribute","collidersStore","storage","worldMatrixInverseUniform","Matrix4","initializeSkinningPosition","Fn","If","instanceIndex","Return","uIndex","wPos","skinningWorldPosition","updateSkinningPoints","factor","mix","computeVertexForces","position","force","springPointer","springCount","ptrStart","ptrEnd","Loop","springIndex","spring","restLength","bitcast","neighborIndex","select","delta","dist","dir","f","windForce","triNoise3D","time","cPos","cRad","float","deltaSphere","sphereForce","magnetIndex","magnetData","magnetPosition","magnetStrength","magnetForce","calculateRestLengths","vertexIds","posA","assignVerticesToMagnet","selectedIndex","uint","minDist","currentMagnet","removeVerticesFromMagnet","ids","positionNode_","attribute","vNormal","face","v0","v1","v2","edge1","edge2","normal","cross","localNormal","transformNormalToView","frontFacing","updateCollidersPositions","init","steps","worldPos","strength","getWPos","updateMagnetPosition","SimpleCloth","__publicField"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/SimpleCloth.ts"],"sourcesContent":["import {\n\tBone,\n BufferAttribute,\n DoubleSide,\n Material,\n Matrix4,\n Mesh,\n Object3D,\n Scene,\n Skeleton,\n Vector3,\n type SkinnedMesh,\n} from \"three\";\nimport { ShaderCallNodeInternal } from \"three/src/nodes/TSL.js\";\nimport {\n attribute,\n computeSkinning,\n Fn,\n If,\n instancedArray,\n instanceIndex,\n Loop,\n mix,\n objectWorldMatrix,\n Return,\n select,\n storage,\n time,\n triNoise3D,\n uniform,\n float,\n\tfrontFacing,\n\tcross,\n\ttransformNormalToView,\n\tuint,\n\tbitcast,\n} from \"three/tsl\";\nimport {\n\tMeshPhysicalNodeMaterial,\n Node,\n NodeMaterial,\n StorageInstancedBufferAttribute,\n type WebGPURenderer,\n} from \"three/webgpu\";\n\nconst v = new Vector3();\n\ntype Collider = {\n\tradius:number,\n\tposition:Object3D|Vector3\n}\n\nexport type MagnetAPI = {\n\t/**\n\t * Updates the world position of the magnet by re-reading the original vector 3 passed as position\n\t */\n\tupdate:VoidFunction\n\n\t/**\n\t * Updates the world position of the magnet by setting it to these values\n\t */\n\tupdatePosition:(x:number, y:number, z:number) => void \n\n\t/**\n\t * clears every vertex from this magnet. This is the \"release\" action.\n\t */\n\tdeactivate:VoidFunction\n}\n\n// function hash3(a: number, b: number, c: number) {\n// const q = 1e6; // precision control\n// let x = (a * q) | 0;\n// let y = (b * q) | 0;\n// let z = (c * q) | 0;\n\n// let h = x * 374761393 + y * 668265263 + z * 2147483647;\n// h = (h ^ (h >> 13)) * 1274126177;\n// h = h ^ (h >> 16);\n\n// return h >>> 0;\n// } \n\n/**\n * Here we calculate the geometry of the cloth.\n * We need to know the unique vertices, the springs (edges), and the faces.\n * \n * @param mesh The mesh to calculate the geometry of.\n * @param $maskAttribute The attribute to use as a mask (default: \"color\").\n * @returns An object containing the information for the cloth\n */\nfunction calculateGeometry(mesh: Mesh, $maskAttribute = \"color\") {\n const geometry = mesh.geometry;\n const pos = geometry.attributes.position;\n\n\t/**\n\t * The vertex paint info. We assume you pain in red, and blender's default background is white. \n\t * So we will use the blue channel to determine the weight of the cloth.\n\t */\n const mask = geometry.getAttribute($maskAttribute);\n\n const count = pos.count;\n\n // Map of position string -> unique index\n const map = new Map<string, number>();\n const springPerVertex = new Map<number, number[]>();\n\n // Array to store the unique index for each vertex\n const indices = new Uint32Array(count);\n\n const vPos: number[] = [];\n \n const vVertexToFace: number[] = [];\n const vFaces: number[][] = [];\n\n let uniqueCount = 0;\n const v = new Vector3();\n\n //\n // identify unique vertices (because some may be repeated but actually the same spacial vertex)\n //\n for (let i = 0; i < count; i++) {\n const x = pos.getX(i);\n const y = pos.getY(i);\n const z = pos.getZ(i);\n // Defaults to 0 if mask is missing. \n // Logic: 1 = Pinned (Skin), 0 = Simulated (Cloth)\n const weight = mask ? mask.getY(i) : 0; \n\n // Create a unique key for the position\n const key = `${x},${y},${z}`;// hash3(x, y, z);\n\n if (!map.has(key)) {\n map.set(key, uniqueCount);\n\n //\n // convert to world space.\n //\n v.set(x, y, z); \n \n\t\t\tv.applyMatrix4(mesh.matrixWorld) \n\n vPos.push(v.x, v.y, v.z, weight);\n \n uniqueCount++;\n }\n\n indices[i] = map.get(key)!;\n }\n\n //\n // now, create the \"springs\" ( the connections between them )\n //\n const springs: number[] = []; // unique index id of a A-B vertex pair + rest length float + unused \n const vA = new Vector3();\n const vB = new Vector3();\n const springDefined = new Set<string>();\n\n const addSpringToVertex = (vertex: number, springID: number) => {\n if (springPerVertex.has(vertex)) {\n springPerVertex.get(vertex)!.push(springID);\n } else {\n springPerVertex.set(vertex, [springID]);\n }\n };\n\n const addSpring = (A: number, B: number) => {\n const hash = A + \"-\" + B; //(A * 73856093) ^ (B * 19349663);\n const hash2 = B + \"-\" + A; //(B * 73856093) ^ (A * 19349663);\n\n if (springDefined.has(hash) || springDefined.has(hash2)) {\n return;\n }\n\n const springID = springs.length/4;\n\n springs.push(A, B, 0, 0);\n\n addSpringToVertex(A, springID);\n addSpringToVertex(B, springID); \n\n springDefined.add(hash);\n };\n\n //\n // now for each triangle, create a spring from each edge...\n // \n const gIndices = geometry.index!.array;\n\n\n for (let i = 0; i < gIndices.length; i += 3) {\n const Ai = indices[gIndices[i]];\n const Bi = indices[gIndices[i + 1]];\n const Ci = indices[gIndices[i + 2]];\n\n //AB BC CA | rest length + force\n addSpring(Ai, Bi);\n addSpring( Ci, Bi,);\n addSpring( Ai , Ci, );\n\n // This is a face... make all indices point to these 3 indices...\n const faceIndex = vFaces.length;\n\n // Add the \"face\" to the face index\n vFaces.push([Ai, Bi, Ci]);\n\n\t\tvVertexToFace[gIndices[i]] = faceIndex;\n\t\tvVertexToFace[gIndices[i+1]] = faceIndex;\n\t\tvVertexToFace[gIndices[i+2]] = faceIndex;\n } \n\n //\n // build springs pointer array (adjacency list)\n // This allows O(1) lookup of springs for each vertex in the shader\n //\n const springsPerVertexArray: number[] = [];\n const springsPointer = new Uint32Array(uniqueCount);\n \n for (let i = 0; i < uniqueCount; i++) {\n springsPointer[i] = springsPerVertexArray.length;\n const springsForV = springPerVertex.get(i) || [];\n // Store count, then the spring IDs\n\t\tif( springsForV.length==0 )\n\t\t{\n\t\t\tdebugger\n\t\t}\n springsPerVertexArray.push(springsForV.length, ...springsForV);\n }\n \n\n return {\n vFaces: new Uint32Array(vFaces.flat()), //vec3[]\n vVertexToFace: new Uint32Array(vVertexToFace), // uint\n\n springsPointer: new Uint32Array(springsPointer),\n springsPerVertexArray: new Uint32Array(springsPerVertexArray),\n\n uniqueCount, // unique vertices\n indices, // for each vertice, stores the index of the unique one in the vPos array\n vPos: new Float32Array(vPos), // 4 components, a vector 3 positions of the unique vertices ( in world space ) + the weight\n\n springs: new Uint32Array(springs), // Pair of index points in vPos representing a spring \n };\n}\n\ntype ClothConfig = {\n\n\t/**\n\t * Usually it is \"color\" but sometimes it may be other like \"color_1\"\n\t */\n\tcolorAttributeName?: string;\n\n\t/**\n\t * Log stats to the console ( about the cloth mesh )\n\t */\n\tlogStats?: boolean;\n\n\t/**\n\t * The root object to search for colliders. \n\t * Colliders are expected to be empty objects with uniform scale and `userData.stickto=\"bonename\"` OR `userData.clothCollider=true` properties.\n\t * The radius of the collider will be the absolute value of `scale.x * colliderRadiusMultiplier`.\n\t */\n\tcollidersRoot?: Object3D;\n\n\tstiffness?: number;\n\tdampening?: number;\n\n\t/**\n\t * you can tweak the radius of the colliders ( which are spheres attached to bones )\n\t * \n\t * @param radius 1.0 is the default\n\t */\n\tcolliderRadiusMultiplier?: number; \n\n\t/**\n\t * Wind DIRECTION in world space (noise will be used to add variation)\n\t */\n\twindPerSecond?:Vector3\n\n\t/**\n\t * Gravity force in world space\n\t */\n\tgravityPerSecond?:Vector3 \n\n\t/**\n\t * How many magnets to use ( cloch grab manipulators )\n\t */\n\tmagnets:number;\n\n\t/**\n\t * The material used by the SkinnedMesh to turn into \"cloth\" must apply and use these TSL nodes...\n\t * By default it will try to guess the most common case when you import a model from blender...\n\t * \n\t * @param positionNode \n\t * @param normalNode \n\t * @returns \n\t */\n\tupdateMaterial: ( base:Material, positionNode:Node, normalNode:Node ) => NodeMaterial\n}\n \n\n/**\n * Looks for objects ( empty uniformlyscaled Spheres from blender ) with a userData.stickto = \"name of a bone\"\n * @param root \n * @returns \n */\nfunction getCollidersFrom( root:Object3D, skeleton:Skeleton, multiplier:number =1)\n{\n\tconst colliders:Collider[] = []; \n\tlet scene:Scene;\n\n\troot.traverseAncestors((o)=>{\n\t\tif( o instanceof Scene ){\n\t\t\tscene = o;\n\t\t}\n\t});\n\n\t//\n\t// collect colliders\n\t//\n\troot.traverse((o)=>{\n\t\tif( o.userData.stickto || o.userData.clothCollider )\n\t\t{\n\t\t\tcolliders.push({\n\t\t\t\tposition: o,\n\t\t\t\tradius: 0, \n\t\t\t});\n\t\t}\n\t}); \n\n\t//\n\t// attatch to skeleton and calculate world dimension\n\t//\n\tcolliders.forEach( col => {\n\t\tconst obj = col.position as Object3D;\n\t\tlet bone :Bone|undefined;\n\t\t\n\t\tif( obj.userData.stickto )\n\t\t{\n\t\t\tbone = skeleton.getBoneByName?.( obj.userData.stickto.replaceAll(/[\\.\\:]/g,\"\") );\n\n\t\t\tif( !bone ){\n\t\t\t\tthrow new Error(\"Bone not found for collider: \" + obj.userData.stickto)+ \" ???\";\n\t\t\t} \n\t\t} \n\t\t\n\t\tscene.attach(obj);\n\t\t\n\t\t//\n\t\t// the world scale is the radius of the collider ( uniform scale assumed!! )\n\t\t//\n\t\tcol.radius = Math.abs( obj.getWorldScale(v).x ) * multiplier ;\n\t \n\n\t\tbone?.attach( obj ); \n\n\t} );\n\n\n\treturn colliders;\n}\n\nfunction assumeTheModelCameFromBlenderAndWasTexturedNormally(base:Material, posNode:ShaderCallNodeInternal, normalNode:ShaderCallNodeInternal ) {\n\tif( \"isNodeMaterial\" in base )\n\t{\n\t\tconst m = base as NodeMaterial;\n\t\tm.positionNode = posNode;\n\t\tm.normalNode = normalNode;\n\t\treturn m;\n\t}\n\telse \n\t{\n\t\tconst m = new MeshPhysicalNodeMaterial({ \n\t\t\tside: DoubleSide,\n\t\t\t// wireframe:true, \n\t\t\twireframe: base.wireframe,\n\t\t\tflatShading: base.flatShading,\n\t\t\ttransparent: base.transparent,\n\t\t\tdepthWrite: base.depthWrite,\n\t\t\tdepthTest: base.depthTest,\n\t\t});\n\t\tm.positionNode = posNode;\n\t\tm.normalNode = normalNode;\n\n\t\tm.color = base.color;\n\t\tm.map = base.map;\n\n\t\tm.emissive = base.emissive;\n\t\tm.emissiveMap = base.emissiveMap;\n\t\tm.emissiveIntensity = base.emissiveIntensity;\n\n\t\tm.roughness = base.roughness;\n\t\tm.roughnessMap = base.roughnessMap;\n\n\t\tm.metalness = base.metalness;\n\t\tm.metalnessMap = base.metalnessMap;\n\n\t\tm.normalMap = base.normalMap;\n\t\tm.normalScale = base.normalScale;\n\n\t\tm.alphaMap = base.alphaMap;\n\t\tm.opacity = base.opacity;\n\t\tm.transparent = base.transparent;\n\n\t\tm.aoMap = base.aoMap;\n\n\n\t\treturn m; \n\t} \n}\n\nfunction setupClothOnSkinnedMesh(\n mesh: SkinnedMesh,\n renderer: WebGPURenderer,\n\tconfig?: Partial<ClothConfig>, \n) {\n\tmesh.updateWorldMatrix(true, false);\n\n\t\n\tconst $cfg : ClothConfig = {\n\t\tcolorAttributeName: \"color\",\n\t\tlogStats: false,\n\t\tstiffness: 0.2,\n\t\tdampening: 0.96,\n\t\tcolliderRadiusMultiplier:1,\n\t\twindPerSecond: new Vector3(0,0,0),\n\t\tgravityPerSecond: new Vector3(0, -9.8,0), \n\t\tupdateMaterial: assumeTheModelCameFromBlenderAndWasTexturedNormally,\n\t\tmagnets: 0,\n\t\t...config\n\t}\n\n\t//\n\t// -- Look for colliders\n\t//\n\tconst colliders:Collider[] = config?.collidersRoot ? getCollidersFrom(config.collidersRoot, mesh.skeleton, $cfg.colliderRadiusMultiplier) : []\n \n const {\n indices,\n uniqueCount,\n vPos,\n springs, \n springsPointer,\n springsPerVertexArray,\n\t\tvFaces,\n\t\tvVertexToFace\n } = calculateGeometry(mesh, $cfg.colorAttributeName!);\n\n\tif( $cfg.logStats ){\n\t\tconsole.group(\"Stats\") \n\t\tconsole.log(\"vertices\", uniqueCount); \n\t\tconsole.log(\"edges\", springs.length/4); \n\t\tconsole.log(\"faces\", vFaces.length/3); \n\t\n\n\t\tfor(let i=0; i<uniqueCount; i++){\n\t\t\tlet hasString = false;\n\t\t\tfor( let j=0; j<springs.length; j+=4){\n\t\t\t\tif(springs[j] === i || springs[j+1] === i){\n\t\t\t\t\thasString = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(!hasString){\n\t\t\t\tconsole.log(\"WARNING!: vertex\", i, \"has no strings! wtf?\");\n\t\t\t}\n\t\t} \n\n\t\tconsole.groupEnd();\n\t}\n \n\t// for each vertex position, this will help us know which unique spatial vertex on the cloth this represents.\n mesh.geometry.setAttribute(\"uniqueIndex\", new BufferAttribute(indices, 1));\n\n\t// from what face this vertex is part of.\n mesh.geometry.setAttribute(\"faceIndex\", new BufferAttribute(vVertexToFace, 1));\n\t\t \n\n const stiffnessUniform = uniform($cfg.stiffness); \n const dampeningUniform = uniform($cfg.dampening); \n \n\t/**\n\t * Delta time (updated on .update)\n\t */\n const dt = uniform(0);\n\n\t/**\n\t * Gravity ( force acting on the cloth on every compute )\n\t */\n const gravityUniform = uniform( $cfg.gravityPerSecond!, \"vec3\"); \n\t\n\t/**\n\t * Wind (updated on .update)\n\t */\n const windUniform = uniform( $cfg.windPerSecond, \"vec3\"); \n\n\t/**\n\t * position of each unique spatial index XYZ and the W is the value of the vertex paint mask ( 1:skinned, ..., 0:physics )\n\t */\n const vPosStore = instancedArray(vPos, \"vec4\") ;\n\n\t/**\n\t * The force vector acting on each unique spatial index.\n\t */\n const vForceStore = instancedArray(uniqueCount, \"vec3\") ; \n\n\t/**\n\t * (I know this is messy...)\n\t * For each unique vertex, this is a pointer to the location in `vSpringsPerVertexArray` where the list of springs for that vertex begins.\n\t * It starts with \"count\" followed by the IDs of each spring in the `springsStore` array\n\t * --\n\t * .x = pointer to the location in `vSpringsPerVertexArray` where the list of springs for that vertex begins.\n\t * .y = magnet index\n\t */\n\tconst vVertexIntsArray = new Uint32Array( uniqueCount * 2 );\n\tfor(let i=0; i<uniqueCount; i++){\n\t\tvVertexIntsArray[i*2] = springsPointer[i];\n\t\tvVertexIntsArray[i*2+1] = 0;\n\t}\n\n\t/**\n\t * 2 Ids packed. \n\t * .x = pointer to the location in `vSpringsPerVertexArray` where the list of springs for that vertex begins.\n\t * .y = magnet index\n\t */\n const vVertexInts = instancedArray(vVertexIntsArray, \"uvec2\");\n\n\t/**\n\t * Contains [ count, ID1, ID2, ID3, count, ID1, ID2, count, ID etc... ]\n\t * Count then a serie of IDs\n\t */\n const vSpringsPerVertexArray = instancedArray(\n springsPerVertexArray,\n \"uint\",\n );\n\n\t/**\n\t * How many springs (edges) the cloth has. It will equal the number of edges of the mesh.\n\t */\n const totalSprings = springs.length / 4; // because each spring has 2 vertices + 1 rest length + 1 unused\n\n\t/**\n\t * Total number of vertices in the mesh (not the unique vertices, the actual mesh like the one you see in Blender's stats)\n\t */\n const countOfPoints = indices.length;\n\n\t/**\n\t * Stores:\n\t * XY: a pair of A,B IDs. (id of the unique vertices that this spring will try to keep at a certain distance )\n\t * Z: rest length of the spring ( in world space )\n\t * W: unused\n\t */\n const springsStore = instancedArray(springs, \"uvec4\"); \n\tconst springForceBuffer = instancedArray(totalSprings * 3, \"vec3\");\n\n\t/**\n\t * array triplets defining a face ( a triangle )\n\t */\n\tconst vFacesStore = instancedArray(vFaces, \"uvec3\"); \n \n\t/**\n\t * basically a map from each mesh's vertex to the ID of the unique spatial vertlet. ( since many vertices may exist in the space spatial position )\n\t */\n const indicesStore = instancedArray(indices, \"uint\");\n\n\n\tconst magnet = instancedArray(Math.max(1, $cfg.magnets), \"vec4\"); \n\tconst magnetToAssign = uniform(0,\"uint\");\n\n\n const worldMatrix = objectWorldMatrix(mesh);\n\n\t/**\n\t * This puppy is the node that runs the skinning process setting the positions of the vertices to match the skeleton.\n\t */\n const skinningPosition = computeSkinning(mesh);\n\n\t/**\n\t * Position XYZ and Radius W\n\t */\n\tconst collidersArray = new Float32Array(Math.max(1, colliders?.length ?? 0) * 4);\n\tconst colliderAttr = new StorageInstancedBufferAttribute(collidersArray, 4);\n\tconst collidersStore = storage(colliderAttr, \"vec4\"); \n\n\tconst worldMatrixInverseUniform = uniform(new Matrix4());\n\n /** \n * Initial setup\n */\n const initializeSkinningPosition = Fn(() => {\n If(instanceIndex.greaterThanEqual(countOfPoints), () => Return());\n\n const uIndex = indicesStore.element(instanceIndex);\n const wPos = vPosStore.element(uIndex); \n \n const skinningWorldPosition = worldMatrix.mul(skinningPosition) ;\n wPos.xyz.assign(skinningWorldPosition) ; \n\n })()\n .compute(countOfPoints)\n .setName(\"Initialize skinning points\"); \n\n /**\n * < SYNC TO SKINNED MESH >\n * Skinning --> unique vertices\n * Runs once per frame before physics steps.\n * Updates positions of pinned vertices to match the animation.\n */\n const updateSkinningPoints = Fn(() => {\n If(instanceIndex.greaterThanEqual(countOfPoints), () => Return());\n\n const uIndex = indicesStore.element(instanceIndex);\n const wPos = vPosStore.element(uIndex); \n const factor = wPos.w;//.pow(2); // 1 = skinned (Pinned), 0 = cloth (Simulated)\n\n const skinningWorldPosition = worldMatrix.mul(skinningPosition) ; \n\n\t\t// Handover \n\t\twPos.xyz.assign(mix(wPos.xyz, skinningWorldPosition, factor)); \n\n })()\n .compute(countOfPoints)\n .setName(\"Update skinning points\"); \n\n\n\t/**\n\t * Calculates the force of each spring\n\t */\n\tconst computeSpringForces = Fn(()=>{\n\n\t\tIf( instanceIndex.greaterThanEqual( uint( totalSprings ) ), () => Return() );\n\n\t\tconst vertexIds = springsStore.element( instanceIndex );\n\t\tconst restLength = bitcast( vertexIds.z, \"float\" );\n\n\t\tconst vertex0Position = vPosStore.element( vertexIds.x );\n\t\tconst vertex1Position = vPosStore.element( vertexIds.y );\n\n\t\tconst delta = vertex1Position.sub( vertex0Position ).toVar();\n\t\tconst dist = delta.length().max( 0.000001 ).toVar();\n\t\tconst force = dist.sub( restLength ).mul( stiffnessUniform ).mul( delta ).mul( 0.5 ).div( dist );\n\t\tspringForceBuffer.element( instanceIndex ).assign( force );\n\t\t\n\t})().compute( totalSprings ).setName(\"computeSpringForces\"); \n\n\n\t/**\n\t * Applies the forces to each point + solves folliders & magnets\n\t */\n\tconst computeVertexForces = Fn( () => {\n\n\t If( instanceIndex.greaterThanEqual( uniqueCount ), () => Return() );\n\n\t\tconst vertex = vPosStore.element( instanceIndex )\n\t const position = vertex.xyz ;\n\t\tconst clothMask = vertex.w.oneMinus() ; \n\n\t If( clothMask.equal(0), () => Return() ); \n\t \n\t const force = vForceStore.element( instanceIndex ) ; \n\t \n\t\tforce.mulAssign( dampeningUniform );\n\n\n\t\tconst { x:springPointer, y:magnetIndex } = vVertexInts.element(instanceIndex); \n\t\t \n const springCount = vSpringsPerVertexArray.element(springPointer);\n\n const ptrStart = springPointer.add(1).toVar(\"ptrStart\");\n const ptrEnd = ptrStart.add(springCount).toVar(\"ptrEnd\");\n\n\t Loop( { start: ptrStart, end: ptrEnd, type: 'uint', condition: '<' }, ( { i } ) => {\n\n\t const springIndex = vSpringsPerVertexArray.element(i).toVar(\"springId\"); \n\t const spring = springsStore.element(springIndex).toVar();\n\n\t const springForce = springForceBuffer.element( springIndex ); \n\t const factor = select( spring.x.equal( instanceIndex ), 1.0, - 1.0 );\n\t force.addAssign( springForce.mul( factor ) );\n\n\t } );\n\n\t \n\t\tforce.addAssign(gravityUniform.mul(dt).mul(dt)); \n\n\n\t\t// ---------------\n\t\t// Wind\n\t\t//\n const noise = triNoise3D(position, 1, time).sub(0.2).mul(0.1);\n const windForce = noise.mul(windUniform);\n force.addAssign(windForce.mul(dt) );\n\n\n\t\t//------------------\n\t\t// Sphere collisions\n\t\t//\n\t\tif (colliders) {\n\t\t\tfor (let i = 0; i < colliders.length; i++) {\n\n\t\t\t\t// collision with sphere\n\t\t\t\tconst cPos = collidersStore.element(i).xyz;\n\t\t\t\tconst cRad = collidersStore.element(i).w;\n\t\t\t\tconst deltaSphere = position.add( force ).sub( cPos );\n\t\t\t\tconst dist = deltaSphere.length();\n\t\t\t\tconst sphereForce = cRad.sub( dist ).max( 0 ).mul( deltaSphere ).div( dist ) ;\n\t\t\t\tforce.addAssign( sphereForce.mul( 0.5) ); \n\t\t\t}\n\t\t}\n\n\t\t//\n\t\t// Mask the force so the non-cloth vertices are not affected\n\t\t//\n\t\tforce.mulAssign( clothMask ); \n\t\t\n\n\t\t//\n\t\t// Cap the force so it doesnt act too crazy\n\t\t//\n\t\tconst forceLength = force.length();\n\t\tconst maxForce = 0.01 ;\n\t\tIf( forceLength.greaterThan( maxForce ), () => {\n\t\t\tforce.assign( force.normalize().mul( maxForce ) );\n\t\t});\n\n\t\t//\n\t\t// save the force\n\t\t//\n\t vForceStore.element( instanceIndex ).assign( force ); \n\n\t\t//\n\t\t// Magnet \"attraction\": if it is being controlled by a magnet, ignore the force.\n\t\t// \n\n\t\tIf( magnetIndex.greaterThan(0), ()=>{\n\n\t\t\tconst magnetData = magnet.element(magnetIndex.sub(1)) ;\n\t\t\tconst magnetPosition = magnetData.xyz;\n\t\t\tconst magnetStrength = magnetData.w;\n\n\t\t\tIf( magnetStrength.greaterThan(0), ()=>{\n\t\t\t\tconst magnetForce = magnetPosition.sub(position).mul(magnetStrength) ;\n\t\t\t\tposition.addAssign(magnetForce);\n\t\t\t}) \n\n\t\t}) \n\t\t.Else(()=>{\n\t\t\tposition.addAssign( force );\n\t\t}) ;\n\n\n\t} )().compute( uniqueCount ) \n \n\t/**\n\t * < CALCULATE REST LENGTHS>\n\t * the leght of each spring is calculated and stored in the Z component of the spring data.\n\t */\n\tconst calculateRestLengths = Fn(()=>{\n\t\tIf(instanceIndex.lessThan(totalSprings), () => {\n\t\t\tconst vertexIds = springsStore.element( instanceIndex );\n\t\t\tconst restLength = vertexIds.z ;\n\n\t\t\tconst Ai = vertexIds.x;\n\t\t\tconst Bi = vertexIds.y; \n\n\t\t\tconst posA = vPosStore.element(Ai).xyz;\n\t\t\tconst posB = vPosStore.element(Bi).xyz;\n\n\t\t\tconst delta = posB.sub(posA);\n\t\t\tconst dist = delta.length().max(0.000001);\n\n\t\t\trestLength.assign( bitcast(dist, \"uint\") ); \n\n\t\t});\n\t})().compute( totalSprings ).setName(\"calculate Rest Lengths\"); \n\n\t/**\n\t * Scans all vertices and assigns the nearest vertex to the magnet.\n\t * Check the length of each spring and pick the closest one, then assign that one to the magnet.\n\t */\n\tconst assignVerticesToMagnet = Fn(() => { \n\n\t const magnetPosition = magnet.element(magnetToAssign).xyz;\n\t const selectedIndex = uint(0).toVar();\n\t const minDist = float(10000).toVar(\"minDist\"); // sentinel — no special casing needed\n\n\t\tLoop( uniqueCount, ({ i })=>{\n\n\t\t\tconst vertlet = vPosStore.element(i) ; \n\t\t\tconst position = vertlet.xyz ; \n\t\t\tconst dist = position.sub(magnetPosition).length() ; \n\t\t\tconst currentMagnet = vVertexInts.element(i).y ;\n\n\t\t\t// If it already has a magnet, ignore it.\n\t\t\tIf( currentMagnet.equal(0).and( dist.lessThan(minDist) ) , ()=>{\n\t\t\t\tminDist.assign(dist);\n\t\t\t\tselectedIndex.assign(i); \n\t\t\t})\n\t\t\t\n\t\t}) ;\n\n\t\tIf( minDist.lessThan(10000), () => {\n\t\t\tconst ids = vVertexInts.element(selectedIndex);\n\t\t\tids.y.assign(magnetToAssign.add(1));\n\t\t}) \n\n\t})().compute(1).setName(\"assign Vertices To Magnet\"); \n\n\t/**\n\t * Removes vertices from the magnet.\n\t * Check the y component of the vertex data and if it is equal to the magnetToAssign uniform, \n\t * then remove the vertex from the magnet.\n\t */\n\tconst removeVerticesFromMagnet = Fn(() => {\n\n\t\tIf( instanceIndex.lessThan(uniqueCount), ()=>{\n \n\t const ids = vVertexInts.element(instanceIndex);\n\n\t If(ids.y.equal(magnetToAssign.toUint().add(1)), () => {\n\t ids.y.assign(0);\n\t });\n\t\t});\n \n\t})().compute(uniqueCount).setName(\"remove Vertices From Magnet\");\n \n\n\tconst positionNode_ = Fn(()=>{\n\t\tconst uIndex = attribute(\"uniqueIndex\", \"uint\");\n\t\tconst position = vPosStore.element(uIndex).xyz;\n\t\treturn worldMatrixInverseUniform.mul(position);\n\t})();\n\t// hack(?) to make it NOT re-skin after positionNode changes.\n\t// without this, after the positionNode runs, the skinning process will change the positions based on the skeleton.\n\t// but we already did that in the updateSkinningPoints compute node. Setting this to false apparently skips that... \n\tmesh.isSkinnedMesh = false;\n\t\n\tconst calculateNormal = Fn(() => { \n\t\tconst uIndex = attribute(\"faceIndex\", \"uint\");\n\t\tconst face = vFacesStore.element(uIndex);\n\t\tconst v0 = vPosStore.element(face.x).toVar();\n\t\tconst v1 = vPosStore.element(face.y).toVar();\n\t\tconst v2 = vPosStore.element(face.z).toVar(); \n\n\t\t// Compute edges from the actual vertices\n\t\tconst edge1 = v1.sub(v0);\n\t\tconst edge2 = v2.sub(v0);\n\t\t\n\t\t// Cross product gives the normal\n\t\tconst normal = cross(edge1, edge2).normalize();\n\t\t\n\t\tconst localNormal = worldMatrixInverseUniform.transformDirection(normal);\n\t\treturn transformNormalToView(localNormal);\n\t});\n\n\tconst vNormal = calculateNormal().toVarying();\n\tconst normalNode = select(frontFacing, vNormal, vNormal.negate());\n\n\t/**\n\t * updates the positions of the colliders in the colliderAttr array.\n\t * This is called every frame.\n\t */\n\tconst updateCollidersPositions = ()=>{\n\t\tif(!colliders?.length){\n\t\t\treturn;\n\t\t}\n\n\t\tconst collidersArray = colliderAttr.array;\n\n\t\tfor(let i = 0; i < colliders.length; i++){ \n\t\t\tconst col = colliders[i];\n\t\t\tif( col.position instanceof Vector3 )\n\t\t\t{\n\t\t\t\tv.copy(col.position)\n\t\t\t}\n\t\t\telse \n\t\t\t{\n\t\t\t\tcol.position.updateMatrixWorld(true);\n\t\t\t\tcol.position.getWorldPosition(v);\n\t\t\t}\n\n\t\t\tcollidersArray[i * 4] = v.x;\n\t\t\tcollidersArray[i * 4 + 1] = v.y;\n\t\t\tcollidersArray[i * 4 + 2] = v.z;\n\t\t\tcollidersArray[i * 4 + 3] = col.radius ;\n\t\t} \n\t\t\n\t\tcolliderAttr.needsUpdate = true;\n\t}\n\n\tmesh.material = $cfg.updateMaterial!(mesh.material as Material, positionNode_, normalNode); \n\t\n\t\n\tworldMatrixInverseUniform.value.copy(mesh.matrixWorld).invert();\n\n\tlet init = false;\n\n\t//\n\t// I do it this way because if you set the position of the rig before adding it to the scene it will calculate all wrong\n\t// and I haven't figured out how to fix that yet.\n\t//\n\trequestAnimationFrame(()=>{\n\t\trenderer.compute( initializeSkinningPosition );\n\t\trenderer.compute( calculateRestLengths ); \n\t\tinit = true;\n\t})\n\n\tlet timeSinceLastStep = 0;\n\tlet timestamp = 0;\n\n return {\n\n\t\tstiffnessUniform,\n\t\tdampeningUniform,\n\t\tgravityUniform,\n\t\twindUniform,\n\t\tcolliders, \n\n\t\t/** \n\t\t * Runs the cloth simulation...\n\t\t * \n\t\t * @param delta seconds passed since last render\n\t\t * @param steps number of steps to run the simulation ( more steps = more \"stable\" but slower ) \n\t\t */\n update: (delta: number, steps=360) => {\n\n\t\t\tif( !init ) return;\n\n\t\t\tmesh.updateMatrixWorld(); \n\t\t\tworldMatrixInverseUniform.value.copy(mesh.matrixWorld).invert(); \n\n\t\t\t//\n\t\t\t// extract the position of the colliders and send them to the GPU\n\t\t\t//\n\t\t\tupdateCollidersPositions(); \n\n\t\t\tconst deltaTime = Math.min( delta, 1 / 60 ); // don't advance the time too far, for example when the window is out of focus\n\t\t\tconst stepsPerSecond = steps; // ensure the same amount of simulation steps per second on all systems, independent of refresh rate\n\t\t\tconst timePerStep = 1 / stepsPerSecond;\n\n\t\t\tdt.value = timePerStep;\n\n\t\t\ttimeSinceLastStep += deltaTime;\n\n\t\t\trenderer.compute( updateSkinningPoints );\n\n\t\t\twhile ( timeSinceLastStep >= timePerStep ) {\n\t\t\t\t// run a verlet system simulation step\n\t\t\t\ttimestamp += timePerStep;\n\t\t\t\ttimeSinceLastStep -= timePerStep;\n\t\t\t\t \n\t\t\t\trenderer.compute( computeSpringForces );\n\t\t\t\trenderer.compute( computeVertexForces );\n\t\t\t}\n },\n\n\t\t/**\n\t\t * Grab the closest vertex to the given magnet. An object to update the magnet position is returned. \n\t\t * This is designed so that when you call this, it is assumed to be during a \"grab\" action. You then\n\t\t * should call the `deactivate` callback to produce the \"release\" action.\n\t\t * \t\n\t\t * @param magnetIndex Index of the magnet to use.\n\t\t * @param worldPos World position. This object now controls the position of the magnet. you can change the XYZ.\n\t\t * @param strength Strength of the magnet. Default is .5.\n\t\t * @returns An object with update and release methods.\n\t\t */\n\t\tactivateMagnet: ( magnetIndex:number, worldPos:Vector3|Object3D, strength = 1 ) => { \n \n\t\t\tconst v = new Vector3();\n\t\t\tconst getWPos = ()=>{\n\t\t\t\tif(worldPos instanceof Vector3)\n\t\t\t\t{\n\t\t\t\t\tv.copy(worldPos);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tworldPos.getWorldPosition(v);\n\t\t\t\t}\n\t\t\t\treturn v;\n\t\t\t}\n\n\t\t\t\n\n\n\t\t\tconst updateMagnetPosition = (x:number, y:number, z:number)=>{\n\t\t\t\t//\n\t\t\t\t// set the value of the magnet to use\n\t\t\t\t//\n\t\t\t\tmagnet.value.setXYZW(magnetIndex , x, y, z, strength);\n\t\t\t\tmagnet.value.needsUpdate = true; \n\t\t\t}\n\n\t\t\tmesh.updateMatrixWorld(true);\n\n\t\t\tmagnetToAssign.value = magnetIndex; \n\t\t\tmagnetToAssign.needsUpdate = true;\n\n\t\t\tconst pos = getWPos();\n\t\t\tupdateMagnetPosition(pos.x, pos.y, pos.z);\n\t\t\t\n\t\t\trenderer.compute(assignVerticesToMagnet); \n\n\t\t\treturn {\n\t\t\t\tupdate: ()=>{\n\t\t\t\t\tconst pos = getWPos();\n\t\t\t\t\tupdateMagnetPosition(pos.x, pos.y, pos.z);\n\t\t\t\t},\n\t\t\t\tupdatePosition: updateMagnetPosition,\n\t\t\t\tdeactivate: ()=>{\n\t\t\t\t\tmagnet.value.setXYZW(magnetIndex, 0, 0, 0, 0);\n\t\t\t\t\tmagnet.value.needsUpdate = true;\n\t\t\t\t\tmagnetToAssign.value = magnetIndex;\n\t\t\t\t\trenderer.compute(removeVerticesFromMagnet);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n };\n}\n\n\n/**\n * A SIMPLE cloth simulation. Goal is to have a minimal interface to just get some mesh to act kind of like a cloth. \n * Adaptation/Based on the Three's Official examples: https://github.com/mrdoob/three.js/blob/a58e9ecf225b50e4a28a934442e854878bc2a959/examples/webgpu_compute_cloth.html\n * \n */\nexport class SimpleCloth {\n \n\t/**\n\t * Turns the vertex painted parts of a skinned mesh into a cloth simulation.\n\t * Red paint is assumed to be the part of the mesh that should be simulated.\n\t * The rest is assumed to be white. \n\t * \n \t * @param mesh The skinned mesh to turn into a cloth simulation.\n\t * @param renderer The renderer ( because we need to run compute shaders )\n\t * @param options The options for the simulation.\n\t * @returns The cloth simulation's API.\n\t */\n\tstatic onSkinnedMesh = setupClothOnSkinnedMesh;\n}\n"],"names":["v","Vector3","calculateGeometry","mesh","$maskAttribute","geometry","pos","mask","count","map","springPerVertex","indices","vPos","vVertexToFace","vFaces","uniqueCount","i","x","y","z","weight","key","springs","springDefined","addSpringToVertex","vertex","springID","addSpring","A","B","hash","hash2","gIndices","Ai","Bi","Ci","faceIndex","springsPerVertexArray","springsPointer","springsForV","getCollidersFrom","root","skeleton","multiplier","colliders","scene","o","Scene","col","obj","bone","_a","assumeTheModelCameFromBlenderAndWasTexturedNormally","base","posNode","normalNode","m","MeshPhysicalNodeMaterial","DoubleSide","setupClothOnSkinnedMesh","renderer","config","$cfg","hasString","j","BufferAttribute","stiffnessUniform","uniform","dampeningUniform","dt","gravityUniform","windUniform","vPosStore","instancedArray","vForceStore","vVertexIntsArray","vVertexInts","vSpringsPerVertexArray","totalSprings","countOfPoints","springsStore","springForceBuffer","vFacesStore","indicesStore","magnet","magnetToAssign","worldMatrix","objectWorldMatrix","skinningPosition","computeSkinning","collidersArray","colliderAttr","StorageInstancedBufferAttribute","collidersStore","storage","worldMatrixInverseUniform","Matrix4","initializeSkinningPosition","Fn","If","instanceIndex","Return","uIndex","wPos","skinningWorldPosition","updateSkinningPoints","factor","mix","computeSpringForces","uint","vertexIds","restLength","bitcast","vertex0Position","delta","dist","force","computeVertexForces","position","clothMask","springPointer","magnetIndex","springCount","ptrStart","ptrEnd","Loop","springIndex","spring","springForce","select","windForce","triNoise3D","time","cPos","cRad","deltaSphere","sphereForce","forceLength","maxForce","magnetData","magnetPosition","magnetStrength","magnetForce","calculateRestLengths","posA","assignVerticesToMagnet","selectedIndex","minDist","float","currentMagnet","removeVerticesFromMagnet","ids","positionNode_","attribute","vNormal","face","v0","v1","v2","edge1","edge2","normal","cross","localNormal","transformNormalToView","frontFacing","updateCollidersPositions","init","timeSinceLastStep","steps","deltaTime","timePerStep","worldPos","strength","getWPos","updateMagnetPosition","SimpleCloth","__publicField"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-simplecloth",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "type": "module",
5
5
  "description": "Simple cloth simulation for Three.js WebGPU",
6
6
  "repository": {