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