loomlarge 0.1.4 → 0.2.0
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/dist/index.cjs +209 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +89 -2
- package/dist/index.d.ts +89 -2
- package/dist/index.js +196 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
var three = require('three');
|
|
6
|
+
|
|
5
7
|
var __defProp = Object.defineProperty;
|
|
6
8
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
7
9
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -358,6 +360,107 @@ var BONE_AU_TO_BINDINGS = {
|
|
|
358
360
|
{ node: "TONGUE", channel: "rx", scale: 1, maxDegrees: 20 }
|
|
359
361
|
]
|
|
360
362
|
};
|
|
363
|
+
var isMixedAU = (id) => !!(AU_TO_MORPHS[id]?.length && BONE_AU_TO_BINDINGS[id]?.length);
|
|
364
|
+
var hasLeftRightMorphs = (auId) => {
|
|
365
|
+
const keys = AU_TO_MORPHS[auId] || [];
|
|
366
|
+
return keys.some((k) => /_L$|_R$| L$| R$|Left$|Right$/i.test(k));
|
|
367
|
+
};
|
|
368
|
+
var COMPOSITE_ROTATIONS = [
|
|
369
|
+
{
|
|
370
|
+
node: "JAW",
|
|
371
|
+
pitch: { aus: [25, 26, 27], axis: "rz" },
|
|
372
|
+
// Jaw drop (opens mouth downward)
|
|
373
|
+
yaw: { aus: [30, 35], axis: "ry", negative: 30, positive: 35 },
|
|
374
|
+
// Jaw lateral (left/right)
|
|
375
|
+
roll: null
|
|
376
|
+
// Jaw doesn't have roll
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
node: "HEAD",
|
|
380
|
+
pitch: { aus: [54, 53], axis: "rx", negative: 54, positive: 53 },
|
|
381
|
+
// Head down/up
|
|
382
|
+
yaw: { aus: [51, 52], axis: "ry", negative: 51, positive: 52 },
|
|
383
|
+
// Head turn left/right
|
|
384
|
+
roll: { aus: [55, 56], axis: "rz", negative: 55, positive: 56 }
|
|
385
|
+
// Head tilt left/right
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
node: "EYE_L",
|
|
389
|
+
pitch: { aus: [64, 63], axis: "rx", negative: 64, positive: 63 },
|
|
390
|
+
// Eyes down/up
|
|
391
|
+
yaw: { aus: [61, 62], axis: "rz", negative: 61, positive: 62 },
|
|
392
|
+
// Eyes left/right (rz for CC4)
|
|
393
|
+
roll: null
|
|
394
|
+
// Eyes don't have roll
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
node: "EYE_R",
|
|
398
|
+
pitch: { aus: [64, 63], axis: "rx", negative: 64, positive: 63 },
|
|
399
|
+
// Eyes down/up
|
|
400
|
+
yaw: { aus: [61, 62], axis: "rz", negative: 61, positive: 62 },
|
|
401
|
+
// Eyes left/right (rz for CC4)
|
|
402
|
+
roll: null
|
|
403
|
+
// Eyes don't have roll
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
node: "TONGUE",
|
|
407
|
+
pitch: { aus: [38, 37], axis: "rz", negative: 38, positive: 37 },
|
|
408
|
+
// Tongue down/up
|
|
409
|
+
yaw: { aus: [39, 40], axis: "ry", negative: 39, positive: 40 },
|
|
410
|
+
// Tongue left/right
|
|
411
|
+
roll: { aus: [41, 42], axis: "rx", negative: 41, positive: 42 }
|
|
412
|
+
// Tongue tilt left/right
|
|
413
|
+
}
|
|
414
|
+
];
|
|
415
|
+
var CONTINUUM_PAIRS_MAP = {
|
|
416
|
+
// Eyes horizontal (yaw) - both eyes share same AUs
|
|
417
|
+
61: { pairId: 62, isNegative: true, axis: "yaw", node: "EYE_L" },
|
|
418
|
+
62: { pairId: 61, isNegative: false, axis: "yaw", node: "EYE_L" },
|
|
419
|
+
// Eyes vertical (pitch)
|
|
420
|
+
64: { pairId: 63, isNegative: true, axis: "pitch", node: "EYE_L" },
|
|
421
|
+
63: { pairId: 64, isNegative: false, axis: "pitch", node: "EYE_L" },
|
|
422
|
+
// Head yaw (turn left/right)
|
|
423
|
+
51: { pairId: 52, isNegative: true, axis: "yaw", node: "HEAD" },
|
|
424
|
+
52: { pairId: 51, isNegative: false, axis: "yaw", node: "HEAD" },
|
|
425
|
+
// Head pitch (up/down)
|
|
426
|
+
54: { pairId: 53, isNegative: true, axis: "pitch", node: "HEAD" },
|
|
427
|
+
53: { pairId: 54, isNegative: false, axis: "pitch", node: "HEAD" },
|
|
428
|
+
// Head roll (tilt left/right)
|
|
429
|
+
55: { pairId: 56, isNegative: true, axis: "roll", node: "HEAD" },
|
|
430
|
+
56: { pairId: 55, isNegative: false, axis: "roll", node: "HEAD" },
|
|
431
|
+
// Jaw yaw (left/right)
|
|
432
|
+
30: { pairId: 35, isNegative: true, axis: "yaw", node: "JAW" },
|
|
433
|
+
35: { pairId: 30, isNegative: false, axis: "yaw", node: "JAW" },
|
|
434
|
+
// Tongue yaw (left/right)
|
|
435
|
+
39: { pairId: 40, isNegative: true, axis: "yaw", node: "TONGUE" },
|
|
436
|
+
40: { pairId: 39, isNegative: false, axis: "yaw", node: "TONGUE" },
|
|
437
|
+
// Tongue pitch (up/down)
|
|
438
|
+
38: { pairId: 37, isNegative: true, axis: "pitch", node: "TONGUE" },
|
|
439
|
+
37: { pairId: 38, isNegative: false, axis: "pitch", node: "TONGUE" },
|
|
440
|
+
// Tongue roll (tilt left/right)
|
|
441
|
+
41: { pairId: 42, isNegative: true, axis: "roll", node: "TONGUE" },
|
|
442
|
+
42: { pairId: 41, isNegative: false, axis: "roll", node: "TONGUE" },
|
|
443
|
+
// Extended tongue morphs (continuum pairs)
|
|
444
|
+
73: { pairId: 74, isNegative: true, axis: "yaw", node: "TONGUE" },
|
|
445
|
+
// Tongue Narrow/Wide
|
|
446
|
+
74: { pairId: 73, isNegative: false, axis: "yaw", node: "TONGUE" },
|
|
447
|
+
76: { pairId: 77, isNegative: false, axis: "pitch", node: "TONGUE" },
|
|
448
|
+
// Tongue Tip Up/Down
|
|
449
|
+
77: { pairId: 76, isNegative: true, axis: "pitch", node: "TONGUE" }
|
|
450
|
+
};
|
|
451
|
+
var CONTINUUM_LABELS = {
|
|
452
|
+
"61-62": "Eyes \u2014 Horizontal",
|
|
453
|
+
"64-63": "Eyes \u2014 Vertical",
|
|
454
|
+
"51-52": "Head \u2014 Horizontal",
|
|
455
|
+
"54-53": "Head \u2014 Vertical",
|
|
456
|
+
"55-56": "Head \u2014 Tilt",
|
|
457
|
+
"30-35": "Jaw \u2014 Horizontal",
|
|
458
|
+
"38-37": "Tongue \u2014 Vertical",
|
|
459
|
+
"39-40": "Tongue \u2014 Horizontal",
|
|
460
|
+
"41-42": "Tongue \u2014 Tilt",
|
|
461
|
+
"73-74": "Tongue \u2014 Width",
|
|
462
|
+
"76-77": "Tongue Tip \u2014 Vertical"
|
|
463
|
+
};
|
|
361
464
|
var CC4_BONE_NODES = {
|
|
362
465
|
EYE_L: "CC_Base_L_Eye",
|
|
363
466
|
EYE_R: "CC_Base_R_Eye",
|
|
@@ -490,6 +593,41 @@ var AU_MIX_DEFAULTS = {
|
|
|
490
593
|
35: 0.5
|
|
491
594
|
// jaw left/right
|
|
492
595
|
};
|
|
596
|
+
var CC4_MESHES = {
|
|
597
|
+
// Body (6 meshes, 80 morphs each) - default render order 0
|
|
598
|
+
"CC_Base_Body_1": { category: "body", morphCount: 80 },
|
|
599
|
+
"CC_Base_Body_2": { category: "body", morphCount: 80 },
|
|
600
|
+
"CC_Base_Body_3": { category: "body", morphCount: 80 },
|
|
601
|
+
"CC_Base_Body_4": { category: "body", morphCount: 80 },
|
|
602
|
+
"CC_Base_Body_5": { category: "body", morphCount: 80 },
|
|
603
|
+
"CC_Base_Body_6": { category: "body", morphCount: 80 },
|
|
604
|
+
// Eyes (bone-driven, no morphs) - render first (behind everything)
|
|
605
|
+
"CC_Base_Eye": { category: "eye", morphCount: 0, material: { renderOrder: -10 } },
|
|
606
|
+
"CC_Base_Eye_1": { category: "eye", morphCount: 0, material: { renderOrder: -10 } },
|
|
607
|
+
"CC_Base_Eye_2": { category: "eye", morphCount: 0, material: { renderOrder: -10 } },
|
|
608
|
+
"CC_Base_Eye_3": { category: "eye", morphCount: 0, material: { renderOrder: -10 } },
|
|
609
|
+
"CC_Base_Eye_4": { category: "eye", morphCount: 0, material: { renderOrder: -10 } },
|
|
610
|
+
// Eye occlusion (94 morphs each) - render on top of eyes with transparency support
|
|
611
|
+
"CC_Base_EyeOcclusion_1": { category: "eyeOcclusion", morphCount: 94, material: { renderOrder: 2, transparent: true, opacity: 1, depthWrite: true, depthTest: true, blending: "Normal" } },
|
|
612
|
+
"CC_Base_EyeOcclusion_2": { category: "eyeOcclusion", morphCount: 94, material: { renderOrder: 2, transparent: true, opacity: 1, depthWrite: true, depthTest: true, blending: "Normal" } },
|
|
613
|
+
// Tear lines (90 morphs each) - on top of eyes/face
|
|
614
|
+
"CC_Base_TearLine_1": { category: "tearLine", morphCount: 90, material: { renderOrder: 2 } },
|
|
615
|
+
"CC_Base_TearLine_2": { category: "tearLine", morphCount: 90, material: { renderOrder: 2 } },
|
|
616
|
+
// Cornea (no morphs) - render first with eyes
|
|
617
|
+
"CC_Base_Cornea": { category: "cornea", morphCount: 0, material: { renderOrder: -10 } },
|
|
618
|
+
"CC_Base_Cornea_1": { category: "cornea", morphCount: 0, material: { renderOrder: -10 } },
|
|
619
|
+
// Teeth (no morphs, follow jaw bone) - default render order
|
|
620
|
+
"CC_Base_Teeth_1": { category: "teeth", morphCount: 0 },
|
|
621
|
+
"CC_Base_Teeth_2": { category: "teeth", morphCount: 0 },
|
|
622
|
+
// Tongue (23 morphs) - default render order
|
|
623
|
+
"CC_Base_Tongue": { category: "tongue", morphCount: 23 },
|
|
624
|
+
// Eyebrows (91 morphs each) - above face
|
|
625
|
+
"Male_Bushy_1": { category: "eyebrow", morphCount: 91, material: { renderOrder: 5 } },
|
|
626
|
+
"Male_Bushy_2": { category: "eyebrow", morphCount: 91, material: { renderOrder: 5 } },
|
|
627
|
+
// Hair (14 styling morphs each) - render last (on top of everything)
|
|
628
|
+
"Side_part_wavy_1": { category: "hair", morphCount: 14, material: { renderOrder: 10 } },
|
|
629
|
+
"Side_part_wavy_2": { category: "hair", morphCount: 14, material: { renderOrder: 10 } }
|
|
630
|
+
};
|
|
493
631
|
var MORPH_TO_MESH = {
|
|
494
632
|
// Face/AU morphs affect the main face mesh and both eyebrow meshes.
|
|
495
633
|
face: ["CC_Base_Body_1", "Male_Bushy_1", "Male_Bushy_2"],
|
|
@@ -541,6 +679,10 @@ var _LoomLargeThree = class _LoomLargeThree {
|
|
|
541
679
|
__publicField(this, "mixWeights", {});
|
|
542
680
|
// Viseme state
|
|
543
681
|
__publicField(this, "visemeValues", new Array(15).fill(0));
|
|
682
|
+
// Internal RAF loop
|
|
683
|
+
__publicField(this, "clock", new three.Clock());
|
|
684
|
+
__publicField(this, "rafId", null);
|
|
685
|
+
__publicField(this, "running", false);
|
|
544
686
|
this.config = config.auMappings || CC4_PRESET;
|
|
545
687
|
this.mixWeights = { ...this.config.auMixDefaults };
|
|
546
688
|
this.animation = animation || new AnimationThree();
|
|
@@ -577,6 +719,7 @@ var _LoomLargeThree = class _LoomLargeThree {
|
|
|
577
719
|
this.rigReady = true;
|
|
578
720
|
this.missingBoneWarnings.clear();
|
|
579
721
|
this.initBoneRotations();
|
|
722
|
+
this.applyMeshMaterialSettings(model);
|
|
580
723
|
}
|
|
581
724
|
update(deltaSeconds) {
|
|
582
725
|
const dtSeconds = Math.max(0, deltaSeconds || 0);
|
|
@@ -584,7 +727,30 @@ var _LoomLargeThree = class _LoomLargeThree {
|
|
|
584
727
|
this.animation.tick(dtSeconds);
|
|
585
728
|
this.flushPendingComposites();
|
|
586
729
|
}
|
|
730
|
+
/** Start the internal RAF loop */
|
|
731
|
+
start() {
|
|
732
|
+
if (this.running) return;
|
|
733
|
+
this.running = true;
|
|
734
|
+
this.clock.start();
|
|
735
|
+
const tick = () => {
|
|
736
|
+
if (!this.running) return;
|
|
737
|
+
const dt = this.clock.getDelta();
|
|
738
|
+
this.update(dt);
|
|
739
|
+
this.rafId = requestAnimationFrame(tick);
|
|
740
|
+
};
|
|
741
|
+
this.rafId = requestAnimationFrame(tick);
|
|
742
|
+
}
|
|
743
|
+
/** Stop the internal RAF loop */
|
|
744
|
+
stop() {
|
|
745
|
+
this.running = false;
|
|
746
|
+
if (this.rafId !== null) {
|
|
747
|
+
cancelAnimationFrame(this.rafId);
|
|
748
|
+
this.rafId = null;
|
|
749
|
+
}
|
|
750
|
+
this.clock.stop();
|
|
751
|
+
}
|
|
587
752
|
dispose() {
|
|
753
|
+
this.stop();
|
|
588
754
|
this.clearTransitions();
|
|
589
755
|
this.meshes = [];
|
|
590
756
|
this.model = null;
|
|
@@ -1008,6 +1174,35 @@ var _LoomLargeThree = class _LoomLargeThree {
|
|
|
1008
1174
|
cancel: () => handles.forEach((h) => h.cancel())
|
|
1009
1175
|
};
|
|
1010
1176
|
}
|
|
1177
|
+
/**
|
|
1178
|
+
* Apply render order and material settings from CC4_MESHES to all meshes.
|
|
1179
|
+
* This ensures proper layering (e.g., hair renders on top of eyebrows).
|
|
1180
|
+
*/
|
|
1181
|
+
applyMeshMaterialSettings(root) {
|
|
1182
|
+
root.traverse((obj) => {
|
|
1183
|
+
if (!obj.isMesh || !obj.name) return;
|
|
1184
|
+
const meshInfo = CC4_MESHES[obj.name];
|
|
1185
|
+
if (!meshInfo?.material) return;
|
|
1186
|
+
const settings = meshInfo.material;
|
|
1187
|
+
if (typeof settings.renderOrder === "number") {
|
|
1188
|
+
obj.renderOrder = settings.renderOrder;
|
|
1189
|
+
}
|
|
1190
|
+
if (obj.material) {
|
|
1191
|
+
if (typeof settings.transparent === "boolean") {
|
|
1192
|
+
obj.material.transparent = settings.transparent;
|
|
1193
|
+
}
|
|
1194
|
+
if (typeof settings.opacity === "number") {
|
|
1195
|
+
obj.material.opacity = settings.opacity;
|
|
1196
|
+
}
|
|
1197
|
+
if (typeof settings.depthWrite === "boolean") {
|
|
1198
|
+
obj.material.depthWrite = settings.depthWrite;
|
|
1199
|
+
}
|
|
1200
|
+
if (typeof settings.depthTest === "boolean") {
|
|
1201
|
+
obj.material.depthTest = settings.depthTest;
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
});
|
|
1205
|
+
}
|
|
1011
1206
|
};
|
|
1012
1207
|
// Viseme jaw amounts
|
|
1013
1208
|
__publicField(_LoomLargeThree, "VISEME_JAW_AMOUNTS", [
|
|
@@ -1165,12 +1360,26 @@ var HairPhysics = class {
|
|
|
1165
1360
|
}
|
|
1166
1361
|
};
|
|
1167
1362
|
|
|
1363
|
+
exports.AU_INFO = AU_INFO;
|
|
1364
|
+
exports.AU_MIX_DEFAULTS = AU_MIX_DEFAULTS;
|
|
1365
|
+
exports.AU_TO_MORPHS = AU_TO_MORPHS;
|
|
1168
1366
|
exports.AnimationThree = AnimationThree;
|
|
1367
|
+
exports.BONE_AU_TO_BINDINGS = BONE_AU_TO_BINDINGS;
|
|
1368
|
+
exports.CC4_BONE_NODES = CC4_BONE_NODES;
|
|
1369
|
+
exports.CC4_EYE_MESH_NODES = CC4_EYE_MESH_NODES;
|
|
1370
|
+
exports.CC4_MESHES = CC4_MESHES;
|
|
1169
1371
|
exports.CC4_PRESET = CC4_PRESET;
|
|
1372
|
+
exports.COMPOSITE_ROTATIONS = COMPOSITE_ROTATIONS;
|
|
1373
|
+
exports.CONTINUUM_LABELS = CONTINUUM_LABELS;
|
|
1374
|
+
exports.CONTINUUM_PAIRS_MAP = CONTINUUM_PAIRS_MAP;
|
|
1170
1375
|
exports.DEFAULT_HAIR_PHYSICS_CONFIG = DEFAULT_HAIR_PHYSICS_CONFIG;
|
|
1171
1376
|
exports.HairPhysics = HairPhysics;
|
|
1172
1377
|
exports.LoomLargeThree = LoomLargeThree;
|
|
1378
|
+
exports.MORPH_TO_MESH = MORPH_TO_MESH;
|
|
1379
|
+
exports.VISEME_KEYS = VISEME_KEYS;
|
|
1173
1380
|
exports.collectMorphMeshes = collectMorphMeshes;
|
|
1174
1381
|
exports.default = LoomLargeThree;
|
|
1382
|
+
exports.hasLeftRightMorphs = hasLeftRightMorphs;
|
|
1383
|
+
exports.isMixedAU = isMixedAU;
|
|
1175
1384
|
//# sourceMappingURL=index.cjs.map
|
|
1176
1385
|
//# sourceMappingURL=index.cjs.map
|