three-mediapipe-rig 0.0.3 → 0.0.4
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.
- package/README.md +14 -23
- package/dist/three-mediapipe-rig.js +177 -165
- package/dist/three-mediapipe-rig.js.map +1 -1
- package/dist/tracking/HandTracker.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
|
|
2
2
|

|
|
3
3
|
|
|
4
|
-
#
|
|
4
|
+
# Control a skeleton with the webcam
|
|
5
5
|
|
|
6
|
-
Integrate [Google MediaPipe](https://ai.google.dev/edge/mediapipe/solutions/guide)'s **webcam motion tracking** with [Three.js](https://threejs.org/) skeletal rigs.
|
|
6
|
+
Integrate [Google MediaPipe](https://ai.google.dev/edge/mediapipe/solutions/guide)'s **webcam motion tracking** with [Three.js](https://threejs.org/) skeletal rigs.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
The motion from the webcam will be applied to a skeleton. Angle based so it works with any size skeleton.
|
|
9
9
|
|
|
10
10
|
This will run 3 models: face, body, hands. So expect a FPS drop.
|
|
11
11
|
|
|
@@ -52,41 +52,32 @@ npm install three-mediapipe-rig
|
|
|
52
52
|
|
|
53
53
|
## Quick Start
|
|
54
54
|
|
|
55
|
-
```ts
|
|
56
|
-
// 1. Create your renderer
|
|
57
|
-
const renderer = new THREE.WebGPURenderer({ antialias: true });
|
|
58
|
-
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
59
|
-
document.body.appendChild(renderer.domElement);
|
|
55
|
+
```ts
|
|
60
56
|
|
|
61
|
-
//
|
|
57
|
+
// 1. Initialize the tracker (loads MediaPipe models)
|
|
62
58
|
await setupTracker({ ...config... })
|
|
63
59
|
|
|
64
60
|
const rig = scene.getObjectByName("rig")!;
|
|
65
61
|
|
|
66
|
-
//
|
|
62
|
+
// 2. Bind the rig to the tracker
|
|
67
63
|
const binding = tracker.bind(rig);
|
|
68
64
|
|
|
69
65
|
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const clock = new THREE.Timer();
|
|
75
|
-
renderer.setAnimationLoop((time: number) => {
|
|
76
|
-
const delta = clock.update(time).getDelta();
|
|
66
|
+
// 3. Start the webcam ( must be initialized by a user triggered event like a click )
|
|
67
|
+
button.addEventListener('click', () => {
|
|
68
|
+
tracker.start(); //<-- will ask webcam access!
|
|
69
|
+
})
|
|
77
70
|
|
|
78
|
-
// 6. update the skeleton...
|
|
79
|
-
binding?.update(delta);
|
|
80
71
|
|
|
81
|
-
|
|
82
|
-
|
|
72
|
+
// 4. Update the rig in your render loop ( this keels the skeleton in-sync)
|
|
73
|
+
binding?.update(delta);
|
|
83
74
|
```
|
|
84
75
|
|
|
85
76
|
### Skeleton
|
|
86
|
-
You can use the skeleton provided in `rig.blend` or use your own and provide a bone name mapping so we know where the bones are in the second argument for the `.bind` method. But pay attention to the bone
|
|
77
|
+
You can use the skeleton provided in `rig.blend` or use your own and provide a bone name mapping so we know where the bones are in the second argument for the `.bind` method. But pay attention to the [**bone roll**](https://docs.blender.org/manual/en/latest/animation/armatures/bones/editing/bone_roll.html) of the provided skeleton, as it is the one expected by this module.
|
|
87
78
|
|
|
88
79
|
### Facial Animation
|
|
89
|
-
Media Pipe provides blend shape keys for the face ( estimated from the webcam ). The face it is expected to be a separated mesh
|
|
80
|
+
Media Pipe provides blend shape keys for the face ( estimated from the webcam ). The face it is expected to be a separated mesh with a name that starts with "face", with blend shape keys named as the ones provided by Media Pipe. See [Blend Shape Keys reference](/face-blendshapekeys.md) You don't have to have all of them, if they are not found, they will be ignored.
|
|
90
81
|
|
|
91
82
|
|
|
92
83
|
## API
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var k = (
|
|
4
|
-
import { PoseLandmarker as
|
|
5
|
-
import * as
|
|
6
|
-
import { Vector3 as P, Quaternion as
|
|
1
|
+
var he = Object.defineProperty;
|
|
2
|
+
var ce = (h, s, e) => s in h ? he(h, s, { enumerable: !0, configurable: !0, writable: !0, value: e }) : h[s] = e;
|
|
3
|
+
var k = (h, s, e) => ce(h, typeof s != "symbol" ? s + "" : s, e);
|
|
4
|
+
import { PoseLandmarker as se, HandLandmarker as D, FaceLandmarker as C, FilesetResolver as le, DrawingUtils as pe } from "@mediapipe/tasks-vision";
|
|
5
|
+
import * as l from "three/webgpu";
|
|
6
|
+
import { Vector3 as P, Quaternion as ie } from "three/webgpu";
|
|
7
7
|
import * as S from "three";
|
|
8
|
-
import { Bone as
|
|
9
|
-
import { GLTFExporter as
|
|
10
|
-
const V = new P(), z = new P(),
|
|
8
|
+
import { Bone as me } from "three";
|
|
9
|
+
import { GLTFExporter as ue } from "three/examples/jsm/Addons.js";
|
|
10
|
+
const V = new P(), z = new P(), fe = new P(1, 0, 0), ye = new P(-1, 0, 0), we = new P(0, 1, 0), Le = new P(0, -1, 0), B = new P(0, 0, 1);
|
|
11
11
|
new P(0, 0, -1);
|
|
12
|
-
const I = new P(),
|
|
13
|
-
function A(
|
|
14
|
-
|
|
15
|
-
const o = t == "+x" ?
|
|
16
|
-
|
|
17
|
-
const i = I, r =
|
|
18
|
-
U.setFromAxisAngle(B, c),
|
|
12
|
+
const I = new P(), ke = new P(), be = new P(), U = new ie(), O = new ie();
|
|
13
|
+
function A(h, s, e, t = "+x") {
|
|
14
|
+
h.lookAt(s);
|
|
15
|
+
const o = t == "+x" ? fe : t == "-x" ? ye : t == "+y" ? we : Le;
|
|
16
|
+
h.getWorldPosition(z), h.getWorldQuaternion(O), V.subVectors(e, z).normalize(), I.copy(o).applyQuaternion(O);
|
|
17
|
+
const i = I, r = ke.copy(B).applyQuaternion(O), n = V.clone().addScaledVector(r, -V.dot(r)).normalize(), a = be.crossVectors(i, n), c = Math.atan2(a.dot(r), i.dot(n));
|
|
18
|
+
U.setFromAxisAngle(B, c), h.quaternion.multiply(U);
|
|
19
19
|
}
|
|
20
|
-
const N = new
|
|
21
|
-
new
|
|
20
|
+
const N = new l.Vector3(), M = new l.Vector3(), T = new l.Vector3();
|
|
21
|
+
new l.Vector3();
|
|
22
22
|
class _ {
|
|
23
23
|
constructor(s, e) {
|
|
24
24
|
k(this, "objectGhost");
|
|
@@ -27,9 +27,9 @@ class _ {
|
|
|
27
27
|
* per landmark index, it points to it's object3D equivalent.
|
|
28
28
|
*/
|
|
29
29
|
k(this, "marks", {});
|
|
30
|
-
this.points = s, this.debugConnections = e, this.root = new
|
|
30
|
+
this.points = s, this.debugConnections = e, this.root = new l.Object3D(), this.objectGhost = /* @__PURE__ */ new Map();
|
|
31
31
|
for (let t in this.points)
|
|
32
|
-
this.marks[t] = new
|
|
32
|
+
this.marks[t] = new xe(), this.root.add(this.marks[t]);
|
|
33
33
|
}
|
|
34
34
|
updateLandmarks(s, e, t) {
|
|
35
35
|
for (let o in this.points) {
|
|
@@ -50,7 +50,7 @@ class _ {
|
|
|
50
50
|
getGhost(s) {
|
|
51
51
|
var e;
|
|
52
52
|
if (!this.objectGhost.has(s)) {
|
|
53
|
-
const t = new
|
|
53
|
+
const t = new Re();
|
|
54
54
|
t.position.copy(s.position), t.quaternion.copy(s.quaternion), (e = s.parent) == null || e.add(t), this.objectGhost.set(s, t);
|
|
55
55
|
}
|
|
56
56
|
return this.objectGhost.get(s);
|
|
@@ -69,43 +69,43 @@ class _ {
|
|
|
69
69
|
this.marks[r].getWorldPosition(T), this.marks[i].getWorldPosition(M);
|
|
70
70
|
const a = T.sub(M);
|
|
71
71
|
o.getWorldPosition(M), M.add(a);
|
|
72
|
-
const c = M,
|
|
73
|
-
A(f, c,
|
|
72
|
+
const c = M, p = o.getWorldPosition(T).sub(t), f = this.getGhost(o);
|
|
73
|
+
A(f, c, p, n), f.rotateX(Math.PI / 2), o.position.lerp(f.position, e * 4), o.quaternion.slerp(f.quaternion, e * 4);
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
getBone(s, e) {
|
|
77
77
|
return s.getObjectByName(e.replace(/[\.\:]/g, ""));
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
class
|
|
80
|
+
class xe extends l.Mesh {
|
|
81
81
|
constructor() {
|
|
82
|
-
super(new
|
|
83
|
-
k(this, "_worldPosition", new
|
|
84
|
-
this.add(new
|
|
82
|
+
super(new l.SphereGeometry(0.01, 3, 3), new l.MeshStandardMaterial({ color: 16711680, wireframe: !0 }));
|
|
83
|
+
k(this, "_worldPosition", new l.Vector3());
|
|
84
|
+
this.add(new l.AxesHelper(1e-3));
|
|
85
85
|
}
|
|
86
86
|
get worldPosition() {
|
|
87
87
|
return this.getWorldPosition(this._worldPosition), this._worldPosition;
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
-
class
|
|
90
|
+
class Re extends l.Object3D {
|
|
91
91
|
lerp(s, e, t = 8) {
|
|
92
92
|
s.position.lerp(this.position, e * t), s.quaternion.slerp(this.quaternion, e * t);
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
|
-
function F(
|
|
96
|
-
return e.worldToLocal(s.getWorldPosition(
|
|
95
|
+
function F(h, s, e) {
|
|
96
|
+
return e.worldToLocal(s.getWorldPosition(h)), h;
|
|
97
97
|
}
|
|
98
|
-
function
|
|
99
|
-
return
|
|
98
|
+
function Pe(h) {
|
|
99
|
+
return h.replace(/[\.\:]/g, "");
|
|
100
100
|
}
|
|
101
|
-
function x(
|
|
101
|
+
function x(h, s) {
|
|
102
102
|
let e;
|
|
103
|
-
return s =
|
|
104
|
-
t.name.indexOf(s) === 0 && t instanceof
|
|
105
|
-
}), e || console.log("Bone not found: ", s,
|
|
103
|
+
return s = Pe(s), h.traverse((t) => {
|
|
104
|
+
t.name.indexOf(s) === 0 && t instanceof me && (e = t);
|
|
105
|
+
}), e || console.log("Bone not found: ", s, h.name), e;
|
|
106
106
|
}
|
|
107
|
-
async function
|
|
108
|
-
const e = await
|
|
107
|
+
async function We(h, s) {
|
|
108
|
+
const e = await se.createFromOptions(h, {
|
|
109
109
|
baseOptions: {
|
|
110
110
|
modelAssetPath: (s == null ? void 0 : s.modelPath) ?? "pose_landmarker_lite.task",
|
|
111
111
|
//modelAssetPath: `https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task`,
|
|
@@ -115,9 +115,9 @@ async function Pe(d, s) {
|
|
|
115
115
|
runningMode: "VIDEO",
|
|
116
116
|
numPoses: 1
|
|
117
117
|
});
|
|
118
|
-
return new
|
|
118
|
+
return new ge(e, s);
|
|
119
119
|
}
|
|
120
|
-
const
|
|
120
|
+
const Ee = {
|
|
121
121
|
hips: [24, 23],
|
|
122
122
|
neck: [12, 11],
|
|
123
123
|
leftLeg: 23,
|
|
@@ -139,10 +139,10 @@ const We = {
|
|
|
139
139
|
torso: [24, 23, 12, 11],
|
|
140
140
|
leftEar: 7,
|
|
141
141
|
rightEar: 8
|
|
142
|
-
},
|
|
143
|
-
class
|
|
142
|
+
}, Fe = new l.Vector3(), G = new l.Vector3(), Ae = new l.Vector3(), Me = new l.Vector3(), ve = new l.Vector3(), H = new l.Vector3(), $ = new l.Vector3();
|
|
143
|
+
class ge extends _ {
|
|
144
144
|
constructor(e, t) {
|
|
145
|
-
super(
|
|
145
|
+
super(Ee, se.POSE_CONNECTIONS);
|
|
146
146
|
k(this, "_leftWristNormalizedPosition");
|
|
147
147
|
k(this, "_rightWristNormalizedPosition");
|
|
148
148
|
this.poseLandmarker = e, this.config = t, this.root.scale.y *= -2, this.root.scale.z *= -2, this.root.scale.x *= 2;
|
|
@@ -192,24 +192,24 @@ class ve extends _ {
|
|
|
192
192
|
rightFoot: x(e, t.footR)
|
|
193
193
|
};
|
|
194
194
|
(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);
|
|
195
|
-
const i = new
|
|
196
|
-
if (!
|
|
197
|
-
const
|
|
198
|
-
F(H,
|
|
199
|
-
const u = this.getGhost(
|
|
200
|
-
A(u, H, $, m), u.rotateX(Math.PI / 2), u.lerp(
|
|
195
|
+
const i = new l.Vector3(), r = new l.Vector3(), n = (c, p, f, R, d, m) => {
|
|
196
|
+
if (!p) return;
|
|
197
|
+
const L = this.marks[R].getWorldPosition(i).sub(this.marks[f].getWorldPosition(r)).normalize();
|
|
198
|
+
F(H, p, e).add(L).applyMatrix4(e.matrixWorld), F($, p, e).add(d).applyMatrix4(e.matrixWorld);
|
|
199
|
+
const u = this.getGhost(p);
|
|
200
|
+
A(u, H, $, m), u.rotateX(Math.PI / 2), u.lerp(p, c);
|
|
201
201
|
};
|
|
202
202
|
return {
|
|
203
203
|
update: (c) => {
|
|
204
|
-
const
|
|
205
|
-
n(c, o.hips, "hips", "torso",
|
|
204
|
+
const p = this.marks.leftLeg.getWorldPosition(Fe).sub(this.marks.rightLeg.getWorldPosition(G)).normalize(), f = this.marks.leftArm.getWorldPosition(G).sub(this.marks.rightArm.getWorldPosition(Ae)).normalize(), R = this.marks.leftEar.getWorldPosition(Me).sub(this.marks.rightEar.getWorldPosition(ve)).normalize();
|
|
205
|
+
n(c, o.hips, "hips", "torso", p, "+x"), n(c, o.torso, "torso", "neck", f, "+x"), n(c, o.neck, "neck", "head", R, "+x"), n(c, o.head, "neck", "head", R, "+x"), n(c, o.leftArm, "leftArm", "leftElbow", f, "-x"), n(c, o.leftElbow, "leftElbow", "leftWrist", f, "-x"), n(c, o.leftLeg, "leftLeg", "leftKnee", p, "+x"), n(c, o.leftKnee, "leftKnee", "leftFoot", p, "+x"), n(c, o.leftFoot, "leftFoot", "leftToes", p, "+x"), n(c, o.rightArm, "rightArm", "rightElbow", f, "-x"), n(c, o.rightElbow, "rightElbow", "rightWrist", f, "-x"), n(c, o.rightLeg, "rightLeg", "rightKnee", p, "+x"), n(c, o.rightKnee, "rightKnee", "rightFoot", p, "+x"), n(c, o.rightFoot, "rightFoot", "rightToes", p, "+x");
|
|
206
206
|
}
|
|
207
207
|
};
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
|
-
const j = new
|
|
211
|
-
async function
|
|
212
|
-
const e = await D.createFromOptions(
|
|
210
|
+
const j = new l.Vector2(), q = new l.Vector2();
|
|
211
|
+
async function Se(h, s) {
|
|
212
|
+
const e = await D.createFromOptions(h, {
|
|
213
213
|
baseOptions: {
|
|
214
214
|
modelAssetPath: s.modelPath ?? "hand_landmarker.task",
|
|
215
215
|
//modelAssetPath: `https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task`,
|
|
@@ -217,13 +217,20 @@ async function ge(d, s) {
|
|
|
217
217
|
},
|
|
218
218
|
runningMode: "VIDEO",
|
|
219
219
|
numHands: 2
|
|
220
|
-
}), t = (o, i, r) =>
|
|
220
|
+
}), t = (o, i, r) => {
|
|
221
|
+
try {
|
|
222
|
+
j.copy(o()), q.copy(i());
|
|
223
|
+
} catch (n) {
|
|
224
|
+
return console.warn("No pose data... will just be optimitic and say yes to everything.", n), !0;
|
|
225
|
+
}
|
|
226
|
+
return j.distanceTo(r) < q.distanceTo(r);
|
|
227
|
+
};
|
|
221
228
|
return {
|
|
222
|
-
left: new
|
|
223
|
-
right: new
|
|
229
|
+
left: new te(e, "Left", t.bind(null, s.leftWrist, s.rightWrist)),
|
|
230
|
+
right: new te(e, "Right", t.bind(null, s.rightWrist, s.leftWrist))
|
|
224
231
|
};
|
|
225
232
|
}
|
|
226
|
-
const
|
|
233
|
+
const Ne = {
|
|
227
234
|
wrist: 0,
|
|
228
235
|
palm: [9, 13],
|
|
229
236
|
thumb1: 1,
|
|
@@ -252,20 +259,21 @@ const Se = {
|
|
|
252
259
|
middle: ["middle1", "middle2", "middle3", "middle4"],
|
|
253
260
|
ring: ["ring1", "ring2", "ring3", "ring4"],
|
|
254
261
|
pinky: ["pinky1", "pinky2", "pinky3", "pinky4"]
|
|
255
|
-
},
|
|
256
|
-
new
|
|
257
|
-
new
|
|
258
|
-
|
|
259
|
-
|
|
262
|
+
}, Ve = new l.Vector3(), K = new l.Vector3(), X = new l.Vector3(), Q = new l.Vector3(), Y = new l.Vector3(), Z = new l.Vector3();
|
|
263
|
+
new l.Vector3();
|
|
264
|
+
new l.Vector3();
|
|
265
|
+
new l.Vector3();
|
|
266
|
+
const J = new l.Vector3(), ee = Math.PI / 2, Oe = new l.Vector3(0, -1, 0);
|
|
267
|
+
class te extends _ {
|
|
260
268
|
constructor(e, t, o) {
|
|
261
|
-
super(
|
|
269
|
+
super(Ne, D.HAND_CONNECTIONS);
|
|
262
270
|
k(this, "sign");
|
|
263
271
|
k(this, "isLeft");
|
|
264
272
|
/**
|
|
265
273
|
* the axis used to look at the pole
|
|
266
274
|
*/
|
|
267
275
|
k(this, "lookAtPoleAxis");
|
|
268
|
-
this.handLandmarker = e, this.side = t, this.isMyWrist = o, this.sign = this.side == "Left" ? -1 : 1, this.isLeft = this.side == "Left", this.lookAtPoleAxis = this.sign < 0 ? "+x" : "-x", this.root.scale.setScalar(
|
|
276
|
+
this.handLandmarker = e, this.side = t, this.isMyWrist = o, 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;
|
|
269
277
|
}
|
|
270
278
|
predict(e, t) {
|
|
271
279
|
const o = this.handLandmarker.detectForVideo(e, performance.now());
|
|
@@ -291,42 +299,46 @@ class ee extends _ {
|
|
|
291
299
|
* @see https://ai.google.dev/edge/mediapipe/solutions/vision/hand_landmarker
|
|
292
300
|
*/
|
|
293
301
|
syncHandBones(e, t, o) {
|
|
294
|
-
const i =
|
|
302
|
+
const i = Ve.crossVectors(
|
|
295
303
|
K.copy(this.marks.index1.worldPosition).sub(this.marks.wrist.worldPosition),
|
|
296
304
|
X.copy(this.marks.pinky1.worldPosition).sub(this.marks.wrist.worldPosition)
|
|
297
305
|
).normalize(), r = K.copy(this.marks.palm.worldPosition).sub(this.marks.wrist.worldPosition).normalize(), n = X.copy(this.marks.pinky1.worldPosition).sub(this.marks.index1.worldPosition).normalize();
|
|
298
306
|
if (!(r.dot(Oe) > 0.8)) {
|
|
299
307
|
if (t.wrist) {
|
|
300
|
-
const a = F(Q, t.wrist, o).add(r).applyMatrix4(o.matrixWorld), c = F(Y, t.wrist, o).sub(n).applyMatrix4(o.matrixWorld),
|
|
301
|
-
A(
|
|
308
|
+
const a = F(Q, t.wrist, o).add(r).applyMatrix4(o.matrixWorld), c = F(Y, t.wrist, o).sub(n).applyMatrix4(o.matrixWorld), p = this.getGhost(t.wrist);
|
|
309
|
+
A(p, a, c, "-y"), p.rotateX(ee), p.lerp(t.wrist, e);
|
|
302
310
|
}
|
|
303
|
-
this.syncFinger(e, o, i, r, n, t, v.index, "middle1"), this.syncFinger(e, o, i, r, n, t, v.middle, "ring1"), this.syncFinger(e, o, i, r, n, t, v.ring, "pinky1"), this.syncFinger(e, o, i, r, n, t, v.pinky, "ring1"), this.syncFinger(e, o, i, r, n, t, v.thumb, "index1");
|
|
311
|
+
this.syncFinger(e, o, i, r, n, t, v.index, "middle1"), this.syncFinger(e, o, i, r, n, t, v.middle, "ring1"), this.syncFinger(e, o, i, r, n, t, v.ring, "pinky1"), this.syncFinger(e, o, i, r, n, t, v.pinky, "ring1", !0), this.syncFinger(e, o, i, r, n, t, v.thumb, "index1");
|
|
304
312
|
}
|
|
305
313
|
}
|
|
306
|
-
syncFinger(e, t, o, i, r, n, a, c,
|
|
314
|
+
syncFinger(e, t, o, i, r, n, a, c, p = !1) {
|
|
307
315
|
for (let f = 0; f < a.length - 1; f++) {
|
|
308
316
|
const R = n[a[f]];
|
|
309
317
|
if (!R) continue;
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
318
|
+
const d = this.getGhost(R), m = Q.copy(this.marks[a[f + 1]].worldPosition).sub(this.marks[a[f]].worldPosition).normalize(), L = F(Y, R, t);
|
|
319
|
+
if (f == 0) {
|
|
320
|
+
const u = Z.copy(this.marks[c].worldPosition).sub(this.marks[a[0]].worldPosition).normalize();
|
|
321
|
+
p && u.negate(), J.copy(u), A(
|
|
322
|
+
d,
|
|
323
|
+
m.add(L).applyMatrix4(t.matrixWorld),
|
|
324
|
+
u.add(L).applyMatrix4(t.matrixWorld),
|
|
325
|
+
this.lookAtPoleAxis
|
|
326
|
+
);
|
|
327
|
+
} else
|
|
328
|
+
A(
|
|
329
|
+
d,
|
|
330
|
+
m.add(L).applyMatrix4(t.matrixWorld),
|
|
331
|
+
Z.copy(J).add(L).applyMatrix4(t.matrixWorld),
|
|
332
|
+
this.lookAtPoleAxis
|
|
333
|
+
);
|
|
334
|
+
d.rotateX(ee), d.lerp(R, e);
|
|
324
335
|
}
|
|
325
336
|
}
|
|
326
337
|
bind(e, t) {
|
|
327
338
|
const o = {}, i = (r, n) => {
|
|
328
339
|
const a = x(e, r);
|
|
329
|
-
|
|
340
|
+
if (a)
|
|
341
|
+
return o[n] = a, n;
|
|
330
342
|
};
|
|
331
343
|
return i(this.isLeft ? t.handL : t.handR, "wrist"), i(this.isLeft ? t.index1L : t.index1R, "index1"), i(this.isLeft ? t.index2L : t.index2R, "index2"), i(this.isLeft ? t.index3L : t.index3R, "index3"), i(this.isLeft ? t.middle1L : t.middle1R, "middle1"), i(this.isLeft ? t.middle2L : t.middle2R, "middle2"), i(this.isLeft ? t.middle3L : t.middle3R, "middle3"), i(this.isLeft ? t.ring1L : t.ring1R, "ring1"), i(this.isLeft ? t.ring2L : t.ring2R, "ring2"), i(this.isLeft ? t.ring3L : t.ring3R, "ring3"), i(this.isLeft ? t.pinky1L : t.pinky1R, "pinky1"), i(this.isLeft ? t.pinky2L : t.pinky2R, "pinky2"), i(this.isLeft ? t.pinky3L : t.pinky3R, "pinky3"), i(this.isLeft ? t.thumb1L : t.thumb1R, "thumb1"), i(this.isLeft ? t.thumb2L : t.thumb2R, "thumb2"), i(this.isLeft ? t.thumb3L : t.thumb3R, "thumb3"), {
|
|
332
344
|
update: (r) => {
|
|
@@ -335,8 +347,8 @@ class ee extends _ {
|
|
|
335
347
|
};
|
|
336
348
|
}
|
|
337
349
|
}
|
|
338
|
-
async function Te(
|
|
339
|
-
const e = await C.createFromOptions(
|
|
350
|
+
async function Te(h, s) {
|
|
351
|
+
const e = await C.createFromOptions(h, {
|
|
340
352
|
baseOptions: {
|
|
341
353
|
modelAssetPath: (s == null ? void 0 : s.modelPath) ?? "face_landmarker.task",
|
|
342
354
|
delegate: "GPU"
|
|
@@ -360,7 +372,7 @@ const De = {
|
|
|
360
372
|
noseBone: 6,
|
|
361
373
|
chin: 152,
|
|
362
374
|
forehead: 10
|
|
363
|
-
}, Ce = new P(), _e = new P(),
|
|
375
|
+
}, Ce = new P(), _e = new P(), ne = new P(), ze = new P(), Be = new P();
|
|
364
376
|
new P();
|
|
365
377
|
class Ie extends _ {
|
|
366
378
|
// lower = smoother but more lag, higher = more responsive
|
|
@@ -395,17 +407,17 @@ class Ie extends _ {
|
|
|
395
407
|
};
|
|
396
408
|
}
|
|
397
409
|
bind(e) {
|
|
398
|
-
const t = new
|
|
410
|
+
const t = new oe(e, "L"), o = new oe(e, "R"), i = x(e, "head");
|
|
399
411
|
return {
|
|
400
412
|
update: (r) => {
|
|
401
413
|
if (t.update(r, this.blendshapeMap), o.update(r, this.blendshapeMap), !i) return;
|
|
402
|
-
const n = Ce.copy(this.marks.earL.worldPosition), a = _e.copy(this.marks.earR.worldPosition), c =
|
|
403
|
-
A(i, m,
|
|
414
|
+
const n = Ce.copy(this.marks.earL.worldPosition), a = _e.copy(this.marks.earR.worldPosition), c = ne.subVectors(n, a).multiplyScalar(0.5).add(a), p = ze.subVectors(this.marks.noseTip.worldPosition, c), f = n.sub(a), R = F(Be, i, e), d = f.add(R).applyMatrix4(e.matrixWorld), m = p.add(R).applyMatrix4(e.matrixWorld);
|
|
415
|
+
A(i, m, d, "+x");
|
|
404
416
|
}
|
|
405
417
|
};
|
|
406
418
|
}
|
|
407
419
|
}
|
|
408
|
-
class
|
|
420
|
+
class oe {
|
|
409
421
|
constructor(s, e) {
|
|
410
422
|
k(this, "eyeBone");
|
|
411
423
|
k(this, "eyeLookOut");
|
|
@@ -419,12 +431,12 @@ class te {
|
|
|
419
431
|
}
|
|
420
432
|
update(s, e) {
|
|
421
433
|
if (!this.eyeBone) return;
|
|
422
|
-
F(
|
|
434
|
+
F(ne, this.eyeBone, this.rig);
|
|
423
435
|
const t = e.get(this.eyeLookOut) ?? 0, o = e.get(this.eyeLookIn) ?? 0, i = e.get(this.eyeLookUp) ?? 0, r = e.get(this.eyeLookDown) ?? 0, n = o - t, a = r - i;
|
|
424
436
|
this.eyeBone.rotation.y = n * this.sign / 2, this.eyeBone.rotation.x = a / 2;
|
|
425
437
|
}
|
|
426
438
|
}
|
|
427
|
-
const
|
|
439
|
+
const re = {
|
|
428
440
|
faceMesh: "face",
|
|
429
441
|
head: "head",
|
|
430
442
|
hips: "hips",
|
|
@@ -526,33 +538,33 @@ const ne = {
|
|
|
526
538
|
"mouthUpperUpRight",
|
|
527
539
|
"tongueOut"
|
|
528
540
|
];
|
|
529
|
-
function Ge(
|
|
530
|
-
const t = [], o =
|
|
541
|
+
function Ge(h, s, e = 30) {
|
|
542
|
+
const t = [], o = h.getObjectByName(
|
|
531
543
|
s.faceMesh
|
|
532
544
|
), i = /* @__PURE__ */ new Set();
|
|
533
545
|
if (o != null && o.morphTargetDictionary)
|
|
534
|
-
for (const
|
|
535
|
-
Ue.includes(
|
|
546
|
+
for (const L in o.morphTargetDictionary)
|
|
547
|
+
Ue.includes(L) && i.add(L);
|
|
536
548
|
const r = Object.keys(s);
|
|
537
|
-
|
|
538
|
-
if (
|
|
539
|
-
const u = r.find((W) =>
|
|
549
|
+
h.traverse((L) => {
|
|
550
|
+
if (L instanceof S.Bone) {
|
|
551
|
+
const u = r.find((W) => L.name.indexOf(s[W]) === 0);
|
|
540
552
|
u && t.push({
|
|
541
|
-
ref:
|
|
542
|
-
name:
|
|
553
|
+
ref: L,
|
|
554
|
+
name: L.name,
|
|
543
555
|
normalizedName: u
|
|
544
556
|
});
|
|
545
557
|
}
|
|
546
558
|
});
|
|
547
559
|
const n = [], a = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map();
|
|
548
|
-
let
|
|
560
|
+
let p = !1, f = 0;
|
|
549
561
|
function R() {
|
|
550
|
-
a.clear(), c.clear(), n.length = 0, f = performance.now() / 1e3,
|
|
562
|
+
a.clear(), c.clear(), n.length = 0, f = performance.now() / 1e3, p = !0;
|
|
551
563
|
}
|
|
552
|
-
function
|
|
553
|
-
if (!
|
|
554
|
-
const
|
|
555
|
-
n.push(
|
|
564
|
+
function d() {
|
|
565
|
+
if (!p) return;
|
|
566
|
+
const L = performance.now() / 1e3 - f;
|
|
567
|
+
n.push(L);
|
|
556
568
|
for (const u of t) {
|
|
557
569
|
a.has(u.name) || a.set(u.name, []);
|
|
558
570
|
const W = a.get(u.name), b = u.ref.quaternion;
|
|
@@ -564,8 +576,8 @@ function Ge(d, s, e = 30) {
|
|
|
564
576
|
W.push(E);
|
|
565
577
|
}
|
|
566
578
|
}
|
|
567
|
-
function m(
|
|
568
|
-
|
|
579
|
+
function m(L = "RecordedClip") {
|
|
580
|
+
p = !1;
|
|
569
581
|
const u = [];
|
|
570
582
|
for (const [b, E] of a)
|
|
571
583
|
u.push(
|
|
@@ -578,22 +590,22 @@ function Ge(d, s, e = 30) {
|
|
|
578
590
|
for (const [b, E] of c)
|
|
579
591
|
u.push(
|
|
580
592
|
new S.NumberKeyframeTrack(
|
|
581
|
-
`${
|
|
593
|
+
`${re.faceMesh}.morphTargetInfluences[${b}]`,
|
|
582
594
|
n,
|
|
583
595
|
E
|
|
584
596
|
)
|
|
585
597
|
);
|
|
586
|
-
const W = new S.AnimationClip(
|
|
598
|
+
const W = new S.AnimationClip(L, -1, u);
|
|
587
599
|
return {
|
|
588
600
|
clip: W,
|
|
589
601
|
saveToFile: () => {
|
|
590
|
-
new
|
|
591
|
-
|
|
602
|
+
new ue().parse(
|
|
603
|
+
h,
|
|
592
604
|
(E) => {
|
|
593
|
-
const
|
|
605
|
+
const w = new Blob([E], {
|
|
594
606
|
type: "model/gltf-binary"
|
|
595
|
-
}), y = URL.createObjectURL(
|
|
596
|
-
g.href = y, g.download =
|
|
607
|
+
}), y = URL.createObjectURL(w), g = document.createElement("a");
|
|
608
|
+
g.href = y, g.download = L + ".glb", g.click();
|
|
597
609
|
},
|
|
598
610
|
(E) => {
|
|
599
611
|
console.error(E);
|
|
@@ -606,13 +618,13 @@ function Ge(d, s, e = 30) {
|
|
|
606
618
|
}
|
|
607
619
|
};
|
|
608
620
|
}
|
|
609
|
-
return { start: R, captureFrame:
|
|
621
|
+
return { start: R, captureFrame: d, stop: m, isRecording: () => p };
|
|
610
622
|
}
|
|
611
623
|
const He = () => {
|
|
612
|
-
var
|
|
613
|
-
return !!((
|
|
624
|
+
var h;
|
|
625
|
+
return !!((h = navigator.mediaDevices) != null && h.getUserMedia);
|
|
614
626
|
};
|
|
615
|
-
async function Qe(
|
|
627
|
+
async function Qe(h) {
|
|
616
628
|
const s = {
|
|
617
629
|
debugFrame: void 0,
|
|
618
630
|
displayScale: 1,
|
|
@@ -625,41 +637,41 @@ async function Qe(d) {
|
|
|
625
637
|
hand: "https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task",
|
|
626
638
|
face: "https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task"
|
|
627
639
|
},
|
|
628
|
-
...
|
|
640
|
+
...h
|
|
629
641
|
};
|
|
630
642
|
let e;
|
|
631
|
-
const t = await
|
|
643
|
+
const t = await le.forVisionTasks(s.modelPaths.vision ?? "/wasm"), o = await We(t, {
|
|
632
644
|
ignoreLegs: s.ignoreLegs,
|
|
633
645
|
modelPath: s.modelPaths.pose
|
|
634
|
-
}), i = await
|
|
646
|
+
}), i = await Se(t, {
|
|
635
647
|
leftWrist: () => o.leftWristNormalizedPosition,
|
|
636
648
|
rightWrist: () => o.rightWristNormalizedPosition,
|
|
637
649
|
modelPath: s.modelPaths.hand,
|
|
638
|
-
...
|
|
650
|
+
...h == null ? void 0 : h.handsTrackerOptions
|
|
639
651
|
}), r = s.ignoreFace ? void 0 : await Te(t, { modelPath: s.modelPaths.face }), n = document.createElement("div");
|
|
640
652
|
n.style.position = "absolute", n.style.top = "0px", n.style.left = "0px", n.style.zIndex = "21", n.classList.add("three-mediapipe-rig"), document.body.appendChild(n);
|
|
641
|
-
const a = document.createElement("canvas"), c = a.getContext("2d"),
|
|
653
|
+
const a = document.createElement("canvas"), c = a.getContext("2d"), p = new pe(c);
|
|
642
654
|
a.style.zIndex = "22", a.style.position = "absolute", a.style.top = "0px", a.style.left = "0px", a.style.pointerEvents = "none", n.appendChild(a);
|
|
643
|
-
function f(
|
|
644
|
-
c.save(), c.clearRect(0, 0, a.width, a.height), o == null || o.predict(
|
|
655
|
+
function f(d) {
|
|
656
|
+
c.save(), c.clearRect(0, 0, a.width, a.height), o == null || o.predict(d, p), i == null || i.left.predict(d, p), i == null || i.right.predict(d, p), r == null || r.predict(d, p), c.restore();
|
|
645
657
|
}
|
|
646
658
|
function R() {
|
|
647
659
|
e = document.createElement("video"), n.appendChild(e);
|
|
648
|
-
let
|
|
660
|
+
let d = -1;
|
|
649
661
|
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());
|
|
650
662
|
function m() {
|
|
651
|
-
|
|
663
|
+
d !== e.currentTime && (f(e), d = e.currentTime), window.requestAnimationFrame(m);
|
|
652
664
|
}
|
|
653
665
|
e.addEventListener("loadeddata", () => {
|
|
654
666
|
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(m);
|
|
655
667
|
});
|
|
656
668
|
}
|
|
657
669
|
if (s.debugFrame) {
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
|
|
670
|
+
const d = document.createElement("img");
|
|
671
|
+
d.src = s.debugFrame, d.style.zIndex = "21", d.style.position = "absolute", d.style.top = "0px", d.style.left = "0px", n.appendChild(d), d.addEventListener("load", () => {
|
|
672
|
+
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";
|
|
661
673
|
function m() {
|
|
662
|
-
f(
|
|
674
|
+
f(d);
|
|
663
675
|
}
|
|
664
676
|
window.requestAnimationFrame(m);
|
|
665
677
|
});
|
|
@@ -677,40 +689,40 @@ async function Qe(d) {
|
|
|
677
689
|
* Start the webcam feed. This must be initiated by a user triggered event ( a click on a button ) due to security reasons.
|
|
678
690
|
*/
|
|
679
691
|
start: async () => {
|
|
680
|
-
let
|
|
692
|
+
let d = !1;
|
|
681
693
|
if (!He())
|
|
682
694
|
throw new Error("Webcam not supported");
|
|
683
695
|
e || R();
|
|
684
696
|
let m;
|
|
685
|
-
function w
|
|
686
|
-
console.warn("Camera track ended, attempting recovery..."), u(
|
|
697
|
+
function L(w) {
|
|
698
|
+
console.warn("Camera track ended, attempting recovery..."), u(w), W(w);
|
|
687
699
|
}
|
|
688
|
-
function u(
|
|
689
|
-
m == null || m.getTracks().forEach((y) => y.stop()), m = void 0,
|
|
700
|
+
function u(w) {
|
|
701
|
+
m == null || m.getTracks().forEach((y) => y.stop()), m = void 0, w.srcObject = null;
|
|
690
702
|
}
|
|
691
|
-
async function W(
|
|
692
|
-
const
|
|
703
|
+
async function W(w, y = 0) {
|
|
704
|
+
const ae = Math.min(1e3 * 2 ** y, 16e3);
|
|
693
705
|
if (y >= 5)
|
|
694
706
|
throw new Error("Camera recovery failed after max attempts");
|
|
695
|
-
if (await new Promise((
|
|
707
|
+
if (await new Promise((de) => setTimeout(de, ae)), !d)
|
|
696
708
|
try {
|
|
697
|
-
await b(
|
|
709
|
+
await b(w), console.log("Camera recovered successfully");
|
|
698
710
|
} catch {
|
|
699
|
-
W(
|
|
711
|
+
W(w, y + 1);
|
|
700
712
|
}
|
|
701
713
|
}
|
|
702
|
-
async function b(
|
|
714
|
+
async function b(w) {
|
|
703
715
|
try {
|
|
704
|
-
m = await navigator.mediaDevices.getUserMedia({ video: !0 }),
|
|
705
|
-
y.addEventListener("ended", () => w
|
|
716
|
+
m = await navigator.mediaDevices.getUserMedia({ video: !0 }), w.srcObject = m, await w.play(), m.getVideoTracks().forEach((y) => {
|
|
717
|
+
y.addEventListener("ended", () => L(w));
|
|
706
718
|
});
|
|
707
719
|
} catch (y) {
|
|
708
|
-
E(y,
|
|
720
|
+
E(y, w);
|
|
709
721
|
}
|
|
710
722
|
}
|
|
711
|
-
function E(
|
|
712
|
-
if (
|
|
713
|
-
switch (
|
|
723
|
+
function E(w, y) {
|
|
724
|
+
if (w instanceof DOMException)
|
|
725
|
+
switch (w.name) {
|
|
714
726
|
case "NotAllowedError":
|
|
715
727
|
throw new Error("Permission denied — prompt user to allow camera");
|
|
716
728
|
case "NotFoundError":
|
|
@@ -720,12 +732,12 @@ async function Qe(d) {
|
|
|
720
732
|
console.error("Camera in use by another app"), W(y);
|
|
721
733
|
break;
|
|
722
734
|
default:
|
|
723
|
-
console.error("Camera error:",
|
|
735
|
+
console.error("Camera error:", w.message), W(y);
|
|
724
736
|
}
|
|
725
737
|
}
|
|
726
738
|
return await b(e), {
|
|
727
739
|
stop: () => {
|
|
728
|
-
|
|
740
|
+
d = !0, u(e);
|
|
729
741
|
}
|
|
730
742
|
};
|
|
731
743
|
},
|
|
@@ -734,25 +746,25 @@ async function Qe(d) {
|
|
|
734
746
|
* @param rig The rig that contains all the bones and skinned meshes of your character.
|
|
735
747
|
* @param magging The bone mapping to use for the rig.
|
|
736
748
|
*/
|
|
737
|
-
bind: (
|
|
738
|
-
m = m ||
|
|
739
|
-
const
|
|
749
|
+
bind: (d, m) => {
|
|
750
|
+
m = m || re;
|
|
751
|
+
const L = o.bind(d, m), u = i.left.bind(d, m), W = i.right.bind(d, m);
|
|
740
752
|
let b;
|
|
741
|
-
const E = r == null ? void 0 : r.bind(
|
|
742
|
-
|
|
743
|
-
y instanceof
|
|
753
|
+
const E = r == null ? void 0 : r.bind(d);
|
|
754
|
+
d.traverse((y) => {
|
|
755
|
+
y instanceof l.Mesh && y.name.indexOf(m.faceMesh) === 0 && (y.frustumCulled = !1, b = r == null ? void 0 : r.bindShapeKeys(y));
|
|
744
756
|
});
|
|
745
|
-
const
|
|
757
|
+
const w = Ge(d, m);
|
|
746
758
|
return {
|
|
747
759
|
/**
|
|
748
760
|
* Will save the tracked movement of the rig to an animation clip.
|
|
749
761
|
* Only the bones moved by the bone mapping will be recorded.
|
|
750
762
|
*/
|
|
751
|
-
startRecording:
|
|
752
|
-
stopRecording:
|
|
753
|
-
isRecording: () =>
|
|
763
|
+
startRecording: w.start,
|
|
764
|
+
stopRecording: w.stop,
|
|
765
|
+
isRecording: () => w.isRecording(),
|
|
754
766
|
update: (y) => {
|
|
755
|
-
|
|
767
|
+
L.update(y), u.update(y), W.update(y), b == null || b.update(y), E == null || E.update(y), w.isRecording() && w.captureFrame();
|
|
756
768
|
}
|
|
757
769
|
};
|
|
758
770
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"three-mediapipe-rig.js","sources":["../src/tracking/util/lookAt.ts","../src/tracking/Tracker.ts","../src/tracking/util/getRootPosition.ts","../src/tracking/util/cleanBoneName.ts","../src/tracking/util/getBoneByName.ts","../src/tracking/PoseTracker.ts","../src/tracking/HandTracker.ts","../src/tracking/FaceTracker.ts","../src/tracking/BoneMapping.ts","../src/tracking/blendShapeKeyNames.ts","../src/tracking/recoding/recorder.ts","../src/tracking/TrackerManager.ts"],"sourcesContent":["import { Object3D, Quaternion, Vector3 } from \"three/webgpu\";\n\nconst poleDir = new Vector3();\nconst objectPosition = new Vector3();\n\nconst XAxis = new Vector3(1,0,0);\nconst XAxisNeg = new Vector3(-1,0,0);\nconst YAxis = new Vector3(0,1,0); \nconst YAxisNeg = new Vector3(0,-1,0); \nconst ZAxis = new Vector3(0,0,1); \nconst ZAxisNeg = new Vector3(0,0,-1); \n\nconst pole = new Vector3();\nconst lookDir = new Vector3();\n\nconst v = new Vector3();\nconst correction = new Quaternion();\nconst worldQuat = new Quaternion();\n\nexport type LookAtPoleAxis = \"+x\"|\"+y\"|\"-x\"|\"-y\"\n\n/**\n * Will point the Z axis of object at target and the X or Y axis in the general direction of the pole target\n * @param object The object to rotate\n * @param target The point to look at ( in world coord )\n * @param poleTarget The goal of the pole axis ( in world coord )\n * @param poleAxis The axis to use as the pole axis ( z is the one pointing at the target )\n */\nexport function lookAt( object:Object3D, target:Vector3, poleTarget:Vector3, poleAxis:LookAtPoleAxis = \"+x\" )\n{ \n\t//\n\t// look at target (handles parent transforms internally)\n\t// \n\tobject.lookAt(target);\n\n\tconst axis = poleAxis==\"+x\"?XAxis: poleAxis==\"-x\"?XAxisNeg: poleAxis==\"+y\"?YAxis: YAxisNeg;\n\n\tobject.getWorldPosition(objectPosition);\n\tobject.getWorldQuaternion(worldQuat);\n\n\tpoleDir.subVectors(poleTarget, objectPosition).normalize();\n\n\t// direction in which the pole axis is currently pointing (in world space)\n\tpole.copy(axis).applyQuaternion(worldQuat);\n\n\tconst currentPole = pole;\n\n\t// look direction in world space\n\tconst lookAxisDir = lookDir.copy( ZAxis ).applyQuaternion(worldQuat);\n\n\t// project desired pole direction onto the plane perpendicular to the look axis\n\tconst desiredPoleDir = poleDir.clone().addScaledVector(lookAxisDir, -poleDir.dot(lookAxisDir)).normalize();\n\n\t// signed angle between current pole and desired pole around the look axis\n\tconst cross = v.crossVectors(currentPole, desiredPoleDir);\n\tconst angle = Math.atan2(cross.dot(lookAxisDir), currentPole.dot(desiredPoleDir));\n\n\t// The correction is a spin around the look axis (local Z after lookAt).\n\t// Since lookAt aligned local Z to the target, we can apply around the local Z axis directly.\n\tcorrection.setFromAxisAngle(ZAxis, angle);\n\tobject.quaternion.multiply(correction);\n}","import * as THREE from \"three/webgpu\";\nimport {\n Landmark,\n NormalizedLandmark,\n\tDrawingUtils, \n} from \"@mediapipe/tasks-vision\"; \nimport { lookAt, LookAtPoleAxis } from \"./util/lookAt\";\n\n \n\nconst v = new THREE.Vector3();\nconst A = new THREE.Vector3();\nconst B = new THREE.Vector3();\nconst C = new THREE.Vector3();\n\nexport class Tracker<T extends Record<string, number|number[]> > {\n\tprivate objectGhost : Map<THREE.Object3D, Ghost> ;\n\treadonly root:THREE.Object3D;\n\n\t/**\n\t * per landmark index, it points to it's object3D equivalent.\n\t */\n\tprotected marks: { [name in keyof T]: Mark } = {} as { [name in keyof T]: Mark };\n\n\tconstructor( protected readonly points:T, private readonly debugConnections?:{start:number,end:number}[] ){\n\t\tthis.root = new THREE.Object3D();\n\t\tthis.objectGhost = new Map();\n\n\t\t// por each key in points\n\t\tfor( let key in this.points ){\n\t\t\tthis.marks[key] = new Mark();\n \n\t\t\tthis.root.add(this.marks[key]);\n\t\t}\n\t}\n\n\tprotected updateLandmarks( landmarks:Landmark[], debugLandmarks?:NormalizedLandmark[], debugDrawer?:DrawingUtils ) {\n\t\tfor( let key in this.points ){\n\t\t\tconst point = this.points[key];\n\t\t\tconst mark = this.marks[key];\n\t\t\tif( mark ){\n\t\t\t\tif( point instanceof Array )\n\t\t\t\t{\n\t\t\t\t\t\n\t\t\t\t\tv.copy( landmarks[ point[0] ] ) \n\t\t\t\t\tmark.position.copy( landmarks[ point[1] ] ).sub( v ).divideScalar(2).add(landmarks[ point[0] ]);\n\t\t\t\t\t\n\t\t\t\t\tif( point.length==4 )\n\t\t\t\t\t{\n\t\t\t\t\t\tv.subVectors(\n\t\t\t\t\t\t\tlandmarks[ point[3] ],\n\t\t\t\t\t\t\tlandmarks[ point[2] ]\n\t\t\t\t\t\t).divideScalar(2).add(landmarks[ point[2] ]) \n\n\t\t\t\t\t\t.sub( mark.position )\n\t\t\t\t\t\t.divideScalar(2) \n\n\t\t\t\t\t\tmark.position.add( v );\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t}\n\t\t\t\telse \n\t\t\t\t{\n\t\t\t\t\tmark.position.copy( landmarks[ point as number ] )\n\t\t\t\t}\n \n\t\t\t}\n\t\t}\n\n\t\tif( debugDrawer && debugLandmarks )\n\t\t{ \n\t\t\t// debugDrawer.drawLandmarks(debugLandmarks, {\n\t\t\t// \tradius: (data) =>\n\t\t\t// \t\tDrawingUtils.lerp(data.from!.z, -0.15, 0.1, 5, 1),\n\t\t\t// \tlineWidth:1\n\t\t\t// });\n\t\t\tdebugDrawer.drawConnectors(\n\t\t\t\tdebugLandmarks,\n\t\t\t\tthis.debugConnections,\n\t\t\t\t{\n\t\t\t\t\tlineWidth:1\n\t\t\t\t}\n\t\t\t); \n\t\t}\n\t}\n\n\tprotected getGhost( object:THREE.Object3D ){\n\t\tif( !this.objectGhost.has(object)) \n\t\t{\n\t\t\tconst o = new Ghost()\n\n\t\t\to.position.copy(object.position)\n\t\t\to.quaternion.copy(object.quaternion)\n\t\t\tobject.parent?.add(o);\n\n\t\t\tthis.objectGhost.set(object, o)\n\t\t} \n\t\treturn this.objectGhost.get(object)!;\n\t}\n\n\tpredict( source:TexImageSource, drawingUtils:DrawingUtils ){\n\t\tthrow new Error(\"Method 'predict' must be implemented.\");\n\t}\n\n\tsync ( delta:number, objects: [THREE.Object3D, keyof T, keyof T, LookAtPoleAxis][] ) {\n\t\tthrow new Error(\"Method 'sync' must be implemented.\"); \n\t}\n\n\ttest( key:keyof T ){\n\t\tthis.marks[key]!.position.set(1,2,3)\n\t}\n\n\tprotected syncObjects(objects: [THREE.Object3D, keyof T, keyof T,LookAtPoleAxis][], delta:number, normal:THREE.Vector3 ){\n\t\tfor( const [object, root, target, poleAxis] of objects ){\n\n\t\t\t//\n\t\t\t// position A and B where the landmarks are\n\t\t\t//\n\t\t\tthis.marks[target].getWorldPosition(B)\n\t\t\tthis.marks[root].getWorldPosition(A)\n\n\t\t\t//\n\t\t\t// calcuate the offset\n\t\t\t//\n\t\t\tconst offset = B.sub(A); // offset from root to taget in world units\n\n\t\t\t//\n\t\t\t// now position A in object position\n\t\t\t//\n\t\t\tobject.getWorldPosition(A)\n\n\t\t\t//\n\t\t\t// and displace it by the offset ( this will be the look at target )\n\t\t\t//\n\t\t\tA.add(offset);\n\n\t\t\t \n\t\t\tconst objectLookAtGoal = A;\n\t\t\tconst polePosition = object.getWorldPosition(B).sub( normal )\n\n\t\t\tconst ghost = this.getGhost(object);\n \n\n\t\t\t \n\t\t\t\tlookAt( ghost, objectLookAtGoal, polePosition, poleAxis);\n\n\t\t\t\tghost.rotateX( Math.PI/2) \n\t\t\t\n\t\t\t//ghost.rotateY( Math.PI/2)\n\n\t\t\tobject.position.lerp(ghost.position, delta * 4)\n\t\t\tobject.quaternion.slerp(ghost.quaternion, delta * 4) \n\t\t}\n\t}\n\n\tprotected getBone( rig:THREE.Object3D, name:string ){\n\t\treturn rig.getObjectByName(name.replace(/[\\.\\:]/g,\"\")) ;\n\t}\n}\n\n// const t = {\n// \tpepe:[1,2]\n// }\n// const d = new Tracker(t)\n// d.test(\"pepe\")\n\nclass Mark extends THREE.Mesh {\n\tprivate _worldPosition = new THREE.Vector3();\n\tconstructor() {\n\t\tsuper(new THREE.SphereGeometry(0.01,3,3), new THREE.MeshStandardMaterial({ color: 0xff0000, wireframe:true }));\n\t\tthis.add( new THREE.AxesHelper(0.001))\n\t}\n\n\tget worldPosition(){\n\t\tthis.getWorldPosition(this._worldPosition);\n\t\treturn this._worldPosition;\n\t}\n}\n\nclass Ghost extends THREE.Object3D { \n\tlerp( target:THREE.Object3D, delta:number, speed = 8 )\n\t{\n\t\ttarget.position.lerp(this.position, delta * speed)\n\t\ttarget.quaternion.slerp(this.quaternion, delta * speed) \n\t}\n}","import { Object3D, Vector3 } from \"three/webgpu\";\n\n\n/**\n * Gets the position of `object` relative to `root`.\n * @param out \n * @param object \n * @param root \n * @returns \n */\nexport function rootPosition( out:Vector3, object:Object3D, root:Object3D ) {\n\n\troot.worldToLocal( object.getWorldPosition(out) )\n\n\treturn out;\n}","export function cleanBoneName(name:string) {\n\treturn name.replace(/[\\.\\:]/g,\"\")\n}","import { Bone, Object3D } from \"three\";\nimport { cleanBoneName } from \"./cleanBoneName\";\n\nexport function getBoneByName(rig:Object3D, name:string) {\n\tlet bone:Bone|undefined;\n\tname = cleanBoneName(name); \n\t\n\trig.traverse( (o:Object3D) => {\n\t\tif( o.name.indexOf(name)===0 && o instanceof Bone ) bone = o as Bone;\n\t})\n\n\tif( !bone ) console.log(\"Bone not found: \", name, rig.name)\n\n\treturn bone;\n}","import {\n DrawingUtils,\n NormalizedLandmark,\n PoseLandmarker,\n} from \"@mediapipe/tasks-vision\"; \nimport * as THREE from \"three/webgpu\";\nimport { lookAt, LookAtPoleAxis } from \"./util/lookAt\";\nimport { Tracker } from \"./Tracker\";\nimport { rootPosition } from \"./util/getRootPosition\";\nimport { getBoneByName } from \"./util/getBoneByName\";\nimport { BoneMap } from \"./BoneMapping\";\n\nexport async function loadPoseTracker(vision: any, config?:Partial<PoseTrackerConfig>) {\n\tconst poseLandmarker = await PoseLandmarker.createFromOptions(vision, {\n baseOptions: { \n\t\t\tmodelAssetPath: config?.modelPath ?? \"pose_landmarker_lite.task\",\n //modelAssetPath: `https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task`,\n //modelAssetPath: \"https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_heavy/float16/latest/pose_landmarker_heavy.task\",\n delegate: \"GPU\",\n },\n runningMode: \"VIDEO\",\n numPoses: 1,\n });\n\n\treturn new PoseTracker(poseLandmarker, config);\n} \n\n/**\n * Points derived from https://ai.google.dev/static/mediapipe/images/solutions/pose_landmarks_index.png\n * If the array has 2 elements, the point is between those 2 landmarks.\n * If it has 4, the point is at the center of those 4 landmarks.\n */\nconst poseMarks = {\n\t\t\thips: [24,23],\n\t\t\tneck: [12,11],\n\t\t\tleftLeg: 23,\n\t\t\tleftKnee:25,\n\t\t\tleftFoot: 27,\n\t\t\tleftToes: 31,\n\t\t\tleftArm: 11,\n\t\t\tleftElbow: 13,\n\t\t\tleftWrist: 15,\n\t\t\trightLeg: 24,\n\t\t\trightKnee: 26,\n\t\t\trightFoot: 28,\n\t\t\trightToes: 32,\n\t\t\trightArm: 12,\n\t\t\trightElbow: 14,\n\t\t\trightWrist: 16, \n\t\t\thead: [8,7] //between the ears\n\t\t\t, mouth:[10,9]\n\t\t\t, torso: [24,23, 12,11] //at the center of the torso\n\t\t\t, leftEar: 7\n\t\t\t, rightEar: 8\n\t\t} ;\n\ntype MarkKey = keyof typeof poseMarks;\n\ntype BoneBinding = [THREE.Object3D, MarkKey, MarkKey,LookAtPoleAxis]\n\nconst A = new THREE.Vector3();\nconst B = new THREE.Vector3();\nconst C = new THREE.Vector3();\nconst D = new THREE.Vector3();\nconst E = new THREE.Vector3();\nconst lookGoal = new THREE.Vector3();\nconst poleGoal = new THREE.Vector3();\n\ntype PoseTrackerConfig = {\n\tignoreLegs:boolean\n\tmodelPath:string\n}\n\n/**\n * @see https://ai.google.dev/edge/mediapipe/solutions/vision/pose_landmarker\n */\nclass PoseTracker extends Tracker<typeof poseMarks> {\n\tprivate _leftWristNormalizedPosition!:NormalizedLandmark;\n\tprivate _rightWristNormalizedPosition!:NormalizedLandmark;\n\n\t/**\n\t * Position of the left wrist in normalized coordinates (0..1)\n\t */\n\tget leftWristNormalizedPosition() { return this._leftWristNormalizedPosition; }\n\n\t/**\n\t * Position of the right wrist in normalized coordinates (0..1)\n\t */\n\tget rightWristNormalizedPosition() { return this._rightWristNormalizedPosition; }\n\n\tconstructor(private readonly poseLandmarker:PoseLandmarker, private readonly config?:Partial<PoseTrackerConfig>){ \n\n\t\tsuper(poseMarks, PoseLandmarker.POSE_CONNECTIONS)\n\t\t\n\t\tthis.root.scale.y *= -2\n\t\tthis.root.scale.z *= -2\n\t\tthis.root.scale.x *= 2 \n\t}\n\n\toverride predict( source:TexImageSource, drawingUtils:DrawingUtils ){\n\t\tthis.poseLandmarker.detectForVideo( source, performance.now(), (result) => {\n\n\t\t\tif( result.landmarks.length==0 )\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n \n\t\t\tthis.updateLandmarks( result.worldLandmarks[0], result.landmarks[0], drawingUtils );\n\n\t\t\t\n\t\t\tthis._leftWristNormalizedPosition = result.landmarks[0][ this.points.leftWrist ];\n\t\t\tthis._rightWristNormalizedPosition = result.landmarks[0][ this.points.rightWrist ];\n\t\t} );\n\t}\n\n\t// override sync ( delta:number, objects: BoneBinding[] ) {\n\n\t// \tconst hipsPos = this.marks.hips.getWorldPosition(C); \n\n\t// \tthis.marks.rightArm.getWorldPosition(A).sub(hipsPos);\n\t// \tthis.marks.leftArm.getWorldPosition(B).sub(hipsPos); \n\n\t// \tconst torsoNormal = C.crossVectors(A,B);\n\n\t// \tthis.syncObjects(objects, delta, torsoNormal); \n\n\t// }\n\t\n\n\tbind( rig:THREE.Object3D, magging:BoneMap )\n\t{ \n\t\t \n\t\tconst map : { [key in MarkKey]?:THREE.Object3D } = {\n\t\t\t\"hips\": getBoneByName(rig, magging.hips),\n\t\t\t\"neck\": getBoneByName(rig, magging.neck),\n\t\t\t\"leftArm\": getBoneByName(rig, magging.armL),\n\t\t\t\"leftElbow\": getBoneByName(rig, magging.forearmL),\n\t\t\t\"leftWrist\": getBoneByName(rig, magging.handL),\n\t\t\t\"rightArm\": getBoneByName(rig, magging.armR),\n\t\t\t\"rightElbow\": getBoneByName(rig, magging.forearmR),\n\t\t\t\"rightWrist\": getBoneByName(rig, magging.handR),\n\t\t\t\"head\": getBoneByName(rig, magging.head), \n\t\t\t\"torso\": getBoneByName(rig, magging.torso),\n\t\t\t\"leftLeg\": getBoneByName(rig, magging.thighL),\n\t\t\t\"leftKnee\": getBoneByName(rig, magging.shinL),\n\t\t\t\"leftFoot\": getBoneByName(rig, magging.footL),\n\t\t\t\"rightLeg\": getBoneByName(rig, magging.thighR),\n\t\t\t\"rightKnee\": getBoneByName(rig, magging.shinR),\n\t\t\t\"rightFoot\": getBoneByName(rig, magging.footR),\n\t\t} \n\n\t\tif( this.config?.ignoreLegs ){\n\t\t\tdelete map.leftLeg\n\t\t\tdelete map.leftKnee\n\t\t\tdelete map.leftFoot\n\t\t\tdelete map.leftToes\n\t\t\tdelete map.rightLeg\n\t\t\tdelete map.rightKnee\n\t\t\tdelete map.rightFoot\n\t\t\tdelete map.rightToes\n\t\t}\n\n\t\tconst v = new THREE.Vector3();\n\t\tconst v2 = new THREE.Vector3();\n\n\t\tconst syncBone = ( delta:number, bone:THREE.Object3D|undefined, from:MarkKey, to:MarkKey, sideAxis:THREE.Vector3, poleAxis:LookAtPoleAxis ) => {\n\t\t\tif( !bone ) return;\n\n\t\t\tconst hipsDir = this.marks[to].getWorldPosition(v).sub(this.marks[from].getWorldPosition(v2)).normalize(); \n\n\t\t \n\t\t\trootPosition(lookGoal, bone, rig).add( hipsDir ).applyMatrix4(rig.matrixWorld) ;\n\t\t\trootPosition(poleGoal, bone, rig).add( sideAxis ).applyMatrix4(rig.matrixWorld) ; \n\n\t\t\tconst ghost = this.getGhost(bone)\n\n\t\t\tlookAt(ghost, lookGoal, poleGoal, poleAxis)\n\t\t\tghost.rotateX(Math.PI/2)\n\t\t\t \n\n\t\t\tghost.lerp(bone, delta)\n\t\t}\n\n\t\treturn {\n\t\t\tupdate: (delta:number)=>{\n \n\t\t\t\tconst sideHips = this.marks.leftLeg.getWorldPosition(A).sub(this.marks.rightLeg.getWorldPosition(B)).normalize();\n\t\t\t\tconst sideShoulders = this.marks.leftArm.getWorldPosition(B).sub(this.marks.rightArm.getWorldPosition(C)).normalize();\n\t\t\t\tconst sideHead = this.marks.leftEar.getWorldPosition(D).sub(this.marks.rightEar.getWorldPosition(E)).normalize();\n\n\t\t\t\tsyncBone(delta, map.hips, \"hips\", \"torso\", sideHips, \"+x\")\n\t\t\t\tsyncBone(delta, map.torso, \"torso\", \"neck\", sideShoulders, \"+x\")\n\t\t\t\tsyncBone(delta, map.neck, \"neck\", \"head\", sideHead, \"+x\")\n\t\t\t\tsyncBone(delta, map.head, \"neck\", \"head\", sideHead, \"+x\")\n\n\t\t\t\tsyncBone(delta, map.leftArm, \"leftArm\", \"leftElbow\", sideShoulders, \"-x\")\n\t\t\t\tsyncBone(delta, map.leftElbow, \"leftElbow\", \"leftWrist\", sideShoulders, \"-x\")\n\t\t\t\tsyncBone(delta, map.leftLeg, \"leftLeg\", \"leftKnee\", sideHips, \"+x\") \n\t\t\t\tsyncBone(delta, map.leftKnee, \"leftKnee\", \"leftFoot\", sideHips, \"+x\") \n\t\t\t\tsyncBone(delta, map.leftFoot, \"leftFoot\", \"leftToes\", sideHips, \"+x\") \n\n\t\t\t\tsyncBone(delta, map.rightArm, \"rightArm\", \"rightElbow\", sideShoulders, \"-x\")\n\t\t\t\tsyncBone(delta, map.rightElbow, \"rightElbow\", \"rightWrist\", sideShoulders, \"-x\")\n\t\t\t\tsyncBone(delta, map.rightLeg, \"rightLeg\", \"rightKnee\", sideHips, \"+x\") \n\t\t\t\tsyncBone(delta, map.rightKnee, \"rightKnee\", \"rightFoot\", sideHips, \"+x\") \n\t\t\t\tsyncBone(delta, map.rightFoot, \"rightFoot\", \"rightToes\", sideHips, \"+x\") \n\t\t\t\t\n\t\t\t}\n\t\t}\n\t}\n}\n ","import {\n\tDrawingUtils,\n HandLandmarker,\n\tHandLandmarkerOptions,\n\tNormalizedLandmark,\n} from \"@mediapipe/tasks-vision\";\nimport * as THREE from \"three/webgpu\";\nimport { lookAt, LookAtPoleAxis } from \"./util/lookAt\";\nimport { Tracker } from \"./Tracker\";\nimport { rootPosition } from \"./util/getRootPosition\";\nimport { getBoneByName } from \"./util/getBoneByName\";\nimport { BoneMap } from \"./BoneMapping\";\n\nexport type HandsTrackerConfig = {\n\tleftWrist: ()=>NormalizedLandmark;\n\trightWrist: ()=>NormalizedLandmark;\n\tmodelPath?:string\n} & Partial<HandLandmarkerOptions>;\n\nconst A = new THREE.Vector2();\nconst B = new THREE.Vector2();\n\nexport async function loadHandTracker(vision: any, config:HandsTrackerConfig ) {\n const landmarker = await HandLandmarker.createFromOptions(vision, {\n baseOptions: {\n modelAssetPath: config.modelPath ?? \"hand_landmarker.task\",\n //modelAssetPath: `https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task`,\n delegate: \"GPU\",\n },\n runningMode: \"VIDEO\",\n numHands: 2,\n });\n\n\tconst isMyWrist = ( myWrist:()=>NormalizedLandmark, otherWrist:()=>NormalizedLandmark, handWrist:NormalizedLandmark ) => {\n\t\tA.copy(myWrist());\n\t\tB.copy(otherWrist());\n\t\treturn A.distanceTo(handWrist) < B.distanceTo(handWrist);\n\t}\n\n return {\n\t\tleft:new HandsTracker(landmarker, \"Left\", isMyWrist.bind(null, config.leftWrist, config.rightWrist) ),\n\t\tright:new HandsTracker(landmarker, \"Right\", isMyWrist.bind(null, config.rightWrist, config.leftWrist) )\n\t};\n}\n\nconst handMarks = {\n wrist: 0,\n\tpalm: [9,13],\n\n thumb1: 1,\n thumb2: 2,\n thumb3: 3,\n thumb4: 4,\n\n index1: 5,\n index2: 6,\n index3: 7,\n index4: 8,\n\n middle1: 9,\n middle2: 10,\n middle3: 11,\n middle4: 12,\n\n ring1: 13,\n ring2: 14,\n ring3: 15,\n ring4: 16,\n\n pinky1: 17,\n pinky2: 18,\n pinky3: 19,\n pinky4: 20,\n};\n\nexport type HandMarkName = keyof typeof handMarks;\n\nconst fingerKeys = {\n\tthumb: [\"thumb1\",\"thumb2\",\"thumb3\",\"thumb4\"],\n\tindex: [\"index1\",\"index2\",\"index3\",\"index4\"],\n\tmiddle: [\"middle1\",\"middle2\",\"middle3\",\"middle4\"],\n\tring: [\"ring1\",\"ring2\",\"ring3\",\"ring4\"],\n\tpinky: [\"pinky1\",\"pinky2\",\"pinky3\",\"pinky4\"]\n} as { [key:string]: HandMarkName[]} ;\n\n\ntype HandSide = \"Left\" | \"Right\"\nexport type Mark2Bone = Partial<{ [key in HandMarkName]: THREE.Object3D }>;\n\nconst v1 = new THREE.Vector3();\nconst v2 = new THREE.Vector3();\nconst v3 = new THREE.Vector3();\nconst v4 = new THREE.Vector3();\nconst v5 = new THREE.Vector3();\nconst v6 = new THREE.Vector3();\n\nconst currNormal = new THREE.Vector3();\nconst currForward = new THREE.Vector3();\nconst currSide = new THREE.Vector3();\nconst HALF_PI = Math.PI/2\nconst DOWN = new THREE.Vector3(0,-1,0);\n\nclass HandsTracker extends Tracker<typeof handMarks> {\n\tprivate readonly sign:number;\n\tprivate readonly isLeft:boolean;\n\t/**\n\t * the axis used to look at the pole\n\t */\n\tprivate readonly lookAtPoleAxis:LookAtPoleAxis;\n\n\tconstructor(private readonly handLandmarker:HandLandmarker, private readonly side:HandSide, private readonly isMyWrist:( handWrist:NormalizedLandmark )=>boolean ){\n\t\tsuper(handMarks, HandLandmarker.HAND_CONNECTIONS)\n\n\t\tthis.sign = this.side==\"Left\" ? -1 : 1;\n\t\tthis.isLeft = this.side==\"Left\";\n\t\tthis.lookAtPoleAxis = this.sign<0? \"+x\" : \"-x\";\n\t\tthis.root.scale.setScalar(2)\n\t\tthis.root.scale.y *= -1\n\t\tthis.root.scale.z *= -1\n\t}\n\n\toverride predict( source:TexImageSource, drawingUtils:DrawingUtils ){\n\t\tconst result = this.handLandmarker.detectForVideo(source, performance.now());\n\n\t\tif( result.landmarks.length )\n\t\t{\n\t\t\t//console.log(`DETECTED ${result.landmarks.length} hands`, result.handedness)\n\n\n\t\t\tfor(let i=0; i<result.landmarks.length; i++){\n\t\t\t\tconst hand = result.landmarks[i];\n\t\t\t\tconst wrist = hand[this.points.wrist];\n\t\t\t\tconst isMyWrist = this.isMyWrist(wrist);\n\t\t\t\tif( isMyWrist ){\n\t\t\t\t\tthis.updateLandmarks( result.worldLandmarks[i] );\n\n\t\t\t\t\tdrawingUtils.drawConnectors(hand, HandLandmarker.HAND_CONNECTIONS, {\n\t\t\t\t\t\tcolor: this.side==\"Left\" ? \"#00FF00\" : \"#0000FF\",\n\t\t\t\t\t\tlineWidth: 4\n\t\t\t\t\t});\n\t\t\t\t\tdrawingUtils.drawLandmarks(hand, { color: this.side==\"Left\" ? \"#00FF00\" : \"#0000FF\", lineWidth: 3, radius: 1 }); \n\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} \n \n \n\t\t} \n\t}\n\n\toverride sync ( delta:number, objects: [THREE.Object3D, HandMarkName, HandMarkName, LookAtPoleAxis][] ) {\n\n\t\tthrow new Error(\"Not used. Use syncHandBones instead\");\n\t}\n\t\t\n\t/**\n\t * \n\t * @param delta time since last frame\n\t * @param landmark2bones Array the same size as the umber of hand landmarks, and on each positionthe bone that belongs to that point.\n\t * @see https://ai.google.dev/edge/mediapipe/solutions/vision/hand_landmarker\n\t */\n\tsyncHandBones( delta:number, markToBone:Mark2Bone, rig:THREE.Object3D )\n\t{ \n\t\tconst palmNormal = v1.crossVectors(\n\t\t\tv2.copy(this.marks.index1.worldPosition).sub(this.marks.wrist.worldPosition),\n\t\t\tv3.copy(this.marks.pinky1.worldPosition).sub(this.marks.wrist.worldPosition)\n\t\t).normalize();\n\n\t\tconst parlmDir = v2.copy(this.marks.palm.worldPosition).sub(this.marks.wrist.worldPosition).normalize();\n\t\tconst palmSide = v3.copy(this.marks.pinky1.worldPosition).sub(this.marks.index1.worldPosition).normalize();\n\t\t \n\t\tif( parlmDir.dot(DOWN)>0.8 )\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tif( markToBone.wrist )\n\t\t{\n\t\t\tconst palmLookAt = rootPosition(v4, markToBone.wrist, rig ).add( parlmDir ).applyMatrix4(rig.matrixWorld) //markToBone.wrist.getWorldPosition(v4).add( parlmDir );\n\t\t\tconst polPosition = rootPosition(v5, markToBone.wrist, rig ).sub( palmSide ).applyMatrix4(rig.matrixWorld) //markToBone.wrist.getWorldPosition(v5).sub( palmSide );\n\n\t\t\tconst palmGhost = this.getGhost(markToBone.wrist)\n\n\t\t\tlookAt( palmGhost, palmLookAt, polPosition, \"-y\" );\n\t\t\tpalmGhost.rotateX( HALF_PI ) ; \n\n\t\t\tpalmGhost.lerp(markToBone.wrist, delta)\n\t\t}\n\t\t\n\n\t\t// palmLookAtOffset.normalize();\n\n\t\t \n\t\t// const palmSide = v3.crossVectors(palmNormal, palmLookAtOffset).normalize();\n \n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.index, \"middle1\" )\n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.middle, \"ring1\" )\n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.ring, \"pinky1\" )\n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.pinky, \"ring1\" )\n\n\t\t// //thumb...\n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.thumb, \"index1\" )\n\n\t\t\n\t}\n\n\tprivate syncFinger( delta:number, rig:THREE.Object3D, palmNormal:THREE.Vector3, palmForward:THREE.Vector3, palmSide:THREE.Vector3, markToBone:Mark2Bone, fingerKeys:HandMarkName[], sideGoal:HandMarkName, negateSideGoal:boolean=false ){\n\t \n\t\tlet signMult = 1;\n\n\t\tfor(let i=0; i<fingerKeys.length-1;i++) { \n\t\t\t\n\t\t\tconst bone = markToBone[fingerKeys[i]];\n\t\t\t//const bonePole = markToBone[sideGoal];\n\n\t\t\tif(!bone ) continue;\n\n\t\t\tconst myDir = v4.copy( this.marks[fingerKeys[i+1]].worldPosition ).sub( this.marks[fingerKeys[i]].worldPosition).normalize(); \n\t\t\t\n\t\t\tconst bonePos = rootPosition(v5, bone, rig) //bone.getWorldPosition(v5);\n\t\t\tconst poleOffset = v6.copy(bonePos).add(palmSide) //rootPosition(v6, bonePole, rig).sub( bonePos );//bonePole.getWorldPosition(v6).sub( bonePos );\n\n\t\t\tif( negateSideGoal ) poleOffset.negate();\n\n\t\t\tconst fingerGhost = this.getGhost(bone)\n\n\n\t\t\tif( i==0 )\n\t\t\t{ \n\n\t\t\t\tcurrSide.copy(poleOffset);\n\n\t\t\t\t\n\t\t\t\tlookAt( fingerGhost, \n\t\t\t\t\tmyDir.add( bonePos ).applyMatrix4(rig.matrixWorld), \n\t\t\t\t\tpoleOffset.add(bonePos).applyMatrix4(rig.matrixWorld), \n\t\t\t\t\tthis.lookAtPoleAxis );\n\n\t\t\t\t\n\t\t\t}\n\t\t\telse \n\t\t\t{ \n\t\t\t\tpoleOffset.copy( currSide );\n\t\t\t\tlookAt( fingerGhost, \n\t\t\t\t\tmyDir.add( bonePos ).applyMatrix4(rig.matrixWorld), \n\t\t\t\t\tpoleOffset.add(bonePos).applyMatrix4(rig.matrixWorld), \n\t\t\t\t\tthis.lookAtPoleAxis );\n\t\t\t} \n\n\t\t\tfingerGhost.rotateX( HALF_PI ); \n\n\t\t\tfingerGhost.lerp(bone, delta)\n\n\t\t}\n\n \n\t}\n \n\tbind( rig:THREE.Object3D, magging:BoneMap ){\n\n\t\tconst map:Mark2Bone = {\n\t\t\t\n\t\t}\t \n\n\t\tconst addBind = ( boneName:string, markName:HandMarkName ) => {\n\t\t\t//const bone = rig.getObjectByName( cleanBoneName( boneName.replace(\"X\", this.sign<0 ? \"L\" : \"R\") ));\n\n\t\t\tconst bone = getBoneByName(rig, boneName );\n\n\t\t\tif( bone ){\n\t\t\t\tmap[markName] = bone;\n\t\t\t}\n\t\t}\n\n\t\taddBind( this.isLeft ? magging.handL : magging.handR, \"wrist\" )\n\t\taddBind( this.isLeft ? magging.index1L : magging.index1R, \"index1\" )\n\t\taddBind( this.isLeft ? magging.index2L : magging.index2R, \"index2\" )\n\t\taddBind( this.isLeft ? magging.index3L : magging.index3R, \"index3\" ) \n\n\t\taddBind( this.isLeft ? magging.middle1L : magging.middle1R, \"middle1\" )\n\t\taddBind( this.isLeft ? magging.middle2L : magging.middle2R, \"middle2\" )\n\t\taddBind( this.isLeft ? magging.middle3L : magging.middle3R, \"middle3\" ) \n\n\t\taddBind( this.isLeft ? magging.ring1L : magging.ring1R, \"ring1\" )\n\t\taddBind( this.isLeft ? magging.ring2L : magging.ring2R, \"ring2\" )\n\t\taddBind( this.isLeft ? magging.ring3L : magging.ring3R, \"ring3\" ) \n\n\t\taddBind( this.isLeft ? magging.pinky1L : magging.pinky1R, \"pinky1\" )\n\t\taddBind( this.isLeft ? magging.pinky2L : magging.pinky2R, \"pinky2\" )\n\t\taddBind( this.isLeft ? magging.pinky3L : magging.pinky3R, \"pinky3\" ) \n\n\t\taddBind( this.isLeft ? magging.thumb1L : magging.thumb1R, \"thumb1\" )\n\t\taddBind( this.isLeft ? magging.thumb2L : magging.thumb2R, \"thumb2\" )\n\t\taddBind( this.isLeft ? magging.thumb3L : magging.thumb3R, \"thumb3\" ) \n\n\t\treturn {\n\t\t\tupdate: ( delta:number )=> { \n\t\t\t\tthis.syncHandBones(delta, map, rig);\n\t\t\t}\n\t\t}\t\n\t}\n}\n","import {\n Category,\n DrawingUtils,\n FaceLandmarker\n} from \"@mediapipe/tasks-vision\";\nimport { Mesh, Object3D, Vector3 } from \"three/webgpu\";\nimport { Tracker } from \"./Tracker\";\nimport { rootPosition } from \"./util/getRootPosition\";\nimport { getBoneByName } from \"./util/getBoneByName\";\nimport { lookAt } from \"./util/lookAt\";\n\nexport async function loadFaceTracker(vision: any, cfg?: { modelPath?: string }) {\n const faceLandmarker = await FaceLandmarker.createFromOptions(vision, {\n baseOptions: {\n modelAssetPath: cfg?.modelPath ?? \"face_landmarker.task\",\n\t\t\tdelegate: \"GPU\", \n },\n\t\toutputFaceBlendshapes: true,\n runningMode: \"VIDEO\",\n\t\tnumFaces: 1,\n });\n\n\treturn new FaceTracker(faceLandmarker);\n}\n\n/**\n * @see https://storage.googleapis.com/mediapipe-assets/documentation/mediapipe_face_landmark_fullsize.png\n */\nconst faceMarks = {\n\teyeL: 473,\n\teyeR: 468,\n\teyeStartL: 463,\n\teyeStartR: 243,\n\teyeEndL: 263,\n\teyeEndR: 33, \n\n\tearL: 454,\n\tearR: 234,\n\tnoseTip: 4,\n\tnoseBone:6,\n\tchin:152,\n\tforehead: 10\n\n}\n\ntype MarkKey = keyof typeof faceMarks;\nconst v = new Vector3();\nconst v2 = new Vector3();\nconst v3 = new Vector3();\nconst v4 = new Vector3();\nconst v5 = new Vector3();\nconst v6 = new Vector3();\n\nclass FaceTracker extends Tracker<typeof faceMarks> {\n\tprivate blendshapeCategories: Category[] | undefined;\n\tprivate blendshapeMap: Map<string, number> = new Map();\n\tprivate smoothed: Record<string, number> = {};\n\tprivate smoothing =.0003; // lower = smoother but more lag, higher = more responsive\n\n\tconstructor(private faceLandmarker: FaceLandmarker) {\n\t\tsuper(faceMarks, FaceLandmarker.FACE_LANDMARKS_TESSELATION)\n\n\t\tthis.root.scale.y*=-1\n\t\tthis.root.scale.z*=-1\n\t\tthis.root.scale.multiplyScalar(3)\n\t}\n\n\toverride predict(frame: TexImageSource, drawingUtils: DrawingUtils) {\n\t\tconst result = this.faceLandmarker.detectForVideo(frame, performance.now());\n\t\tif (result.faceLandmarks[0]) {\n\t\t\tdrawingUtils.drawConnectors(result.faceLandmarks[0], FaceLandmarker.FACE_LANDMARKS_TESSELATION, { color: \"#00fff2ff\", lineWidth: .1 });\n\t\t\tdrawingUtils.drawLandmarks(result.faceLandmarks[0], { color: \"#00ff00\", lineWidth: .1, radius: .4 });\t\n\n\t\t\tthis.updateLandmarks(result.faceLandmarks[0], result.faceLandmarks[0] );\n\t\t}\n\n\t\tthis.blendshapeCategories = result.faceBlendshapes?.[0]?.categories; \n\n\t\tthis.blendshapeCategories?.forEach((category) => {\n\t\t\tthis.blendshapeMap.set(category.categoryName, category.score);\n\t\t});\n\t\t\n\t}\n\n\tbindShapeKeys(mesh: Mesh) {\n\t\tconst meshKeys = mesh.morphTargetDictionary; \n\n\t\treturn {\n\t\t\tupdate: (delta: number) => {\n\t\t\t\tthis.blendshapeCategories?.forEach((category) => {\n\t\t\t\t\tconst { categoryName, score } = category;\n\n\t\t\t\t\tif (!meshKeys?.hasOwnProperty(categoryName)) return;\n\n\t\t\t\t\t// Initialize if first time seeing this key\n\t\t\t\t\tif (this.smoothed[categoryName] === undefined)\n\t\t\t\t\t\tthis.smoothed[categoryName] = score;\n\n\t\t\t\t\t// Lerp toward target score\n\t\t\t\t\tconst factor = 1 - Math.pow(this.smoothing, delta);\n\t\t\t\t\tthis.smoothed[categoryName] += (score - this.smoothed[categoryName]) * factor;\n\n\t\t\t\t\tmesh.morphTargetInfluences![meshKeys[categoryName]] = this.smoothed[categoryName];\n\t\t\t\t});\n\n\t\t\t\t//eyes\n\t\t\t}\n\t\t}\n\t}\n\n\tbind( rig:Object3D ) {\n\n\t\tconst eyeL = new EyeRig(rig, \"L\");\n\t\tconst eyeR = new EyeRig(rig, \"R\");\n\t\tconst headBone = getBoneByName(rig, \"head\") ;\n \n\t\treturn {\n\t\t\tupdate: ( delta:number )=> {\n\t\t\t\t \n\t\t\t\teyeL.update(delta, this.blendshapeMap);\n\t\t\t\teyeR.update(delta, this.blendshapeMap); \n\t\t\t\t\n\t\t\t\tif(!headBone) return;\n\n\t\t\t\t//\n\t\t\t\tconst markEarL = v.copy( this.marks.earL.worldPosition );\n\t\t\t\tconst markEarR = v2.copy( this.marks.earR.worldPosition );\n\t\t\t\tconst headcenter = v3.subVectors(markEarL, markEarR).multiplyScalar(.5).add(markEarR);\n\t\t\t\tconst headForward = v4.subVectors(this.marks.noseTip.worldPosition, headcenter) ;\n\t\t\t\tconst headSideNormal = markEarL.sub(markEarR) ;\n\n\t\t\t\t\n\t\t\t\tconst headPosition = rootPosition( v5, headBone, rig); \n\n\t\t\t\tconst poleLookAt = headSideNormal.add( headPosition ).applyMatrix4(rig.matrixWorld);\n\t\t\t\tconst faceLookAt = headForward.add( headPosition ).applyMatrix4(rig.matrixWorld);\n\n\t\t\t\tlookAt( headBone, faceLookAt, poleLookAt,\"+x\" );\n\t\t\t\t \n\n\t\t\t\t// headLookAtPos.applyMatrix4(rig.matrixWorld);\n\t\t\t\t//headBone.lookAt( headLookAtPos );\n\t\t\t\t// \n\t\t\t}\n\t\t}\n\t\t\n\t}\n}\n\nclass EyeRig {\n\tprivate eyeBone:Object3D|undefined; \n\n\tprivate eyeLookOut:string;\n\tprivate eyeLookIn:string;\n\tprivate eyeLookUp:string;\n\tprivate eyeLookDown:string;\n\tprivate sign = 1;\n\t\n\tconstructor( readonly rig:Object3D, readonly side:\"L\"|\"R\" ) {\n\t\tthis.eyeBone = rig.getObjectByName(`eye${side}`) as Object3D; \n\n\t\tconst sideName = side == \"L\" ? \"Left\" : \"Right\";\n\t\tthis.eyeLookOut = `eyeLookOut${sideName}`;\n\t\tthis.eyeLookIn = `eyeLookIn${sideName}`;\n\t\tthis.eyeLookUp = `eyeLookUp${sideName}`;\n\t\tthis.eyeLookDown = `eyeLookDown${sideName}`;\n\n\t\tthis.sign = side == \"L\" ? -1 : 1;\n\t}\n\n\tupdate( delta:number, blendshapes: Map<string, number> ) {\n\t\tif( !this.eyeBone ) return; \n \n\t\tconst eye = rootPosition(v3, this.eyeBone, this.rig); \n\n\t\t\n\t\t\n\t\t// From MediaPipe blendshapes\n\t\tconst lookLeft = blendshapes.get(this.eyeLookOut) ?? 0; // or eyeLookInRight\n\t\tconst lookRight = blendshapes.get(this.eyeLookIn) ?? 0; // or eyeLookOutRight\n\t\tconst lookUp = blendshapes.get(this.eyeLookUp) ?? 0;\n\t\tconst lookDown = blendshapes.get(this.eyeLookDown) ?? 0;\n\n\t\t\n\t\t// Map to a -1..1 range\n\t\tconst sideMovement = lookRight - lookLeft // horizontal\n\t\tconst verticalMovement = lookDown - lookUp // vertical\n \n\n\t\tthis.eyeBone.rotation.y =( sideMovement * this.sign) / 2; \n\t\tthis.eyeBone.rotation.x = verticalMovement / 2; \n\t\t// // Then drive your rig bone with a target offset\n\t\t// const lookAtPos = eyeCenter\n\t\t// .add(eyeHorizontalDir ) // -sideMovement * eyeRange)\n\t\t// //.addScaledVector(eyeVerticalDir, verticalMovement * eyeRange/3)\n\t\t// .applyMatrix4(this.rig.matrixWorld);\n\n\t\t// this.eyeBone.lookAt(lookAtPos);\n\t\t// this.eyeBone.rotateX(Math.PI/2)\n\t}\n}","/**\n * The bone mapping to use for the rig.\n */\nexport type BoneMap = {\n\tfaceMesh:string\n\thead: string;\n\thips:string\n\tneck:string\n\ttorso:string\n\tarmL:string\n\tforearmL:string\n\n\tarmR:string\n\tforearmR:string\n\n\tthighL:string\n\tshinL:string\n\tfootL:string\n\ttoesL:string\n\n\tthighR:string\n\tshinR:string\n\tfootR:string\n\ttoesR:string\n\t \n\t\n\thandL:string\n\tindex1L:string\n\tindex2L:string\n\tindex3L:string\n\n\tmiddle1L:string\n\tmiddle2L:string\n\tmiddle3L:string\n\n\tring1L:string\n\tring2L:string\n\tring3L:string\n\n\tpinky1L:string\n\tpinky2L:string\n\tpinky3L:string\n\n\tthumb1L:string\n\tthumb2L:string\n\tthumb3L:string\n\n\thandR:string\n\tindex1R:string\n\tindex2R:string\n\tindex3R:string\n\n\tmiddle1R:string\n\tmiddle2R:string\n\tmiddle3R:string\n\n\tring1R:string\n\tring2R:string\n\tring3R:string\n\n\tpinky1R:string\n\tpinky2R:string\n\tpinky3R:string\n\n\tthumb1R:string\n\tthumb2R:string\n\tthumb3R:string\n \n}\n\nexport const defaultBoneMap:BoneMap = {\n\tfaceMesh:\"face\",\n\t\n\thead: \"head\",\n\thips:\"hips\",\n\tneck:\"neck\",\n\ttorso:\"torso\",\n\n\tarmL:\"upper_armL\",\n\tforearmL:\"forearmL\",\n\n\tarmR:\"upper_armR\",\n\tforearmR:\"forearmR\",\n\n\tthighL:\"thighL\",\n\tshinL:\"shinL\",\n\tfootL:\"footL\",\n\n\tthighR:\"thighR\",\n\tshinR:\"shinR\",\n\tfootR:\"footR\",\n\t \n\t\n\thandL:\"handL\",\n\tindex1L:\"index1L\",\n\tindex2L:\"index2L\",\n\tindex3L:\"index3L\",\n\n\tmiddle1L:\"middle1L\",\n\tmiddle2L:\"middle2L\",\n\tmiddle3L:\"middle3L\",\n\n\tring1L:\"ring1L\",\n\tring2L:\"ring2L\",\n\tring3L:\"ring3L\",\n\n\tpinky1L:\"pinky1L\",\n\tpinky2L:\"pinky2L\",\n\tpinky3L:\"pinky3L\",\n\n\tthumb1L:\"thumb1L\",\n\tthumb2L:\"thumb2L\",\n\tthumb3L:\"thumb3L\",\n\n\thandR:\"handR\",\n\tindex1R:\"index1R\",\n\tindex2R:\"index2R\",\n\tindex3R:\"index3R\",\n\n\tmiddle1R:\"middle1R\",\n\tmiddle2R:\"middle2R\",\n\tmiddle3R:\"middle3R\",\n\n\tring1R:\"ring1R\",\n\tring2R:\"ring2R\",\n\tring3R:\"ring3R\",\n\n\tpinky1R:\"pinky1R\",\n\tpinky2R:\"pinky2R\",\n\tpinky3R:\"pinky3R\",\n\n\tthumb1R:\"thumb1R\",\n\tthumb2R:\"thumb2R\",\n\tthumb3R:\"thumb3R\",\n \n}","/**\n * A list of blend shape key names that are used by mediapipe face mesh. \n */\nexport const blendShapeKeyNames = [\n \"eyeBlinkLeft\",\n \"eyeBlinkRight\",\n \"eyeLookDownLeft\",\n \"eyeLookDownRight\",\n \"eyeLookInLeft\",\n \"eyeLookInRight\",\n \"eyeLookOutLeft\",\n \"eyeLookOutRight\",\n \"eyeLookUpLeft\",\n \"eyeLookUpRight\",\n \"eyeSquintLeft\",\n \"eyeSquintRight\",\n \"eyeWideLeft\",\n \"eyeWideRight\",\n \"browDownLeft\",\n \"browDownRight\",\n \"browInnerUp\",\n \"browOuterUpLeft\",\n \"browOuterUpRight\",\n \"noseSneerLeft\",\n \"noseSneerRight\",\n \"cheekPuff\",\n \"cheekSquintLeft\",\n \"cheekSquintRight\",\n \"jawForward\",\n \"jawLeft\",\n \"jawOpen\",\n \"jawRight\",\n \"mouthClose\",\n \"mouthDimpleLeft\",\n \"mouthDimpleRight\",\n \"mouthFrownLeft\",\n \"mouthFrownRight\",\n \"mouthFunnel\",\n \"mouthLeft\",\n \"mouthLowerDownLeft\",\n \"mouthLowerDownRight\",\n \"mouthPressLeft\",\n \"mouthPressRight\",\n \"mouthPucker\",\n \"mouthRight\",\n \"mouthRollLower\",\n \"mouthRollUpper\",\n \"mouthShrugLower\",\n \"mouthShrugUpper\",\n \"mouthSmileLeft\",\n \"mouthSmileRight\",\n \"mouthStretchLeft\",\n \"mouthStretchRight\",\n \"mouthUpperUpLeft\",\n \"mouthUpperUpRight\",\n \"tongueOut\"\n]","import * as THREE from \"three\";\nimport { BoneMap, defaultBoneMap } from \"../BoneMapping\";\nimport { GLTFExporter } from \"three/examples/jsm/Addons.js\";\nimport { blendShapeKeyNames } from \"../blendShapeKeyNames\";\n\ntype BoneRef = {\n ref: THREE.Bone;\n name: string;\n\tnormalizedName: string;\n};\n\n/**\n * Records the local rotation of the bones in the rig. The name used will be the normalized bone name.\n * @param rigRoot\n * @param magging\n * @param fps\n * @returns\n */\nexport function createRigRecorder(\n rigRoot: THREE.Object3D,\n magging: BoneMap,\n fps = 30,\n) {\n const bones: BoneRef[] = [];\n const faceMesh = rigRoot.getObjectByName(\n magging.faceMesh,\n ) as THREE.SkinnedMesh;\n const usedBlendShapeKeys = new Set<string>();\n\n //\n // collect used blend shape keys...\n //\n if (faceMesh?.morphTargetDictionary) {\n for (const key in faceMesh.morphTargetDictionary) {\n if (blendShapeKeyNames.includes(key)) {\n usedBlendShapeKeys.add(key);\n }\n }\n }\n\n\n\t//\n\t// look for the bones\n\t//\n\tconst boneKeys = Object.keys(magging);\n\trigRoot.traverse( o => {\n\t\tif(o instanceof THREE.Bone)\n\t\t{\n\t\t\t// check if the bone name is in the mapping\n\t\t\tconst key = boneKeys.find(k => o.name.indexOf( magging[k as keyof typeof magging] )=== 0 );\n\t\t\tif(key)\n\t\t\t{\n\t\t\t\tbones.push({\n\t\t\t\t\tref: o,\n\t\t\t\t\tname: o.name, \n\t\t\t\t\tnormalizedName: key,\n\t\t\t\t}); \n\t\t\t}\n\t\t}\n\t});\n \n\n\tconst times :number[] = [];\n const boneTracks = new Map<\n string,\n number[] //vec4 array\n >();\n\n\tconst blendShapeTracks = new Map<\n\t\tstring,\n\t\tnumber[]\n\t>();\n\n let recording = false;\n let startTime = 0;\n\n function start() {\n boneTracks.clear();\n\t\tblendShapeTracks.clear();\n\t\ttimes.length = 0;\n startTime = performance.now() / 1000;\n recording = true;\n }\n\n function captureFrame() {\n if (!recording) return;\n\n const time = performance.now() / 1000 - startTime;\n\n\t\ttimes.push(time);\n\n for (const bone of bones) {\n if (!boneTracks.has(bone.name)) {\n boneTracks.set(bone.name, []);\n }\n\n const track = boneTracks.get(bone.name)!; \n\t\t\t \n const q = bone.ref.quaternion;\n track.push(q.x, q.y, q.z, q.w);\n } \n\n\t\tfor (const key of usedBlendShapeKeys) {\n\t\t\tif (!blendShapeTracks.has(key)) {\n\t\t\t\tblendShapeTracks.set(key, []);\n\t\t\t}\n\n\t\t\tconst track = blendShapeTracks.get(key)!; \n\n\t\t\tconst keyIndex = faceMesh.morphTargetDictionary![key];\n\t\t\tconst v = faceMesh.morphTargetInfluences![keyIndex];\n\t\t\ttrack.push(v);\n\t\t}\n }\n\n\t/** \n\t * @param name name of the resulting clip\n\t * @returns \n\t */\n function stop(name = \"RecordedClip\") {\n recording = false;\n\n const keyframeTracks: THREE.KeyframeTrack[] = [];\n\n\t\t\n \n for (const [boneName, data] of boneTracks) {\n keyframeTracks.push(\n new THREE.QuaternionKeyframeTrack(\n `${boneName}.quaternion`,\n times,\n data,\n ),\n );\n } \n\n\t\tfor (const [key, data] of blendShapeTracks) {\n\t\t\tkeyframeTracks.push(\n\t\t\t\tnew THREE.NumberKeyframeTrack(\n\t\t\t\t\t`${defaultBoneMap.faceMesh}.morphTargetInfluences[${key}]`,\n\t\t\t\t\ttimes,\n\t\t\t\t\tdata,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n const clip = new THREE.AnimationClip(name, -1, keyframeTracks);\n \n\n return {\n\t\t\tclip,\n\t\t\tsaveToFile:() => {\n\t const exporter = new GLTFExporter();\n\t exporter.parse(\n\t rigRoot,\n\t (gltf) => {\n\t // binary .glb\n\t const blob = new Blob([gltf], {\n\t type: \"model/gltf-binary\",\n\t });\n\t const url = URL.createObjectURL(blob);\n\n\t const a = document.createElement(\"a\");\n\t a.href = url;\n\t a.download = name + \".glb\";\n\t a.click();\n\t },\n\t (error) => {\n\t console.error(error);\n\t },\n\t {\n\t binary: true,\n\t animations: [clip],\n\t },\n\t );\n\t }\n\t\t};\n }\n\n return { start, captureFrame, stop, isRecording: () => recording };\n}\n","import {\n DrawingUtils,\n FilesetResolver,\n HandLandmarkerOptions,\n PoseLandmarker,\n} from \"@mediapipe/tasks-vision\";\nimport * as THREE from \"three/webgpu\";\nimport { loadPoseTracker } from \"./PoseTracker\";\nimport { loadHandTracker } from \"./HandTracker\"; \nimport { loadFaceTracker } from \"./FaceTracker\";\nimport { BoneMap, defaultBoneMap } from \"./BoneMapping\";\nimport { createRigRecorder } from \"./recoding/recorder\";\n\nexport type TrackerConfig = {\n /**\n * Use an image file. Useful to test a particular pose.\n */\n debugFrame?: string;\n\n /**\n * Scale of the video display\n */\n displayScale: number;\n\n /**\n * If the body pose should ignore the legs\n */\n ignoreLegs: boolean;\n\n /**\n * Use a video file instead of the webcam\n */\n debugVideo?: string;\n\n /**\n * Don't track the face\n */\n ignoreFace: boolean;\n\n /**\n * @see https://ai.google.dev/edge/mediapipe/solutions/vision/hand_landmarker/web_js#configuration_options\n */\n handsTrackerOptions: HandLandmarkerOptions | undefined;\n\n\tmodelPaths?: {\n\t\tvision?:string;\n\t\tpose?: string;\n\t\thand?: string;\n\t\tface?: string;\n\t}\n};\n\nexport interface BindingHandler {\n\n\t/**\n\t * Updates the rig with the latest landmarks.\n\t * @param delta The time elapsed since the last frame in seconds.\n\t */\n update: (delta: number) => void;\n\n}\n\nexport interface RecorderHandler { \n\t/**\n\t * Starts recording the rig's movement and active shape keys ( from media pipe ).\n\t */\n\tstartRecording: VoidFunction;\n\n\t/**\n\t * Stops recording the rig's movement.\n\t * @returns A function that can be called to SAVE the recording to a file.\n\t */\n\tstopRecording: ReturnType<typeof createRigRecorder>['stop'];\n\n\t/**\n\t * Checks if the rig is currently recording.\n\t * @returns True if the rig is recording, false otherwise.\n\t */\n\tisRecording: () => boolean;\n}\n\nexport interface RecordableBindingHandler extends BindingHandler, RecorderHandler {}\n\n// Check if webcam access is supported.\nconst hasGetUserMedia = () => !!navigator.mediaDevices?.getUserMedia;\n\nexport async function setupTracker(config?: Partial<TrackerConfig>) {\n const $cfg = {\n debugFrame: undefined,\n displayScale: 1,\n ignoreLegs: false,\n debugVideo: undefined,\n ignoreFace: false,\n\t\tmodelPaths: {\n\t\t\tvision: \"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.3/wasm\",\n\t\t\tpose: \"https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task\",\n\t\t\thand: \"https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task\",\n\t\t\tface: \"https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task\",\n\t\t},\n ...config,\n };\n let video: HTMLVideoElement | undefined;\n const vision = await FilesetResolver.forVisionTasks( $cfg.modelPaths.vision ?? \"/wasm\" );\n const poseTracker = await loadPoseTracker(vision, {\n ignoreLegs: $cfg.ignoreLegs,\n\t\tmodelPath: $cfg.modelPaths.pose!,\n });\n const handsTracker = await loadHandTracker(vision, {\n leftWrist: () => poseTracker.leftWristNormalizedPosition,\n rightWrist: () => poseTracker.rightWristNormalizedPosition,\n\t\tmodelPath: $cfg.modelPaths.hand!,\n ...config?.handsTrackerOptions,\n });\n const faceTracker = $cfg.ignoreFace\n ? undefined\n : await loadFaceTracker(vision, { modelPath: $cfg.modelPaths.face! });\n\n //#region setup Camera and Canvas...\n\tconst viewport = document.createElement(\"div\");\n\tviewport.style.position = \"absolute\";\n\tviewport.style.top = \"0px\";\n\tviewport.style.left = \"0px\"; \n\tviewport.style.zIndex = \"21\";\n\tviewport.classList.add(\"three-mediapipe-rig\")\n\tdocument.body.appendChild(viewport);\n\n const canvasElement = document.createElement(\"canvas\");\n const canvasCtx = canvasElement.getContext(\"2d\")!;\n const drawingUtils = new DrawingUtils(canvasCtx);\n\n canvasElement.style.zIndex = \"22\";\n canvasElement.style.position = \"absolute\";\n canvasElement.style.top = \"0px\";\n canvasElement.style.left = \"0px\";\n canvasElement.style.pointerEvents = \"none\";\n viewport.appendChild(canvasElement);\n\n function predict(source: TexImageSource) {\n canvasCtx.save();\n canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);\n poseTracker?.predict(source, drawingUtils);\n handsTracker?.left.predict(source, drawingUtils);\n handsTracker?.right.predict(source, drawingUtils);\n faceTracker?.predict(source, drawingUtils);\n canvasCtx.restore();\n }\n\n function initializeVideo() {\n video = document.createElement(\"video\");\n viewport.appendChild(video);\n\n let lastVideoTime = -1;\n\n video.style.zIndex = \"21\";\n video.style.position = \"absolute\";\n video.style.top = \"0px\";\n video.style.left = \"0px\";\n\n if ($cfg.debugVideo) {\n video.src = $cfg.debugVideo;\n video.controls = true;\n video.loop = true;\n video.muted = true;\n video.controls = true;\n video.play();\n }\n\n function predictWebcam() {\n if (lastVideoTime !== video!.currentTime) {\n predict(video!);\n lastVideoTime = video!.currentTime;\n }\n window.requestAnimationFrame(predictWebcam);\n }\n\n video.addEventListener(\"loadeddata\", () => {\n video!.width = video!.videoWidth * $cfg.displayScale;\n video!.height = video!.videoHeight * $cfg.displayScale;\n canvasElement.width = video!.videoWidth;\n canvasElement.height = video!.videoHeight;\n canvasElement.style.height = video!.height + \"px\";\n canvasElement.style.width = video!.width + \"px\";\n\n window.requestAnimationFrame(predictWebcam);\n });\n }\n\n if ($cfg.debugFrame) {\n //#region Debug Frame mode — use a static image\n const img = document.createElement(\"img\");\n img.src = $cfg.debugFrame;\n img.style.zIndex = \"21\";\n img.style.position = \"absolute\";\n img.style.top = \"0px\";\n img.style.left = \"0px\";\n document.body.appendChild(img);\n\n img.addEventListener(\"load\", () => {\n img.width = img.naturalWidth * $cfg.displayScale;\n img.height = img.naturalHeight * $cfg.displayScale;\n canvasElement.width = img.naturalWidth;\n canvasElement.height = img.naturalWidth;\n canvasElement.style.width = img.width + \"px\";\n canvasElement.style.height = img.height + \"px\";\n\n function predictFrame() {\n predict(img);\n }\n\n window.requestAnimationFrame(predictFrame);\n });\n //#endregion\n } else if( $cfg.debugVideo ) {\n //#region Video mode\n initializeVideo();\n //#endregion\n } \n\n return {\n poseTracker,\n handsTracker,\n faceTracker,\n video,\n\n\t\t/**\n\t\t * A div that contains the video and canvas used to display the landmarks stacked on top of each other.\n\t\t */\n\t\tdomElement: viewport,\n\n\t\t/**\n\t\t * Start the webcam feed. This must be initiated by a user triggered event ( a click on a button ) due to security reasons. \n\t\t */\n start: async () => {\n\t\t\tlet stopped = false;\n\n if (!hasGetUserMedia()) {\n throw new Error(\"Webcam not supported\");\n }\n\n if (!video) {\n initializeVideo();\n }\n\n let stream: Awaited<MediaStream> | undefined;\n\n\t\t\tfunction onTrackEnded(video: HTMLVideoElement): void {\n\t\t\t\tconsole.warn('Camera track ended, attempting recovery...');\n\t\t\t\tstopCamera(video);\n\t\t\t\tretryWithBackoff(video);\n\t\t\t}\n\n\t\t\tfunction stopCamera(video: HTMLVideoElement): void {\n\t\t\t\tstream?.getTracks().forEach(t => t.stop());\n\t\t\t\tstream = undefined;\n\t\t\t\tvideo.srcObject = null;\n\t\t\t}\n\n\t\t\tasync function retryWithBackoff(video: HTMLVideoElement, attempt = 0): Promise<void> {\n\t\t\t const MAX_ATTEMPTS = 5;\n\t\t\t const delay = Math.min(1000 * 2 ** attempt, 16000); // 1s, 2s, 4s, 8s, 16s\n\n\t\t\t if (attempt >= MAX_ATTEMPTS) { \n\t\t\t throw new Error('Camera recovery failed after max attempts');\n\t\t\t }\n\n\t\t\t await new Promise(res => setTimeout(res, delay)); \n\n\t\t\t if(stopped) return;\n\n\t\t\t try {\n\t\t\t await startCamera(video);\n\t\t\t console.log('Camera recovered successfully');\n\t\t\t } catch {\n\t\t\t retryWithBackoff(video, attempt + 1);\n\t\t\t }\n\t\t\t}\n\n\t\t\tasync function startCamera(video: HTMLVideoElement): Promise<void> {\n\t\t\t try {\n\t\t\t stream = await navigator.mediaDevices.getUserMedia({ video: true });\n\t\t\t video.srcObject = stream;\n\t\t\t await video.play();\n\n\t\t\t // Listen for track ending (camera disconnected / permission revoked)\n\t\t\t stream.getVideoTracks().forEach(track => {\n\t\t\t track.addEventListener('ended', () => onTrackEnded(video));\n\t\t\t });\n\n\t\t\t } catch (err) {\n\t\t\t handleCameraError(err, video);\n\t\t\t }\n\t\t\t}\n\n\t\t\tfunction handleCameraError(err: unknown, video: HTMLVideoElement): void {\n\t\t\t if (err instanceof DOMException) {\n\t\t\t switch (err.name) {\n\t\t\t case 'NotAllowedError':\n\t\t\t throw new Error('Permission denied — prompt user to allow camera');\n\t\t\t break;\n\t\t\t case 'NotFoundError':\n\t\t\t console.error('No camera found — retry when device is connected');\n\t\t\t retryWithBackoff(video); // device might be plugged in later\n\t\t\t break;\n\t\t\t case 'NotReadableError':\n\t\t\t console.error('Camera in use by another app');\n\t\t\t retryWithBackoff(video);\n\t\t\t break;\n\t\t\t default:\n\t\t\t console.error('Camera error:', err.message);\n\t\t\t retryWithBackoff(video);\n\t\t\t }\n\t\t\t }\n\t\t\t} \n\n await startCamera(video!);\n\n\t\t\treturn {\n\t\t\t\tstop:()=>{\n\t\t\t\t\tstopped = true;\n\t\t\t\t\tstopCamera(video!);\n\t\t\t\t}\n\t\t\t}\n },\n\n /**\n * Binds the bones of the rig to the landmarks provided by media pipe.\n * @param rig The rig that contains all the bones and skinned meshes of your character.\n\t\t * @param magging The bone mapping to use for the rig.\n */\n bind: ( rig: THREE.Object3D, magging?:BoneMap ) => {\n\n\t\t\tmagging = magging || defaultBoneMap;\n\n const bodyBindin = poseTracker.bind(rig, magging);\n const leftHandBinding = handsTracker.left.bind(rig, magging);\n const rightHandBinding = handsTracker.right.bind(rig, magging);\n let faceKeys: BindingHandler | undefined;\n const faceRig = faceTracker?.bind(rig);\n\n rig.traverse((child) => {\n if (\n child instanceof THREE.Mesh &&\n child.name.indexOf( magging.faceMesh ) === 0\n ) {\n child.frustumCulled = false;\n faceKeys = faceTracker?.bindShapeKeys(child);\n }\n });\n\n\t\t\tconst recorder = createRigRecorder(rig, magging)\n\n return {\n\n\t\t\t\t/**\n\t\t\t\t * Will save the tracked movement of the rig to an animation clip.\n\t\t\t\t * Only the bones moved by the bone mapping will be recorded.\n\t\t\t\t */\n\t\t\t\tstartRecording: recorder.start,\n\t\t\t\tstopRecording: recorder.stop,\n\t\t\t\tisRecording: () => recorder.isRecording(),\n\n update: (delta: number) => {\n bodyBindin.update(delta);\n leftHandBinding.update(delta);\n rightHandBinding.update(delta);\n faceKeys?.update(delta);\n faceRig?.update(delta);\n\n\t\t\t\t\tif( recorder.isRecording() ) {\n\t\t\t\t\t\trecorder.captureFrame()\n\t\t\t\t\t}\n },\n } as RecordableBindingHandler;\n },\n };\n}\n"],"names":["poleDir","Vector3","objectPosition","XAxis","XAxisNeg","YAxis","YAxisNeg","ZAxis","pole","lookDir","v","correction","Quaternion","worldQuat","lookAt","object","target","poleTarget","poleAxis","axis","currentPole","lookAxisDir","desiredPoleDir","cross","angle","THREE","A","B","Tracker","points","debugConnections","__publicField","key","Mark","landmarks","debugLandmarks","debugDrawer","point","mark","o","Ghost","_a","source","drawingUtils","delta","objects","normal","root","offset","objectLookAtGoal","polePosition","ghost","rig","name","speed","rootPosition","out","cleanBoneName","getBoneByName","bone","Bone","loadPoseTracker","vision","config","poseLandmarker","PoseLandmarker","PoseTracker","poseMarks","C","D","E","lookGoal","poleGoal","result","magging","map","v2","syncBone","from","to","sideAxis","hipsDir","sideHips","sideShoulders","sideHead","loadHandTracker","landmarker","HandLandmarker","isMyWrist","myWrist","otherWrist","handWrist","HandsTracker","handMarks","fingerKeys","v1","v3","v4","v5","v6","currSide","HALF_PI","DOWN","handLandmarker","side","hand","wrist","markToBone","palmNormal","parlmDir","palmSide","palmLookAt","polPosition","palmGhost","palmForward","sideGoal","negateSideGoal","i","myDir","bonePos","poleOffset","fingerGhost","addBind","boneName","markName","loadFaceTracker","cfg","faceLandmarker","FaceLandmarker","FaceTracker","faceMarks","frame","_b","_c","category","mesh","meshKeys","categoryName","score","factor","eyeL","EyeRig","eyeR","headBone","markEarL","markEarR","headcenter","headForward","headSideNormal","headPosition","poleLookAt","faceLookAt","sideName","blendshapes","lookLeft","lookRight","lookUp","lookDown","sideMovement","verticalMovement","defaultBoneMap","blendShapeKeyNames","createRigRecorder","rigRoot","fps","bones","faceMesh","usedBlendShapeKeys","boneKeys","k","times","boneTracks","blendShapeTracks","recording","startTime","start","captureFrame","time","track","q","keyIndex","stop","keyframeTracks","data","clip","GLTFExporter","gltf","blob","url","a","error","hasGetUserMedia","setupTracker","$cfg","video","FilesetResolver","poseTracker","handsTracker","faceTracker","viewport","canvasElement","canvasCtx","DrawingUtils","predict","initializeVideo","lastVideoTime","predictWebcam","img","predictFrame","stopped","stream","onTrackEnded","stopCamera","retryWithBackoff","t","attempt","delay","res","startCamera","err","handleCameraError","bodyBindin","leftHandBinding","rightHandBinding","faceKeys","faceRig","child","recorder"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"three-mediapipe-rig.js","sources":["../src/tracking/util/lookAt.ts","../src/tracking/Tracker.ts","../src/tracking/util/getRootPosition.ts","../src/tracking/util/cleanBoneName.ts","../src/tracking/util/getBoneByName.ts","../src/tracking/PoseTracker.ts","../src/tracking/HandTracker.ts","../src/tracking/FaceTracker.ts","../src/tracking/BoneMapping.ts","../src/tracking/blendShapeKeyNames.ts","../src/tracking/recoding/recorder.ts","../src/tracking/TrackerManager.ts"],"sourcesContent":["import { Object3D, Quaternion, Vector3 } from \"three/webgpu\";\n\nconst poleDir = new Vector3();\nconst objectPosition = new Vector3();\n\nconst XAxis = new Vector3(1,0,0);\nconst XAxisNeg = new Vector3(-1,0,0);\nconst YAxis = new Vector3(0,1,0); \nconst YAxisNeg = new Vector3(0,-1,0); \nconst ZAxis = new Vector3(0,0,1); \nconst ZAxisNeg = new Vector3(0,0,-1); \n\nconst pole = new Vector3();\nconst lookDir = new Vector3();\n\nconst v = new Vector3();\nconst correction = new Quaternion();\nconst worldQuat = new Quaternion();\n\nexport type LookAtPoleAxis = \"+x\"|\"+y\"|\"-x\"|\"-y\"\n\n/**\n * Will point the Z axis of object at target and the X or Y axis in the general direction of the pole target\n * @param object The object to rotate\n * @param target The point to look at ( in world coord )\n * @param poleTarget The goal of the pole axis ( in world coord )\n * @param poleAxis The axis to use as the pole axis ( z is the one pointing at the target )\n */\nexport function lookAt( object:Object3D, target:Vector3, poleTarget:Vector3, poleAxis:LookAtPoleAxis = \"+x\" )\n{ \n\t//\n\t// look at target (handles parent transforms internally)\n\t// \n\tobject.lookAt(target);\n\n\tconst axis = poleAxis==\"+x\"?XAxis: poleAxis==\"-x\"?XAxisNeg: poleAxis==\"+y\"?YAxis: YAxisNeg;\n\n\tobject.getWorldPosition(objectPosition);\n\tobject.getWorldQuaternion(worldQuat);\n\n\tpoleDir.subVectors(poleTarget, objectPosition).normalize();\n\n\t// direction in which the pole axis is currently pointing (in world space)\n\tpole.copy(axis).applyQuaternion(worldQuat);\n\n\tconst currentPole = pole;\n\n\t// look direction in world space\n\tconst lookAxisDir = lookDir.copy( ZAxis ).applyQuaternion(worldQuat);\n\n\t// project desired pole direction onto the plane perpendicular to the look axis\n\tconst desiredPoleDir = poleDir.clone().addScaledVector(lookAxisDir, -poleDir.dot(lookAxisDir)).normalize();\n\n\t// signed angle between current pole and desired pole around the look axis\n\tconst cross = v.crossVectors(currentPole, desiredPoleDir);\n\tconst angle = Math.atan2(cross.dot(lookAxisDir), currentPole.dot(desiredPoleDir));\n\n\t// The correction is a spin around the look axis (local Z after lookAt).\n\t// Since lookAt aligned local Z to the target, we can apply around the local Z axis directly.\n\tcorrection.setFromAxisAngle(ZAxis, angle);\n\tobject.quaternion.multiply(correction);\n}","import * as THREE from \"three/webgpu\";\nimport {\n Landmark,\n NormalizedLandmark,\n\tDrawingUtils, \n} from \"@mediapipe/tasks-vision\"; \nimport { lookAt, LookAtPoleAxis } from \"./util/lookAt\";\n\n \n\nconst v = new THREE.Vector3();\nconst A = new THREE.Vector3();\nconst B = new THREE.Vector3();\nconst C = new THREE.Vector3();\n\nexport class Tracker<T extends Record<string, number|number[]> > {\n\tprivate objectGhost : Map<THREE.Object3D, Ghost> ;\n\treadonly root:THREE.Object3D;\n\n\t/**\n\t * per landmark index, it points to it's object3D equivalent.\n\t */\n\tprotected marks: { [name in keyof T]: Mark } = {} as { [name in keyof T]: Mark };\n\n\tconstructor( protected readonly points:T, private readonly debugConnections?:{start:number,end:number}[] ){\n\t\tthis.root = new THREE.Object3D();\n\t\tthis.objectGhost = new Map();\n\n\t\t// por each key in points\n\t\tfor( let key in this.points ){\n\t\t\tthis.marks[key] = new Mark();\n \n\t\t\tthis.root.add(this.marks[key]);\n\t\t}\n\t}\n\n\tprotected updateLandmarks( landmarks:Landmark[], debugLandmarks?:NormalizedLandmark[], debugDrawer?:DrawingUtils ) {\n\t\tfor( let key in this.points ){\n\t\t\tconst point = this.points[key];\n\t\t\tconst mark = this.marks[key];\n\t\t\tif( mark ){\n\t\t\t\tif( point instanceof Array )\n\t\t\t\t{\n\t\t\t\t\t\n\t\t\t\t\tv.copy( landmarks[ point[0] ] ) \n\t\t\t\t\tmark.position.copy( landmarks[ point[1] ] ).sub( v ).divideScalar(2).add(landmarks[ point[0] ]);\n\t\t\t\t\t\n\t\t\t\t\tif( point.length==4 )\n\t\t\t\t\t{\n\t\t\t\t\t\tv.subVectors(\n\t\t\t\t\t\t\tlandmarks[ point[3] ],\n\t\t\t\t\t\t\tlandmarks[ point[2] ]\n\t\t\t\t\t\t).divideScalar(2).add(landmarks[ point[2] ]) \n\n\t\t\t\t\t\t.sub( mark.position )\n\t\t\t\t\t\t.divideScalar(2) \n\n\t\t\t\t\t\tmark.position.add( v );\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t}\n\t\t\t\telse \n\t\t\t\t{\n\t\t\t\t\tmark.position.copy( landmarks[ point as number ] )\n\t\t\t\t}\n \n\t\t\t}\n\t\t}\n\n\t\tif( debugDrawer && debugLandmarks )\n\t\t{ \n\t\t\t// debugDrawer.drawLandmarks(debugLandmarks, {\n\t\t\t// \tradius: (data) =>\n\t\t\t// \t\tDrawingUtils.lerp(data.from!.z, -0.15, 0.1, 5, 1),\n\t\t\t// \tlineWidth:1\n\t\t\t// });\n\t\t\tdebugDrawer.drawConnectors(\n\t\t\t\tdebugLandmarks,\n\t\t\t\tthis.debugConnections,\n\t\t\t\t{\n\t\t\t\t\tlineWidth:1\n\t\t\t\t}\n\t\t\t); \n\t\t}\n\t}\n\n\tprotected getGhost( object:THREE.Object3D ){\n\t\tif( !this.objectGhost.has(object)) \n\t\t{\n\t\t\tconst o = new Ghost()\n\n\t\t\to.position.copy(object.position)\n\t\t\to.quaternion.copy(object.quaternion)\n\t\t\tobject.parent?.add(o);\n\n\t\t\tthis.objectGhost.set(object, o)\n\t\t} \n\t\treturn this.objectGhost.get(object)!;\n\t}\n\n\tpredict( source:TexImageSource, drawingUtils:DrawingUtils ){\n\t\tthrow new Error(\"Method 'predict' must be implemented.\");\n\t}\n\n\tsync ( delta:number, objects: [THREE.Object3D, keyof T, keyof T, LookAtPoleAxis][] ) {\n\t\tthrow new Error(\"Method 'sync' must be implemented.\"); \n\t}\n\n\ttest( key:keyof T ){\n\t\tthis.marks[key]!.position.set(1,2,3)\n\t}\n\n\tprotected syncObjects(objects: [THREE.Object3D, keyof T, keyof T,LookAtPoleAxis][], delta:number, normal:THREE.Vector3 ){\n\t\tfor( const [object, root, target, poleAxis] of objects ){\n\n\t\t\t//\n\t\t\t// position A and B where the landmarks are\n\t\t\t//\n\t\t\tthis.marks[target].getWorldPosition(B)\n\t\t\tthis.marks[root].getWorldPosition(A)\n\n\t\t\t//\n\t\t\t// calcuate the offset\n\t\t\t//\n\t\t\tconst offset = B.sub(A); // offset from root to taget in world units\n\n\t\t\t//\n\t\t\t// now position A in object position\n\t\t\t//\n\t\t\tobject.getWorldPosition(A)\n\n\t\t\t//\n\t\t\t// and displace it by the offset ( this will be the look at target )\n\t\t\t//\n\t\t\tA.add(offset);\n\n\t\t\t \n\t\t\tconst objectLookAtGoal = A;\n\t\t\tconst polePosition = object.getWorldPosition(B).sub( normal )\n\n\t\t\tconst ghost = this.getGhost(object);\n \n\n\t\t\t \n\t\t\t\tlookAt( ghost, objectLookAtGoal, polePosition, poleAxis);\n\n\t\t\t\tghost.rotateX( Math.PI/2) \n\t\t\t\n\t\t\t//ghost.rotateY( Math.PI/2)\n\n\t\t\tobject.position.lerp(ghost.position, delta * 4)\n\t\t\tobject.quaternion.slerp(ghost.quaternion, delta * 4) \n\t\t}\n\t}\n\n\tprotected getBone( rig:THREE.Object3D, name:string ){\n\t\treturn rig.getObjectByName(name.replace(/[\\.\\:]/g,\"\")) ;\n\t}\n}\n\n// const t = {\n// \tpepe:[1,2]\n// }\n// const d = new Tracker(t)\n// d.test(\"pepe\")\n\nclass Mark extends THREE.Mesh {\n\tprivate _worldPosition = new THREE.Vector3();\n\tconstructor() {\n\t\tsuper(new THREE.SphereGeometry(0.01,3,3), new THREE.MeshStandardMaterial({ color: 0xff0000, wireframe:true }));\n\t\tthis.add( new THREE.AxesHelper(0.001))\n\t}\n\n\tget worldPosition(){\n\t\tthis.getWorldPosition(this._worldPosition);\n\t\treturn this._worldPosition;\n\t}\n}\n\nclass Ghost extends THREE.Object3D { \n\tlerp( target:THREE.Object3D, delta:number, speed = 8 )\n\t{\n\t\ttarget.position.lerp(this.position, delta * speed)\n\t\ttarget.quaternion.slerp(this.quaternion, delta * speed) \n\t}\n}","import { Object3D, Vector3 } from \"three/webgpu\";\n\n\n/**\n * Gets the position of `object` relative to `root`.\n * @param out \n * @param object \n * @param root \n * @returns \n */\nexport function rootPosition( out:Vector3, object:Object3D, root:Object3D ) {\n\n\troot.worldToLocal( object.getWorldPosition(out) )\n\n\treturn out;\n}","export function cleanBoneName(name:string) {\n\treturn name.replace(/[\\.\\:]/g,\"\")\n}","import { Bone, Object3D } from \"three\";\nimport { cleanBoneName } from \"./cleanBoneName\";\n\nexport function getBoneByName(rig:Object3D, name:string) {\n\tlet bone:Bone|undefined;\n\tname = cleanBoneName(name); \n\t\n\trig.traverse( (o:Object3D) => {\n\t\tif( o.name.indexOf(name)===0 && o instanceof Bone ) bone = o as Bone;\n\t})\n\n\tif( !bone ) console.log(\"Bone not found: \", name, rig.name)\n\n\treturn bone;\n}","import {\n DrawingUtils,\n NormalizedLandmark,\n PoseLandmarker,\n} from \"@mediapipe/tasks-vision\"; \nimport * as THREE from \"three/webgpu\";\nimport { lookAt, LookAtPoleAxis } from \"./util/lookAt\";\nimport { Tracker } from \"./Tracker\";\nimport { rootPosition } from \"./util/getRootPosition\";\nimport { getBoneByName } from \"./util/getBoneByName\";\nimport { BoneMap } from \"./BoneMapping\";\n\nexport async function loadPoseTracker(vision: any, config?:Partial<PoseTrackerConfig>) {\n\tconst poseLandmarker = await PoseLandmarker.createFromOptions(vision, {\n baseOptions: { \n\t\t\tmodelAssetPath: config?.modelPath ?? \"pose_landmarker_lite.task\",\n //modelAssetPath: `https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task`,\n //modelAssetPath: \"https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_heavy/float16/latest/pose_landmarker_heavy.task\",\n delegate: \"GPU\",\n },\n runningMode: \"VIDEO\",\n numPoses: 1,\n });\n\n\treturn new PoseTracker(poseLandmarker, config);\n} \n\n/**\n * Points derived from https://ai.google.dev/static/mediapipe/images/solutions/pose_landmarks_index.png\n * If the array has 2 elements, the point is between those 2 landmarks.\n * If it has 4, the point is at the center of those 4 landmarks.\n */\nconst poseMarks = {\n\t\t\thips: [24,23],\n\t\t\tneck: [12,11],\n\t\t\tleftLeg: 23,\n\t\t\tleftKnee:25,\n\t\t\tleftFoot: 27,\n\t\t\tleftToes: 31,\n\t\t\tleftArm: 11,\n\t\t\tleftElbow: 13,\n\t\t\tleftWrist: 15,\n\t\t\trightLeg: 24,\n\t\t\trightKnee: 26,\n\t\t\trightFoot: 28,\n\t\t\trightToes: 32,\n\t\t\trightArm: 12,\n\t\t\trightElbow: 14,\n\t\t\trightWrist: 16, \n\t\t\thead: [8,7] //between the ears\n\t\t\t, mouth:[10,9]\n\t\t\t, torso: [24,23, 12,11] //at the center of the torso\n\t\t\t, leftEar: 7\n\t\t\t, rightEar: 8\n\t\t} ;\n\ntype MarkKey = keyof typeof poseMarks;\n\ntype BoneBinding = [THREE.Object3D, MarkKey, MarkKey,LookAtPoleAxis]\n\nconst A = new THREE.Vector3();\nconst B = new THREE.Vector3();\nconst C = new THREE.Vector3();\nconst D = new THREE.Vector3();\nconst E = new THREE.Vector3();\nconst lookGoal = new THREE.Vector3();\nconst poleGoal = new THREE.Vector3();\n\ntype PoseTrackerConfig = {\n\tignoreLegs:boolean\n\tmodelPath:string\n}\n\n/**\n * @see https://ai.google.dev/edge/mediapipe/solutions/vision/pose_landmarker\n */\nclass PoseTracker extends Tracker<typeof poseMarks> {\n\tprivate _leftWristNormalizedPosition!:NormalizedLandmark;\n\tprivate _rightWristNormalizedPosition!:NormalizedLandmark;\n\n\t/**\n\t * Position of the left wrist in normalized coordinates (0..1)\n\t */\n\tget leftWristNormalizedPosition() { return this._leftWristNormalizedPosition; }\n\n\t/**\n\t * Position of the right wrist in normalized coordinates (0..1)\n\t */\n\tget rightWristNormalizedPosition() { return this._rightWristNormalizedPosition; }\n\n\tconstructor(private readonly poseLandmarker:PoseLandmarker, private readonly config?:Partial<PoseTrackerConfig>){ \n\n\t\tsuper(poseMarks, PoseLandmarker.POSE_CONNECTIONS)\n\t\t\n\t\tthis.root.scale.y *= -2\n\t\tthis.root.scale.z *= -2\n\t\tthis.root.scale.x *= 2 \n\t}\n\n\toverride predict( source:TexImageSource, drawingUtils:DrawingUtils ){\n\t\tthis.poseLandmarker.detectForVideo( source, performance.now(), (result) => {\n\n\t\t\tif( result.landmarks.length==0 )\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n \n\t\t\tthis.updateLandmarks( result.worldLandmarks[0], result.landmarks[0], drawingUtils );\n\n\t\t\t\n\t\t\tthis._leftWristNormalizedPosition = result.landmarks[0][ this.points.leftWrist ];\n\t\t\tthis._rightWristNormalizedPosition = result.landmarks[0][ this.points.rightWrist ];\n\t\t} );\n\t}\n\n\t// override sync ( delta:number, objects: BoneBinding[] ) {\n\n\t// \tconst hipsPos = this.marks.hips.getWorldPosition(C); \n\n\t// \tthis.marks.rightArm.getWorldPosition(A).sub(hipsPos);\n\t// \tthis.marks.leftArm.getWorldPosition(B).sub(hipsPos); \n\n\t// \tconst torsoNormal = C.crossVectors(A,B);\n\n\t// \tthis.syncObjects(objects, delta, torsoNormal); \n\n\t// }\n\t\n\n\tbind( rig:THREE.Object3D, magging:BoneMap )\n\t{ \n\t\t \n\t\tconst map : { [key in MarkKey]?:THREE.Object3D } = {\n\t\t\t\"hips\": getBoneByName(rig, magging.hips),\n\t\t\t\"neck\": getBoneByName(rig, magging.neck),\n\t\t\t\"leftArm\": getBoneByName(rig, magging.armL),\n\t\t\t\"leftElbow\": getBoneByName(rig, magging.forearmL),\n\t\t\t\"leftWrist\": getBoneByName(rig, magging.handL),\n\t\t\t\"rightArm\": getBoneByName(rig, magging.armR),\n\t\t\t\"rightElbow\": getBoneByName(rig, magging.forearmR),\n\t\t\t\"rightWrist\": getBoneByName(rig, magging.handR),\n\t\t\t\"head\": getBoneByName(rig, magging.head), \n\t\t\t\"torso\": getBoneByName(rig, magging.torso),\n\t\t\t\"leftLeg\": getBoneByName(rig, magging.thighL),\n\t\t\t\"leftKnee\": getBoneByName(rig, magging.shinL),\n\t\t\t\"leftFoot\": getBoneByName(rig, magging.footL),\n\t\t\t\"rightLeg\": getBoneByName(rig, magging.thighR),\n\t\t\t\"rightKnee\": getBoneByName(rig, magging.shinR),\n\t\t\t\"rightFoot\": getBoneByName(rig, magging.footR),\n\t\t} \n\n\t\tif( this.config?.ignoreLegs ){\n\t\t\tdelete map.leftLeg\n\t\t\tdelete map.leftKnee\n\t\t\tdelete map.leftFoot\n\t\t\tdelete map.leftToes\n\t\t\tdelete map.rightLeg\n\t\t\tdelete map.rightKnee\n\t\t\tdelete map.rightFoot\n\t\t\tdelete map.rightToes\n\t\t}\n\n\t\tconst v = new THREE.Vector3();\n\t\tconst v2 = new THREE.Vector3();\n\n\t\tconst syncBone = ( delta:number, bone:THREE.Object3D|undefined, from:MarkKey, to:MarkKey, sideAxis:THREE.Vector3, poleAxis:LookAtPoleAxis ) => {\n\t\t\tif( !bone ) return;\n\n\t\t\tconst hipsDir = this.marks[to].getWorldPosition(v).sub(this.marks[from].getWorldPosition(v2)).normalize(); \n\n\t\t \n\t\t\trootPosition(lookGoal, bone, rig).add( hipsDir ).applyMatrix4(rig.matrixWorld) ;\n\t\t\trootPosition(poleGoal, bone, rig).add( sideAxis ).applyMatrix4(rig.matrixWorld) ; \n\n\t\t\tconst ghost = this.getGhost(bone)\n\n\t\t\tlookAt(ghost, lookGoal, poleGoal, poleAxis)\n\t\t\tghost.rotateX(Math.PI/2)\n\t\t\t \n\n\t\t\tghost.lerp(bone, delta)\n\t\t}\n\n\t\treturn {\n\t\t\tupdate: (delta:number)=>{\n \n\t\t\t\tconst sideHips = this.marks.leftLeg.getWorldPosition(A).sub(this.marks.rightLeg.getWorldPosition(B)).normalize();\n\t\t\t\tconst sideShoulders = this.marks.leftArm.getWorldPosition(B).sub(this.marks.rightArm.getWorldPosition(C)).normalize();\n\t\t\t\tconst sideHead = this.marks.leftEar.getWorldPosition(D).sub(this.marks.rightEar.getWorldPosition(E)).normalize();\n\n\t\t\t\tsyncBone(delta, map.hips, \"hips\", \"torso\", sideHips, \"+x\")\n\t\t\t\tsyncBone(delta, map.torso, \"torso\", \"neck\", sideShoulders, \"+x\")\n\t\t\t\tsyncBone(delta, map.neck, \"neck\", \"head\", sideHead, \"+x\")\n\t\t\t\tsyncBone(delta, map.head, \"neck\", \"head\", sideHead, \"+x\")\n\n\t\t\t\tsyncBone(delta, map.leftArm, \"leftArm\", \"leftElbow\", sideShoulders, \"-x\")\n\t\t\t\tsyncBone(delta, map.leftElbow, \"leftElbow\", \"leftWrist\", sideShoulders, \"-x\")\n\t\t\t\tsyncBone(delta, map.leftLeg, \"leftLeg\", \"leftKnee\", sideHips, \"+x\") \n\t\t\t\tsyncBone(delta, map.leftKnee, \"leftKnee\", \"leftFoot\", sideHips, \"+x\") \n\t\t\t\tsyncBone(delta, map.leftFoot, \"leftFoot\", \"leftToes\", sideHips, \"+x\") \n\n\t\t\t\tsyncBone(delta, map.rightArm, \"rightArm\", \"rightElbow\", sideShoulders, \"-x\")\n\t\t\t\tsyncBone(delta, map.rightElbow, \"rightElbow\", \"rightWrist\", sideShoulders, \"-x\")\n\t\t\t\tsyncBone(delta, map.rightLeg, \"rightLeg\", \"rightKnee\", sideHips, \"+x\") \n\t\t\t\tsyncBone(delta, map.rightKnee, \"rightKnee\", \"rightFoot\", sideHips, \"+x\") \n\t\t\t\tsyncBone(delta, map.rightFoot, \"rightFoot\", \"rightToes\", sideHips, \"+x\") \n\t\t\t\t\n\t\t\t}\n\t\t}\n\t}\n}\n ","import {\n\tDrawingUtils,\n HandLandmarker,\n\tHandLandmarkerOptions,\n\tNormalizedLandmark,\n} from \"@mediapipe/tasks-vision\";\nimport * as THREE from \"three/webgpu\";\nimport { lookAt, LookAtPoleAxis } from \"./util/lookAt\";\nimport { Tracker } from \"./Tracker\";\nimport { rootPosition } from \"./util/getRootPosition\";\nimport { getBoneByName } from \"./util/getBoneByName\";\nimport { BoneMap } from \"./BoneMapping\";\n\nexport type HandsTrackerConfig = {\n\tleftWrist: ()=>NormalizedLandmark;\n\trightWrist: ()=>NormalizedLandmark;\n\tmodelPath?:string\n} & Partial<HandLandmarkerOptions>;\n\nconst A = new THREE.Vector2();\nconst B = new THREE.Vector2();\n\nexport async function loadHandTracker(vision: any, config:HandsTrackerConfig ) {\n const landmarker = await HandLandmarker.createFromOptions(vision, {\n baseOptions: {\n modelAssetPath: config.modelPath ?? \"hand_landmarker.task\",\n //modelAssetPath: `https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task`,\n delegate: \"GPU\",\n },\n runningMode: \"VIDEO\",\n numHands: 2,\n });\n\n\tconst isMyWrist = ( myWrist:()=>NormalizedLandmark, otherWrist:()=>NormalizedLandmark, handWrist:NormalizedLandmark ) => {\n\n\t\ttry{\n\t\t\tA.copy(myWrist());\n\t\t\tB.copy(otherWrist());\n\t\t}catch(e){\n\t\t\tconsole.warn(\"No pose data... will just be optimitic and say yes to everything.\", e);\n\t\t\treturn true;\n\t\t}\n\t\treturn A.distanceTo(handWrist) < B.distanceTo(handWrist);\n\t}\n\n return {\n\t\tleft:new HandsTracker(landmarker, \"Left\", isMyWrist.bind(null, config.leftWrist, config.rightWrist) ),\n\t\tright:new HandsTracker(landmarker, \"Right\", isMyWrist.bind(null, config.rightWrist, config.leftWrist) )\n\t};\n}\n\nconst handMarks = {\n wrist: 0,\n\tpalm: [9,13],\n\n thumb1: 1,\n thumb2: 2,\n thumb3: 3,\n thumb4: 4,\n\n index1: 5,\n index2: 6,\n index3: 7,\n index4: 8,\n\n middle1: 9,\n middle2: 10,\n middle3: 11,\n middle4: 12,\n\n ring1: 13,\n ring2: 14,\n ring3: 15,\n ring4: 16,\n\n pinky1: 17,\n pinky2: 18,\n pinky3: 19,\n pinky4: 20,\n};\n\nexport type HandMarkName = keyof typeof handMarks;\n\nconst fingerKeys = {\n\tthumb: [\"thumb1\",\"thumb2\",\"thumb3\",\"thumb4\"],\n\tindex: [\"index1\",\"index2\",\"index3\",\"index4\"],\n\tmiddle: [\"middle1\",\"middle2\",\"middle3\",\"middle4\"],\n\tring: [\"ring1\",\"ring2\",\"ring3\",\"ring4\"],\n\tpinky: [\"pinky1\",\"pinky2\",\"pinky3\",\"pinky4\"]\n} as { [key:string]: HandMarkName[]} ;\n\n\ntype HandSide = \"Left\" | \"Right\"\nexport type Mark2Bone = Partial<{ [key in HandMarkName]: THREE.Object3D }>;\n\nconst v1 = new THREE.Vector3();\nconst v2 = new THREE.Vector3();\nconst v3 = new THREE.Vector3();\nconst v4 = new THREE.Vector3();\nconst v5 = new THREE.Vector3();\nconst v6 = new THREE.Vector3();\nconst v7 = new THREE.Vector3();\n\nconst currNormal = new THREE.Vector3();\nconst currForward = new THREE.Vector3();\nconst currSide = new THREE.Vector3();\nconst HALF_PI = Math.PI/2\nconst DOWN = new THREE.Vector3(0,-1,0);\n\nclass HandsTracker extends Tracker<typeof handMarks> {\n\tprivate readonly sign:number;\n\tprivate readonly isLeft:boolean;\n\t/**\n\t * the axis used to look at the pole\n\t */\n\tprivate readonly lookAtPoleAxis:LookAtPoleAxis;\n\n\tconstructor(private readonly handLandmarker:HandLandmarker, private readonly side:HandSide, private readonly isMyWrist:( handWrist:NormalizedLandmark )=>boolean ){\n\t\tsuper(handMarks, HandLandmarker.HAND_CONNECTIONS)\n\n\t\tthis.sign = this.side==\"Left\" ? -1 : 1;\n\t\tthis.isLeft = this.side==\"Left\";\n\t\tthis.lookAtPoleAxis = this.sign<0? \"+x\" : \"-x\";\n\t\tthis.root.scale.setScalar(7)\n\t\tthis.root.scale.y *= -1\n\t\tthis.root.scale.z *= -1\n\t}\n\n\toverride predict( source:TexImageSource, drawingUtils:DrawingUtils ){\n\t\tconst result = this.handLandmarker.detectForVideo(source, performance.now());\n\n\t\tif( result.landmarks.length )\n\t\t{\n\t\t\t//console.log(`DETECTED ${result.landmarks.length} hands`, result.handedness)\n\n\n\t\t\tfor(let i=0; i<result.landmarks.length; i++){\n\t\t\t\tconst hand = result.landmarks[i];\n\t\t\t\tconst wrist = hand[this.points.wrist];\n\t\t\t\tconst isMyWrist = this.isMyWrist(wrist);\n\t\t\t\tif( isMyWrist ){\n\t\t\t\t\tthis.updateLandmarks( result.worldLandmarks[i] );\n\n\t\t\t\t\tdrawingUtils.drawConnectors(hand, HandLandmarker.HAND_CONNECTIONS, {\n\t\t\t\t\t\tcolor: this.side==\"Left\" ? \"#00FF00\" : \"#0000FF\",\n\t\t\t\t\t\tlineWidth: 4\n\t\t\t\t\t});\n\t\t\t\t\tdrawingUtils.drawLandmarks(hand, { color: this.side==\"Left\" ? \"#00FF00\" : \"#0000FF\", lineWidth: 3, radius: 1 }); \n\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} \n \n \n\t\t} \n\t}\n\n\toverride sync ( delta:number, objects: [THREE.Object3D, HandMarkName, HandMarkName, LookAtPoleAxis][] ) {\n\n\t\tthrow new Error(\"Not used. Use syncHandBones instead\");\n\t}\n\t\t\n\t/**\n\t * \n\t * @param delta time since last frame\n\t * @param landmark2bones Array the same size as the umber of hand landmarks, and on each positionthe bone that belongs to that point.\n\t * @see https://ai.google.dev/edge/mediapipe/solutions/vision/hand_landmarker\n\t */\n\tsyncHandBones( delta:number, markToBone:Mark2Bone, rig:THREE.Object3D )\n\t{ \n\t\tconst palmNormal = v1.crossVectors(\n\t\t\tv2.copy(this.marks.index1.worldPosition).sub(this.marks.wrist.worldPosition),\n\t\t\tv3.copy(this.marks.pinky1.worldPosition).sub(this.marks.wrist.worldPosition)\n\t\t).normalize();\n\n\t\tconst parlmDir = v2.copy(this.marks.palm.worldPosition).sub(this.marks.wrist.worldPosition).normalize();\n\t\tconst palmSide = v3.copy(this.marks.pinky1.worldPosition).sub(this.marks.index1.worldPosition).normalize();\n\t\t \n\t\tif( parlmDir.dot(DOWN)>0.8 )\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\t//\n\t\t// positioning of the palm's bone\n\t\t//\n\t\tif( markToBone.wrist )\n\t\t{\n\t\t\tconst palmLookAt = rootPosition(v4, markToBone.wrist, rig ).add( parlmDir ).applyMatrix4(rig.matrixWorld) //markToBone.wrist.getWorldPosition(v4).add( parlmDir );\n\t\t\tconst polPosition = rootPosition(v5, markToBone.wrist, rig ).sub( palmSide ).applyMatrix4(rig.matrixWorld) //markToBone.wrist.getWorldPosition(v5).sub( palmSide );\n\n\t\t\tconst palmGhost = this.getGhost(markToBone.wrist)\n\n\t\t\tlookAt( palmGhost, palmLookAt, polPosition, \"-y\" );\n\t\t\tpalmGhost.rotateX( HALF_PI ) ; \n\n\t\t\tpalmGhost.lerp(markToBone.wrist, delta)\n\t\t}\n\n\t\t// palmLookAtOffset.normalize();\n\t\t// const palmSide = v3.crossVectors(palmNormal, palmLookAtOffset).normalize();\n \n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.index, \"middle1\" )\n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.middle, \"ring1\" )\n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.ring, \"pinky1\" )\n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.pinky, \"ring1\", true )\n\n\t\t// //thumb...\n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.thumb, \"index1\" )\n\n\t\t\n\t}\n\n\tprivate syncFinger( delta:number, rig:THREE.Object3D, palmNormal:THREE.Vector3, palmForward:THREE.Vector3, palmSide:THREE.Vector3, markToBone:Mark2Bone, fingerKeys:HandMarkName[], sideGoal:HandMarkName, negateSideGoal:boolean=false ){\n\t \n\t\tlet signMult = 1;\n\n\t\tfor(let i=0; i<fingerKeys.length-1;i++) { \n\t\t\t\n\t\t\tconst bone = markToBone[fingerKeys[i]];\n\t\t\t//const bonePole = markToBone[sideGoal];\n\n\t\t\tif(!bone ) continue;\n\n\t\t\tconst fingerGhost = this.getGhost(bone)\n\n\t\t\t// finger's direction\n\t\t\tconst myDir = v4.copy( this.marks[fingerKeys[i+1]].worldPosition ).sub( this.marks[fingerKeys[i]].worldPosition).normalize() ; \n\t\t\t\n\t\t\tconst bonePos = rootPosition(v5, bone, rig) //bone.getWorldPosition(v5); \n\n\n\t\t\t//const poleOffset = v6.copy(bonePos).add(palmSide) //rootPosition(v6, bonePole, rig).sub( bonePos );//bonePole.getWorldPosition(v6).sub( bonePos );\n\n\t\t\t//if( negateSideGoal ) poleOffset.negate(); \n\n\n\t\t\tif( i==0 )\n\t\t\t{ \n\t\t\t\tconst fingerSideNormal = v6.copy(this.marks[sideGoal].worldPosition).sub(this.marks[fingerKeys[0]].worldPosition).normalize() ;\n \n\t\t\t\tif( negateSideGoal )\n\t\t\t\t\tfingerSideNormal.negate();\n \n\n\t\t\t\t// if( this.isLeft )\n\t\t\t\t// \tsideDir.negate();\n\n\t\t\t\tcurrSide.copy(fingerSideNormal);\n\n\t\t\t\t\n\t\t\t\tlookAt( fingerGhost, \n\t\t\t\t\tmyDir.add( bonePos ).applyMatrix4(rig.matrixWorld), \n\t\t\t\t\tfingerSideNormal.add(bonePos).applyMatrix4(rig.matrixWorld), \n\t\t\t\t\tthis.lookAtPoleAxis ); \n\n\t\t\t\t\n\t\t\t}\n\t\t\telse \n\t\t\t{ \n\t\t\t\tlookAt( fingerGhost, \n\t\t\t\t\tmyDir.add( bonePos ).applyMatrix4(rig.matrixWorld), \n\t\t\t\t\tv6.copy(currSide).add(bonePos).applyMatrix4(rig.matrixWorld), \n\t\t\t\t\tthis.lookAtPoleAxis );\n\t\t\t} \n\n\t\t\tfingerGhost.rotateX( HALF_PI ); \n\n\t\t\tfingerGhost.lerp(bone, delta)\n\n\t\t}\n\n \n\t}\n \n\tbind( rig:THREE.Object3D, magging:BoneMap ){\n\n\t\tconst map:Mark2Bone = {\n\t\t\t\n\t\t}\t \n\n\t\tconst addBind = ( boneName:string, markName:HandMarkName ) => {\n\t\t\t//const bone = rig.getObjectByName( cleanBoneName( boneName.replace(\"X\", this.sign<0 ? \"L\" : \"R\") ));\n\n\t\t\tconst bone = getBoneByName(rig, boneName );\n\n\t\t\tif( bone ){\n\t\t\t\tmap[markName] = bone;\n\t\t\t\treturn markName;\n\t\t\t}\n\t\t}\n\n\t\taddBind( this.isLeft ? magging.handL : magging.handR, \"wrist\" )\n\t\taddBind( this.isLeft ? magging.index1L : magging.index1R, \"index1\" )\n\t\taddBind( this.isLeft ? magging.index2L : magging.index2R, \"index2\" )\n\t\taddBind( this.isLeft ? magging.index3L : magging.index3R, \"index3\" ) \n\n\t\taddBind( this.isLeft ? magging.middle1L : magging.middle1R, \"middle1\" )\n\t\taddBind( this.isLeft ? magging.middle2L : magging.middle2R, \"middle2\" )\n\t\taddBind( this.isLeft ? magging.middle3L : magging.middle3R, \"middle3\" ) \n\n\t\taddBind( this.isLeft ? magging.ring1L : magging.ring1R, \"ring1\" )\n\t\taddBind( this.isLeft ? magging.ring2L : magging.ring2R, \"ring2\" )\n\t\taddBind( this.isLeft ? magging.ring3L : magging.ring3R, \"ring3\" ) \n\n\t\taddBind( this.isLeft ? magging.pinky1L : magging.pinky1R, \"pinky1\" )\n\t\taddBind( this.isLeft ? magging.pinky2L : magging.pinky2R, \"pinky2\" )\n\t\taddBind( this.isLeft ? magging.pinky3L : magging.pinky3R, \"pinky3\" ) \n\n\t\taddBind( this.isLeft ? magging.thumb1L : magging.thumb1R, \"thumb1\" )\n\t\taddBind( this.isLeft ? magging.thumb2L : magging.thumb2R, \"thumb2\" )\n\t\taddBind( this.isLeft ? magging.thumb3L : magging.thumb3R, \"thumb3\" ) \n\n\t\treturn {\n\t\t\tupdate: ( delta:number )=> { \n\t\t\t\tthis.syncHandBones(delta, map, rig);\n\t\t\t}\n\t\t}\t\n\t}\n}\n","import {\n Category,\n DrawingUtils,\n FaceLandmarker\n} from \"@mediapipe/tasks-vision\";\nimport { Mesh, Object3D, Vector3 } from \"three/webgpu\";\nimport { Tracker } from \"./Tracker\";\nimport { rootPosition } from \"./util/getRootPosition\";\nimport { getBoneByName } from \"./util/getBoneByName\";\nimport { lookAt } from \"./util/lookAt\";\n\nexport async function loadFaceTracker(vision: any, cfg?: { modelPath?: string }) {\n const faceLandmarker = await FaceLandmarker.createFromOptions(vision, {\n baseOptions: {\n modelAssetPath: cfg?.modelPath ?? \"face_landmarker.task\",\n\t\t\tdelegate: \"GPU\", \n },\n\t\toutputFaceBlendshapes: true,\n runningMode: \"VIDEO\",\n\t\tnumFaces: 1,\n });\n\n\treturn new FaceTracker(faceLandmarker);\n}\n\n/**\n * @see https://storage.googleapis.com/mediapipe-assets/documentation/mediapipe_face_landmark_fullsize.png\n */\nconst faceMarks = {\n\teyeL: 473,\n\teyeR: 468,\n\teyeStartL: 463,\n\teyeStartR: 243,\n\teyeEndL: 263,\n\teyeEndR: 33, \n\n\tearL: 454,\n\tearR: 234,\n\tnoseTip: 4,\n\tnoseBone:6,\n\tchin:152,\n\tforehead: 10\n\n}\n\ntype MarkKey = keyof typeof faceMarks;\nconst v = new Vector3();\nconst v2 = new Vector3();\nconst v3 = new Vector3();\nconst v4 = new Vector3();\nconst v5 = new Vector3();\nconst v6 = new Vector3();\n\nclass FaceTracker extends Tracker<typeof faceMarks> {\n\tprivate blendshapeCategories: Category[] | undefined;\n\tprivate blendshapeMap: Map<string, number> = new Map();\n\tprivate smoothed: Record<string, number> = {};\n\tprivate smoothing =.0003; // lower = smoother but more lag, higher = more responsive\n\n\tconstructor(private faceLandmarker: FaceLandmarker) {\n\t\tsuper(faceMarks, FaceLandmarker.FACE_LANDMARKS_TESSELATION)\n\n\t\tthis.root.scale.y*=-1\n\t\tthis.root.scale.z*=-1\n\t\tthis.root.scale.multiplyScalar(3)\n\t}\n\n\toverride predict(frame: TexImageSource, drawingUtils: DrawingUtils) {\n\t\tconst result = this.faceLandmarker.detectForVideo(frame, performance.now());\n\t\tif (result.faceLandmarks[0]) {\n\t\t\tdrawingUtils.drawConnectors(result.faceLandmarks[0], FaceLandmarker.FACE_LANDMARKS_TESSELATION, { color: \"#00fff2ff\", lineWidth: .1 });\n\t\t\tdrawingUtils.drawLandmarks(result.faceLandmarks[0], { color: \"#00ff00\", lineWidth: .1, radius: .4 });\t\n\n\t\t\tthis.updateLandmarks(result.faceLandmarks[0], result.faceLandmarks[0] );\n\t\t}\n\n\t\tthis.blendshapeCategories = result.faceBlendshapes?.[0]?.categories; \n\n\t\tthis.blendshapeCategories?.forEach((category) => {\n\t\t\tthis.blendshapeMap.set(category.categoryName, category.score);\n\t\t});\n\t\t\n\t}\n\n\tbindShapeKeys(mesh: Mesh) {\n\t\tconst meshKeys = mesh.morphTargetDictionary; \n\n\t\treturn {\n\t\t\tupdate: (delta: number) => {\n\t\t\t\tthis.blendshapeCategories?.forEach((category) => {\n\t\t\t\t\tconst { categoryName, score } = category;\n\n\t\t\t\t\tif (!meshKeys?.hasOwnProperty(categoryName)) return;\n\n\t\t\t\t\t// Initialize if first time seeing this key\n\t\t\t\t\tif (this.smoothed[categoryName] === undefined)\n\t\t\t\t\t\tthis.smoothed[categoryName] = score;\n\n\t\t\t\t\t// Lerp toward target score\n\t\t\t\t\tconst factor = 1 - Math.pow(this.smoothing, delta);\n\t\t\t\t\tthis.smoothed[categoryName] += (score - this.smoothed[categoryName]) * factor;\n\n\t\t\t\t\tmesh.morphTargetInfluences![meshKeys[categoryName]] = this.smoothed[categoryName];\n\t\t\t\t});\n\n\t\t\t\t//eyes\n\t\t\t}\n\t\t}\n\t}\n\n\tbind( rig:Object3D ) {\n\n\t\tconst eyeL = new EyeRig(rig, \"L\");\n\t\tconst eyeR = new EyeRig(rig, \"R\");\n\t\tconst headBone = getBoneByName(rig, \"head\") ;\n \n\t\treturn {\n\t\t\tupdate: ( delta:number )=> {\n\t\t\t\t \n\t\t\t\teyeL.update(delta, this.blendshapeMap);\n\t\t\t\teyeR.update(delta, this.blendshapeMap); \n\t\t\t\t\n\t\t\t\tif(!headBone) return;\n\n\t\t\t\t//\n\t\t\t\tconst markEarL = v.copy( this.marks.earL.worldPosition );\n\t\t\t\tconst markEarR = v2.copy( this.marks.earR.worldPosition );\n\t\t\t\tconst headcenter = v3.subVectors(markEarL, markEarR).multiplyScalar(.5).add(markEarR);\n\t\t\t\tconst headForward = v4.subVectors(this.marks.noseTip.worldPosition, headcenter) ;\n\t\t\t\tconst headSideNormal = markEarL.sub(markEarR) ;\n\n\t\t\t\t\n\t\t\t\tconst headPosition = rootPosition( v5, headBone, rig); \n\n\t\t\t\tconst poleLookAt = headSideNormal.add( headPosition ).applyMatrix4(rig.matrixWorld);\n\t\t\t\tconst faceLookAt = headForward.add( headPosition ).applyMatrix4(rig.matrixWorld);\n\n\t\t\t\tlookAt( headBone, faceLookAt, poleLookAt,\"+x\" );\n\t\t\t\t \n\n\t\t\t\t// headLookAtPos.applyMatrix4(rig.matrixWorld);\n\t\t\t\t//headBone.lookAt( headLookAtPos );\n\t\t\t\t// \n\t\t\t}\n\t\t}\n\t\t\n\t}\n}\n\nclass EyeRig {\n\tprivate eyeBone:Object3D|undefined; \n\n\tprivate eyeLookOut:string;\n\tprivate eyeLookIn:string;\n\tprivate eyeLookUp:string;\n\tprivate eyeLookDown:string;\n\tprivate sign = 1;\n\t\n\tconstructor( readonly rig:Object3D, readonly side:\"L\"|\"R\" ) {\n\t\tthis.eyeBone = rig.getObjectByName(`eye${side}`) as Object3D; \n\n\t\tconst sideName = side == \"L\" ? \"Left\" : \"Right\";\n\t\tthis.eyeLookOut = `eyeLookOut${sideName}`;\n\t\tthis.eyeLookIn = `eyeLookIn${sideName}`;\n\t\tthis.eyeLookUp = `eyeLookUp${sideName}`;\n\t\tthis.eyeLookDown = `eyeLookDown${sideName}`;\n\n\t\tthis.sign = side == \"L\" ? -1 : 1;\n\t}\n\n\tupdate( delta:number, blendshapes: Map<string, number> ) {\n\t\tif( !this.eyeBone ) return; \n \n\t\tconst eye = rootPosition(v3, this.eyeBone, this.rig); \n\n\t\t\n\t\t\n\t\t// From MediaPipe blendshapes\n\t\tconst lookLeft = blendshapes.get(this.eyeLookOut) ?? 0; // or eyeLookInRight\n\t\tconst lookRight = blendshapes.get(this.eyeLookIn) ?? 0; // or eyeLookOutRight\n\t\tconst lookUp = blendshapes.get(this.eyeLookUp) ?? 0;\n\t\tconst lookDown = blendshapes.get(this.eyeLookDown) ?? 0;\n\n\t\t\n\t\t// Map to a -1..1 range\n\t\tconst sideMovement = lookRight - lookLeft // horizontal\n\t\tconst verticalMovement = lookDown - lookUp // vertical\n \n\n\t\tthis.eyeBone.rotation.y =( sideMovement * this.sign) / 2; \n\t\tthis.eyeBone.rotation.x = verticalMovement / 2; \n\t\t// // Then drive your rig bone with a target offset\n\t\t// const lookAtPos = eyeCenter\n\t\t// .add(eyeHorizontalDir ) // -sideMovement * eyeRange)\n\t\t// //.addScaledVector(eyeVerticalDir, verticalMovement * eyeRange/3)\n\t\t// .applyMatrix4(this.rig.matrixWorld);\n\n\t\t// this.eyeBone.lookAt(lookAtPos);\n\t\t// this.eyeBone.rotateX(Math.PI/2)\n\t}\n}","/**\n * The bone mapping to use for the rig.\n */\nexport type BoneMap = {\n\tfaceMesh:string\n\thead: string;\n\thips:string\n\tneck:string\n\ttorso:string\n\tarmL:string\n\tforearmL:string\n\n\tarmR:string\n\tforearmR:string\n\n\tthighL:string\n\tshinL:string\n\tfootL:string\n\ttoesL:string\n\n\tthighR:string\n\tshinR:string\n\tfootR:string\n\ttoesR:string\n\t \n\t\n\thandL:string\n\tindex1L:string\n\tindex2L:string\n\tindex3L:string\n\n\tmiddle1L:string\n\tmiddle2L:string\n\tmiddle3L:string\n\n\tring1L:string\n\tring2L:string\n\tring3L:string\n\n\tpinky1L:string\n\tpinky2L:string\n\tpinky3L:string\n\n\tthumb1L:string\n\tthumb2L:string\n\tthumb3L:string\n\n\thandR:string\n\tindex1R:string\n\tindex2R:string\n\tindex3R:string\n\n\tmiddle1R:string\n\tmiddle2R:string\n\tmiddle3R:string\n\n\tring1R:string\n\tring2R:string\n\tring3R:string\n\n\tpinky1R:string\n\tpinky2R:string\n\tpinky3R:string\n\n\tthumb1R:string\n\tthumb2R:string\n\tthumb3R:string\n \n}\n\nexport const defaultBoneMap:BoneMap = {\n\tfaceMesh:\"face\",\n\t\n\thead: \"head\",\n\thips:\"hips\",\n\tneck:\"neck\",\n\ttorso:\"torso\",\n\n\tarmL:\"upper_armL\",\n\tforearmL:\"forearmL\",\n\n\tarmR:\"upper_armR\",\n\tforearmR:\"forearmR\",\n\n\tthighL:\"thighL\",\n\tshinL:\"shinL\",\n\tfootL:\"footL\",\n\n\tthighR:\"thighR\",\n\tshinR:\"shinR\",\n\tfootR:\"footR\",\n\t \n\t\n\thandL:\"handL\",\n\tindex1L:\"index1L\",\n\tindex2L:\"index2L\",\n\tindex3L:\"index3L\",\n\n\tmiddle1L:\"middle1L\",\n\tmiddle2L:\"middle2L\",\n\tmiddle3L:\"middle3L\",\n\n\tring1L:\"ring1L\",\n\tring2L:\"ring2L\",\n\tring3L:\"ring3L\",\n\n\tpinky1L:\"pinky1L\",\n\tpinky2L:\"pinky2L\",\n\tpinky3L:\"pinky3L\",\n\n\tthumb1L:\"thumb1L\",\n\tthumb2L:\"thumb2L\",\n\tthumb3L:\"thumb3L\",\n\n\thandR:\"handR\",\n\tindex1R:\"index1R\",\n\tindex2R:\"index2R\",\n\tindex3R:\"index3R\",\n\n\tmiddle1R:\"middle1R\",\n\tmiddle2R:\"middle2R\",\n\tmiddle3R:\"middle3R\",\n\n\tring1R:\"ring1R\",\n\tring2R:\"ring2R\",\n\tring3R:\"ring3R\",\n\n\tpinky1R:\"pinky1R\",\n\tpinky2R:\"pinky2R\",\n\tpinky3R:\"pinky3R\",\n\n\tthumb1R:\"thumb1R\",\n\tthumb2R:\"thumb2R\",\n\tthumb3R:\"thumb3R\",\n \n}","/**\n * A list of blend shape key names that are used by mediapipe face mesh. \n */\nexport const blendShapeKeyNames = [\n \"eyeBlinkLeft\",\n \"eyeBlinkRight\",\n \"eyeLookDownLeft\",\n \"eyeLookDownRight\",\n \"eyeLookInLeft\",\n \"eyeLookInRight\",\n \"eyeLookOutLeft\",\n \"eyeLookOutRight\",\n \"eyeLookUpLeft\",\n \"eyeLookUpRight\",\n \"eyeSquintLeft\",\n \"eyeSquintRight\",\n \"eyeWideLeft\",\n \"eyeWideRight\",\n \"browDownLeft\",\n \"browDownRight\",\n \"browInnerUp\",\n \"browOuterUpLeft\",\n \"browOuterUpRight\",\n \"noseSneerLeft\",\n \"noseSneerRight\",\n \"cheekPuff\",\n \"cheekSquintLeft\",\n \"cheekSquintRight\",\n \"jawForward\",\n \"jawLeft\",\n \"jawOpen\",\n \"jawRight\",\n \"mouthClose\",\n \"mouthDimpleLeft\",\n \"mouthDimpleRight\",\n \"mouthFrownLeft\",\n \"mouthFrownRight\",\n \"mouthFunnel\",\n \"mouthLeft\",\n \"mouthLowerDownLeft\",\n \"mouthLowerDownRight\",\n \"mouthPressLeft\",\n \"mouthPressRight\",\n \"mouthPucker\",\n \"mouthRight\",\n \"mouthRollLower\",\n \"mouthRollUpper\",\n \"mouthShrugLower\",\n \"mouthShrugUpper\",\n \"mouthSmileLeft\",\n \"mouthSmileRight\",\n \"mouthStretchLeft\",\n \"mouthStretchRight\",\n \"mouthUpperUpLeft\",\n \"mouthUpperUpRight\",\n \"tongueOut\"\n]","import * as THREE from \"three\";\nimport { BoneMap, defaultBoneMap } from \"../BoneMapping\";\nimport { GLTFExporter } from \"three/examples/jsm/Addons.js\";\nimport { blendShapeKeyNames } from \"../blendShapeKeyNames\";\n\ntype BoneRef = {\n ref: THREE.Bone;\n name: string;\n\tnormalizedName: string;\n};\n\n/**\n * Records the local rotation of the bones in the rig. The name used will be the normalized bone name.\n * @param rigRoot\n * @param magging\n * @param fps\n * @returns\n */\nexport function createRigRecorder(\n rigRoot: THREE.Object3D,\n magging: BoneMap,\n fps = 30,\n) {\n const bones: BoneRef[] = [];\n const faceMesh = rigRoot.getObjectByName(\n magging.faceMesh,\n ) as THREE.SkinnedMesh;\n const usedBlendShapeKeys = new Set<string>();\n\n //\n // collect used blend shape keys...\n //\n if (faceMesh?.morphTargetDictionary) {\n for (const key in faceMesh.morphTargetDictionary) {\n if (blendShapeKeyNames.includes(key)) {\n usedBlendShapeKeys.add(key);\n }\n }\n }\n\n\n\t//\n\t// look for the bones\n\t//\n\tconst boneKeys = Object.keys(magging);\n\trigRoot.traverse( o => {\n\t\tif(o instanceof THREE.Bone)\n\t\t{\n\t\t\t// check if the bone name is in the mapping\n\t\t\tconst key = boneKeys.find(k => o.name.indexOf( magging[k as keyof typeof magging] )=== 0 );\n\t\t\tif(key)\n\t\t\t{\n\t\t\t\tbones.push({\n\t\t\t\t\tref: o,\n\t\t\t\t\tname: o.name, \n\t\t\t\t\tnormalizedName: key,\n\t\t\t\t}); \n\t\t\t}\n\t\t}\n\t});\n \n\n\tconst times :number[] = [];\n const boneTracks = new Map<\n string,\n number[] //vec4 array\n >();\n\n\tconst blendShapeTracks = new Map<\n\t\tstring,\n\t\tnumber[]\n\t>();\n\n let recording = false;\n let startTime = 0;\n\n function start() {\n boneTracks.clear();\n\t\tblendShapeTracks.clear();\n\t\ttimes.length = 0;\n startTime = performance.now() / 1000;\n recording = true;\n }\n\n function captureFrame() {\n if (!recording) return;\n\n const time = performance.now() / 1000 - startTime;\n\n\t\ttimes.push(time);\n\n for (const bone of bones) {\n if (!boneTracks.has(bone.name)) {\n boneTracks.set(bone.name, []);\n }\n\n const track = boneTracks.get(bone.name)!; \n\t\t\t \n const q = bone.ref.quaternion;\n track.push(q.x, q.y, q.z, q.w);\n } \n\n\t\tfor (const key of usedBlendShapeKeys) {\n\t\t\tif (!blendShapeTracks.has(key)) {\n\t\t\t\tblendShapeTracks.set(key, []);\n\t\t\t}\n\n\t\t\tconst track = blendShapeTracks.get(key)!; \n\n\t\t\tconst keyIndex = faceMesh.morphTargetDictionary![key];\n\t\t\tconst v = faceMesh.morphTargetInfluences![keyIndex];\n\t\t\ttrack.push(v);\n\t\t}\n }\n\n\t/** \n\t * @param name name of the resulting clip\n\t * @returns \n\t */\n function stop(name = \"RecordedClip\") {\n recording = false;\n\n const keyframeTracks: THREE.KeyframeTrack[] = [];\n\n\t\t\n \n for (const [boneName, data] of boneTracks) {\n keyframeTracks.push(\n new THREE.QuaternionKeyframeTrack(\n `${boneName}.quaternion`,\n times,\n data,\n ),\n );\n } \n\n\t\tfor (const [key, data] of blendShapeTracks) {\n\t\t\tkeyframeTracks.push(\n\t\t\t\tnew THREE.NumberKeyframeTrack(\n\t\t\t\t\t`${defaultBoneMap.faceMesh}.morphTargetInfluences[${key}]`,\n\t\t\t\t\ttimes,\n\t\t\t\t\tdata,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n const clip = new THREE.AnimationClip(name, -1, keyframeTracks);\n \n\n return {\n\t\t\tclip,\n\t\t\tsaveToFile:() => {\n\t const exporter = new GLTFExporter();\n\t exporter.parse(\n\t rigRoot,\n\t (gltf) => {\n\t // binary .glb\n\t const blob = new Blob([gltf], {\n\t type: \"model/gltf-binary\",\n\t });\n\t const url = URL.createObjectURL(blob);\n\n\t const a = document.createElement(\"a\");\n\t a.href = url;\n\t a.download = name + \".glb\";\n\t a.click();\n\t },\n\t (error) => {\n\t console.error(error);\n\t },\n\t {\n\t binary: true,\n\t animations: [clip],\n\t },\n\t );\n\t }\n\t\t};\n }\n\n return { start, captureFrame, stop, isRecording: () => recording };\n}\n","import {\n DrawingUtils,\n FilesetResolver,\n HandLandmarkerOptions,\n PoseLandmarker,\n} from \"@mediapipe/tasks-vision\";\nimport * as THREE from \"three/webgpu\";\nimport { loadPoseTracker } from \"./PoseTracker\";\nimport { loadHandTracker } from \"./HandTracker\"; \nimport { loadFaceTracker } from \"./FaceTracker\";\nimport { BoneMap, defaultBoneMap } from \"./BoneMapping\";\nimport { createRigRecorder } from \"./recoding/recorder\";\n\nexport type TrackerConfig = {\n /**\n * Use an image file. Useful to test a particular pose.\n */\n debugFrame?: string;\n\n /**\n * Scale of the video display\n */\n displayScale: number;\n\n /**\n * If the body pose should ignore the legs\n */\n ignoreLegs: boolean;\n\n /**\n * Use a video file instead of the webcam\n */\n debugVideo?: string;\n\n /**\n * Don't track the face\n */\n ignoreFace: boolean;\n\n /**\n * @see https://ai.google.dev/edge/mediapipe/solutions/vision/hand_landmarker/web_js#configuration_options\n */\n handsTrackerOptions: HandLandmarkerOptions | undefined;\n\n\tmodelPaths?: {\n\t\tvision?:string;\n\t\tpose?: string;\n\t\thand?: string;\n\t\tface?: string;\n\t}\n};\n\nexport interface BindingHandler {\n\n\t/**\n\t * Updates the rig with the latest landmarks.\n\t * @param delta The time elapsed since the last frame in seconds.\n\t */\n update: (delta: number) => void;\n\n}\n\nexport interface RecorderHandler { \n\t/**\n\t * Starts recording the rig's movement and active shape keys ( from media pipe ).\n\t */\n\tstartRecording: VoidFunction;\n\n\t/**\n\t * Stops recording the rig's movement.\n\t * @returns A function that can be called to SAVE the recording to a file.\n\t */\n\tstopRecording: ReturnType<typeof createRigRecorder>['stop'];\n\n\t/**\n\t * Checks if the rig is currently recording.\n\t * @returns True if the rig is recording, false otherwise.\n\t */\n\tisRecording: () => boolean;\n}\n\nexport interface RecordableBindingHandler extends BindingHandler, RecorderHandler {}\n\n// Check if webcam access is supported.\nconst hasGetUserMedia = () => !!navigator.mediaDevices?.getUserMedia;\n\nexport async function setupTracker(config?: Partial<TrackerConfig>) {\n const $cfg = {\n debugFrame: undefined,\n displayScale: 1,\n ignoreLegs: false,\n debugVideo: undefined,\n ignoreFace: false,\n\t\tmodelPaths: {\n\t\t\tvision: \"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.3/wasm\",\n\t\t\tpose: \"https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task\",\n\t\t\thand: \"https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task\",\n\t\t\tface: \"https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task\",\n\t\t},\n ...config,\n };\n let video: HTMLVideoElement | undefined;\n const vision = await FilesetResolver.forVisionTasks( $cfg.modelPaths.vision ?? \"/wasm\" );\n const poseTracker = await loadPoseTracker(vision, {\n ignoreLegs: $cfg.ignoreLegs,\n\t\tmodelPath: $cfg.modelPaths.pose!,\n });\n const handsTracker = await loadHandTracker(vision, {\n leftWrist: () => poseTracker.leftWristNormalizedPosition,\n rightWrist: () => poseTracker.rightWristNormalizedPosition,\n\t\tmodelPath: $cfg.modelPaths.hand!,\n ...config?.handsTrackerOptions,\n });\n const faceTracker = $cfg.ignoreFace\n ? undefined\n : await loadFaceTracker(vision, { modelPath: $cfg.modelPaths.face! });\n\n //#region setup Camera and Canvas...\n\tconst viewport = document.createElement(\"div\");\n\tviewport.style.position = \"absolute\";\n\tviewport.style.top = \"0px\";\n\tviewport.style.left = \"0px\"; \n\tviewport.style.zIndex = \"21\";\n\tviewport.classList.add(\"three-mediapipe-rig\")\n\tdocument.body.appendChild(viewport);\n\n const canvasElement = document.createElement(\"canvas\");\n const canvasCtx = canvasElement.getContext(\"2d\")!;\n const drawingUtils = new DrawingUtils(canvasCtx);\n\n canvasElement.style.zIndex = \"22\";\n canvasElement.style.position = \"absolute\";\n canvasElement.style.top = \"0px\";\n canvasElement.style.left = \"0px\";\n canvasElement.style.pointerEvents = \"none\";\n viewport.appendChild(canvasElement);\n\n function predict(source: TexImageSource) {\n canvasCtx.save();\n canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);\n poseTracker?.predict(source, drawingUtils);\n handsTracker?.left.predict(source, drawingUtils);\n handsTracker?.right.predict(source, drawingUtils);\n faceTracker?.predict(source, drawingUtils);\n canvasCtx.restore();\n }\n\n function initializeVideo() {\n video = document.createElement(\"video\");\n viewport.appendChild(video);\n\n let lastVideoTime = -1;\n\n video.style.zIndex = \"21\";\n video.style.position = \"absolute\";\n video.style.top = \"0px\";\n video.style.left = \"0px\";\n\n if ($cfg.debugVideo) {\n video.src = $cfg.debugVideo;\n video.controls = true;\n video.loop = true;\n video.muted = true;\n video.controls = true;\n video.play();\n }\n\n function predictWebcam() {\n if (lastVideoTime !== video!.currentTime) {\n predict(video!);\n lastVideoTime = video!.currentTime;\n }\n window.requestAnimationFrame(predictWebcam);\n }\n\n video.addEventListener(\"loadeddata\", () => {\n video!.width = video!.videoWidth * $cfg.displayScale;\n video!.height = video!.videoHeight * $cfg.displayScale;\n canvasElement.width = video!.videoWidth;\n canvasElement.height = video!.videoHeight;\n canvasElement.style.height = video!.height + \"px\";\n canvasElement.style.width = video!.width + \"px\";\n\n window.requestAnimationFrame(predictWebcam);\n });\n }\n\n if ($cfg.debugFrame) {\n //#region Debug Frame mode — use a static image\n const img = document.createElement(\"img\");\n img.src = $cfg.debugFrame;\n img.style.zIndex = \"21\";\n img.style.position = \"absolute\";\n img.style.top = \"0px\";\n img.style.left = \"0px\";\n\t\tviewport.appendChild(img);\n\n img.addEventListener(\"load\", () => {\n img.width = img.naturalWidth * $cfg.displayScale;\n img.height = img.naturalHeight * $cfg.displayScale;\n canvasElement.width = img.naturalWidth;\n canvasElement.height = img.naturalWidth;\n canvasElement.style.width = img.width + \"px\";\n canvasElement.style.height = img.height + \"px\";\n\n function predictFrame() {\n predict(img);\n\t\t\t\t//window.requestAnimationFrame(predictFrame);\n }\n\n window.requestAnimationFrame(predictFrame);\n });\n //#endregion\n } else if( $cfg.debugVideo ) {\n //#region Video mode\n initializeVideo();\n //#endregion\n } \n\n return {\n poseTracker,\n handsTracker,\n faceTracker,\n video,\n\n\t\t/**\n\t\t * A div that contains the video and canvas used to display the landmarks stacked on top of each other.\n\t\t */\n\t\tdomElement: viewport,\n\n\t\t/**\n\t\t * Start the webcam feed. This must be initiated by a user triggered event ( a click on a button ) due to security reasons. \n\t\t */\n start: async () => {\n\t\t\tlet stopped = false;\n\n if (!hasGetUserMedia()) {\n throw new Error(\"Webcam not supported\");\n }\n\n if (!video) {\n initializeVideo();\n }\n\n let stream: Awaited<MediaStream> | undefined;\n\n\t\t\tfunction onTrackEnded(video: HTMLVideoElement): void {\n\t\t\t\tconsole.warn('Camera track ended, attempting recovery...');\n\t\t\t\tstopCamera(video);\n\t\t\t\tretryWithBackoff(video);\n\t\t\t}\n\n\t\t\tfunction stopCamera(video: HTMLVideoElement): void {\n\t\t\t\tstream?.getTracks().forEach(t => t.stop());\n\t\t\t\tstream = undefined;\n\t\t\t\tvideo.srcObject = null;\n\t\t\t}\n\n\t\t\tasync function retryWithBackoff(video: HTMLVideoElement, attempt = 0): Promise<void> {\n\t\t\t const MAX_ATTEMPTS = 5;\n\t\t\t const delay = Math.min(1000 * 2 ** attempt, 16000); // 1s, 2s, 4s, 8s, 16s\n\n\t\t\t if (attempt >= MAX_ATTEMPTS) { \n\t\t\t throw new Error('Camera recovery failed after max attempts');\n\t\t\t }\n\n\t\t\t await new Promise(res => setTimeout(res, delay)); \n\n\t\t\t if(stopped) return;\n\n\t\t\t try {\n\t\t\t await startCamera(video);\n\t\t\t console.log('Camera recovered successfully');\n\t\t\t } catch {\n\t\t\t retryWithBackoff(video, attempt + 1);\n\t\t\t }\n\t\t\t}\n\n\t\t\tasync function startCamera(video: HTMLVideoElement): Promise<void> {\n\t\t\t try {\n\t\t\t stream = await navigator.mediaDevices.getUserMedia({ video: true });\n\t\t\t video.srcObject = stream;\n\t\t\t await video.play();\n\n\t\t\t // Listen for track ending (camera disconnected / permission revoked)\n\t\t\t stream.getVideoTracks().forEach(track => {\n\t\t\t track.addEventListener('ended', () => onTrackEnded(video));\n\t\t\t });\n\n\t\t\t } catch (err) {\n\t\t\t handleCameraError(err, video);\n\t\t\t }\n\t\t\t}\n\n\t\t\tfunction handleCameraError(err: unknown, video: HTMLVideoElement): void {\n\t\t\t if (err instanceof DOMException) {\n\t\t\t switch (err.name) {\n\t\t\t case 'NotAllowedError':\n\t\t\t throw new Error('Permission denied — prompt user to allow camera');\n\t\t\t break;\n\t\t\t case 'NotFoundError':\n\t\t\t console.error('No camera found — retry when device is connected');\n\t\t\t retryWithBackoff(video); // device might be plugged in later\n\t\t\t break;\n\t\t\t case 'NotReadableError':\n\t\t\t console.error('Camera in use by another app');\n\t\t\t retryWithBackoff(video);\n\t\t\t break;\n\t\t\t default:\n\t\t\t console.error('Camera error:', err.message);\n\t\t\t retryWithBackoff(video);\n\t\t\t }\n\t\t\t }\n\t\t\t} \n\n await startCamera(video!);\n\n\t\t\treturn {\n\t\t\t\tstop:()=>{\n\t\t\t\t\tstopped = true;\n\t\t\t\t\tstopCamera(video!);\n\t\t\t\t}\n\t\t\t}\n },\n\n /**\n * Binds the bones of the rig to the landmarks provided by media pipe.\n * @param rig The rig that contains all the bones and skinned meshes of your character.\n\t\t * @param magging The bone mapping to use for the rig.\n */\n bind: ( rig: THREE.Object3D, magging?:BoneMap ) => {\n\n\t\t\tmagging = magging || defaultBoneMap;\n\n const bodyBindin = poseTracker.bind(rig, magging);\n const leftHandBinding = handsTracker.left.bind(rig, magging);\n const rightHandBinding = handsTracker.right.bind(rig, magging);\n let faceKeys: BindingHandler | undefined;\n const faceRig = faceTracker?.bind(rig);\n\n rig.traverse((child) => {\n if (\n child instanceof THREE.Mesh &&\n child.name.indexOf( magging.faceMesh ) === 0\n ) {\n child.frustumCulled = false;\n faceKeys = faceTracker?.bindShapeKeys(child);\n }\n });\n\n\t\t\tconst recorder = createRigRecorder(rig, magging)\n\n return {\n\n\t\t\t\t/**\n\t\t\t\t * Will save the tracked movement of the rig to an animation clip.\n\t\t\t\t * Only the bones moved by the bone mapping will be recorded.\n\t\t\t\t */\n\t\t\t\tstartRecording: recorder.start,\n\t\t\t\tstopRecording: recorder.stop,\n\t\t\t\tisRecording: () => recorder.isRecording(),\n\n update: (delta: number) => {\n bodyBindin.update(delta);\n leftHandBinding.update(delta);\n rightHandBinding.update(delta);\n faceKeys?.update(delta);\n faceRig?.update(delta);\n\n\t\t\t\t\tif( recorder.isRecording() ) {\n\t\t\t\t\t\trecorder.captureFrame()\n\t\t\t\t\t}\n },\n } as RecordableBindingHandler;\n },\n };\n}\n"],"names":["poleDir","Vector3","objectPosition","XAxis","XAxisNeg","YAxis","YAxisNeg","ZAxis","pole","lookDir","v","correction","Quaternion","worldQuat","lookAt","object","target","poleTarget","poleAxis","axis","currentPole","lookAxisDir","desiredPoleDir","cross","angle","THREE","A","B","Tracker","points","debugConnections","__publicField","key","Mark","landmarks","debugLandmarks","debugDrawer","point","mark","o","Ghost","_a","source","drawingUtils","delta","objects","normal","root","offset","objectLookAtGoal","polePosition","ghost","rig","name","speed","rootPosition","out","cleanBoneName","getBoneByName","bone","Bone","loadPoseTracker","vision","config","poseLandmarker","PoseLandmarker","PoseTracker","poseMarks","C","D","E","lookGoal","poleGoal","result","magging","map","v2","syncBone","from","to","sideAxis","hipsDir","sideHips","sideShoulders","sideHead","loadHandTracker","landmarker","HandLandmarker","isMyWrist","myWrist","otherWrist","handWrist","e","HandsTracker","handMarks","fingerKeys","v1","v3","v4","v5","v6","currSide","HALF_PI","DOWN","handLandmarker","side","hand","wrist","markToBone","palmNormal","parlmDir","palmSide","palmLookAt","polPosition","palmGhost","palmForward","sideGoal","negateSideGoal","i","fingerGhost","myDir","bonePos","fingerSideNormal","addBind","boneName","markName","loadFaceTracker","cfg","faceLandmarker","FaceLandmarker","FaceTracker","faceMarks","frame","_b","_c","category","mesh","meshKeys","categoryName","score","factor","eyeL","EyeRig","eyeR","headBone","markEarL","markEarR","headcenter","headForward","headSideNormal","headPosition","poleLookAt","faceLookAt","sideName","blendshapes","lookLeft","lookRight","lookUp","lookDown","sideMovement","verticalMovement","defaultBoneMap","blendShapeKeyNames","createRigRecorder","rigRoot","fps","bones","faceMesh","usedBlendShapeKeys","boneKeys","k","times","boneTracks","blendShapeTracks","recording","startTime","start","captureFrame","time","track","q","keyIndex","stop","keyframeTracks","data","clip","GLTFExporter","gltf","blob","url","a","error","hasGetUserMedia","setupTracker","$cfg","video","FilesetResolver","poseTracker","handsTracker","faceTracker","viewport","canvasElement","canvasCtx","DrawingUtils","predict","initializeVideo","lastVideoTime","predictWebcam","img","predictFrame","stopped","stream","onTrackEnded","stopCamera","retryWithBackoff","t","attempt","delay","res","startCamera","err","handleCameraError","bodyBindin","leftHandBinding","rightHandBinding","faceKeys","faceRig","child","recorder"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HandTracker.d.ts","sourceRoot":"","sources":["../../src/tracking/HandTracker.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,YAAY,EACT,cAAc,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAU,cAAc,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,MAAM,MAAM,kBAAkB,GAAG;IAChC,SAAS,EAAE,MAAI,kBAAkB,CAAC;IAClC,UAAU,EAAE,MAAI,kBAAkB,CAAC;IACnC,SAAS,CAAC,EAAC,MAAM,CAAA;CACjB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAKnC,wBAAsB,eAAe,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAC,kBAAkB;;;
|
|
1
|
+
{"version":3,"file":"HandTracker.d.ts","sourceRoot":"","sources":["../../src/tracking/HandTracker.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,YAAY,EACT,cAAc,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAU,cAAc,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,MAAM,MAAM,kBAAkB,GAAG;IAChC,SAAS,EAAE,MAAI,kBAAkB,CAAC;IAClC,UAAU,EAAE,MAAI,kBAAkB,CAAC;IACnC,SAAS,CAAC,EAAC,MAAM,CAAA;CACjB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAKnC,wBAAsB,eAAe,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAC,kBAAkB;;;GA2B3E;AAED,QAAA,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;CA4Bd,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,SAAS,CAAC;AAWlD,KAAK,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAA;AAChC,MAAM,MAAM,SAAS,GAAG,OAAO,CAAC;KAAG,GAAG,IAAI,YAAY,GAAG,KAAK,CAAC,QAAQ;CAAE,CAAC,CAAC;AAgB3E,cAAM,YAAa,SAAQ,OAAO,CAAC,OAAO,SAAS,CAAC;IAQvC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAAiB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAW,OAAO,CAAC,QAAQ,CAAC,SAAS;IAPtH,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAQ;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;gBAElB,cAAc,EAAC,cAAc,EAAmB,IAAI,EAAC,QAAQ,EAAmB,SAAS,EAAC,CAAE,SAAS,EAAC,kBAAkB,KAAI,OAAO;IAWvJ,OAAO,CAAE,MAAM,EAAC,cAAc,EAAE,YAAY,EAAC,YAAY;IA8BzD,IAAI,CAAG,KAAK,EAAC,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE;IAKrG;;;;;OAKG;IACH,aAAa,CAAE,KAAK,EAAC,MAAM,EAAE,UAAU,EAAC,SAAS,EAAE,GAAG,EAAC,KAAK,CAAC,QAAQ;IA6CrE,OAAO,CAAC,UAAU;IA8DlB,IAAI,CAAE,GAAG,EAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAC,OAAO;wBAuCvB,MAAM;;CAKxB"}
|
package/package.json
CHANGED