@needle-tools/three-animation-pointer 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +1 -0
- package/dist/three-animation-pointer.js +135 -132
- package/package.json +2 -2
- package/src/GLTFLoaderAnimationPointer.js +15 -7
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to this package will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [1.1.2] - 2026-06-17
|
|
8
|
+
- Fix: don't mutate the `KHR_animation_pointer.pointer` value in `parser.json`. The resolved three.js property path is now kept in plugin-local state, so other plugins / app code can still read the original spec-defined pointer after load — by @0b5vr in [#2](https://github.com/needle-tools/three-animation-pointer/pull/2)
|
|
9
|
+
|
|
10
|
+
## [1.1.1] - 2026-06-12
|
|
11
|
+
- Fix: morph target (blend shape) weight animation was silently dropped for multi-material meshes without skin/bones. The multi-material morph branch only bound children that were `SkinnedMesh`; such meshes load as a `Group` of plain `Mesh` children, so no track was created (and the empty-but-truthy result skipped the fallback). Now any child with `morphTargetInfluences` is bound.
|
|
12
|
+
|
|
7
13
|
## [1.1.0] - 2026-06-01
|
|
8
14
|
- Add: support for `/nodes/{}/weights/{}` to animate individual morph target weights (works with multi-material meshes / primitives) — by @0b5vr in [#1](https://github.com/needle-tools/three-animation-pointer/pull/1)
|
|
9
15
|
|
package/README.md
CHANGED
|
@@ -6,6 +6,7 @@ This package adds a [three.js](https://github.com/mrdoob/three.js) GLTFLoader pl
|
|
|
6
6
|
- all material properties 💎 (including texture transforms)
|
|
7
7
|
- cameras 🎥
|
|
8
8
|
- lights 💡
|
|
9
|
+
- morph target weights 😀 (all weights or individual ones via `/nodes/{}/weights/{}`)
|
|
9
10
|
- custom code/scripts 📄
|
|
10
11
|
|
|
11
12
|
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
const
|
|
1
|
+
import { InterpolateDiscrete as M, InterpolateLinear as F, AnimationClip as w, PropertyBinding as C, QuaternionKeyframeTrack as S, ColorKeyframeTrack as W, VectorKeyframeTrack as B, BooleanKeyframeTrack as D, NumberKeyframeTrack as E } from "three";
|
|
2
|
+
const k = {
|
|
3
3
|
node: "node",
|
|
4
4
|
material: "material",
|
|
5
5
|
camera: "camera",
|
|
6
6
|
light: "light"
|
|
7
|
-
},
|
|
7
|
+
}, R = "KHR_animation_pointer", O = {
|
|
8
8
|
// We use a custom interpolant (GLTFCubicSplineInterpolation) for CUBICSPLINE tracks. Each
|
|
9
9
|
// keyframe track will be initialized with a default interpolation type, then modified.
|
|
10
10
|
CUBICSPLINE: void 0,
|
|
11
11
|
LINEAR: F,
|
|
12
|
-
STEP:
|
|
12
|
+
STEP: M
|
|
13
13
|
};
|
|
14
|
-
class
|
|
14
|
+
class z {
|
|
15
15
|
/** @type {import("three/examples/jsm/loaders/GLTFLoader").GLTFParser} */
|
|
16
16
|
constructor(a) {
|
|
17
|
-
this.name =
|
|
17
|
+
this.name = R, this.parser = a, this.animationPointerResolver = null, this.pointerPathMap = /* @__PURE__ */ new Map();
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* @param {import("..").AnimationPointerResolver | null} animationPointerResolver
|
|
@@ -24,30 +24,30 @@ class G {
|
|
|
24
24
|
}
|
|
25
25
|
/* DUPLICATE of functionality in GLTFLoader */
|
|
26
26
|
loadAnimationTargetFromChannel(a) {
|
|
27
|
-
const
|
|
27
|
+
const s = a.target, r = s.node !== void 0 ? s.node : s.id;
|
|
28
28
|
return this.parser.getDependency("node", r);
|
|
29
29
|
}
|
|
30
30
|
loadAnimationTargetFromChannelWithAnimationPointer(a) {
|
|
31
|
-
var
|
|
32
|
-
|
|
33
|
-
const
|
|
31
|
+
var o;
|
|
32
|
+
L();
|
|
33
|
+
const s = a.target, r = s.extensions && s.extensions[R] && s.path && s.path === "pointer";
|
|
34
34
|
if (!r) return null;
|
|
35
|
-
let e,
|
|
35
|
+
let e, t = k.node, n;
|
|
36
36
|
if (r) {
|
|
37
|
-
const
|
|
38
|
-
let
|
|
39
|
-
if (!
|
|
40
|
-
console.warn("Invalid path",
|
|
37
|
+
const m = s.extensions[R];
|
|
38
|
+
let i = m.pointer;
|
|
39
|
+
if (!i) {
|
|
40
|
+
console.warn("Invalid path", m, s);
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
|
-
if (
|
|
44
|
-
console.warn("Failed resolving animation node id: " +
|
|
43
|
+
if (i.startsWith("/materials/") ? t = k.material : i.startsWith("/extensions/KHR_lights_punctual/lights/") ? t = k.light : i.startsWith("/cameras/") && (t = k.camera), n = this._tryResolveTargetId(i, t), n === null || isNaN(n)) {
|
|
44
|
+
console.warn("Failed resolving animation node id: " + n, i);
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
|
-
switch (
|
|
48
|
-
case
|
|
49
|
-
const
|
|
50
|
-
switch (e =
|
|
47
|
+
switch (t) {
|
|
48
|
+
case k.material:
|
|
49
|
+
const h = ("/materials/" + n.toString() + "/").length, y = i.substring(0, h);
|
|
50
|
+
switch (e = i.substring(h), e) {
|
|
51
51
|
case "pbrMetallicRoughness/baseColorFactor":
|
|
52
52
|
e = "color";
|
|
53
53
|
break;
|
|
@@ -130,13 +130,13 @@ class G {
|
|
|
130
130
|
e = "specularColor";
|
|
131
131
|
break;
|
|
132
132
|
}
|
|
133
|
-
|
|
133
|
+
i = y + e;
|
|
134
134
|
break;
|
|
135
|
-
case
|
|
136
|
-
const
|
|
137
|
-
if (e =
|
|
138
|
-
const
|
|
139
|
-
/^\d+$/.test(
|
|
135
|
+
case k.node:
|
|
136
|
+
const f = ("/nodes/" + n.toString() + "/").length, d = i.substring(0, f);
|
|
137
|
+
if (e = i.substring(f), e.startsWith("weights/")) {
|
|
138
|
+
const l = e.substring(8);
|
|
139
|
+
/^\d+$/.test(l) ? e = "morphTargetInfluences[" + l + "]" : console.warn(R + ": invalid weight index", e, i);
|
|
140
140
|
} else
|
|
141
141
|
switch (e) {
|
|
142
142
|
case "translation":
|
|
@@ -155,11 +155,11 @@ class G {
|
|
|
155
155
|
e = "visible";
|
|
156
156
|
break;
|
|
157
157
|
}
|
|
158
|
-
|
|
158
|
+
i = d + e;
|
|
159
159
|
break;
|
|
160
|
-
case
|
|
161
|
-
const
|
|
162
|
-
switch (e =
|
|
160
|
+
case k.light:
|
|
161
|
+
const p = ("/extensions/KHR_lights_punctual/lights/" + n.toString() + "/").length;
|
|
162
|
+
switch (e = i.substring(p), e) {
|
|
163
163
|
case "color":
|
|
164
164
|
break;
|
|
165
165
|
case "intensity":
|
|
@@ -174,11 +174,11 @@ class G {
|
|
|
174
174
|
e = "distance";
|
|
175
175
|
break;
|
|
176
176
|
}
|
|
177
|
-
|
|
177
|
+
i = "/lights/" + n.toString() + "/" + e;
|
|
178
178
|
break;
|
|
179
|
-
case
|
|
180
|
-
const
|
|
181
|
-
switch (e =
|
|
179
|
+
case k.camera:
|
|
180
|
+
const c = ("/cameras/" + n.toString() + "/").length, b = i.substring(0, c);
|
|
181
|
+
switch (e = i.substring(c), e) {
|
|
182
182
|
case "perspective/yfov":
|
|
183
183
|
e = "fov";
|
|
184
184
|
break;
|
|
@@ -200,91 +200,94 @@ class G {
|
|
|
200
200
|
e = "zoom";
|
|
201
201
|
break;
|
|
202
202
|
}
|
|
203
|
-
|
|
203
|
+
i = b + e;
|
|
204
204
|
break;
|
|
205
205
|
}
|
|
206
|
-
(
|
|
206
|
+
(o = this.animationPointerResolver) != null && o.resolvePath && (i = this.animationPointerResolver.resolvePath(i));
|
|
207
|
+
const v = m.pointer;
|
|
208
|
+
this.pointerPathMap.set(v, i);
|
|
207
209
|
}
|
|
208
|
-
if (
|
|
209
|
-
console.warn("Failed resolving animation node id: " +
|
|
210
|
+
if (n == null || isNaN(n)) {
|
|
211
|
+
console.warn("Failed resolving animation node id: " + n, s);
|
|
210
212
|
return;
|
|
211
213
|
}
|
|
212
|
-
let
|
|
213
|
-
return
|
|
214
|
+
let u;
|
|
215
|
+
return t === k.node ? u = this.parser.getDependency("node", n) : t === k.material ? u = this.parser.getDependency("material", n) : t === k.light ? u = this.parser.getDependency("light", n) : t === k.camera ? u = this.parser.getDependency("camera", n) : console.error("Unhandled type", t), u;
|
|
214
216
|
}
|
|
215
|
-
createAnimationTracksWithAnimationPointer(a,
|
|
216
|
-
var
|
|
217
|
-
if (!(
|
|
218
|
-
|
|
219
|
-
|
|
217
|
+
createAnimationTracksWithAnimationPointer(a, s, r, e, t) {
|
|
218
|
+
var d;
|
|
219
|
+
if (!(t.extensions && t.extensions[R] && t.path && t.path === "pointer")) return null;
|
|
220
|
+
const u = t.extensions[R].pointer;
|
|
221
|
+
let o = this.pointerPathMap.get(u);
|
|
222
|
+
if (!o) return null;
|
|
220
223
|
const m = [];
|
|
221
|
-
|
|
222
|
-
const
|
|
223
|
-
var
|
|
224
|
-
if (
|
|
225
|
-
const
|
|
224
|
+
o = o.replaceAll("/", ".");
|
|
225
|
+
const i = o.split(".");
|
|
226
|
+
var h = a.name !== void 0 && a.name !== null ? a.name : a.uuid;
|
|
227
|
+
if (i[2] = h, (d = i[3]) != null && d.startsWith("morphTargetInfluences")) {
|
|
228
|
+
const p = i[3];
|
|
226
229
|
if (a.type === "Group") {
|
|
227
|
-
for (const
|
|
228
|
-
|
|
230
|
+
for (const c of a.children)
|
|
231
|
+
c.morphTargetInfluences && (i[3] = c.name, i[4] = p, f(this.parser));
|
|
229
232
|
return m;
|
|
230
233
|
}
|
|
231
234
|
}
|
|
232
|
-
|
|
233
|
-
function
|
|
235
|
+
f(this.parser);
|
|
236
|
+
function y(p, c) {
|
|
234
237
|
try {
|
|
235
|
-
const
|
|
236
|
-
return
|
|
238
|
+
const b = c.split(".").filter(Boolean), g = b[b.length - 1].replace(/\[.*\]$/, "");
|
|
239
|
+
return g in p ? typeof p[g] == "boolean" : !1;
|
|
237
240
|
} catch {
|
|
238
241
|
return !1;
|
|
239
242
|
}
|
|
240
243
|
}
|
|
241
|
-
function
|
|
242
|
-
|
|
243
|
-
let
|
|
244
|
+
function f(p) {
|
|
245
|
+
o = i.join(".");
|
|
246
|
+
let c, b = !1;
|
|
244
247
|
switch (r.itemSize) {
|
|
245
248
|
case 1:
|
|
246
249
|
Object.prototype.toString.call(r.array) === "[object Uint8Array]" && // UNSIGNED_BYTE as a strong hint
|
|
247
|
-
|
|
250
|
+
y(a, o) ? (c = D, b = !0) : c = E;
|
|
248
251
|
break;
|
|
249
252
|
case 2:
|
|
250
253
|
case 3:
|
|
251
|
-
|
|
254
|
+
c = B;
|
|
252
255
|
break;
|
|
253
256
|
case 4:
|
|
254
|
-
|
|
257
|
+
o.endsWith(".quaternion") ? c = S : c = W;
|
|
255
258
|
break;
|
|
256
259
|
}
|
|
257
|
-
if (!
|
|
260
|
+
if (!c) {
|
|
258
261
|
console.warn("Unsupported output accessor format", r);
|
|
259
262
|
return;
|
|
260
263
|
}
|
|
261
|
-
const
|
|
262
|
-
let
|
|
263
|
-
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
264
|
+
const l = e.interpolation !== void 0 ? O[e.interpolation] : F;
|
|
265
|
+
let g = p._getArrayFromAccessor(r);
|
|
266
|
+
o.endsWith(".fov") && (g = g.map((x) => x / Math.PI * 180)), b && (g = g.map((x) => x > 0));
|
|
267
|
+
const _ = new c(
|
|
268
|
+
o,
|
|
269
|
+
s.array,
|
|
270
|
+
g,
|
|
271
|
+
l
|
|
269
272
|
);
|
|
270
|
-
if (
|
|
271
|
-
const
|
|
272
|
-
for (let
|
|
273
|
-
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
273
|
+
if (l === "CUBICSPLINE" && p._createCubicSplineTrackInterpolant(_), m.push(_), o && r.itemSize === 4 && o.startsWith(".materials.") && o.endsWith(".color")) {
|
|
274
|
+
const x = new Float32Array(g.length / 4);
|
|
275
|
+
for (let T = 0, K = g.length / 4; T < K; T += 1)
|
|
276
|
+
x[T] = g[T * 4 + 3];
|
|
277
|
+
const I = new c(
|
|
278
|
+
o.replace(".color", ".opacity"),
|
|
279
|
+
s.array,
|
|
280
|
+
x,
|
|
281
|
+
l
|
|
279
282
|
);
|
|
280
|
-
|
|
283
|
+
l === "CUBICSPLINE" && p._createCubicSplineTrackInterpolant(_), m.push(I);
|
|
281
284
|
}
|
|
282
285
|
}
|
|
283
286
|
return m;
|
|
284
287
|
}
|
|
285
|
-
_tryResolveTargetId(a,
|
|
288
|
+
_tryResolveTargetId(a, s) {
|
|
286
289
|
let r = "";
|
|
287
|
-
return
|
|
290
|
+
return s === "node" ? r = a.substring(7) : s === "material" ? r = a.substring(11) : s === "light" ? r = a.substring(39) : s === "camera" && (r = a.substring(9)), r = r.substring(0, r.indexOf("/")), Number.parseInt(r);
|
|
288
291
|
}
|
|
289
292
|
/* MOSTLY DUPLICATE of GLTFLoader.loadAnimation, but also tries to resolve KHR_animation_pointer. */
|
|
290
293
|
/**
|
|
@@ -293,72 +296,72 @@ class G {
|
|
|
293
296
|
* @return {Promise<AnimationClip>}
|
|
294
297
|
*/
|
|
295
298
|
loadAnimation(a) {
|
|
296
|
-
const
|
|
297
|
-
for (let
|
|
298
|
-
const
|
|
299
|
-
let
|
|
300
|
-
|
|
299
|
+
const s = this, r = this.parser.json, e = this.parser, t = r.animations[a], n = t.name ? t.name : "animation_" + a, u = [], o = [], m = [], i = [], v = [];
|
|
300
|
+
for (let h = 0, y = t.channels.length; h < y; h++) {
|
|
301
|
+
const f = t.channels[h], d = t.samplers[f.sampler], p = f.target, c = t.parameters !== void 0 ? t.parameters[d.input] : d.input, b = t.parameters !== void 0 ? t.parameters[d.output] : d.output;
|
|
302
|
+
let l = s.loadAnimationTargetFromChannelWithAnimationPointer(f);
|
|
303
|
+
l || (l = s.loadAnimationTargetFromChannel(f)), u.push(l), o.push(e.getDependency("accessor", c)), m.push(e.getDependency("accessor", b)), i.push(d), v.push(p);
|
|
301
304
|
}
|
|
302
305
|
return Promise.all([
|
|
303
|
-
Promise.all(
|
|
304
|
-
Promise.all(m),
|
|
305
|
-
Promise.all(h),
|
|
306
|
+
Promise.all(u),
|
|
306
307
|
Promise.all(o),
|
|
307
|
-
Promise.all(
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
308
|
+
Promise.all(m),
|
|
309
|
+
Promise.all(i),
|
|
310
|
+
Promise.all(v)
|
|
311
|
+
]).then(function(h) {
|
|
312
|
+
const y = h[0], f = h[1], d = h[2], p = h[3], c = h[4], b = [];
|
|
313
|
+
for (let l = 0, g = y.length; l < g; l++) {
|
|
314
|
+
const _ = y[l], x = f[l], I = d[l], T = p[l], K = c[l];
|
|
315
|
+
if (_ === void 0) continue;
|
|
316
|
+
_.updateMatrix && (_.updateMatrix(), _.matrixAutoUpdate = !0);
|
|
317
|
+
let P = s.createAnimationTracksWithAnimationPointer(_, x, I, T, K);
|
|
318
|
+
if (P || (P = e._createAnimationTracks(_, x, I, T, K)), P)
|
|
319
|
+
for (let N = 0; N < P.length; N++)
|
|
320
|
+
b.push(P[N]);
|
|
318
321
|
}
|
|
319
|
-
return new
|
|
322
|
+
return new w(n, void 0, b);
|
|
320
323
|
});
|
|
321
324
|
}
|
|
322
325
|
}
|
|
323
|
-
let H = !1,
|
|
324
|
-
function
|
|
326
|
+
let H = !1, U = null;
|
|
327
|
+
function L() {
|
|
325
328
|
if (H) return;
|
|
326
329
|
H = !0;
|
|
327
|
-
const
|
|
328
|
-
C.findNode = function(a,
|
|
329
|
-
if (!
|
|
330
|
-
if (
|
|
331
|
-
const r =
|
|
332
|
-
let
|
|
333
|
-
return a.traverse((
|
|
334
|
-
|
|
335
|
-
}),
|
|
336
|
-
} else if (
|
|
337
|
-
const r =
|
|
330
|
+
const A = U || (U = C.findNode);
|
|
331
|
+
C.findNode = function(a, s) {
|
|
332
|
+
if (!s) return A(a, s);
|
|
333
|
+
if (s.startsWith(".materials.")) {
|
|
334
|
+
const r = s.substring(11).substring(s.indexOf(".")), e = r.indexOf("."), t = e < 0 ? r : r.substring(0, e);
|
|
335
|
+
let n = null;
|
|
336
|
+
return a.traverse((u) => {
|
|
337
|
+
n !== null || u.type !== "Mesh" && u.type !== "SkinnedMesh" || u.material && (u.material.uuid === t || u.material.name === t) && (n = u.material, n !== null && (r.endsWith(".map") ? n = n.map : r.endsWith(".emissiveMap") && (n = n.emissiveMap)));
|
|
338
|
+
}), n;
|
|
339
|
+
} else if (s.startsWith(".nodes.") || s.startsWith(".lights.") || s.startsWith(".cameras.")) {
|
|
340
|
+
const r = s.split(".");
|
|
338
341
|
let e;
|
|
339
|
-
for (let
|
|
340
|
-
const
|
|
341
|
-
if (
|
|
342
|
-
e = a.getObjectByProperty("uuid",
|
|
343
|
-
else if (e && e[
|
|
344
|
-
const
|
|
345
|
-
let
|
|
346
|
-
|
|
342
|
+
for (let t = 1; t < r.length; t++) {
|
|
343
|
+
const n = r[t];
|
|
344
|
+
if (n.length == 36)
|
|
345
|
+
e = a.getObjectByProperty("uuid", n);
|
|
346
|
+
else if (e && e[n]) {
|
|
347
|
+
const o = Number.parseInt(n);
|
|
348
|
+
let m = n;
|
|
349
|
+
o >= 0 && (m = o), e = e[m];
|
|
347
350
|
} else {
|
|
348
|
-
const
|
|
349
|
-
|
|
351
|
+
const o = a.getObjectByName(n);
|
|
352
|
+
o && (e = o);
|
|
350
353
|
}
|
|
351
354
|
}
|
|
352
355
|
if (!e) {
|
|
353
|
-
const
|
|
354
|
-
return
|
|
356
|
+
const t = A(a, r[2]);
|
|
357
|
+
return t || console.warn(R + ": Property binding not found", s, a, a.name, r), t;
|
|
355
358
|
}
|
|
356
359
|
return e;
|
|
357
360
|
}
|
|
358
|
-
return
|
|
361
|
+
return A(a, s);
|
|
359
362
|
};
|
|
360
363
|
}
|
|
361
364
|
export {
|
|
362
|
-
|
|
363
|
-
|
|
365
|
+
z as GLTFAnimationPointerExtension,
|
|
366
|
+
z as default
|
|
364
367
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/three-animation-pointer",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "KHR_animation_pointer support for three.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/three-animation-pointer.js",
|
|
@@ -46,4 +46,4 @@
|
|
|
46
46
|
"registry": "https://registry.npmjs.org/",
|
|
47
47
|
"access": "public"
|
|
48
48
|
}
|
|
49
|
-
}
|
|
49
|
+
}
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
PropertyBinding,
|
|
8
8
|
QuaternionKeyframeTrack,
|
|
9
9
|
VectorKeyframeTrack,
|
|
10
|
-
SkinnedMesh,
|
|
11
10
|
BooleanKeyframeTrack
|
|
12
11
|
} from 'three';
|
|
13
12
|
|
|
@@ -55,6 +54,12 @@ export class GLTFAnimationPointerExtension {
|
|
|
55
54
|
/** @type {import("..").AnimationPointerResolver | null} */
|
|
56
55
|
this.animationPointerResolver = null;
|
|
57
56
|
|
|
57
|
+
/**
|
|
58
|
+
* @type {Map<string, string>}
|
|
59
|
+
* Maps from original pointer paths to resolved three.js property paths.
|
|
60
|
+
*/
|
|
61
|
+
this.pointerPathMap = new Map();
|
|
62
|
+
|
|
58
63
|
}
|
|
59
64
|
|
|
60
65
|
/**
|
|
@@ -352,7 +357,8 @@ export class GLTFAnimationPointerExtension {
|
|
|
352
357
|
|
|
353
358
|
}
|
|
354
359
|
|
|
355
|
-
|
|
360
|
+
const pointer = ext.pointer;
|
|
361
|
+
this.pointerPathMap.set( pointer, path );
|
|
356
362
|
|
|
357
363
|
}
|
|
358
364
|
|
|
@@ -385,7 +391,8 @@ export class GLTFAnimationPointerExtension {
|
|
|
385
391
|
const useExtension = target.extensions && target.extensions[ KHR_ANIMATION_POINTER ] && target.path && target.path === 'pointer';
|
|
386
392
|
if ( ! useExtension ) return null;
|
|
387
393
|
|
|
388
|
-
|
|
394
|
+
const pointer = target.extensions[ KHR_ANIMATION_POINTER ].pointer;
|
|
395
|
+
let animationPointerPropertyPath = this.pointerPathMap.get( pointer );
|
|
389
396
|
if ( ! animationPointerPropertyPath ) return null;
|
|
390
397
|
|
|
391
398
|
const tracks = [];
|
|
@@ -408,12 +415,13 @@ export class GLTFAnimationPointerExtension {
|
|
|
408
415
|
if ( node.type === 'Group' ) {
|
|
409
416
|
|
|
410
417
|
if ( _animationPointerDebug )
|
|
411
|
-
console.log( 'Detected multi-material
|
|
418
|
+
console.log( 'Detected multi-material mesh export', animationPointerPropertyPath, node );
|
|
412
419
|
|
|
413
|
-
//
|
|
420
|
+
// Bind any child that has morph influences. The children may be plain
|
|
421
|
+
// Mesh (no skin/bones) or SkinnedMesh, so we must not require SkinnedMesh.
|
|
414
422
|
for ( const ch of node.children ) {
|
|
415
423
|
|
|
416
|
-
if ( ch
|
|
424
|
+
if ( ch.morphTargetInfluences ) {
|
|
417
425
|
|
|
418
426
|
parts[ 3 ] = ch.name;
|
|
419
427
|
parts[ 4 ] = property;
|
|
@@ -810,4 +818,4 @@ function _ensurePropertyBindingPatch() {
|
|
|
810
818
|
|
|
811
819
|
};
|
|
812
820
|
|
|
813
|
-
}
|
|
821
|
+
}
|