three-mediapipe-rig 0.1.0 → 0.1.2

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.
Files changed (38) hide show
  1. package/README.md +7 -2
  2. package/dist/face-tracker-utils-xt9__vBF.js +16 -0
  3. package/dist/meshcap/atlas-builder.d.ts +10 -0
  4. package/dist/meshcap/atlas-builder.d.ts.map +1 -0
  5. package/dist/meshcap/constants.d.ts +3 -0
  6. package/dist/meshcap/constants.d.ts.map +1 -0
  7. package/dist/meshcap/material.d.ts +53 -0
  8. package/dist/meshcap/material.d.ts.map +1 -0
  9. package/dist/meshcap/meshcap.d.ts +5 -0
  10. package/dist/meshcap/meshcap.d.ts.map +1 -0
  11. package/dist/meshcap/parse-mcap-file.d.ts +8 -0
  12. package/dist/meshcap/parse-mcap-file.d.ts.map +1 -0
  13. package/dist/meshcap/types.d.ts +53 -0
  14. package/dist/meshcap/types.d.ts.map +1 -0
  15. package/dist/meshcap/write-mcap-file.d.ts +3 -0
  16. package/dist/meshcap/write-mcap-file.d.ts.map +1 -0
  17. package/dist/meshcap.d.ts +2 -0
  18. package/dist/meshcap.js +316 -0
  19. package/dist/module.d.ts +1 -0
  20. package/dist/module.d.ts.map +1 -1
  21. package/dist/rigger.d.ts +2 -0
  22. package/dist/rigger.js +853 -0
  23. package/dist/tracking/BoneMapping.d.ts.map +1 -1
  24. package/dist/tracking/FaceTracker.d.ts +13 -2
  25. package/dist/tracking/FaceTracker.d.ts.map +1 -1
  26. package/dist/tracking/HandTracker.d.ts +3 -3
  27. package/dist/tracking/HandTracker.d.ts.map +1 -1
  28. package/dist/tracking/PoseTracker.d.ts +1 -1
  29. package/dist/tracking/PoseTracker.d.ts.map +1 -1
  30. package/dist/tracking/TrackerManager.d.ts +118 -0
  31. package/dist/tracking/TrackerManager.d.ts.map +1 -0
  32. package/dist/tracking/recoding/recorder.d.ts +10 -8
  33. package/dist/tracking/recoding/recorder.d.ts.map +1 -1
  34. package/dist/tracking/util/face-tracker-utils.d.ts +9 -0
  35. package/dist/tracking/util/face-tracker-utils.d.ts.map +1 -0
  36. package/package.json +17 -12
  37. package/dist/three-mediapipe-rig.js +0 -830
  38. package/dist/three-mediapipe-rig.js.map +0 -1
@@ -1,830 +0,0 @@
1
- var pe = Object.defineProperty;
2
- var me = (c, s, e) => s in c ? pe(c, s, { enumerable: !0, configurable: !0, writable: !0, value: e }) : c[s] = e;
3
- var x = (c, s, e) => me(c, typeof s != "symbol" ? s + "" : s, e);
4
- import { PoseLandmarker as de, HandLandmarker as z, FaceLandmarker as B, FilesetResolver as ue, DrawingUtils as fe } from "@mediapipe/tasks-vision";
5
- import * as m from "three/webgpu";
6
- import { Vector3 as P, Quaternion as ce, BufferAttribute as ye, VideoTexture as we, SRGBColorSpace as Le, MeshPhysicalNodeMaterial as ke } from "three/webgpu";
7
- import * as O from "three";
8
- import { Bone as be } from "three";
9
- import { uniform as xe, attribute as Re, instancedArray as Pe, varying as ve, vec3 as Ee, texture as We, vec2 as Fe } from "three/tsl";
10
- import { GLTFExporter as Ae } from "three/examples/jsm/Addons.js";
11
- const _ = new P(), $ = new P(), ge = new P(1, 0, 0), Me = new P(-1, 0, 0), Se = new P(0, 1, 0), Ne = new P(0, -1, 0), H = new P(0, 0, 1);
12
- new P(0, 0, -1);
13
- const j = new P(), Ve = new P(), Oe = new P(), q = new ce(), D = new ce();
14
- function M(c, s, e, t = "+x") {
15
- c.lookAt(s);
16
- const o = t == "+x" ? ge : t == "-x" ? Me : t == "+y" ? Se : Ne;
17
- c.getWorldPosition($), c.getWorldQuaternion(D), _.subVectors(e, $).normalize(), j.copy(o).applyQuaternion(D);
18
- const n = j, r = Ve.copy(H).applyQuaternion(D), i = _.clone().addScaledVector(r, -_.dot(r)).normalize(), a = Oe.crossVectors(n, i), l = Math.atan2(a.dot(r), n.dot(i));
19
- q.setFromAxisAngle(H, l), c.quaternion.multiply(q);
20
- }
21
- const T = new m.Vector3(), S = new m.Vector3(), C = new m.Vector3();
22
- new m.Vector3();
23
- class I {
24
- constructor(s, e) {
25
- x(this, "objectGhost");
26
- x(this, "root");
27
- /**
28
- * per landmark index, it points to it's object3D equivalent.
29
- */
30
- x(this, "marks", {});
31
- this.points = s, this.debugConnections = e, this.root = new m.Object3D(), this.objectGhost = /* @__PURE__ */ new Map();
32
- for (let t in this.points)
33
- this.marks[t] = new Te(), this.root.add(this.marks[t]);
34
- }
35
- updateLandmarks(s, e, t) {
36
- for (let o in this.points) {
37
- const n = this.points[o], r = this.marks[o];
38
- r && (n instanceof Array ? (T.copy(s[n[0]]), r.position.copy(s[n[1]]).sub(T).divideScalar(2).add(s[n[0]]), n.length == 4 && (T.subVectors(
39
- s[n[3]],
40
- s[n[2]]
41
- ).divideScalar(2).add(s[n[2]]).sub(r.position).divideScalar(2), r.position.add(T))) : r.position.copy(s[n]));
42
- }
43
- t && e && t.drawConnectors(
44
- e,
45
- this.debugConnections,
46
- {
47
- lineWidth: 1
48
- }
49
- );
50
- }
51
- getGhost(s) {
52
- var e;
53
- if (!this.objectGhost.has(s)) {
54
- const t = new _e();
55
- t.position.copy(s.position), t.quaternion.copy(s.quaternion), (e = s.parent) == null || e.add(t), this.objectGhost.set(s, t);
56
- }
57
- return this.objectGhost.get(s);
58
- }
59
- predict(s, e) {
60
- throw new Error("Method 'predict' must be implemented.");
61
- }
62
- sync(s, e) {
63
- throw new Error("Method 'sync' must be implemented.");
64
- }
65
- test(s) {
66
- this.marks[s].position.set(1, 2, 3);
67
- }
68
- syncObjects(s, e, t) {
69
- for (const [o, n, r, i] of s) {
70
- this.marks[r].getWorldPosition(C), this.marks[n].getWorldPosition(S);
71
- const a = C.sub(S);
72
- o.getWorldPosition(S), S.add(a);
73
- const l = S, p = o.getWorldPosition(C).sub(t), f = this.getGhost(o);
74
- M(f, l, p, i), f.rotateX(Math.PI / 2), o.position.lerp(f.position, e * 4), o.quaternion.slerp(f.quaternion, e * 4);
75
- }
76
- }
77
- getBone(s, e) {
78
- return s.getObjectByName(e.replace(/[\.\:]/g, ""));
79
- }
80
- }
81
- class Te extends m.Mesh {
82
- constructor() {
83
- super(new m.SphereGeometry(0.01, 3, 3), new m.MeshStandardMaterial({ color: 16711680, wireframe: !0 }));
84
- x(this, "_worldPosition", new m.Vector3());
85
- this.add(new m.AxesHelper(1e-3));
86
- }
87
- get worldPosition() {
88
- return this.getWorldPosition(this._worldPosition), this._worldPosition;
89
- }
90
- }
91
- class _e extends m.Object3D {
92
- lerp(s, e, t = 8) {
93
- s.position.lerp(this.position, e * t), s.quaternion.slerp(this.quaternion, e * t);
94
- }
95
- }
96
- function A(c, s, e) {
97
- return e.worldToLocal(s.getWorldPosition(c)), c;
98
- }
99
- function De(c) {
100
- return c.replace(/[\.\:]/g, "");
101
- }
102
- function v(c, s) {
103
- let e;
104
- return s = De(s), c.traverse((t) => {
105
- t.name.indexOf(s) === 0 && t instanceof be && (e = t);
106
- }), e || console.log("Bone not found: ", s, c.name), e;
107
- }
108
- async function Ce(c, s) {
109
- const e = await de.createFromOptions(c, {
110
- baseOptions: {
111
- modelAssetPath: (s == null ? void 0 : s.modelPath) ?? "pose_landmarker_lite.task",
112
- //modelAssetPath: `https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task`,
113
- //modelAssetPath: "https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_heavy/float16/latest/pose_landmarker_heavy.task",
114
- delegate: "GPU"
115
- },
116
- runningMode: "VIDEO",
117
- numPoses: 1
118
- });
119
- return new $e(e, s);
120
- }
121
- const ze = {
122
- hips: [24, 23],
123
- neck: [12, 11],
124
- leftLeg: 23,
125
- leftKnee: 25,
126
- leftFoot: 27,
127
- leftToes: 31,
128
- leftArm: 11,
129
- leftElbow: 13,
130
- leftWrist: 15,
131
- rightLeg: 24,
132
- rightKnee: 26,
133
- rightFoot: 28,
134
- rightToes: 32,
135
- rightArm: 12,
136
- rightElbow: 14,
137
- rightWrist: 16,
138
- head: [8, 7],
139
- mouth: [10, 9],
140
- torso: [24, 23, 12, 11],
141
- leftEar: 7,
142
- rightEar: 8
143
- }, Be = new m.Vector3(), K = new m.Vector3(), Ie = new m.Vector3(), Ue = new m.Vector3(), Ge = new m.Vector3(), X = new m.Vector3(), Q = new m.Vector3();
144
- class $e extends I {
145
- constructor(e, t) {
146
- super(ze, de.POSE_CONNECTIONS);
147
- x(this, "_leftWristNormalizedPosition");
148
- x(this, "_rightWristNormalizedPosition");
149
- this.poseLandmarker = e, this.config = t, this.root.scale.y *= -2, this.root.scale.z *= -2, this.root.scale.x *= 2;
150
- }
151
- /**
152
- * Position of the left wrist in normalized coordinates (0..1)
153
- */
154
- get leftWristNormalizedPosition() {
155
- return this._leftWristNormalizedPosition;
156
- }
157
- /**
158
- * Position of the right wrist in normalized coordinates (0..1)
159
- */
160
- get rightWristNormalizedPosition() {
161
- return this._rightWristNormalizedPosition;
162
- }
163
- predict(e, t) {
164
- this.poseLandmarker.detectForVideo(e, performance.now(), (o) => {
165
- var n;
166
- o.landmarks.length != 0 && (this.updateLandmarks(o.worldLandmarks[0], ((n = this.config) == null ? void 0 : n.drawLandmarks) === !1 ? void 0 : o.landmarks[0], t), this._leftWristNormalizedPosition = o.landmarks[0][this.points.leftWrist], this._rightWristNormalizedPosition = o.landmarks[0][this.points.rightWrist]);
167
- });
168
- }
169
- // override sync ( delta:number, objects: BoneBinding[] ) {
170
- // const hipsPos = this.marks.hips.getWorldPosition(C);
171
- // this.marks.rightArm.getWorldPosition(A).sub(hipsPos);
172
- // this.marks.leftArm.getWorldPosition(B).sub(hipsPos);
173
- // const torsoNormal = C.crossVectors(A,B);
174
- // this.syncObjects(objects, delta, torsoNormal);
175
- // }
176
- bind(e, t) {
177
- var a;
178
- const o = {
179
- hips: v(e, t.hips),
180
- neck: v(e, t.neck),
181
- leftArm: v(e, t.armL),
182
- leftElbow: v(e, t.forearmL),
183
- leftWrist: v(e, t.handL),
184
- rightArm: v(e, t.armR),
185
- rightElbow: v(e, t.forearmR),
186
- rightWrist: v(e, t.handR),
187
- head: v(e, t.head),
188
- torso: v(e, t.torso),
189
- leftLeg: v(e, t.thighL),
190
- leftKnee: v(e, t.shinL),
191
- leftFoot: v(e, t.footL),
192
- rightLeg: v(e, t.thighR),
193
- rightKnee: v(e, t.shinR),
194
- rightFoot: v(e, t.footR)
195
- };
196
- (a = this.config) != null && a.ignoreLegs && (delete o.leftLeg, delete o.leftKnee, delete o.leftFoot, delete o.leftToes, delete o.rightLeg, delete o.rightKnee, delete o.rightFoot, delete o.rightToes);
197
- const n = new m.Vector3(), r = new m.Vector3(), i = (l, p, f, R, d, u) => {
198
- if (!p) return;
199
- const w = this.marks[R].getWorldPosition(n).sub(this.marks[f].getWorldPosition(r)).normalize();
200
- A(X, p, e).add(w).applyMatrix4(e.matrixWorld), A(Q, p, e).add(d).applyMatrix4(e.matrixWorld);
201
- const h = this.getGhost(p);
202
- M(h, X, Q, u), h.rotateX(Math.PI / 2), h.lerp(p, l);
203
- };
204
- return {
205
- update: (l) => {
206
- const p = this.marks.leftLeg.getWorldPosition(Be).sub(this.marks.rightLeg.getWorldPosition(K)).normalize(), f = this.marks.leftArm.getWorldPosition(K).sub(this.marks.rightArm.getWorldPosition(Ie)).normalize(), R = this.marks.leftEar.getWorldPosition(Ue).sub(this.marks.rightEar.getWorldPosition(Ge)).normalize();
207
- i(l, o.hips, "hips", "torso", p, "+x"), i(l, o.torso, "torso", "neck", f, "+x"), i(l, o.neck, "neck", "head", R, "+x"), i(l, o.head, "neck", "head", R, "+x"), i(l, o.leftArm, "leftArm", "leftElbow", f, "-x"), i(l, o.leftElbow, "leftElbow", "leftWrist", f, "-x"), i(l, o.leftLeg, "leftLeg", "leftKnee", p, "+x"), i(l, o.leftKnee, "leftKnee", "leftFoot", p, "+x"), i(l, o.leftFoot, "leftFoot", "leftToes", p, "+x"), i(l, o.rightArm, "rightArm", "rightElbow", f, "-x"), i(l, o.rightElbow, "rightElbow", "rightWrist", f, "-x"), i(l, o.rightLeg, "rightLeg", "rightKnee", p, "+x"), i(l, o.rightKnee, "rightKnee", "rightFoot", p, "+x"), i(l, o.rightFoot, "rightFoot", "rightToes", p, "+x");
208
- }
209
- };
210
- }
211
- }
212
- const Y = new m.Vector2(), Z = new m.Vector2();
213
- async function He(c, s) {
214
- const e = await z.createFromOptions(c, {
215
- baseOptions: {
216
- modelAssetPath: s.modelPath ?? "hand_landmarker.task",
217
- //modelAssetPath: `https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task`,
218
- delegate: "GPU"
219
- },
220
- runningMode: "VIDEO",
221
- numHands: 2
222
- }), t = (o, n, r) => {
223
- try {
224
- Y.copy(o()), Z.copy(n());
225
- } catch (i) {
226
- return console.warn("No pose data... will just be optimitic and say yes to everything.", i), !0;
227
- }
228
- return Y.distanceTo(r) < Z.distanceTo(r);
229
- };
230
- return {
231
- left: new re(e, "Left", t.bind(null, s.leftWrist, s.rightWrist), s.drawLandmarks),
232
- right: new re(e, "Right", t.bind(null, s.rightWrist, s.leftWrist), s.drawLandmarks)
233
- };
234
- }
235
- const je = {
236
- wrist: 0,
237
- palm: [9, 13],
238
- thumb1: 1,
239
- thumb2: 2,
240
- thumb3: 3,
241
- thumb4: 4,
242
- index1: 5,
243
- index2: 6,
244
- index3: 7,
245
- index4: 8,
246
- middle1: 9,
247
- middle2: 10,
248
- middle3: 11,
249
- middle4: 12,
250
- ring1: 13,
251
- ring2: 14,
252
- ring3: 15,
253
- ring4: 16,
254
- pinky1: 17,
255
- pinky2: 18,
256
- pinky3: 19,
257
- pinky4: 20
258
- }, N = {
259
- thumb: ["thumb1", "thumb2", "thumb3", "thumb4"],
260
- index: ["index1", "index2", "index3", "index4"],
261
- middle: ["middle1", "middle2", "middle3", "middle4"],
262
- ring: ["ring1", "ring2", "ring3", "ring4"],
263
- pinky: ["pinky1", "pinky2", "pinky3", "pinky4"]
264
- }, qe = new m.Vector3(), J = new m.Vector3(), ee = new m.Vector3(), te = new m.Vector3(), oe = new m.Vector3(), se = new m.Vector3();
265
- new m.Vector3();
266
- new m.Vector3();
267
- new m.Vector3();
268
- const ne = new m.Vector3(), ie = Math.PI / 2, Ke = new m.Vector3(0, -1, 0);
269
- class re extends I {
270
- constructor(e, t, o, n = !0) {
271
- super(je, z.HAND_CONNECTIONS);
272
- x(this, "sign");
273
- x(this, "isLeft");
274
- /**
275
- * the axis used to look at the pole
276
- */
277
- x(this, "lookAtPoleAxis");
278
- this.handLandmarker = e, this.side = t, this.isMyWrist = o, this.drawLandmarks = n, this.sign = this.side == "Left" ? -1 : 1, this.isLeft = this.side == "Left", this.lookAtPoleAxis = this.sign < 0 ? "+x" : "-x", this.root.scale.setScalar(7), this.root.scale.y *= -1, this.root.scale.z *= -1;
279
- }
280
- predict(e, t) {
281
- const o = this.handLandmarker.detectForVideo(e, performance.now());
282
- if (o.landmarks.length)
283
- for (let n = 0; n < o.landmarks.length; n++) {
284
- const r = o.landmarks[n], i = r[this.points.wrist];
285
- if (this.isMyWrist(i)) {
286
- this.updateLandmarks(o.worldLandmarks[n]), this.drawLandmarks && (t.drawConnectors(r, z.HAND_CONNECTIONS, {
287
- color: this.side == "Left" ? "#00FF00" : "#0000FF",
288
- lineWidth: 4
289
- }), t.drawLandmarks(r, { color: this.side == "Left" ? "#00FF00" : "#0000FF", lineWidth: 3, radius: 1 }));
290
- break;
291
- }
292
- }
293
- }
294
- sync(e, t) {
295
- throw new Error("Not used. Use syncHandBones instead");
296
- }
297
- /**
298
- *
299
- * @param delta time since last frame
300
- * @param landmark2bones Array the same size as the umber of hand landmarks, and on each positionthe bone that belongs to that point.
301
- * @see https://ai.google.dev/edge/mediapipe/solutions/vision/hand_landmarker
302
- */
303
- syncHandBones(e, t, o) {
304
- const n = qe.crossVectors(
305
- J.copy(this.marks.index1.worldPosition).sub(this.marks.wrist.worldPosition),
306
- ee.copy(this.marks.pinky1.worldPosition).sub(this.marks.wrist.worldPosition)
307
- ).normalize(), r = J.copy(this.marks.palm.worldPosition).sub(this.marks.wrist.worldPosition).normalize(), i = ee.copy(this.marks.pinky1.worldPosition).sub(this.marks.index1.worldPosition).normalize();
308
- if (!(r.dot(Ke) > 0.8)) {
309
- if (t.wrist) {
310
- const a = A(te, t.wrist, o).add(r).applyMatrix4(o.matrixWorld), l = A(oe, t.wrist, o).sub(i).applyMatrix4(o.matrixWorld), p = this.getGhost(t.wrist);
311
- M(p, a, l, "-y"), p.rotateX(ie), p.lerp(t.wrist, e);
312
- }
313
- this.syncFinger(e, o, n, r, i, t, N.index, "middle1"), this.syncFinger(e, o, n, r, i, t, N.middle, "ring1"), this.syncFinger(e, o, n, r, i, t, N.ring, "pinky1"), this.syncFinger(e, o, n, r, i, t, N.pinky, "ring1", !0), this.syncFinger(e, o, n, r, i, t, N.thumb, "index1");
314
- }
315
- }
316
- syncFinger(e, t, o, n, r, i, a, l, p = !1) {
317
- for (let f = 0; f < a.length - 1; f++) {
318
- const R = i[a[f]];
319
- if (!R) continue;
320
- const d = this.getGhost(R), u = te.copy(this.marks[a[f + 1]].worldPosition).sub(this.marks[a[f]].worldPosition).normalize(), w = A(oe, R, t);
321
- if (f == 0) {
322
- const h = se.copy(this.marks[l].worldPosition).sub(this.marks[a[0]].worldPosition).normalize();
323
- p && h.negate(), ne.copy(h), M(
324
- d,
325
- u.add(w).applyMatrix4(t.matrixWorld),
326
- h.add(w).applyMatrix4(t.matrixWorld),
327
- this.lookAtPoleAxis
328
- );
329
- } else
330
- M(
331
- d,
332
- u.add(w).applyMatrix4(t.matrixWorld),
333
- se.copy(ne).add(w).applyMatrix4(t.matrixWorld),
334
- this.lookAtPoleAxis
335
- );
336
- d.rotateX(ie), d.lerp(R, e);
337
- }
338
- }
339
- bind(e, t) {
340
- const o = {}, n = (r, i) => {
341
- const a = v(e, r);
342
- if (a)
343
- return o[i] = a, i;
344
- };
345
- return n(this.isLeft ? t.handL : t.handR, "wrist"), n(this.isLeft ? t.index1L : t.index1R, "index1"), n(this.isLeft ? t.index2L : t.index2R, "index2"), n(this.isLeft ? t.index3L : t.index3R, "index3"), n(this.isLeft ? t.middle1L : t.middle1R, "middle1"), n(this.isLeft ? t.middle2L : t.middle2R, "middle2"), n(this.isLeft ? t.middle3L : t.middle3R, "middle3"), n(this.isLeft ? t.ring1L : t.ring1R, "ring1"), n(this.isLeft ? t.ring2L : t.ring2R, "ring2"), n(this.isLeft ? t.ring3L : t.ring3R, "ring3"), n(this.isLeft ? t.pinky1L : t.pinky1R, "pinky1"), n(this.isLeft ? t.pinky2L : t.pinky2R, "pinky2"), n(this.isLeft ? t.pinky3L : t.pinky3R, "pinky3"), n(this.isLeft ? t.thumb1L : t.thumb1R, "thumb1"), n(this.isLeft ? t.thumb2L : t.thumb2R, "thumb2"), n(this.isLeft ? t.thumb3L : t.thumb3R, "thumb3"), {
346
- update: (r) => {
347
- this.syncHandBones(r, o, e);
348
- }
349
- };
350
- }
351
- }
352
- async function Xe(c, s) {
353
- const e = await B.createFromOptions(c, {
354
- baseOptions: {
355
- modelAssetPath: (s == null ? void 0 : s.modelPath) ?? "face_landmarker.task",
356
- delegate: "GPU"
357
- },
358
- outputFaceBlendshapes: !0,
359
- runningMode: "VIDEO",
360
- numFaces: 1
361
- });
362
- return new tt(e, { ...s });
363
- }
364
- const Qe = {
365
- eyeL: 473,
366
- eyeR: 468,
367
- eyeStartL: 463,
368
- eyeStartR: 243,
369
- eyeEndL: 263,
370
- eyeEndR: 33,
371
- earL: 454,
372
- earR: 234,
373
- noseTip: 4,
374
- noseBone: 6,
375
- chin: 152,
376
- forehead: 10
377
- }, Ye = new P(), Ze = new P(), le = new P(), Je = new P(), et = new P();
378
- new P();
379
- class tt extends I {
380
- constructor(e, t) {
381
- super(Qe, B.FACE_LANDMARKS_TESSELATION);
382
- x(this, "blendshapeCategories");
383
- x(this, "blendshapeMap", /* @__PURE__ */ new Map());
384
- x(this, "smoothed", {});
385
- x(this, "smoothing", 3e-4);
386
- // lower = smoother but more lag, higher = more responsive
387
- x(this, "_faceLandmarks", []);
388
- this.faceLandmarker = e, this.cfg = t, this.root.scale.y *= -1, this.root.scale.z *= -1, this.root.scale.multiplyScalar(3);
389
- }
390
- predict(e, t) {
391
- var n, r, i;
392
- const o = this.faceLandmarker.detectForVideo(e, performance.now());
393
- o.faceLandmarks[0] && (this.cfg.drawLandmarks && (t.drawConnectors(o.faceLandmarks[0], B.FACE_LANDMARKS_TESSELATION, { color: "#00fff2ff", lineWidth: 0.1 }), t.drawLandmarks(o.faceLandmarks[0], { color: "#00ff00", lineWidth: 0.1, radius: 0.4 })), this.updateLandmarks(o.faceLandmarks[0], o.faceLandmarks[0])), this._faceLandmarks = o.faceLandmarks[0], this.blendshapeCategories = (r = (n = o.faceBlendshapes) == null ? void 0 : n[0]) == null ? void 0 : r.categories, (i = this.blendshapeCategories) == null || i.forEach((a) => {
394
- this.blendshapeMap.set(a.categoryName, a.score);
395
- });
396
- }
397
- get lastKnownLandmarks() {
398
- return this._faceLandmarks;
399
- }
400
- bindShapeKeys(e) {
401
- const t = e.morphTargetDictionary;
402
- return {
403
- update: (o) => {
404
- var n;
405
- (n = this.blendshapeCategories) == null || n.forEach((r) => {
406
- const { categoryName: i, score: a } = r;
407
- if (!(t != null && t.hasOwnProperty(i))) return;
408
- this.smoothed[i] === void 0 && (this.smoothed[i] = a);
409
- const l = 1 - Math.pow(this.smoothing, o);
410
- this.smoothed[i] += (a - this.smoothed[i]) * l, e.morphTargetInfluences[t[i]] = this.smoothed[i];
411
- });
412
- }
413
- };
414
- }
415
- bind(e) {
416
- const t = new ae(e, "L"), o = new ae(e, "R"), n = v(e, "head");
417
- return {
418
- update: (r) => {
419
- if (t.update(r, this.blendshapeMap), o.update(r, this.blendshapeMap), !n) return;
420
- const i = Ye.copy(this.marks.earL.worldPosition), a = Ze.copy(this.marks.earR.worldPosition), l = le.subVectors(i, a).multiplyScalar(0.5).add(a), p = Je.subVectors(this.marks.noseTip.worldPosition, l), f = i.sub(a), R = A(et, n, e), d = f.add(R).applyMatrix4(e.matrixWorld), u = p.add(R).applyMatrix4(e.matrixWorld);
421
- M(n, u, d, "+x");
422
- }
423
- };
424
- }
425
- /**
426
- * The mesh is assumed to be a canonical_face_model because we will be manipulating it's vertices.
427
- *
428
- * @see https://github.com/google-ai-edge/mediapipe/tree/master/mediapipe/modules/face_geometry
429
- * @param mesh basically either the original or a clone of the canonical_face_model
430
- */
431
- bindGeometry(e, t) {
432
- const o = new P(), n = new P(), r = e.geometry, i = r.attributes.position, a = [], l = /* @__PURE__ */ new Map(), p = [];
433
- for (let h = 0; h < i.count; h++) {
434
- const y = `${i.getX(h).toFixed(6)},${i.getY(h).toFixed(6)},${i.getZ(h).toFixed(6)}`;
435
- l.has(y) || (l.set(y, a.length), a.push(h)), p.push(l.get(y));
436
- }
437
- const f = xe(new P(0.5, 0.5, 0.5));
438
- r.setAttribute("landmarkIndex", new ye(new Uint16Array(p), 1));
439
- const R = Re("landmarkIndex", "uint"), d = Pe(468, "vec3"), u = ve(d.element(R)).xy;
440
- let w;
441
- return {
442
- update: (h) => {
443
- var g, V;
444
- if (!w) {
445
- if (w = (V = (g = this.cfg) == null ? void 0 : g.videoElementRef) == null ? void 0 : V.call(g), !w) return;
446
- const W = new we(w);
447
- W.colorSpace = Le;
448
- const U = d.element(R).sub(f).xzy.mul(Ee(1.3, -1.1, 1)), G = We(W, Fe(u.x, u.y.oneMinus()));
449
- t ? t(U, G) : e.material = new ke({
450
- positionNode: U,
451
- colorNode: G,
452
- roughness: 0.93
453
- });
454
- }
455
- const y = this.lastKnownLandmarks;
456
- if (!y) return;
457
- const b = d.value.array;
458
- for (let W = 0; W < y.length; W++)
459
- b[W * 3] = y[W].x, b[W * 3 + 1] = y[W].y, b[W * 3 + 2] = y[W].z;
460
- d.value.needsUpdate = !0;
461
- const E = y[234], k = y[93], L = y[454], F = y[323];
462
- o.copy(E).sub(k).divideScalar(2).add(k), n.copy(L).sub(F).divideScalar(2).add(F), f.value.subVectors(n, o).divideScalar(2).add(o), f.needsUpdate = !0;
463
- }
464
- };
465
- }
466
- }
467
- class ae {
468
- constructor(s, e) {
469
- x(this, "eyeBone");
470
- x(this, "eyeLookOut");
471
- x(this, "eyeLookIn");
472
- x(this, "eyeLookUp");
473
- x(this, "eyeLookDown");
474
- x(this, "sign", 1);
475
- this.rig = s, this.side = e, this.eyeBone = s.getObjectByName(`eye${e}`);
476
- const t = e == "L" ? "Left" : "Right";
477
- this.eyeLookOut = `eyeLookOut${t}`, this.eyeLookIn = `eyeLookIn${t}`, this.eyeLookUp = `eyeLookUp${t}`, this.eyeLookDown = `eyeLookDown${t}`, this.sign = e == "L" ? -1 : 1;
478
- }
479
- update(s, e) {
480
- if (!this.eyeBone) return;
481
- A(le, this.eyeBone, this.rig);
482
- const t = e.get(this.eyeLookOut) ?? 0, o = e.get(this.eyeLookIn) ?? 0, n = e.get(this.eyeLookUp) ?? 0, r = e.get(this.eyeLookDown) ?? 0, i = o - t, a = r - n;
483
- this.eyeBone.rotation.y = i * this.sign / 2, this.eyeBone.rotation.x = a / 2;
484
- }
485
- }
486
- const he = {
487
- faceMesh: "face",
488
- head: "head",
489
- hips: "hips",
490
- neck: "neck",
491
- torso: "torso",
492
- armL: "upper_armL",
493
- forearmL: "forearmL",
494
- armR: "upper_armR",
495
- forearmR: "forearmR",
496
- thighL: "thighL",
497
- shinL: "shinL",
498
- footL: "footL",
499
- thighR: "thighR",
500
- shinR: "shinR",
501
- footR: "footR",
502
- handL: "handL",
503
- index1L: "index1L",
504
- index2L: "index2L",
505
- index3L: "index3L",
506
- middle1L: "middle1L",
507
- middle2L: "middle2L",
508
- middle3L: "middle3L",
509
- ring1L: "ring1L",
510
- ring2L: "ring2L",
511
- ring3L: "ring3L",
512
- pinky1L: "pinky1L",
513
- pinky2L: "pinky2L",
514
- pinky3L: "pinky3L",
515
- thumb1L: "thumb1L",
516
- thumb2L: "thumb2L",
517
- thumb3L: "thumb3L",
518
- handR: "handR",
519
- index1R: "index1R",
520
- index2R: "index2R",
521
- index3R: "index3R",
522
- middle1R: "middle1R",
523
- middle2R: "middle2R",
524
- middle3R: "middle3R",
525
- ring1R: "ring1R",
526
- ring2R: "ring2R",
527
- ring3R: "ring3R",
528
- pinky1R: "pinky1R",
529
- pinky2R: "pinky2R",
530
- pinky3R: "pinky3R",
531
- thumb1R: "thumb1R",
532
- thumb2R: "thumb2R",
533
- thumb3R: "thumb3R"
534
- }, ot = [
535
- "eyeBlinkLeft",
536
- "eyeBlinkRight",
537
- "eyeLookDownLeft",
538
- "eyeLookDownRight",
539
- "eyeLookInLeft",
540
- "eyeLookInRight",
541
- "eyeLookOutLeft",
542
- "eyeLookOutRight",
543
- "eyeLookUpLeft",
544
- "eyeLookUpRight",
545
- "eyeSquintLeft",
546
- "eyeSquintRight",
547
- "eyeWideLeft",
548
- "eyeWideRight",
549
- "browDownLeft",
550
- "browDownRight",
551
- "browInnerUp",
552
- "browOuterUpLeft",
553
- "browOuterUpRight",
554
- "noseSneerLeft",
555
- "noseSneerRight",
556
- "cheekPuff",
557
- "cheekSquintLeft",
558
- "cheekSquintRight",
559
- "jawForward",
560
- "jawLeft",
561
- "jawOpen",
562
- "jawRight",
563
- "mouthClose",
564
- "mouthDimpleLeft",
565
- "mouthDimpleRight",
566
- "mouthFrownLeft",
567
- "mouthFrownRight",
568
- "mouthFunnel",
569
- "mouthLeft",
570
- "mouthLowerDownLeft",
571
- "mouthLowerDownRight",
572
- "mouthPressLeft",
573
- "mouthPressRight",
574
- "mouthPucker",
575
- "mouthRight",
576
- "mouthRollLower",
577
- "mouthRollUpper",
578
- "mouthShrugLower",
579
- "mouthShrugUpper",
580
- "mouthSmileLeft",
581
- "mouthSmileRight",
582
- "mouthStretchLeft",
583
- "mouthStretchRight",
584
- "mouthUpperUpLeft",
585
- "mouthUpperUpRight",
586
- "tongueOut"
587
- ];
588
- function st(c, s, e = 30) {
589
- const t = [], o = c.getObjectByName(
590
- s.faceMesh
591
- ), n = /* @__PURE__ */ new Set();
592
- if (o != null && o.morphTargetDictionary)
593
- for (const w in o.morphTargetDictionary)
594
- ot.includes(w) && n.add(w);
595
- const r = Object.keys(s);
596
- c.traverse((w) => {
597
- if (w instanceof O.Bone) {
598
- const h = r.find((y) => w.name.indexOf(s[y]) === 0);
599
- h && t.push({
600
- ref: w,
601
- name: w.name,
602
- normalizedName: h
603
- });
604
- }
605
- });
606
- const i = [], a = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map();
607
- let p = !1, f = 0;
608
- function R() {
609
- a.clear(), l.clear(), i.length = 0, f = performance.now() / 1e3, p = !0;
610
- }
611
- function d() {
612
- if (!p) return;
613
- const w = performance.now() / 1e3 - f;
614
- i.push(w);
615
- for (const h of t) {
616
- a.has(h.name) || a.set(h.name, []);
617
- const y = a.get(h.name), b = h.ref.quaternion;
618
- y.push(b.x, b.y, b.z, b.w);
619
- }
620
- for (const h of n) {
621
- l.has(h) || l.set(h, []);
622
- const y = l.get(h), b = o.morphTargetDictionary[h], E = o.morphTargetInfluences[b];
623
- y.push(E);
624
- }
625
- }
626
- function u(w = "RecordedClip") {
627
- p = !1;
628
- const h = [];
629
- for (const [b, E] of a)
630
- h.push(
631
- new O.QuaternionKeyframeTrack(
632
- `${b}.quaternion`,
633
- i,
634
- E
635
- )
636
- );
637
- for (const [b, E] of l)
638
- h.push(
639
- new O.NumberKeyframeTrack(
640
- `${he.faceMesh}.morphTargetInfluences[${b}]`,
641
- i,
642
- E
643
- )
644
- );
645
- const y = new O.AnimationClip(w, -1, h);
646
- return {
647
- clip: y,
648
- saveToFile: () => {
649
- new Ae().parse(
650
- c,
651
- (E) => {
652
- const k = new Blob([E], {
653
- type: "model/gltf-binary"
654
- }), L = URL.createObjectURL(k), F = document.createElement("a");
655
- F.href = L, F.download = w + ".glb", F.click();
656
- },
657
- (E) => {
658
- console.error(E);
659
- },
660
- {
661
- binary: !0,
662
- animations: [y]
663
- }
664
- );
665
- }
666
- };
667
- }
668
- return { start: R, captureFrame: d, stop: u, isRecording: () => p };
669
- }
670
- const nt = () => {
671
- var c;
672
- return !!((c = navigator.mediaDevices) != null && c.getUserMedia);
673
- };
674
- async function ht(c) {
675
- const s = {
676
- debugFrame: void 0,
677
- displayScale: 1,
678
- ignoreLegs: !1,
679
- debugVideo: void 0,
680
- ignoreFace: !1,
681
- onlyFace: !1,
682
- drawLandmarksOverlay: !0,
683
- modelPaths: {
684
- vision: "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.3/wasm",
685
- pose: "https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task",
686
- hand: "https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task",
687
- face: "https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task"
688
- },
689
- ...c
690
- };
691
- let e;
692
- const t = await ue.forVisionTasks(s.modelPaths.vision ?? "/wasm"), o = s.onlyFace ? void 0 : await Ce(t, {
693
- ignoreLegs: s.ignoreLegs,
694
- modelPath: s.modelPaths.pose,
695
- drawLandmarks: s.drawLandmarksOverlay
696
- }), n = s.onlyFace ? void 0 : await He(t, {
697
- leftWrist: () => o.leftWristNormalizedPosition,
698
- rightWrist: () => o.rightWristNormalizedPosition,
699
- modelPath: s.modelPaths.hand,
700
- drawLandmarks: s.drawLandmarksOverlay,
701
- ...c == null ? void 0 : c.handsTrackerOptions
702
- }), r = s.ignoreFace ? void 0 : await Xe(t, { modelPath: s.modelPaths.face, videoElementRef: () => e, drawLandmarks: s.drawLandmarksOverlay }), i = document.createElement("div");
703
- i.style.position = "absolute", i.style.top = "0px", i.style.left = "0px", i.style.zIndex = "21", i.classList.add("three-mediapipe-rig"), document.body.appendChild(i);
704
- const a = document.createElement("canvas"), l = a.getContext("2d"), p = new fe(l);
705
- a.style.zIndex = "22", a.style.position = "absolute", a.style.top = "0px", a.style.left = "0px", a.style.pointerEvents = "none", i.appendChild(a);
706
- function f(d) {
707
- l.save(), l.clearRect(0, 0, a.width, a.height), o == null || o.predict(d, p), n == null || n.left.predict(d, p), n == null || n.right.predict(d, p), r == null || r.predict(d, p), l.restore();
708
- }
709
- function R() {
710
- e = document.createElement("video"), i.appendChild(e);
711
- let d = -1;
712
- e.style.zIndex = "21", e.style.position = "absolute", e.style.top = "0px", e.style.left = "0px", s.debugVideo && (e.src = s.debugVideo, e.controls = !0, e.loop = !0, e.muted = !0, e.controls = !0, e.play());
713
- function u() {
714
- d !== e.currentTime && (f(e), d = e.currentTime), window.requestAnimationFrame(u);
715
- }
716
- e.addEventListener("loadeddata", () => {
717
- e.width = e.videoWidth * s.displayScale, e.height = e.videoHeight * s.displayScale, a.width = e.videoWidth, a.height = e.videoHeight, a.style.height = e.height + "px", a.style.width = e.width + "px", window.requestAnimationFrame(u);
718
- });
719
- }
720
- if (s.debugFrame) {
721
- const d = document.createElement("img");
722
- d.src = s.debugFrame, d.style.zIndex = "21", d.style.position = "absolute", d.style.top = "0px", d.style.left = "0px", i.appendChild(d), d.addEventListener("load", () => {
723
- d.width = d.naturalWidth * s.displayScale, d.height = d.naturalHeight * s.displayScale, a.width = d.naturalWidth, a.height = d.naturalWidth, a.style.width = d.width + "px", a.style.height = d.height + "px";
724
- function u() {
725
- f(d);
726
- }
727
- window.requestAnimationFrame(u);
728
- });
729
- } else s.debugVideo && R();
730
- return {
731
- poseTracker: o,
732
- handsTracker: n,
733
- faceTracker: r,
734
- video: e,
735
- canvas: a,
736
- /**
737
- * A div that contains the video and canvas used to display the landmarks stacked on top of each other.
738
- */
739
- domElement: i,
740
- /**
741
- * Start the webcam feed. This must be initiated by a user triggered event ( a click on a button ) due to security reasons.
742
- */
743
- start: async () => {
744
- let d = !1;
745
- if (!nt())
746
- throw new Error("Webcam not supported");
747
- e || R();
748
- let u;
749
- function w(k) {
750
- console.warn("Camera track ended, attempting recovery..."), h(k), y(k);
751
- }
752
- function h(k) {
753
- u == null || u.getTracks().forEach((L) => L.stop()), u = void 0, k.srcObject = null;
754
- }
755
- async function y(k, L = 0) {
756
- const g = Math.min(1e3 * 2 ** L, 16e3);
757
- if (L >= 5)
758
- throw new Error("Camera recovery failed after max attempts");
759
- if (await new Promise((V) => setTimeout(V, g)), !d)
760
- try {
761
- await b(k), console.log("Camera recovered successfully");
762
- } catch {
763
- y(k, L + 1);
764
- }
765
- }
766
- async function b(k) {
767
- try {
768
- u = await navigator.mediaDevices.getUserMedia({ video: !0 }), k.srcObject = u, await k.play(), u.getVideoTracks().forEach((L) => {
769
- L.addEventListener("ended", () => w(k));
770
- });
771
- } catch (L) {
772
- E(L, k);
773
- }
774
- }
775
- function E(k, L) {
776
- if (k instanceof DOMException)
777
- switch (k.name) {
778
- case "NotAllowedError":
779
- throw new Error("Permission denied — prompt user to allow camera");
780
- case "NotFoundError":
781
- console.error("No camera found — retry when device is connected"), y(L);
782
- break;
783
- case "NotReadableError":
784
- console.error("Camera in use by another app"), y(L);
785
- break;
786
- default:
787
- console.error("Camera error:", k.message), y(L);
788
- }
789
- }
790
- return await b(e), {
791
- stop: () => {
792
- d = !0, h(e);
793
- }
794
- };
795
- },
796
- /**
797
- * Binds the bones of the rig to the landmarks provided by media pipe.
798
- * @param rig The rig that contains all the bones and skinned meshes of your character.
799
- * @param magging The bone mapping to use for the rig.
800
- */
801
- bind: (d, u) => {
802
- if (u = u || he, !o) throw new Error("Pose tracker not initialized");
803
- if (!n) throw new Error("Hands tracker not initialized");
804
- if (!r) throw new Error("Face tracker not initialized");
805
- const w = o.bind(d, u), h = n.left.bind(d, u), y = n.right.bind(d, u);
806
- let b;
807
- const E = r == null ? void 0 : r.bind(d);
808
- d.traverse((L) => {
809
- L instanceof m.Mesh && L.name.indexOf(u.faceMesh) === 0 && (L.frustumCulled = !1, b = r == null ? void 0 : r.bindShapeKeys(L));
810
- });
811
- const k = st(d, u);
812
- return {
813
- /**
814
- * Will save the tracked movement of the rig to an animation clip.
815
- * Only the bones moved by the bone mapping will be recorded.
816
- */
817
- startRecording: k.start,
818
- stopRecording: k.stop,
819
- isRecording: () => k.isRecording(),
820
- update: (L) => {
821
- w.update(L), h.update(L), y.update(L), b == null || b.update(L), E == null || E.update(L), k.isRecording() && k.captureFrame();
822
- }
823
- };
824
- }
825
- };
826
- }
827
- export {
828
- ht as setupTracker
829
- };
830
- //# sourceMappingURL=three-mediapipe-rig.js.map