@lovelace_lol/loom3 1.0.4 → 1.0.6
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 +1 -1
- package/dist/index.cjs +149 -131
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -32
- package/dist/index.d.ts +22 -32
- package/dist/index.js +149 -131
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -854,7 +854,7 @@ Only AUs that have both `auToMorphs` AND `auToBones` entries support mixing. Com
|
|
|
854
854
|
- AU26 (Jaw Drop)
|
|
855
855
|
- AU27 (Mouth Stretch)
|
|
856
856
|
- AU51-56 (Head movements)
|
|
857
|
-
- AU61-
|
|
857
|
+
- AU61-72 (Shared + independent eye movements)
|
|
858
858
|
|
|
859
859
|
```typescript
|
|
860
860
|
import { isMixedAU } from '@lovelace_lol/loom3';
|
package/dist/index.cjs
CHANGED
|
@@ -26,11 +26,53 @@ var __defProp = Object.defineProperty;
|
|
|
26
26
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
27
27
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
28
28
|
|
|
29
|
+
// src/core/compositeAxis.ts
|
|
30
|
+
function toAUList(value) {
|
|
31
|
+
if (value === void 0) return [];
|
|
32
|
+
return Array.isArray(value) ? value : [value];
|
|
33
|
+
}
|
|
34
|
+
function findBoneBindingForNode(auToBones, auId, nodeKey) {
|
|
35
|
+
return auToBones[auId]?.find((candidate) => candidate.node === nodeKey) ?? null;
|
|
36
|
+
}
|
|
37
|
+
function getCompositeAxisValue(axisConfig, getValue) {
|
|
38
|
+
if (!axisConfig) return 0;
|
|
39
|
+
const negativeAUs = toAUList(axisConfig.negative);
|
|
40
|
+
const positiveAUs = toAUList(axisConfig.positive);
|
|
41
|
+
if (negativeAUs.length > 0 && positiveAUs.length > 0) {
|
|
42
|
+
const negativeValue = Math.max(...negativeAUs.map(getValue), 0);
|
|
43
|
+
const positiveValue = Math.max(...positiveAUs.map(getValue), 0);
|
|
44
|
+
return positiveValue - negativeValue;
|
|
45
|
+
}
|
|
46
|
+
if (axisConfig.aus.length > 1) {
|
|
47
|
+
return Math.max(...axisConfig.aus.map(getValue), 0);
|
|
48
|
+
}
|
|
49
|
+
return getValue(axisConfig.aus[0]);
|
|
50
|
+
}
|
|
51
|
+
function getCompositeAxisBinding(nodeKey, axisConfig, direction, getValue, auToBones) {
|
|
52
|
+
if (!axisConfig) return null;
|
|
53
|
+
const directionalAUs = direction < 0 ? toAUList(axisConfig.negative) : toAUList(axisConfig.positive);
|
|
54
|
+
const candidates = directionalAUs.length > 0 ? directionalAUs : axisConfig.aus;
|
|
55
|
+
const ranked = [...candidates].sort((a, b) => getValue(b) - getValue(a));
|
|
56
|
+
for (const auId of ranked) {
|
|
57
|
+
const binding = findBoneBindingForNode(auToBones, auId, nodeKey);
|
|
58
|
+
if (binding) return binding;
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
29
63
|
// src/engines/three/balanceUtils.ts
|
|
30
64
|
function clampBalance(value) {
|
|
31
65
|
if (!Number.isFinite(value)) return 0;
|
|
32
66
|
return Math.max(-1, Math.min(1, value));
|
|
33
67
|
}
|
|
68
|
+
function getSideScale(balance, side) {
|
|
69
|
+
if (side !== "left" && side !== "right") return 1;
|
|
70
|
+
const clamped = clampBalance(balance);
|
|
71
|
+
if (side === "left") {
|
|
72
|
+
return clamped > 0 ? 1 - clamped : 1;
|
|
73
|
+
}
|
|
74
|
+
return clamped < 0 ? 1 + clamped : 1;
|
|
75
|
+
}
|
|
34
76
|
function resolveCurveBalance(curveId, globalBalance, balanceMap) {
|
|
35
77
|
if (balanceMap && Object.prototype.hasOwnProperty.call(balanceMap, curveId)) {
|
|
36
78
|
return clampBalance(Number(balanceMap[curveId]));
|
|
@@ -554,43 +596,23 @@ var BakedAnimationController = class {
|
|
|
554
596
|
Object.keys(curves).filter(isNumericAU).map((id) => Number(id))
|
|
555
597
|
);
|
|
556
598
|
const getAxisBinding = (nodeKey, axisConfig, axisValue, t) => {
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
let maxVal = sampleCurve(String(maxAU), t);
|
|
565
|
-
for (const auId2 of axisConfig.aus) {
|
|
566
|
-
const val = sampleCurve(String(auId2), t);
|
|
567
|
-
if (val > maxVal) {
|
|
568
|
-
maxVal = val;
|
|
569
|
-
maxAU = auId2;
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
return config.auToBones[maxAU]?.find((b) => b.node === nodeKey) ?? null;
|
|
573
|
-
}
|
|
574
|
-
const auId = axisConfig.aus[0];
|
|
575
|
-
return config.auToBones[auId]?.find((b) => b.node === nodeKey) ?? null;
|
|
599
|
+
return getCompositeAxisBinding(
|
|
600
|
+
nodeKey,
|
|
601
|
+
axisConfig,
|
|
602
|
+
axisValue,
|
|
603
|
+
(auId) => getAxisSampleForNode(auId, nodeKey, t),
|
|
604
|
+
config.auToBones
|
|
605
|
+
);
|
|
576
606
|
};
|
|
577
|
-
const
|
|
578
|
-
|
|
579
|
-
if (
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
if (axisConfig.aus.length > 1) {
|
|
585
|
-
let maxVal = 0;
|
|
586
|
-
for (const auId of axisConfig.aus) {
|
|
587
|
-
const val = sampleCurve(String(auId), t);
|
|
588
|
-
if (val > maxVal) maxVal = val;
|
|
589
|
-
}
|
|
590
|
-
return maxVal;
|
|
591
|
-
}
|
|
592
|
-
return sampleCurve(String(axisConfig.aus[0]), t);
|
|
607
|
+
const getAxisSampleForNode = (auId, nodeKey, t) => {
|
|
608
|
+
const rawValue = sampleCurve(String(auId), t);
|
|
609
|
+
if (rawValue <= 1e-6) return 0;
|
|
610
|
+
const binding = config.auToBones[auId]?.find((b) => b.node === nodeKey) ?? null;
|
|
611
|
+
if (!binding?.side) return rawValue;
|
|
612
|
+
const curveBalance = resolveCurveBalance(String(auId), globalBalance, balanceMap);
|
|
613
|
+
return rawValue * getSideScale(curveBalance, binding.side);
|
|
593
614
|
};
|
|
615
|
+
const getAxisValue = (nodeKey, axisConfig, t) => getCompositeAxisValue(axisConfig, (auId) => getAxisSampleForNode(auId, nodeKey, t));
|
|
594
616
|
const autoVisemeJawHandledJaw = autoVisemeJaw && jawScale > 0 && visemeJawAmounts && options?.snippetCategory === "visemeSnippet";
|
|
595
617
|
for (const composite of compositeRotations) {
|
|
596
618
|
const nodeKey = composite.node;
|
|
@@ -611,7 +633,7 @@ var BakedAnimationController = class {
|
|
|
611
633
|
const compositeQ = new THREE.Quaternion().copy(entry.baseQuat);
|
|
612
634
|
const applyAxis = (axisConfig) => {
|
|
613
635
|
if (!axisConfig) return;
|
|
614
|
-
let axisValue = getAxisValue(axisConfig, t);
|
|
636
|
+
let axisValue = getAxisValue(nodeKey, axisConfig, t);
|
|
615
637
|
if (Math.abs(axisValue) <= 1e-6) return;
|
|
616
638
|
const binding = getAxisBinding(nodeKey, axisConfig, axisValue, t);
|
|
617
639
|
if (!binding?.maxDegrees || !binding.channel) return;
|
|
@@ -1214,24 +1236,24 @@ var AU_TO_MORPHS = {
|
|
|
1214
1236
|
center: []
|
|
1215
1237
|
},
|
|
1216
1238
|
61: {
|
|
1217
|
-
left: ["Eye_L_Look_L"
|
|
1218
|
-
right: [],
|
|
1239
|
+
left: ["Eye_L_Look_L"],
|
|
1240
|
+
right: ["Eye_R_Look_L"],
|
|
1219
1241
|
center: []
|
|
1220
1242
|
},
|
|
1221
1243
|
62: {
|
|
1222
|
-
left: [],
|
|
1223
|
-
right: ["
|
|
1244
|
+
left: ["Eye_L_Look_R"],
|
|
1245
|
+
right: ["Eye_R_Look_R"],
|
|
1224
1246
|
center: []
|
|
1225
1247
|
},
|
|
1226
1248
|
63: {
|
|
1227
|
-
left: [],
|
|
1228
|
-
right: [],
|
|
1229
|
-
center: [
|
|
1249
|
+
left: ["Eye_L_Look_Up"],
|
|
1250
|
+
right: ["Eye_R_Look_Up"],
|
|
1251
|
+
center: []
|
|
1230
1252
|
},
|
|
1231
1253
|
64: {
|
|
1232
|
-
left: [],
|
|
1233
|
-
right: [],
|
|
1234
|
-
center: [
|
|
1254
|
+
left: ["Eye_L_Look_Down"],
|
|
1255
|
+
right: ["Eye_R_Look_Down"],
|
|
1256
|
+
center: []
|
|
1235
1257
|
},
|
|
1236
1258
|
65: {
|
|
1237
1259
|
left: ["Eye_L_Look_L"],
|
|
@@ -1459,6 +1481,14 @@ var BONE_AU_TO_BINDINGS = {
|
|
|
1459
1481
|
{ node: "EYE_L", channel: "rx", scale: 1, maxDegrees: 20, side: "left" },
|
|
1460
1482
|
{ node: "EYE_R", channel: "rx", scale: 1, maxDegrees: 20, side: "right" }
|
|
1461
1483
|
],
|
|
1484
|
+
65: [{ node: "EYE_L", channel: "rz", scale: 1, maxDegrees: 25, side: "left" }],
|
|
1485
|
+
66: [{ node: "EYE_L", channel: "rz", scale: -1, maxDegrees: 25, side: "left" }],
|
|
1486
|
+
67: [{ node: "EYE_L", channel: "rx", scale: -1, maxDegrees: 20, side: "left" }],
|
|
1487
|
+
68: [{ node: "EYE_L", channel: "rx", scale: 1, maxDegrees: 20, side: "left" }],
|
|
1488
|
+
69: [{ node: "EYE_R", channel: "rz", scale: 1, maxDegrees: 25, side: "right" }],
|
|
1489
|
+
70: [{ node: "EYE_R", channel: "rz", scale: -1, maxDegrees: 25, side: "right" }],
|
|
1490
|
+
71: [{ node: "EYE_R", channel: "rx", scale: -1, maxDegrees: 20, side: "right" }],
|
|
1491
|
+
72: [{ node: "EYE_R", channel: "rx", scale: 1, maxDegrees: 20, side: "right" }],
|
|
1462
1492
|
// Tongue controls (optional, for rigs that expose them)
|
|
1463
1493
|
37: [{ node: "TONGUE", channel: "rz", scale: 1, maxDegrees: 20 }],
|
|
1464
1494
|
38: [{ node: "TONGUE", channel: "rz", scale: -1, maxDegrees: 20 }],
|
|
@@ -1546,18 +1576,18 @@ var COMPOSITE_ROTATIONS = [
|
|
|
1546
1576
|
},
|
|
1547
1577
|
{
|
|
1548
1578
|
node: "EYE_L",
|
|
1549
|
-
pitch: { aus: [64, 63], axis: "rx", negative: 64, positive: 63 },
|
|
1579
|
+
pitch: { aus: [64, 63, 68, 67], axis: "rx", negative: [64, 68], positive: [63, 67] },
|
|
1550
1580
|
// Eyes down/up
|
|
1551
|
-
yaw: { aus: [61, 62], axis: "rz", negative: 61, positive: 62 },
|
|
1581
|
+
yaw: { aus: [61, 62, 65, 66], axis: "rz", negative: [61, 65], positive: [62, 66] },
|
|
1552
1582
|
// Eyes left/right (rz for CC4)
|
|
1553
1583
|
roll: null
|
|
1554
1584
|
// Eyes don't have roll
|
|
1555
1585
|
},
|
|
1556
1586
|
{
|
|
1557
1587
|
node: "EYE_R",
|
|
1558
|
-
pitch: { aus: [64, 63], axis: "rx", negative: 64, positive: 63 },
|
|
1588
|
+
pitch: { aus: [64, 63, 72, 71], axis: "rx", negative: [64, 72], positive: [63, 71] },
|
|
1559
1589
|
// Eyes down/up
|
|
1560
|
-
yaw: { aus: [61, 62], axis: "rz", negative: 61, positive: 62 },
|
|
1590
|
+
yaw: { aus: [61, 62, 69, 70], axis: "rz", negative: [61, 69], positive: [62, 70] },
|
|
1561
1591
|
// Eyes left/right (rz for CC4)
|
|
1562
1592
|
roll: null
|
|
1563
1593
|
// Eyes don't have roll
|
|
@@ -1576,9 +1606,17 @@ var CONTINUUM_PAIRS_MAP = {
|
|
|
1576
1606
|
// Eyes horizontal - both eyes share same AUs (yaw maps to rz via COMPOSITE_ROTATIONS)
|
|
1577
1607
|
61: { pairId: 62, isNegative: true, axis: "yaw", node: "EYE_L" },
|
|
1578
1608
|
62: { pairId: 61, isNegative: false, axis: "yaw", node: "EYE_L" },
|
|
1609
|
+
65: { pairId: 66, isNegative: true, axis: "yaw", node: "EYE_L" },
|
|
1610
|
+
66: { pairId: 65, isNegative: false, axis: "yaw", node: "EYE_L" },
|
|
1611
|
+
69: { pairId: 70, isNegative: true, axis: "yaw", node: "EYE_R" },
|
|
1612
|
+
70: { pairId: 69, isNegative: false, axis: "yaw", node: "EYE_R" },
|
|
1579
1613
|
// Eyes vertical (pitch)
|
|
1580
1614
|
64: { pairId: 63, isNegative: true, axis: "pitch", node: "EYE_L" },
|
|
1581
1615
|
63: { pairId: 64, isNegative: false, axis: "pitch", node: "EYE_L" },
|
|
1616
|
+
68: { pairId: 67, isNegative: true, axis: "pitch", node: "EYE_L" },
|
|
1617
|
+
67: { pairId: 68, isNegative: false, axis: "pitch", node: "EYE_L" },
|
|
1618
|
+
72: { pairId: 71, isNegative: true, axis: "pitch", node: "EYE_R" },
|
|
1619
|
+
71: { pairId: 72, isNegative: false, axis: "pitch", node: "EYE_R" },
|
|
1582
1620
|
// Head yaw (turn left/right)
|
|
1583
1621
|
51: { pairId: 52, isNegative: true, axis: "yaw", node: "HEAD" },
|
|
1584
1622
|
52: { pairId: 51, isNegative: false, axis: "yaw", node: "HEAD" },
|
|
@@ -1611,6 +1649,10 @@ var CONTINUUM_PAIRS_MAP = {
|
|
|
1611
1649
|
var CONTINUUM_LABELS = {
|
|
1612
1650
|
"61-62": "Eyes \u2014 Horizontal",
|
|
1613
1651
|
"64-63": "Eyes \u2014 Vertical",
|
|
1652
|
+
"65-66": "Left Eye \u2014 Horizontal",
|
|
1653
|
+
"68-67": "Left Eye \u2014 Vertical",
|
|
1654
|
+
"69-70": "Right Eye \u2014 Horizontal",
|
|
1655
|
+
"72-71": "Right Eye \u2014 Vertical",
|
|
1614
1656
|
"51-52": "Head \u2014 Horizontal",
|
|
1615
1657
|
"54-53": "Head \u2014 Vertical",
|
|
1616
1658
|
"55-56": "Head \u2014 Tilt",
|
|
@@ -3855,37 +3897,12 @@ var _Loom3 = class _Loom3 {
|
|
|
3855
3897
|
}
|
|
3856
3898
|
const compositeInfo = this.auToCompositeMap.get(id);
|
|
3857
3899
|
if (compositeInfo) {
|
|
3858
|
-
const storedBalance = this.auBalances[id] ?? 0;
|
|
3859
|
-
const { left: leftVal, right: rightVal } = this.computeSideValues(clamp012(v), storedBalance);
|
|
3860
3900
|
for (const nodeKey of compositeInfo.nodes) {
|
|
3861
3901
|
const config = this.compositeRotations.find((c) => c.node === nodeKey);
|
|
3862
3902
|
if (!config) continue;
|
|
3863
3903
|
const axisConfig = config[compositeInfo.axis];
|
|
3864
3904
|
if (!axisConfig) continue;
|
|
3865
|
-
|
|
3866
|
-
if (axisConfig.negative !== void 0 && axisConfig.positive !== void 0) {
|
|
3867
|
-
const negValue = this.auValues[axisConfig.negative] ?? 0;
|
|
3868
|
-
const posValue = this.auValues[axisConfig.positive] ?? 0;
|
|
3869
|
-
axisValue = posValue - negValue;
|
|
3870
|
-
} else if (axisConfig.aus.length > 1) {
|
|
3871
|
-
axisValue = Math.max(...axisConfig.aus.map((auId) => this.auValues[auId] ?? 0));
|
|
3872
|
-
} else {
|
|
3873
|
-
axisValue = v;
|
|
3874
|
-
}
|
|
3875
|
-
const auBoneBindings = this.config.auToBones[id] || [];
|
|
3876
|
-
const sideByNode = /* @__PURE__ */ new Map();
|
|
3877
|
-
for (const binding of auBoneBindings) {
|
|
3878
|
-
if (binding.side === "left" || binding.side === "right") {
|
|
3879
|
-
sideByNode.set(binding.node, binding.side);
|
|
3880
|
-
}
|
|
3881
|
-
}
|
|
3882
|
-
const side = sideByNode.get(nodeKey);
|
|
3883
|
-
if (side) {
|
|
3884
|
-
const baseValue = clamp012(v);
|
|
3885
|
-
const balanceValue = side === "left" ? leftVal : rightVal;
|
|
3886
|
-
const denom = baseValue > 0 ? baseValue : 1;
|
|
3887
|
-
axisValue = axisValue * (balanceValue / denom);
|
|
3888
|
-
}
|
|
3905
|
+
const axisValue = this.getCompositeAxisValueForNode(nodeKey, axisConfig);
|
|
3889
3906
|
this.updateBoneRotation(nodeKey, compositeInfo.axis, axisValue);
|
|
3890
3907
|
this.pendingCompositeNodes.add(nodeKey);
|
|
3891
3908
|
}
|
|
@@ -3913,11 +3930,15 @@ var _Loom3 = class _Loom3 {
|
|
|
3913
3930
|
}
|
|
3914
3931
|
}
|
|
3915
3932
|
const target = clamp012(to);
|
|
3933
|
+
if (balance !== void 0) {
|
|
3934
|
+
this.auBalances[numId] = balance;
|
|
3935
|
+
}
|
|
3936
|
+
const storedBalance = this.auBalances[numId] ?? 0;
|
|
3916
3937
|
const { left: leftKeys, right: rightKeys, center: centerKeys } = this.getAUMorphsBySide(numId);
|
|
3917
3938
|
const bindings = this.config.auToBones[numId] || [];
|
|
3918
3939
|
const mixWeight = this.isMixedAU(numId) ? this.getAUMixWeight(numId) : 1;
|
|
3919
3940
|
const base = target * mixWeight;
|
|
3920
|
-
const { left: leftVal, right: rightVal } = this.computeSideValues(base,
|
|
3941
|
+
const { left: leftVal, right: rightVal } = this.computeSideValues(base, storedBalance);
|
|
3921
3942
|
this.auValues[numId] = target;
|
|
3922
3943
|
const handles = [];
|
|
3923
3944
|
const meshNames = this.getMeshNamesForAU(numId);
|
|
@@ -3945,16 +3966,7 @@ var _Loom3 = class _Loom3 {
|
|
|
3945
3966
|
if (!config) continue;
|
|
3946
3967
|
const axisConfig = config[compositeInfo.axis];
|
|
3947
3968
|
if (!axisConfig) continue;
|
|
3948
|
-
|
|
3949
|
-
if (axisConfig.negative !== void 0 && axisConfig.positive !== void 0) {
|
|
3950
|
-
const negValue = this.auValues[axisConfig.negative] ?? 0;
|
|
3951
|
-
const posValue = this.auValues[axisConfig.positive] ?? 0;
|
|
3952
|
-
axisValue = posValue - negValue;
|
|
3953
|
-
} else if (axisConfig.aus.length > 1) {
|
|
3954
|
-
axisValue = Math.max(...axisConfig.aus.map((auId) => this.auValues[auId] ?? 0));
|
|
3955
|
-
} else {
|
|
3956
|
-
axisValue = target;
|
|
3957
|
-
}
|
|
3969
|
+
const axisValue = this.getCompositeAxisValueForNode(nodeKey, axisConfig);
|
|
3958
3970
|
handles.push(this.transitionBoneRotation(nodeKey, compositeInfo.axis, axisValue, durationMs));
|
|
3959
3971
|
}
|
|
3960
3972
|
}
|
|
@@ -4588,6 +4600,25 @@ var _Loom3 = class _Loom3 {
|
|
|
4588
4600
|
const hasMorphs = !!(morphs?.left?.length || morphs?.right?.length || morphs?.center?.length);
|
|
4589
4601
|
return !!(hasMorphs && this.config.auToBones[id]?.length);
|
|
4590
4602
|
}
|
|
4603
|
+
getEffectiveBoneAUValue(auId, nodeKey) {
|
|
4604
|
+
const rawValue = clamp012(this.auValues[auId] ?? 0);
|
|
4605
|
+
if (rawValue <= 1e-6) return 0;
|
|
4606
|
+
const binding = this.config.auToBones[auId]?.find((candidate) => candidate.node === nodeKey) ?? null;
|
|
4607
|
+
if (!binding?.side) return rawValue;
|
|
4608
|
+
return rawValue * getSideScale(this.auBalances[auId] ?? 0, binding.side);
|
|
4609
|
+
}
|
|
4610
|
+
getCompositeAxisValueForNode(nodeKey, axisConfig) {
|
|
4611
|
+
return getCompositeAxisValue(axisConfig, (auId) => this.getEffectiveBoneAUValue(auId, nodeKey));
|
|
4612
|
+
}
|
|
4613
|
+
getCompositeAxisBindingForNode(nodeKey, axisConfig, direction) {
|
|
4614
|
+
return getCompositeAxisBinding(
|
|
4615
|
+
nodeKey,
|
|
4616
|
+
axisConfig,
|
|
4617
|
+
direction,
|
|
4618
|
+
(auId) => this.getEffectiveBoneAUValue(auId, nodeKey),
|
|
4619
|
+
this.config.auToBones
|
|
4620
|
+
);
|
|
4621
|
+
}
|
|
4591
4622
|
initBoneRotations() {
|
|
4592
4623
|
this.rotations = {};
|
|
4593
4624
|
this.pendingCompositeNodes.clear();
|
|
@@ -4663,30 +4694,10 @@ var _Loom3 = class _Loom3 {
|
|
|
4663
4694
|
if (!config) {
|
|
4664
4695
|
return;
|
|
4665
4696
|
}
|
|
4666
|
-
const getBindingForAxis = (axisConfig, direction) => {
|
|
4667
|
-
if (!axisConfig) return null;
|
|
4668
|
-
if (axisConfig.negative !== void 0 && axisConfig.positive !== void 0) {
|
|
4669
|
-
const auId = direction < 0 ? axisConfig.negative : axisConfig.positive;
|
|
4670
|
-
return this.config.auToBones[auId]?.find((b) => b.node === nodeKey);
|
|
4671
|
-
}
|
|
4672
|
-
if (axisConfig.aus.length > 1) {
|
|
4673
|
-
let maxAU = axisConfig.aus[0];
|
|
4674
|
-
let maxValue = this.auValues[maxAU] ?? 0;
|
|
4675
|
-
for (const auId of axisConfig.aus) {
|
|
4676
|
-
const val = this.auValues[auId] ?? 0;
|
|
4677
|
-
if (val > maxValue) {
|
|
4678
|
-
maxValue = val;
|
|
4679
|
-
maxAU = auId;
|
|
4680
|
-
}
|
|
4681
|
-
}
|
|
4682
|
-
return this.config.auToBones[maxAU]?.find((b) => b.node === nodeKey);
|
|
4683
|
-
}
|
|
4684
|
-
return this.config.auToBones[axisConfig.aus[0]]?.find((b) => b.node === nodeKey);
|
|
4685
|
-
};
|
|
4686
4697
|
const getAxis = (channel) => channel === "rx" ? X_AXIS2 : channel === "ry" ? Y_AXIS2 : Z_AXIS2;
|
|
4687
4698
|
const compositeQ = new THREE.Quaternion().copy(baseQuat);
|
|
4688
4699
|
if (config.yaw && rotState.yaw !== 0) {
|
|
4689
|
-
const binding =
|
|
4700
|
+
const binding = this.getCompositeAxisBindingForNode(nodeKey, config.yaw, rotState.yaw);
|
|
4690
4701
|
if (binding?.maxDegrees && binding.channel) {
|
|
4691
4702
|
const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.yaw) * binding.scale;
|
|
4692
4703
|
const axis = getAxis(binding.channel);
|
|
@@ -4695,7 +4706,7 @@ var _Loom3 = class _Loom3 {
|
|
|
4695
4706
|
}
|
|
4696
4707
|
}
|
|
4697
4708
|
if (config.pitch && rotState.pitch !== 0) {
|
|
4698
|
-
const binding =
|
|
4709
|
+
const binding = this.getCompositeAxisBindingForNode(nodeKey, config.pitch, rotState.pitch);
|
|
4699
4710
|
if (binding?.maxDegrees && binding.channel) {
|
|
4700
4711
|
const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.pitch) * binding.scale;
|
|
4701
4712
|
const axis = getAxis(binding.channel);
|
|
@@ -4704,7 +4715,7 @@ var _Loom3 = class _Loom3 {
|
|
|
4704
4715
|
}
|
|
4705
4716
|
}
|
|
4706
4717
|
if (config.roll && rotState.roll !== 0) {
|
|
4707
|
-
const binding =
|
|
4718
|
+
const binding = this.getCompositeAxisBindingForNode(nodeKey, config.roll, rotState.roll);
|
|
4708
4719
|
if (binding?.maxDegrees && binding.channel) {
|
|
4709
4720
|
const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.roll) * binding.scale;
|
|
4710
4721
|
const axis = getAxis(binding.channel);
|
|
@@ -5573,7 +5584,7 @@ function findMatches(targetNames, candidateNames, prefix, suffix, suffixPattern)
|
|
|
5573
5584
|
return { found, missing };
|
|
5574
5585
|
}
|
|
5575
5586
|
function collectAxisConfigs(axisConfigs) {
|
|
5576
|
-
return axisConfigs.filter((entry) => entry.config);
|
|
5587
|
+
return axisConfigs.filter((entry) => entry.config !== null);
|
|
5577
5588
|
}
|
|
5578
5589
|
function isEyeNodeKey(nodeKey) {
|
|
5579
5590
|
return nodeKey === "EYE_L" || nodeKey === "EYE_R";
|
|
@@ -5643,28 +5654,35 @@ function validateMappingConfig(config) {
|
|
|
5643
5654
|
);
|
|
5644
5655
|
continue;
|
|
5645
5656
|
}
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5657
|
+
for (const auId of toAUList(axisConfig.negative)) {
|
|
5658
|
+
if (!axisConfig.aus.includes(auId)) {
|
|
5659
|
+
push(
|
|
5660
|
+
"error",
|
|
5661
|
+
"COMPOSITE_AU_MISSING",
|
|
5662
|
+
`Composite axis for "${composite.node}" is missing negative AU ${auId} in aus list`,
|
|
5663
|
+
{ node: composite.node, auId }
|
|
5664
|
+
);
|
|
5665
|
+
}
|
|
5653
5666
|
}
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5667
|
+
for (const auId of toAUList(axisConfig.positive)) {
|
|
5668
|
+
if (!axisConfig.aus.includes(auId)) {
|
|
5669
|
+
push(
|
|
5670
|
+
"error",
|
|
5671
|
+
"COMPOSITE_AU_MISSING",
|
|
5672
|
+
`Composite axis for "${composite.node}" is missing positive AU ${auId} in aus list`,
|
|
5673
|
+
{ node: composite.node, auId }
|
|
5674
|
+
);
|
|
5675
|
+
}
|
|
5661
5676
|
}
|
|
5662
|
-
|
|
5677
|
+
const negativeAUs = toAUList(axisConfig.negative);
|
|
5678
|
+
const positiveAUs = toAUList(axisConfig.positive);
|
|
5679
|
+
const overlappingAUs = negativeAUs.filter((auId) => positiveAUs.includes(auId));
|
|
5680
|
+
if (overlappingAUs.length > 0) {
|
|
5663
5681
|
push(
|
|
5664
5682
|
"error",
|
|
5665
5683
|
"COMPOSITE_AU_DUPLICATE",
|
|
5666
|
-
`Composite axis for "${composite.node}"
|
|
5667
|
-
{ node: composite.node, auId:
|
|
5684
|
+
`Composite axis for "${composite.node}" reuses AU ${overlappingAUs[0]} in both negative and positive groups`,
|
|
5685
|
+
{ node: composite.node, auId: overlappingAUs[0] }
|
|
5668
5686
|
);
|
|
5669
5687
|
}
|
|
5670
5688
|
}
|
|
@@ -5754,11 +5772,11 @@ function validateMappingConfig(config) {
|
|
|
5754
5772
|
);
|
|
5755
5773
|
continue;
|
|
5756
5774
|
}
|
|
5757
|
-
const expectedNeg = axisConfig.negative;
|
|
5758
|
-
const expectedPos = axisConfig.positive;
|
|
5775
|
+
const expectedNeg = toAUList(axisConfig.negative);
|
|
5776
|
+
const expectedPos = toAUList(axisConfig.positive);
|
|
5759
5777
|
const negId = info.isNegative ? Number(auIdStr) : info.pairId;
|
|
5760
5778
|
const posId = info.isNegative ? info.pairId : Number(auIdStr);
|
|
5761
|
-
if (negId
|
|
5779
|
+
if (!expectedNeg.includes(negId) || !expectedPos.includes(posId)) {
|
|
5762
5780
|
push(
|
|
5763
5781
|
"warning",
|
|
5764
5782
|
"CONTINUUM_COMPOSITE_MISMATCH",
|