@lovelace_lol/embody 0.0.5 → 0.0.7
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/core/WasmRuntimeCore.d.ts +8 -0
- package/dist/core/index.d.ts +0 -2
- package/dist/core.cjs +27 -512
- package/dist/core.cjs.map +1 -1
- package/dist/core.js +28 -512
- package/dist/core.js.map +1 -1
- package/dist/engines/three/Embody.d.ts +1 -2
- package/dist/index.cjs +164 -502
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.js +166 -503
- package/dist/index.js.map +1 -1
- package/dist/three.cjs +162 -499
- package/dist/three.cjs.map +1 -1
- package/dist/three.js +163 -500
- package/dist/three.js.map +1 -1
- package/dist/wasm/embody_wasm.d.ts +3 -3
- package/dist/wasm/embody_wasm.js +3 -3
- package/dist/wasm/embody_wasm_bg.wasm +0 -0
- package/package.json +1 -1
- package/dist/core/TsRuntimeCore.d.ts +0 -40
package/dist/three.cjs
CHANGED
|
@@ -3511,410 +3511,6 @@ function getBlendingName(value) {
|
|
|
3511
3511
|
return "Normal";
|
|
3512
3512
|
}
|
|
3513
3513
|
|
|
3514
|
-
// src/core/TsRuntimeCore.ts
|
|
3515
|
-
var identityQuat = { x: 0, y: 0, z: 0, w: 1 };
|
|
3516
|
-
function isRotationBoneBinding2(binding) {
|
|
3517
|
-
return binding?.channel === "rx" || binding?.channel === "ry" || binding?.channel === "rz";
|
|
3518
|
-
}
|
|
3519
|
-
var TsRuntimeCore = class {
|
|
3520
|
-
constructor(options) {
|
|
3521
|
-
__publicField(this, "profile");
|
|
3522
|
-
__publicField(this, "model");
|
|
3523
|
-
__publicField(this, "auValues", {});
|
|
3524
|
-
__publicField(this, "auBalances", {});
|
|
3525
|
-
__publicField(this, "visemeValues");
|
|
3526
|
-
__publicField(this, "visemeJawScales");
|
|
3527
|
-
__publicField(this, "mixWeights");
|
|
3528
|
-
this.profile = options.profile;
|
|
3529
|
-
this.model = options.model;
|
|
3530
|
-
this.visemeValues = new Array(getProfileVisemeSlots(this.profile).length).fill(0);
|
|
3531
|
-
this.visemeJawScales = new Array(this.visemeValues.length).fill(1);
|
|
3532
|
-
this.mixWeights = { ...this.profile.auMixDefaults };
|
|
3533
|
-
}
|
|
3534
|
-
setProfile(profile) {
|
|
3535
|
-
this.profile = profile;
|
|
3536
|
-
this.visemeValues = new Array(getProfileVisemeSlots(this.profile).length).fill(0);
|
|
3537
|
-
this.visemeJawScales = new Array(this.visemeValues.length).fill(1);
|
|
3538
|
-
this.mixWeights = { ...this.profile.auMixDefaults };
|
|
3539
|
-
}
|
|
3540
|
-
setModelDescriptor(model) {
|
|
3541
|
-
this.model = model;
|
|
3542
|
-
}
|
|
3543
|
-
setAU(id, value, balance) {
|
|
3544
|
-
if (value < 0 && this.profile.continuumPairs) {
|
|
3545
|
-
const pairInfo = this.profile.continuumPairs[id];
|
|
3546
|
-
if (pairInfo) {
|
|
3547
|
-
const negAU = pairInfo.isNegative ? id : pairInfo.pairId;
|
|
3548
|
-
const posAU = pairInfo.isNegative ? pairInfo.pairId : id;
|
|
3549
|
-
this.setContinuum(negAU, posAU, pairInfo.isNegative ? -value : value, balance);
|
|
3550
|
-
return;
|
|
3551
|
-
}
|
|
3552
|
-
}
|
|
3553
|
-
this.auValues[id] = clamp01(value);
|
|
3554
|
-
if (balance !== void 0) {
|
|
3555
|
-
this.auBalances[id] = clampBalance2(balance);
|
|
3556
|
-
}
|
|
3557
|
-
}
|
|
3558
|
-
getAU(id) {
|
|
3559
|
-
return this.auValues[id] ?? 0;
|
|
3560
|
-
}
|
|
3561
|
-
setContinuum(negAU, posAU, continuumValue, balance) {
|
|
3562
|
-
const value = Math.max(-1, Math.min(1, continuumValue));
|
|
3563
|
-
if (value < 0) {
|
|
3564
|
-
this.setAU(posAU, 0, balance);
|
|
3565
|
-
this.setAU(negAU, Math.abs(value), balance);
|
|
3566
|
-
return;
|
|
3567
|
-
}
|
|
3568
|
-
if (value > 0) {
|
|
3569
|
-
this.setAU(negAU, 0, balance);
|
|
3570
|
-
this.setAU(posAU, value, balance);
|
|
3571
|
-
return;
|
|
3572
|
-
}
|
|
3573
|
-
this.setAU(negAU, 0, balance);
|
|
3574
|
-
this.setAU(posAU, 0, balance);
|
|
3575
|
-
}
|
|
3576
|
-
setViseme(visemeIndex, value, jawScale = 1) {
|
|
3577
|
-
if (visemeIndex < 0 || visemeIndex >= this.visemeValues.length) return;
|
|
3578
|
-
this.visemeValues[visemeIndex] = clamp01(value);
|
|
3579
|
-
this.visemeJawScales[visemeIndex] = jawScale;
|
|
3580
|
-
}
|
|
3581
|
-
setVisemeById(slotId, value, jawScale = 1) {
|
|
3582
|
-
const index = getVisemeSlotIndex(this.profile, slotId);
|
|
3583
|
-
if (index < 0) return;
|
|
3584
|
-
this.setViseme(index, value, jawScale);
|
|
3585
|
-
}
|
|
3586
|
-
setAUMixWeight(id, weight) {
|
|
3587
|
-
this.mixWeights[id] = clamp01(weight);
|
|
3588
|
-
}
|
|
3589
|
-
evaluateFrameDelta(deltaSeconds) {
|
|
3590
|
-
const morphWrites = /* @__PURE__ */ new Map();
|
|
3591
|
-
this.collectAUWrites(morphWrites);
|
|
3592
|
-
this.collectVisemeWrites(morphWrites);
|
|
3593
|
-
return {
|
|
3594
|
-
deltaSeconds,
|
|
3595
|
-
morphTargets: Array.from(morphWrites.values()),
|
|
3596
|
-
bones: this.collectBoneWrites()
|
|
3597
|
-
};
|
|
3598
|
-
}
|
|
3599
|
-
collectAUWrites(morphWrites) {
|
|
3600
|
-
for (const [auIdText, entry] of Object.entries(this.profile.auToMorphs || {})) {
|
|
3601
|
-
const auId = Number(auIdText);
|
|
3602
|
-
if (Number.isNaN(auId) || !entry) continue;
|
|
3603
|
-
const mixWeight = this.isMixedAU(auId) ? this.getAUMixWeight(auId) : 1;
|
|
3604
|
-
const base = clamp01(this.auValues[auId] ?? 0) * mixWeight;
|
|
3605
|
-
const { left, right } = computeSideValues(base, this.auBalances[auId]);
|
|
3606
|
-
const meshNames = getMeshNamesForAUProfile(this.profile, auId);
|
|
3607
|
-
for (const morph of entry.left || []) {
|
|
3608
|
-
this.addMorphWrites(morphWrites, morph, meshNames, left);
|
|
3609
|
-
}
|
|
3610
|
-
for (const morph of entry.right || []) {
|
|
3611
|
-
this.addMorphWrites(morphWrites, morph, meshNames, right);
|
|
3612
|
-
}
|
|
3613
|
-
for (const morph of entry.center || []) {
|
|
3614
|
-
this.addMorphWrites(morphWrites, morph, meshNames, base);
|
|
3615
|
-
}
|
|
3616
|
-
}
|
|
3617
|
-
}
|
|
3618
|
-
collectVisemeWrites(morphWrites) {
|
|
3619
|
-
const meshNames = getMeshNamesForVisemeProfile(this.profile);
|
|
3620
|
-
const localMax = /* @__PURE__ */ new Map();
|
|
3621
|
-
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
3622
|
-
const value = clamp01(this.visemeValues[index] ?? 0);
|
|
3623
|
-
for (const bindingTarget of getVisemeBindingTargets(this.profile, index)) {
|
|
3624
|
-
const weighted = clamp01(value * bindingTarget.weight);
|
|
3625
|
-
for (const resolved of this.resolveMorphTargets(bindingTarget.morph, meshNames)) {
|
|
3626
|
-
const key = morphWriteKey(resolved.mesh.id, resolved.morphTarget.id);
|
|
3627
|
-
const existing = localMax.get(key);
|
|
3628
|
-
if (!existing || weighted > existing.value) {
|
|
3629
|
-
localMax.set(key, {
|
|
3630
|
-
meshId: resolved.mesh.id,
|
|
3631
|
-
morphTargetId: resolved.morphTarget.id,
|
|
3632
|
-
value: weighted,
|
|
3633
|
-
mode: "absolute"
|
|
3634
|
-
});
|
|
3635
|
-
}
|
|
3636
|
-
}
|
|
3637
|
-
}
|
|
3638
|
-
}
|
|
3639
|
-
for (const [key, write] of localMax) {
|
|
3640
|
-
const existing = morphWrites.get(key);
|
|
3641
|
-
if (!existing || write.value > existing.value) {
|
|
3642
|
-
morphWrites.set(key, write);
|
|
3643
|
-
}
|
|
3644
|
-
}
|
|
3645
|
-
}
|
|
3646
|
-
collectBoneWrites() {
|
|
3647
|
-
const writes = [];
|
|
3648
|
-
const rotations = this.computeRotationState();
|
|
3649
|
-
for (const composite of this.profile.compositeRotations || []) {
|
|
3650
|
-
const bone = this.findBoneDescriptor(composite.node);
|
|
3651
|
-
if (!bone) continue;
|
|
3652
|
-
const transform = this.evaluateCompositeTransform(bone, composite, rotations[composite.node]);
|
|
3653
|
-
if (transform) {
|
|
3654
|
-
writes.push({
|
|
3655
|
-
boneId: bone.id,
|
|
3656
|
-
transform,
|
|
3657
|
-
mode: "absolute",
|
|
3658
|
-
space: "local"
|
|
3659
|
-
});
|
|
3660
|
-
}
|
|
3661
|
-
}
|
|
3662
|
-
for (const [nodeKey, translation] of Object.entries(this.computeTranslations())) {
|
|
3663
|
-
const bone = this.findBoneDescriptor(nodeKey);
|
|
3664
|
-
if (!bone) continue;
|
|
3665
|
-
const position = addVec3(bone.restTransform?.position, translation);
|
|
3666
|
-
upsertBoneWrite(writes, bone.id, { position });
|
|
3667
|
-
}
|
|
3668
|
-
const jawAmount = this.getActiveVisemeJawAmount();
|
|
3669
|
-
const jawBinding = this.findAutoVisemeJawBinding();
|
|
3670
|
-
const jawBone = jawBinding ? this.findBoneDescriptor(jawBinding.node) : void 0;
|
|
3671
|
-
if (jawBone && jawBinding?.maxDegrees && jawBinding.channel) {
|
|
3672
|
-
const current = writes.find((write) => write.boneId === jawBone.id);
|
|
3673
|
-
if (jawAmount > 1e-6 || !current?.transform.rotation) {
|
|
3674
|
-
const rest = jawBone.restTransform?.rotation ?? identityQuat;
|
|
3675
|
-
const rotation = jawAmount > 1e-6 ? multiplyQuat(
|
|
3676
|
-
rest,
|
|
3677
|
-
quatFromChannel(jawBinding.channel, deg2rad(jawBinding.maxDegrees) * jawAmount * jawBinding.scale)
|
|
3678
|
-
) : rest;
|
|
3679
|
-
upsertBoneWrite(writes, jawBone.id, { rotation });
|
|
3680
|
-
}
|
|
3681
|
-
}
|
|
3682
|
-
return writes;
|
|
3683
|
-
}
|
|
3684
|
-
computeRotationState() {
|
|
3685
|
-
const rotations = {};
|
|
3686
|
-
for (const composite of this.profile.compositeRotations || []) {
|
|
3687
|
-
rotations[composite.node] = {
|
|
3688
|
-
pitch: this.getCompositeAxisValueForNode(composite.node, composite.pitch),
|
|
3689
|
-
yaw: this.getCompositeAxisValueForNode(composite.node, composite.yaw),
|
|
3690
|
-
roll: this.getCompositeAxisValueForNode(composite.node, composite.roll)
|
|
3691
|
-
};
|
|
3692
|
-
}
|
|
3693
|
-
return rotations;
|
|
3694
|
-
}
|
|
3695
|
-
evaluateCompositeTransform(bone, composite, state) {
|
|
3696
|
-
if (!state) return null;
|
|
3697
|
-
let rotation = bone.restTransform?.rotation ?? identityQuat;
|
|
3698
|
-
const applyAxis = (axisConfig, direction) => {
|
|
3699
|
-
if (!axisConfig || Math.abs(direction) <= 1e-6) return;
|
|
3700
|
-
const binding = getCompositeAxisBinding(
|
|
3701
|
-
composite.node,
|
|
3702
|
-
axisConfig,
|
|
3703
|
-
direction,
|
|
3704
|
-
(auId) => this.getEffectiveBoneAUValue(auId, composite.node),
|
|
3705
|
-
this.profile.auToBones
|
|
3706
|
-
);
|
|
3707
|
-
if (!binding?.maxDegrees || !binding.channel) return;
|
|
3708
|
-
rotation = multiplyQuat(
|
|
3709
|
-
rotation,
|
|
3710
|
-
quatFromChannel(binding.channel, deg2rad(binding.maxDegrees) * Math.abs(direction) * binding.scale)
|
|
3711
|
-
);
|
|
3712
|
-
};
|
|
3713
|
-
applyAxis(composite.yaw, state.yaw);
|
|
3714
|
-
applyAxis(composite.pitch, state.pitch);
|
|
3715
|
-
applyAxis(composite.roll, state.roll);
|
|
3716
|
-
return { rotation };
|
|
3717
|
-
}
|
|
3718
|
-
computeTranslations() {
|
|
3719
|
-
const translations = {};
|
|
3720
|
-
for (const [auIdText, bindings] of Object.entries(this.profile.auToBones || {})) {
|
|
3721
|
-
const auId = Number(auIdText);
|
|
3722
|
-
if (Number.isNaN(auId)) continue;
|
|
3723
|
-
const value = clamp01(this.auValues[auId] ?? 0);
|
|
3724
|
-
for (const binding of bindings || []) {
|
|
3725
|
-
if (binding.channel !== "tx" && binding.channel !== "ty" && binding.channel !== "tz") continue;
|
|
3726
|
-
if (binding.maxUnits === void 0) continue;
|
|
3727
|
-
const current = translations[binding.node] ?? { x: 0, y: 0, z: 0 };
|
|
3728
|
-
translations[binding.node] = current;
|
|
3729
|
-
if (value <= 1e-6) continue;
|
|
3730
|
-
const offset = clampSigned(value * binding.scale) * binding.maxUnits;
|
|
3731
|
-
translations[binding.node] = {
|
|
3732
|
-
x: binding.channel === "tx" ? offset : current.x,
|
|
3733
|
-
y: binding.channel === "ty" ? offset : current.y,
|
|
3734
|
-
z: binding.channel === "tz" ? offset : current.z
|
|
3735
|
-
};
|
|
3736
|
-
}
|
|
3737
|
-
}
|
|
3738
|
-
return translations;
|
|
3739
|
-
}
|
|
3740
|
-
addMorphWrites(morphWrites, morph, meshNames, value) {
|
|
3741
|
-
for (const resolved of this.resolveMorphTargets(morph, meshNames)) {
|
|
3742
|
-
const key = morphWriteKey(resolved.mesh.id, resolved.morphTarget.id);
|
|
3743
|
-
const existing = morphWrites.get(key);
|
|
3744
|
-
if (existing && existing.value >= value) continue;
|
|
3745
|
-
morphWrites.set(key, {
|
|
3746
|
-
meshId: resolved.mesh.id,
|
|
3747
|
-
morphTargetId: resolved.morphTarget.id,
|
|
3748
|
-
value,
|
|
3749
|
-
mode: "absolute"
|
|
3750
|
-
});
|
|
3751
|
-
}
|
|
3752
|
-
}
|
|
3753
|
-
resolveMorphTargets(morph, meshNames) {
|
|
3754
|
-
const result = [];
|
|
3755
|
-
for (const meshName of meshNames) {
|
|
3756
|
-
const mesh = this.model.meshes.find((candidate) => candidate.name === meshName);
|
|
3757
|
-
if (!mesh) continue;
|
|
3758
|
-
const morphTargets = mesh.morphTargetIds.map((id) => this.model.morphTargets.find((candidate) => candidate.id === id)).filter((target2) => !!target2);
|
|
3759
|
-
const target = typeof morph === "number" ? morphTargets.find((candidate) => candidate.hostIndex === morph) : resolveMorphTargetByName(morphTargets, morph, this.profile);
|
|
3760
|
-
if (target) {
|
|
3761
|
-
result.push({ mesh, morphTarget: target });
|
|
3762
|
-
}
|
|
3763
|
-
}
|
|
3764
|
-
return result;
|
|
3765
|
-
}
|
|
3766
|
-
findBoneDescriptor(nodeKey) {
|
|
3767
|
-
const configuredName = this.profile.boneNodes[nodeKey] || nodeKey;
|
|
3768
|
-
const prefix = this.profile.bonePrefix ?? "";
|
|
3769
|
-
const suffix = this.profile.boneSuffix ?? "";
|
|
3770
|
-
const prefixedName = prefix && !configuredName.startsWith(prefix) ? `${prefix}${configuredName}` : configuredName;
|
|
3771
|
-
const fullName = suffix && !prefixedName.endsWith(suffix) ? `${prefixedName}${suffix}` : prefixedName;
|
|
3772
|
-
const candidates = /* @__PURE__ */ new Set([nodeKey, configuredName, fullName]);
|
|
3773
|
-
return this.model.bones.find((bone) => candidates.has(bone.name));
|
|
3774
|
-
}
|
|
3775
|
-
findAutoVisemeJawBinding() {
|
|
3776
|
-
const candidates = [
|
|
3777
|
-
this.profile.auToBones[103]?.find(isRotationBoneBinding2),
|
|
3778
|
-
this.profile.auToBones[26]?.find(isRotationBoneBinding2)
|
|
3779
|
-
].filter((binding) => !!binding);
|
|
3780
|
-
return candidates.find((binding) => !!this.findBoneDescriptor(binding.node)) ?? candidates[0] ?? null;
|
|
3781
|
-
}
|
|
3782
|
-
getActiveVisemeJawAmount() {
|
|
3783
|
-
const jawAmounts = getVisemeJawAmounts(this.profile) ?? [];
|
|
3784
|
-
let jawAmount = 0;
|
|
3785
|
-
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
3786
|
-
const value = clamp01(this.visemeValues[index] ?? 0);
|
|
3787
|
-
if (value <= 1e-6) continue;
|
|
3788
|
-
const jawScale = this.visemeJawScales[index] ?? 1;
|
|
3789
|
-
if (Math.abs(jawScale) <= 1e-6) continue;
|
|
3790
|
-
jawAmount = Math.max(jawAmount, (jawAmounts[index] ?? 0) * value * jawScale);
|
|
3791
|
-
}
|
|
3792
|
-
return jawAmount;
|
|
3793
|
-
}
|
|
3794
|
-
getCompositeAxisValueForNode(nodeKey, axisConfig) {
|
|
3795
|
-
return getCompositeAxisValue(axisConfig, (auId) => this.getEffectiveBoneAUValue(auId, nodeKey));
|
|
3796
|
-
}
|
|
3797
|
-
getEffectiveBoneAUValue(auId, nodeKey) {
|
|
3798
|
-
const rawValue = clamp01(this.auValues[auId] ?? 0);
|
|
3799
|
-
if (rawValue <= 1e-6) return 0;
|
|
3800
|
-
const binding = this.profile.auToBones[auId]?.find((candidate) => candidate.node === nodeKey) ?? null;
|
|
3801
|
-
if (!binding?.side) return rawValue;
|
|
3802
|
-
return rawValue * getSideScale2(this.auBalances[auId] ?? 0, binding.side);
|
|
3803
|
-
}
|
|
3804
|
-
getAUMixWeight(auId) {
|
|
3805
|
-
return this.mixWeights[auId] ?? this.profile.auMixDefaults?.[auId] ?? 1;
|
|
3806
|
-
}
|
|
3807
|
-
isMixedAU(auId) {
|
|
3808
|
-
const morphs = this.profile.auToMorphs[auId];
|
|
3809
|
-
const hasMorphs = !!(morphs?.left?.length || morphs?.right?.length || morphs?.center?.length);
|
|
3810
|
-
return !!(hasMorphs && this.profile.auToBones[auId]?.length);
|
|
3811
|
-
}
|
|
3812
|
-
};
|
|
3813
|
-
function resolveMorphTargetByName(targets, key, profile) {
|
|
3814
|
-
const prefix = profile.morphPrefix || "";
|
|
3815
|
-
const suffix = profile.morphSuffix || "";
|
|
3816
|
-
const fullName = prefix + key + suffix;
|
|
3817
|
-
const exact = targets.find((target) => target.name === fullName);
|
|
3818
|
-
if (exact) return exact;
|
|
3819
|
-
const suffixRegex = profile.suffixPattern ? new RegExp(profile.suffixPattern) : null;
|
|
3820
|
-
if (!suffixRegex) return void 0;
|
|
3821
|
-
return targets.find((target) => {
|
|
3822
|
-
if (!target.name.startsWith(fullName)) return false;
|
|
3823
|
-
const candidateSuffix = target.name.slice(fullName.length);
|
|
3824
|
-
return candidateSuffix === "" || suffixRegex.test(candidateSuffix);
|
|
3825
|
-
});
|
|
3826
|
-
}
|
|
3827
|
-
function computeSideValues(base, balance) {
|
|
3828
|
-
const b = clampBalance2(balance ?? 0);
|
|
3829
|
-
if (b === 0) return { left: base, right: base };
|
|
3830
|
-
if (b < 0) return { left: base, right: base * (1 + b) };
|
|
3831
|
-
return { left: base * (1 - b), right: base };
|
|
3832
|
-
}
|
|
3833
|
-
function getSideScale2(balance, side) {
|
|
3834
|
-
if (side !== "left" && side !== "right") return 1;
|
|
3835
|
-
const b = clampBalance2(balance);
|
|
3836
|
-
if (side === "left") return b > 0 ? 1 - b : 1;
|
|
3837
|
-
return b < 0 ? 1 + b : 1;
|
|
3838
|
-
}
|
|
3839
|
-
function addVec3(base, offset) {
|
|
3840
|
-
return {
|
|
3841
|
-
x: (base?.x ?? 0) + offset.x,
|
|
3842
|
-
y: (base?.y ?? 0) + offset.y,
|
|
3843
|
-
z: (base?.z ?? 0) + offset.z
|
|
3844
|
-
};
|
|
3845
|
-
}
|
|
3846
|
-
function upsertBoneWrite(writes, boneId2, transform) {
|
|
3847
|
-
const existingIndex = writes.findIndex((write) => write.boneId === boneId2);
|
|
3848
|
-
if (existingIndex >= 0) {
|
|
3849
|
-
const existing = writes[existingIndex];
|
|
3850
|
-
writes[existingIndex] = {
|
|
3851
|
-
...existing,
|
|
3852
|
-
transform: {
|
|
3853
|
-
...existing.transform,
|
|
3854
|
-
...transform
|
|
3855
|
-
}
|
|
3856
|
-
};
|
|
3857
|
-
return;
|
|
3858
|
-
}
|
|
3859
|
-
writes.push({
|
|
3860
|
-
boneId: boneId2,
|
|
3861
|
-
transform,
|
|
3862
|
-
mode: "absolute",
|
|
3863
|
-
space: "local"
|
|
3864
|
-
});
|
|
3865
|
-
}
|
|
3866
|
-
function quatFromChannel(channel, radians) {
|
|
3867
|
-
if (channel === "rx") return quatFromAxis({ x: 1, y: 0, z: 0 }, radians);
|
|
3868
|
-
if (channel === "ry") return quatFromAxis({ x: 0, y: 1, z: 0 }, radians);
|
|
3869
|
-
return quatFromAxis({ x: 0, y: 0, z: 1 }, radians);
|
|
3870
|
-
}
|
|
3871
|
-
function quatFromAxis(axis, radians) {
|
|
3872
|
-
const half = radians / 2;
|
|
3873
|
-
const s = Math.sin(half);
|
|
3874
|
-
return normalizeQuat({
|
|
3875
|
-
x: axis.x * s,
|
|
3876
|
-
y: axis.y * s,
|
|
3877
|
-
z: axis.z * s,
|
|
3878
|
-
w: Math.cos(half)
|
|
3879
|
-
});
|
|
3880
|
-
}
|
|
3881
|
-
function multiplyQuat(a, b) {
|
|
3882
|
-
return normalizeQuat({
|
|
3883
|
-
x: a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
|
|
3884
|
-
y: a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
|
|
3885
|
-
z: a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
|
|
3886
|
-
w: a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z
|
|
3887
|
-
});
|
|
3888
|
-
}
|
|
3889
|
-
function normalizeQuat(q) {
|
|
3890
|
-
const len = Math.hypot(q.x, q.y, q.z, q.w);
|
|
3891
|
-
if (len <= 1e-12) return identityQuat;
|
|
3892
|
-
return {
|
|
3893
|
-
x: q.x / len,
|
|
3894
|
-
y: q.y / len,
|
|
3895
|
-
z: q.z / len,
|
|
3896
|
-
w: q.w / len
|
|
3897
|
-
};
|
|
3898
|
-
}
|
|
3899
|
-
function deg2rad(degrees) {
|
|
3900
|
-
return degrees * Math.PI / 180;
|
|
3901
|
-
}
|
|
3902
|
-
function clamp01(value) {
|
|
3903
|
-
if (!Number.isFinite(value)) return 0;
|
|
3904
|
-
return value < 0 ? 0 : value > 1 ? 1 : value;
|
|
3905
|
-
}
|
|
3906
|
-
function clampSigned(value) {
|
|
3907
|
-
if (!Number.isFinite(value)) return 0;
|
|
3908
|
-
return value < -1 ? -1 : value > 1 ? 1 : value;
|
|
3909
|
-
}
|
|
3910
|
-
function clampBalance2(value) {
|
|
3911
|
-
if (!Number.isFinite(value)) return 0;
|
|
3912
|
-
return Math.max(-1, Math.min(1, value));
|
|
3913
|
-
}
|
|
3914
|
-
function morphWriteKey(meshId2, morphTargetId2) {
|
|
3915
|
-
return `${meshId2}:${morphTargetId2}`;
|
|
3916
|
-
}
|
|
3917
|
-
|
|
3918
3514
|
// src/core/contracts/abi.ts
|
|
3919
3515
|
var PACKED_MORPH_FRAME_DELTA_STRIDE = 4;
|
|
3920
3516
|
var PACKED_BONE_FRAME_DELTA_STRIDE = 9;
|
|
@@ -3926,11 +3522,13 @@ var WasmRuntimeCore = class {
|
|
|
3926
3522
|
constructor(options) {
|
|
3927
3523
|
__publicField(this, "wasm");
|
|
3928
3524
|
__publicField(this, "core");
|
|
3525
|
+
__publicField(this, "allowEmptyBindings");
|
|
3929
3526
|
__publicField(this, "profile");
|
|
3930
3527
|
__publicField(this, "model");
|
|
3931
3528
|
this.wasm = options.wasm;
|
|
3932
3529
|
this.profile = options.profile;
|
|
3933
3530
|
this.model = options.model;
|
|
3531
|
+
this.allowEmptyBindings = options.allowEmptyBindings ?? false;
|
|
3934
3532
|
const RuntimeCtor = options.wasm.RuntimeCore;
|
|
3935
3533
|
if (!RuntimeCtor) {
|
|
3936
3534
|
throw new Error("Embody Wasm module does not export RuntimeCore");
|
|
@@ -3949,6 +3547,24 @@ var WasmRuntimeCore = class {
|
|
|
3949
3547
|
setAU(id, value, balance = 0) {
|
|
3950
3548
|
this.core.set_au(id >>> 0, value, balance);
|
|
3951
3549
|
}
|
|
3550
|
+
setContinuum(negativeAU, positiveAU, value, balance = 0) {
|
|
3551
|
+
this.core.set_continuum(negativeAU >>> 0, positiveAU >>> 0, value, balance);
|
|
3552
|
+
}
|
|
3553
|
+
transitionAU(id, to, durationMs, balance = Number.NaN) {
|
|
3554
|
+
this.core.transition_au(id >>> 0, to, durationMs, balance);
|
|
3555
|
+
}
|
|
3556
|
+
transitionViseme(visemeIndex, to, durationMs, jawScale = 1) {
|
|
3557
|
+
this.core.transition_viseme(visemeIndex >>> 0, to, durationMs, jawScale);
|
|
3558
|
+
}
|
|
3559
|
+
update(deltaSeconds) {
|
|
3560
|
+
return this.core.update(deltaSeconds);
|
|
3561
|
+
}
|
|
3562
|
+
activeTransitionCount() {
|
|
3563
|
+
return this.core.active_transition_count();
|
|
3564
|
+
}
|
|
3565
|
+
clearTransitions() {
|
|
3566
|
+
this.core.clear_transitions();
|
|
3567
|
+
}
|
|
3952
3568
|
getAU(id) {
|
|
3953
3569
|
return this.core.get_au(id >>> 0);
|
|
3954
3570
|
}
|
|
@@ -3984,7 +3600,13 @@ var WasmRuntimeCore = class {
|
|
|
3984
3600
|
};
|
|
3985
3601
|
}
|
|
3986
3602
|
reloadBindings() {
|
|
3987
|
-
|
|
3603
|
+
const profileJson = JSON.stringify(this.profile);
|
|
3604
|
+
const modelJson = JSON.stringify(this.model);
|
|
3605
|
+
if (this.allowEmptyBindings) {
|
|
3606
|
+
this.core.configure(profileJson, modelJson);
|
|
3607
|
+
} else {
|
|
3608
|
+
this.core.configure_with_profile(profileJson, modelJson);
|
|
3609
|
+
}
|
|
3988
3610
|
}
|
|
3989
3611
|
};
|
|
3990
3612
|
function unpackBoneFrameDelta(values) {
|
|
@@ -5333,7 +4955,7 @@ var CC4_PRESET = {
|
|
|
5333
4955
|
};
|
|
5334
4956
|
|
|
5335
4957
|
// src/engines/three/hair/HairPhysicsController.ts
|
|
5336
|
-
var
|
|
4958
|
+
var clamp01 = (value) => value < 0 ? 0 : value > 1 ? 1 : value;
|
|
5337
4959
|
var HairPhysicsController = class {
|
|
5338
4960
|
constructor(host) {
|
|
5339
4961
|
__publicField(this, "host");
|
|
@@ -5831,7 +5453,7 @@ var HairPhysicsController = class {
|
|
|
5831
5453
|
}
|
|
5832
5454
|
}
|
|
5833
5455
|
setMorphOnMeshes(meshNames, morphKey, value) {
|
|
5834
|
-
const val =
|
|
5456
|
+
const val = clamp01(value);
|
|
5835
5457
|
for (const name of meshNames) {
|
|
5836
5458
|
const mesh = this.registeredHairObjects.get(name) || this.host.getMeshByName(name);
|
|
5837
5459
|
if (!mesh) continue;
|
|
@@ -6075,9 +5697,9 @@ var HairPhysicsController = class {
|
|
|
6075
5697
|
const deltaVertical = vertical - this.lastHeadVertical;
|
|
6076
5698
|
this.lastHeadHorizontal = horizontal;
|
|
6077
5699
|
this.lastHeadVertical = vertical;
|
|
6078
|
-
const leftWeight =
|
|
6079
|
-
const rightWeight =
|
|
6080
|
-
const frontWeight =
|
|
5700
|
+
const leftWeight = clamp01(deltaHorizontal > 0 ? deltaHorizontal : 0);
|
|
5701
|
+
const rightWeight = clamp01(deltaHorizontal < 0 ? -deltaHorizontal : 0);
|
|
5702
|
+
const frontWeight = clamp01(deltaVertical > 0 ? deltaVertical : 0);
|
|
6081
5703
|
const minTrigger = 0.01;
|
|
6082
5704
|
if (leftWeight <= minTrigger && rightWeight <= minTrigger && frontWeight <= minTrigger) return;
|
|
6083
5705
|
if (this.impulseClipDirty) {
|
|
@@ -7043,7 +6665,7 @@ async function getPresetWithProfile(presetType, profile) {
|
|
|
7043
6665
|
}
|
|
7044
6666
|
|
|
7045
6667
|
// src/engines/three/Embody.ts
|
|
7046
|
-
var
|
|
6668
|
+
var deg2rad = (d) => d * Math.PI / 180;
|
|
7047
6669
|
var X_AXIS2 = new three.Vector3(1, 0, 0);
|
|
7048
6670
|
var Y_AXIS2 = new three.Vector3(0, 1, 0);
|
|
7049
6671
|
var Z_AXIS2 = new three.Vector3(0, 0, 1);
|
|
@@ -7066,9 +6688,18 @@ function buildAUToCompositeMap(composites) {
|
|
|
7066
6688
|
});
|
|
7067
6689
|
return map;
|
|
7068
6690
|
}
|
|
7069
|
-
function
|
|
6691
|
+
function clamp012(x) {
|
|
7070
6692
|
return x < 0 ? 0 : x > 1 ? 1 : x;
|
|
7071
6693
|
}
|
|
6694
|
+
var RESOLVED_TRANSITION_HANDLE = {
|
|
6695
|
+
promise: Promise.resolve(),
|
|
6696
|
+
pause: () => {
|
|
6697
|
+
},
|
|
6698
|
+
resume: () => {
|
|
6699
|
+
},
|
|
6700
|
+
cancel: () => {
|
|
6701
|
+
}
|
|
6702
|
+
};
|
|
7072
6703
|
var _Embody = class _Embody {
|
|
7073
6704
|
constructor(config = {}, animation) {
|
|
7074
6705
|
// Optional hook for animation schedulers.
|
|
@@ -7112,7 +6743,6 @@ var _Embody = class _Embody {
|
|
|
7112
6743
|
__publicField(this, "modelInspector", new ThreeModelInspector());
|
|
7113
6744
|
__publicField(this, "frameApplier", new ThreeFrameApplier());
|
|
7114
6745
|
__publicField(this, "modelDescriptor", null);
|
|
7115
|
-
__publicField(this, "tsRuntimeCore", null);
|
|
7116
6746
|
__publicField(this, "wasmRuntimeCore", null);
|
|
7117
6747
|
__publicField(this, "framePathReady", false);
|
|
7118
6748
|
// Internal animation loop
|
|
@@ -7225,48 +6855,21 @@ var _Embody = class _Embody {
|
|
|
7225
6855
|
bindHostNeutralRuntime(inspection) {
|
|
7226
6856
|
this.modelDescriptor = inspection.descriptor;
|
|
7227
6857
|
this.frameApplier.setBindings(buildFrameApplierBindings(inspection));
|
|
7228
|
-
|
|
6858
|
+
const wasm$1 = wasm.requireInitializedEmbodyCore();
|
|
6859
|
+
this.attachWasmCore(wasm$1);
|
|
6860
|
+
this.wasmRuntimeCore = new WasmRuntimeCore({
|
|
7229
6861
|
profile: this.config,
|
|
7230
|
-
model: inspection.descriptor
|
|
6862
|
+
model: inspection.descriptor,
|
|
6863
|
+
wasm: wasm$1,
|
|
6864
|
+
allowEmptyBindings: true
|
|
7231
6865
|
});
|
|
7232
6866
|
this.syncRuntimeCoreState();
|
|
7233
6867
|
this.framePathReady = true;
|
|
7234
|
-
void wasm.initEmbodyCore().then((wasm) => {
|
|
7235
|
-
if (!this.modelDescriptor) return;
|
|
7236
|
-
this.attachWasmCore(wasm);
|
|
7237
|
-
this.wasmRuntimeCore = new WasmRuntimeCore({
|
|
7238
|
-
profile: this.config,
|
|
7239
|
-
model: this.modelDescriptor,
|
|
7240
|
-
wasm
|
|
7241
|
-
});
|
|
7242
|
-
this.syncRuntimeCoreState();
|
|
7243
|
-
}).catch(() => {
|
|
7244
|
-
this.wasmRuntimeCore = null;
|
|
7245
|
-
});
|
|
7246
6868
|
}
|
|
7247
6869
|
attachWasmCore(core) {
|
|
7248
6870
|
this.hairPhysics.setCore(core);
|
|
7249
6871
|
}
|
|
7250
6872
|
syncRuntimeCoreState() {
|
|
7251
|
-
if (this.tsRuntimeCore) {
|
|
7252
|
-
this.tsRuntimeCore.setProfile(this.config);
|
|
7253
|
-
if (this.modelDescriptor) {
|
|
7254
|
-
this.tsRuntimeCore.setModelDescriptor(this.modelDescriptor);
|
|
7255
|
-
}
|
|
7256
|
-
for (const [auIdText, value] of Object.entries(this.auValues)) {
|
|
7257
|
-
const auId = Number(auIdText);
|
|
7258
|
-
if (Number.isNaN(auId)) continue;
|
|
7259
|
-
this.tsRuntimeCore.setAU(auId, value, this.auBalances[auId]);
|
|
7260
|
-
}
|
|
7261
|
-
for (const [auIdText, weight] of Object.entries(this.mixWeights)) {
|
|
7262
|
-
const auId = Number(auIdText);
|
|
7263
|
-
if (Number.isNaN(auId)) continue;
|
|
7264
|
-
this.tsRuntimeCore.setAUMixWeight(auId, weight);
|
|
7265
|
-
}
|
|
7266
|
-
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
7267
|
-
this.tsRuntimeCore.setViseme(index, this.visemeValues[index] ?? 0, this.visemeJawScales[index] ?? 1);
|
|
7268
|
-
}
|
|
7269
|
-
}
|
|
7270
6873
|
if (this.wasmRuntimeCore) {
|
|
7271
6874
|
this.wasmRuntimeCore.setProfile(this.config);
|
|
7272
6875
|
if (this.modelDescriptor) {
|
|
@@ -7284,7 +6887,7 @@ var _Embody = class _Embody {
|
|
|
7284
6887
|
this.wasmRuntimeCore.setAUMixWeight(auId, weight);
|
|
7285
6888
|
}
|
|
7286
6889
|
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
7287
|
-
this.wasmRuntimeCore.setViseme(index, this.visemeValues[index] ?? 0);
|
|
6890
|
+
this.wasmRuntimeCore.setViseme(index, this.visemeValues[index] ?? 0, this.visemeJawScales[index] ?? 1);
|
|
7288
6891
|
}
|
|
7289
6892
|
}
|
|
7290
6893
|
}
|
|
@@ -7302,25 +6905,13 @@ var _Embody = class _Embody {
|
|
|
7302
6905
|
});
|
|
7303
6906
|
this.modelDescriptor = inspection.descriptor;
|
|
7304
6907
|
this.frameApplier.setBindings(buildFrameApplierBindings(inspection));
|
|
7305
|
-
this.tsRuntimeCore?.setModelDescriptor(inspection.descriptor);
|
|
7306
6908
|
this.wasmRuntimeCore?.setModelDescriptor(inspection.descriptor);
|
|
7307
6909
|
}
|
|
7308
|
-
|
|
7309
|
-
if (!this.framePathReady || !this.model) return false;
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
);
|
|
7314
|
-
return true;
|
|
7315
|
-
}
|
|
7316
|
-
if (this.tsRuntimeCore) {
|
|
7317
|
-
const frame = this.tsRuntimeCore.evaluateFrameDelta();
|
|
7318
|
-
this.frameApplier.applyFrameDelta(this.model, {
|
|
7319
|
-
morphTargets: frame.morphTargets
|
|
7320
|
-
});
|
|
7321
|
-
return true;
|
|
7322
|
-
}
|
|
7323
|
-
return false;
|
|
6910
|
+
applyLiveFrameDelta() {
|
|
6911
|
+
if (!this.framePathReady || !this.model || !this.wasmRuntimeCore) return false;
|
|
6912
|
+
this.frameApplier.applyFrameDelta(this.model, this.wasmRuntimeCore.evaluateFrameDelta());
|
|
6913
|
+
this.pendingCompositeNodes.clear();
|
|
6914
|
+
return true;
|
|
7324
6915
|
}
|
|
7325
6916
|
rebuildMorphTargetsCache() {
|
|
7326
6917
|
this.morphKeyCache.clear();
|
|
@@ -7422,6 +7013,11 @@ var _Embody = class _Embody {
|
|
|
7422
7013
|
const dtSeconds = Math.max(0, deltaSeconds || 0);
|
|
7423
7014
|
if (dtSeconds <= 0 || this.isPaused) return;
|
|
7424
7015
|
this.animation.tick(dtSeconds);
|
|
7016
|
+
const wasmTransitionCount = this.wasmRuntimeCore?.activeTransitionCount() ?? 0;
|
|
7017
|
+
const remainingWasmTransitions = this.wasmRuntimeCore?.update(dtSeconds) ?? 0;
|
|
7018
|
+
if (wasmTransitionCount > 0 || remainingWasmTransitions > 0) {
|
|
7019
|
+
this.applyLiveFrameDelta();
|
|
7020
|
+
}
|
|
7425
7021
|
this.flushPendingComposites();
|
|
7426
7022
|
this.animationController.update(dtSeconds);
|
|
7427
7023
|
this.hairPhysics.update(dtSeconds);
|
|
@@ -7456,7 +7052,6 @@ var _Embody = class _Embody {
|
|
|
7456
7052
|
this.model = null;
|
|
7457
7053
|
this.bones = {};
|
|
7458
7054
|
this.modelDescriptor = null;
|
|
7459
|
-
this.tsRuntimeCore = null;
|
|
7460
7055
|
this.wasmRuntimeCore = null;
|
|
7461
7056
|
this.framePathReady = false;
|
|
7462
7057
|
}
|
|
@@ -7493,15 +7088,14 @@ var _Embody = class _Embody {
|
|
|
7493
7088
|
if (balance !== void 0) {
|
|
7494
7089
|
this.auBalances[id] = balance;
|
|
7495
7090
|
}
|
|
7496
|
-
this.tsRuntimeCore?.setAU(id, v, balance);
|
|
7497
7091
|
this.wasmRuntimeCore?.setAU(id, v, balance ?? this.auBalances[id] ?? 0);
|
|
7498
|
-
const appliedViaFrame = this.
|
|
7092
|
+
const appliedViaFrame = this.applyLiveFrameDelta();
|
|
7499
7093
|
if (!appliedViaFrame) {
|
|
7500
7094
|
const resolvedMorphTargets = this.resolvedAUMorphTargets.get(id);
|
|
7501
7095
|
const { left: leftKeys, right: rightKeys, center: centerKeys } = this.getAUMorphsBySide(id);
|
|
7502
7096
|
if (resolvedMorphTargets) {
|
|
7503
7097
|
const mixWeight = this.isMixedAU(id) ? this.getAUMixWeight(id) : 1;
|
|
7504
|
-
const base =
|
|
7098
|
+
const base = clamp012(v) * mixWeight;
|
|
7505
7099
|
const { left: leftVal, right: rightVal } = this.computeSideValues(base, balance);
|
|
7506
7100
|
if (resolvedMorphTargets.left.length || resolvedMorphTargets.right.length) {
|
|
7507
7101
|
this.applyMorphTargets(resolvedMorphTargets.left, leftVal);
|
|
@@ -7510,7 +7104,7 @@ var _Embody = class _Embody {
|
|
|
7510
7104
|
this.applyMorphTargets(resolvedMorphTargets.center, base);
|
|
7511
7105
|
} else if (leftKeys.length || rightKeys.length || centerKeys.length) {
|
|
7512
7106
|
const mixWeight = this.isMixedAU(id) ? this.getAUMixWeight(id) : 1;
|
|
7513
|
-
const base =
|
|
7107
|
+
const base = clamp012(v) * mixWeight;
|
|
7514
7108
|
const meshNames = this.getMeshNamesForAU(id);
|
|
7515
7109
|
const { left: leftVal, right: rightVal } = this.computeSideValues(base, balance);
|
|
7516
7110
|
if (leftKeys.length || rightKeys.length) {
|
|
@@ -7529,6 +7123,7 @@ var _Embody = class _Embody {
|
|
|
7529
7123
|
}
|
|
7530
7124
|
}
|
|
7531
7125
|
}
|
|
7126
|
+
if (appliedViaFrame) return;
|
|
7532
7127
|
const compositeInfo = this.auToCompositeMap.get(id);
|
|
7533
7128
|
if (compositeInfo) {
|
|
7534
7129
|
for (const nodeKey of compositeInfo.nodes) {
|
|
@@ -7563,7 +7158,7 @@ var _Embody = class _Embody {
|
|
|
7563
7158
|
return this.transitionContinuum(negAU, posAU, continuumValue, durationMs, balance);
|
|
7564
7159
|
}
|
|
7565
7160
|
}
|
|
7566
|
-
const target =
|
|
7161
|
+
const target = clamp012(to);
|
|
7567
7162
|
if (balance !== void 0) {
|
|
7568
7163
|
this.auBalances[numId] = balance;
|
|
7569
7164
|
}
|
|
@@ -7574,6 +7169,19 @@ var _Embody = class _Embody {
|
|
|
7574
7169
|
const base = target * mixWeight;
|
|
7575
7170
|
const { left: leftVal, right: rightVal } = this.computeSideValues(base, storedBalance);
|
|
7576
7171
|
this.auValues[numId] = target;
|
|
7172
|
+
if (this.wasmRuntimeCore) {
|
|
7173
|
+
this.wasmRuntimeCore.transitionAU(
|
|
7174
|
+
numId,
|
|
7175
|
+
target,
|
|
7176
|
+
durationMs,
|
|
7177
|
+
balance ?? this.auBalances[numId] ?? Number.NaN
|
|
7178
|
+
);
|
|
7179
|
+
this.update(0);
|
|
7180
|
+
if (durationMs <= 0) {
|
|
7181
|
+
this.applyLiveFrameDelta();
|
|
7182
|
+
}
|
|
7183
|
+
return RESOLVED_TRANSITION_HANDLE;
|
|
7184
|
+
}
|
|
7577
7185
|
const handles = [];
|
|
7578
7186
|
const meshNames = this.getMeshNamesForAU(numId);
|
|
7579
7187
|
if (leftKeys.length || rightKeys.length) {
|
|
@@ -7636,6 +7244,17 @@ var _Embody = class _Embody {
|
|
|
7636
7244
|
*/
|
|
7637
7245
|
setContinuum(negAU, posAU, continuumValue, balance) {
|
|
7638
7246
|
const value = Math.max(-1, Math.min(1, continuumValue));
|
|
7247
|
+
this.auValues[negAU] = value < 0 ? Math.abs(value) : 0;
|
|
7248
|
+
this.auValues[posAU] = value > 0 ? value : 0;
|
|
7249
|
+
if (balance !== void 0) {
|
|
7250
|
+
this.auBalances[negAU] = balance;
|
|
7251
|
+
this.auBalances[posAU] = balance;
|
|
7252
|
+
}
|
|
7253
|
+
if (this.wasmRuntimeCore) {
|
|
7254
|
+
this.wasmRuntimeCore.setContinuum(negAU, posAU, value, balance ?? 0);
|
|
7255
|
+
this.applyLiveFrameDelta();
|
|
7256
|
+
return;
|
|
7257
|
+
}
|
|
7639
7258
|
if (value < 0) {
|
|
7640
7259
|
this.setAU(posAU, 0, balance);
|
|
7641
7260
|
this.setAU(negAU, Math.abs(value), balance);
|
|
@@ -7661,10 +7280,32 @@ var _Embody = class _Embody {
|
|
|
7661
7280
|
*/
|
|
7662
7281
|
transitionContinuum(negAU, posAU, continuumValue, durationMs = 200, balance) {
|
|
7663
7282
|
const target = Math.max(-1, Math.min(1, continuumValue));
|
|
7664
|
-
const driverKey = `continuum_${negAU}_${posAU}`;
|
|
7665
7283
|
const currentNeg = this.auValues[negAU] ?? 0;
|
|
7666
7284
|
const currentPos = this.auValues[posAU] ?? 0;
|
|
7667
7285
|
const currentContinuum = currentPos - currentNeg;
|
|
7286
|
+
this.auValues[negAU] = target < 0 ? Math.abs(target) : 0;
|
|
7287
|
+
this.auValues[posAU] = target > 0 ? target : 0;
|
|
7288
|
+
if (balance !== void 0) {
|
|
7289
|
+
this.auBalances[negAU] = balance;
|
|
7290
|
+
this.auBalances[posAU] = balance;
|
|
7291
|
+
}
|
|
7292
|
+
if (this.wasmRuntimeCore) {
|
|
7293
|
+
if (target < 0) {
|
|
7294
|
+
this.wasmRuntimeCore.transitionAU(posAU, 0, durationMs, balance ?? this.auBalances[posAU] ?? Number.NaN);
|
|
7295
|
+
this.wasmRuntimeCore.transitionAU(negAU, Math.abs(target), durationMs, balance ?? this.auBalances[negAU] ?? Number.NaN);
|
|
7296
|
+
} else if (target > 0) {
|
|
7297
|
+
this.wasmRuntimeCore.transitionAU(negAU, 0, durationMs, balance ?? this.auBalances[negAU] ?? Number.NaN);
|
|
7298
|
+
this.wasmRuntimeCore.transitionAU(posAU, target, durationMs, balance ?? this.auBalances[posAU] ?? Number.NaN);
|
|
7299
|
+
} else {
|
|
7300
|
+
this.wasmRuntimeCore.transitionAU(negAU, 0, durationMs, balance ?? this.auBalances[negAU] ?? Number.NaN);
|
|
7301
|
+
this.wasmRuntimeCore.transitionAU(posAU, 0, durationMs, balance ?? this.auBalances[posAU] ?? Number.NaN);
|
|
7302
|
+
}
|
|
7303
|
+
if (durationMs <= 0) {
|
|
7304
|
+
this.applyLiveFrameDelta();
|
|
7305
|
+
}
|
|
7306
|
+
return RESOLVED_TRANSITION_HANDLE;
|
|
7307
|
+
}
|
|
7308
|
+
const driverKey = `continuum_${negAU}_${posAU}`;
|
|
7668
7309
|
return this.animation.addTransition(driverKey, currentContinuum, target, durationMs, (value) => this.setContinuum(negAU, posAU, value, balance));
|
|
7669
7310
|
}
|
|
7670
7311
|
// ============================================================================
|
|
@@ -7746,7 +7387,7 @@ var _Embody = class _Embody {
|
|
|
7746
7387
|
this.hairPhysics.refreshMeshSelection();
|
|
7747
7388
|
}
|
|
7748
7389
|
setMorph(key, v, meshNamesOrTargets) {
|
|
7749
|
-
const val =
|
|
7390
|
+
const val = clamp012(v);
|
|
7750
7391
|
if (Array.isArray(meshNamesOrTargets) && meshNamesOrTargets.length > 0 && typeof meshNamesOrTargets[0] === "object" && "infl" in meshNamesOrTargets[0]) {
|
|
7751
7392
|
const targets2 = meshNamesOrTargets;
|
|
7752
7393
|
this.applyMorphTargets(targets2, val);
|
|
@@ -7758,7 +7399,7 @@ var _Embody = class _Embody {
|
|
|
7758
7399
|
this.applyMorphTargets(targets, val);
|
|
7759
7400
|
}
|
|
7760
7401
|
setMorphInfluence(index, v, meshNames) {
|
|
7761
|
-
const val =
|
|
7402
|
+
const val = clamp012(v);
|
|
7762
7403
|
const targets = this.resolveMorphTargetsByIndex(index, meshNames);
|
|
7763
7404
|
if (targets.length === 0) return;
|
|
7764
7405
|
this.applyMorphTargets(targets, val);
|
|
@@ -7833,21 +7474,21 @@ var _Embody = class _Embody {
|
|
|
7833
7474
|
}
|
|
7834
7475
|
transitionMorph(key, to, durationMs = 120, meshNames) {
|
|
7835
7476
|
const transitionKey = meshNames?.length ? `morph_${this.getMorphKeyCacheKey(key, meshNames)}` : `morph_${this.getMorphKeyCacheKey(key)}`;
|
|
7836
|
-
const target =
|
|
7477
|
+
const target = clamp012(to);
|
|
7837
7478
|
const targets = this.resolveMorphTargets(key, meshNames);
|
|
7838
7479
|
const from = targets.length > 0 ? targets[0].infl[targets[0].idx] ?? 0 : this.getMorphValue(key);
|
|
7839
7480
|
return this.animation.addTransition(transitionKey, from, target, durationMs, (value) => {
|
|
7840
|
-
const val =
|
|
7481
|
+
const val = clamp012(value);
|
|
7841
7482
|
this.applyMorphTargets(targets, val);
|
|
7842
7483
|
});
|
|
7843
7484
|
}
|
|
7844
7485
|
transitionMorphInfluence(index, to, durationMs = 120, meshNames) {
|
|
7845
7486
|
const transitionKey = meshNames?.length ? `morph_${this.getMorphIndexCacheKey(index, meshNames)}` : `morph_${this.getMorphIndexCacheKey(index)}`;
|
|
7846
|
-
const target =
|
|
7487
|
+
const target = clamp012(to);
|
|
7847
7488
|
const targets = this.resolveMorphTargetsByIndex(index, meshNames);
|
|
7848
7489
|
const from = targets.length > 0 ? targets[0].infl[targets[0].idx] ?? 0 : this.getMorphValueByIndex(index);
|
|
7849
7490
|
return this.animation.addTransition(transitionKey, from, target, durationMs, (value) => {
|
|
7850
|
-
const val =
|
|
7491
|
+
const val = clamp012(value);
|
|
7851
7492
|
this.applyMorphTargets(targets, val);
|
|
7852
7493
|
});
|
|
7853
7494
|
}
|
|
@@ -7856,7 +7497,7 @@ var _Embody = class _Embody {
|
|
|
7856
7497
|
// ============================================================================
|
|
7857
7498
|
setViseme(visemeIndex, value, jawScale = 1) {
|
|
7858
7499
|
if (visemeIndex < 0 || visemeIndex >= this.visemeValues.length) return;
|
|
7859
|
-
const val =
|
|
7500
|
+
const val = clamp012(value);
|
|
7860
7501
|
this.visemeValues[visemeIndex] = val;
|
|
7861
7502
|
this.visemeJawScales[visemeIndex] = jawScale;
|
|
7862
7503
|
this.applyVisemeRuntimeState();
|
|
@@ -7868,16 +7509,24 @@ var _Embody = class _Embody {
|
|
|
7868
7509
|
}, cancel: () => {
|
|
7869
7510
|
} };
|
|
7870
7511
|
}
|
|
7871
|
-
const target =
|
|
7512
|
+
const target = clamp012(to);
|
|
7872
7513
|
const from = this.visemeValues[visemeIndex] ?? 0;
|
|
7873
7514
|
this.visemeJawScales[visemeIndex] = jawScale;
|
|
7515
|
+
if (this.wasmRuntimeCore) {
|
|
7516
|
+
this.visemeValues[visemeIndex] = target;
|
|
7517
|
+
this.wasmRuntimeCore.transitionViseme(visemeIndex, target, durationMs, jawScale);
|
|
7518
|
+
if (durationMs <= 0) {
|
|
7519
|
+
this.applyLiveFrameDelta();
|
|
7520
|
+
}
|
|
7521
|
+
return RESOLVED_TRANSITION_HANDLE;
|
|
7522
|
+
}
|
|
7874
7523
|
return this.animation.addTransition(
|
|
7875
7524
|
`viseme_value_${visemeIndex}`,
|
|
7876
7525
|
from,
|
|
7877
7526
|
target,
|
|
7878
7527
|
durationMs,
|
|
7879
7528
|
(value) => {
|
|
7880
|
-
this.visemeValues[visemeIndex] =
|
|
7529
|
+
this.visemeValues[visemeIndex] = clamp012(value);
|
|
7881
7530
|
this.visemeJawScales[visemeIndex] = jawScale;
|
|
7882
7531
|
this.applyVisemeRuntimeState();
|
|
7883
7532
|
}
|
|
@@ -7902,8 +7551,7 @@ var _Embody = class _Embody {
|
|
|
7902
7551
|
// MIX WEIGHT CONTROL
|
|
7903
7552
|
// ============================================================================
|
|
7904
7553
|
setAUMixWeight(id, weight) {
|
|
7905
|
-
this.mixWeights[id] =
|
|
7906
|
-
this.tsRuntimeCore?.setAUMixWeight(id, weight);
|
|
7554
|
+
this.mixWeights[id] = clamp012(weight);
|
|
7907
7555
|
this.wasmRuntimeCore?.setAUMixWeight(id, weight);
|
|
7908
7556
|
const v = this.auValues[id] ?? 0;
|
|
7909
7557
|
if (v > 0) this.setAU(id, v);
|
|
@@ -7941,9 +7589,10 @@ var _Embody = class _Embody {
|
|
|
7941
7589
|
}
|
|
7942
7590
|
clearTransitions() {
|
|
7943
7591
|
this.animation.clearTransitions();
|
|
7592
|
+
this.wasmRuntimeCore?.clearTransitions();
|
|
7944
7593
|
}
|
|
7945
7594
|
getActiveTransitionCount() {
|
|
7946
|
-
return this.animation.getActiveTransitionCount();
|
|
7595
|
+
return this.animation.getActiveTransitionCount() + (this.wasmRuntimeCore?.activeTransitionCount() ?? 0);
|
|
7947
7596
|
}
|
|
7948
7597
|
resetToNeutral() {
|
|
7949
7598
|
this.auValues = {};
|
|
@@ -7953,6 +7602,7 @@ var _Embody = class _Embody {
|
|
|
7953
7602
|
this.translations = {};
|
|
7954
7603
|
this.initBoneRotations();
|
|
7955
7604
|
this.clearTransitions();
|
|
7605
|
+
this.wasmRuntimeCore?.clear();
|
|
7956
7606
|
const morphTargetsToReset = [];
|
|
7957
7607
|
for (const m of this.meshes) {
|
|
7958
7608
|
const infl = m.morphTargetInfluences;
|
|
@@ -8131,7 +7781,18 @@ var _Embody = class _Embody {
|
|
|
8131
7781
|
this.bones = this.resolveBones(this.model);
|
|
8132
7782
|
this.missingBoneWarnings.clear();
|
|
8133
7783
|
this.rebuildMorphTargetsCache();
|
|
8134
|
-
|
|
7784
|
+
Object.values(this.bones).forEach((entry) => {
|
|
7785
|
+
if (!entry) return;
|
|
7786
|
+
this.frameApplier.applyObjectTransform(entry.obj, {
|
|
7787
|
+
position: { x: entry.basePos.x, y: entry.basePos.y, z: entry.basePos.z },
|
|
7788
|
+
rotation: {
|
|
7789
|
+
x: entry.baseQuat.x,
|
|
7790
|
+
y: entry.baseQuat.y,
|
|
7791
|
+
z: entry.baseQuat.z,
|
|
7792
|
+
w: entry.baseQuat.w
|
|
7793
|
+
}
|
|
7794
|
+
});
|
|
7795
|
+
});
|
|
8135
7796
|
this.wasmRuntimeCore?.setProfile(this.config);
|
|
8136
7797
|
this.refreshHostNeutralModelDescriptor();
|
|
8137
7798
|
}
|
|
@@ -8248,20 +7909,20 @@ var _Embody = class _Embody {
|
|
|
8248
7909
|
}
|
|
8249
7910
|
applyVisemeRuntimeState() {
|
|
8250
7911
|
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
8251
|
-
this.
|
|
8252
|
-
this.wasmRuntimeCore?.setViseme(index, this.visemeValues[index] ?? 0);
|
|
7912
|
+
this.wasmRuntimeCore?.setViseme(index, this.visemeValues[index] ?? 0, this.visemeJawScales[index] ?? 1);
|
|
8253
7913
|
}
|
|
8254
|
-
|
|
7914
|
+
const appliedViaFrame = this.applyLiveFrameDelta();
|
|
7915
|
+
if (!appliedViaFrame) {
|
|
8255
7916
|
for (const targets of this.resolvedVisemeTargets) {
|
|
8256
7917
|
this.frameApplier.resetMorphTargets(targets || []);
|
|
8257
7918
|
}
|
|
8258
7919
|
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
8259
|
-
const value =
|
|
7920
|
+
const value = clamp012(this.visemeValues[index] ?? 0);
|
|
8260
7921
|
if (value <= 1e-6) continue;
|
|
8261
7922
|
const targets = this.resolvedVisemeTargets[index] || [];
|
|
8262
7923
|
for (const target of targets) {
|
|
8263
7924
|
if (target.idx >= target.infl.length) continue;
|
|
8264
|
-
const weighted =
|
|
7925
|
+
const weighted = clamp012(value * target.weight);
|
|
8265
7926
|
this.frameApplier.applyMorphTargets(
|
|
8266
7927
|
[target],
|
|
8267
7928
|
Math.max(target.infl[target.idx] ?? 0, weighted)
|
|
@@ -8269,7 +7930,9 @@ var _Embody = class _Embody {
|
|
|
8269
7930
|
}
|
|
8270
7931
|
}
|
|
8271
7932
|
}
|
|
8272
|
-
|
|
7933
|
+
if (!appliedViaFrame) {
|
|
7934
|
+
this.updateBoneRotation(this.getJawBoneNodeKey(), "pitch", this.getActiveVisemeJawAmount());
|
|
7935
|
+
}
|
|
8273
7936
|
}
|
|
8274
7937
|
getJawBoneNodeKey() {
|
|
8275
7938
|
const candidates = [
|
|
@@ -8291,7 +7954,7 @@ var _Embody = class _Embody {
|
|
|
8291
7954
|
getActiveVisemeJawAmount() {
|
|
8292
7955
|
let jawAmount = 0;
|
|
8293
7956
|
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
8294
|
-
const value =
|
|
7957
|
+
const value = clamp012(this.visemeValues[index] ?? 0);
|
|
8295
7958
|
if (value <= 1e-6) continue;
|
|
8296
7959
|
const jawScale = this.visemeJawScales[index] ?? 1;
|
|
8297
7960
|
if (Math.abs(jawScale) <= 1e-6) continue;
|
|
@@ -8574,7 +8237,7 @@ var _Embody = class _Embody {
|
|
|
8574
8237
|
return !!(hasMorphs && this.config.auToBones[id]?.length);
|
|
8575
8238
|
}
|
|
8576
8239
|
getEffectiveBoneAUValue(auId, nodeKey) {
|
|
8577
|
-
const rawValue =
|
|
8240
|
+
const rawValue = clamp012(this.auValues[auId] ?? 0);
|
|
8578
8241
|
if (rawValue <= 1e-6) return 0;
|
|
8579
8242
|
const binding = this.config.auToBones[auId]?.find((candidate) => candidate.node === nodeKey) ?? null;
|
|
8580
8243
|
if (!binding?.side) return rawValue;
|
|
@@ -8674,7 +8337,7 @@ var _Embody = class _Embody {
|
|
|
8674
8337
|
if (config.yaw && rotState.yaw !== 0) {
|
|
8675
8338
|
const binding = this.getCompositeAxisBindingForNode(nodeKey, config.yaw, rotState.yaw);
|
|
8676
8339
|
if (binding?.maxDegrees && binding.channel) {
|
|
8677
|
-
const radians =
|
|
8340
|
+
const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.yaw) * binding.scale;
|
|
8678
8341
|
const axis = getAxis(binding.channel);
|
|
8679
8342
|
const deltaQ = new three.Quaternion().setFromAxisAngle(axis, radians);
|
|
8680
8343
|
compositeQ.multiply(deltaQ);
|
|
@@ -8683,7 +8346,7 @@ var _Embody = class _Embody {
|
|
|
8683
8346
|
if (config.pitch && rotState.pitch !== 0) {
|
|
8684
8347
|
const binding = this.getCompositeAxisBindingForNode(nodeKey, config.pitch, rotState.pitch);
|
|
8685
8348
|
if (binding?.maxDegrees && binding.channel) {
|
|
8686
|
-
const radians =
|
|
8349
|
+
const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.pitch) * binding.scale;
|
|
8687
8350
|
const axis = getAxis(binding.channel);
|
|
8688
8351
|
const deltaQ = new three.Quaternion().setFromAxisAngle(axis, radians);
|
|
8689
8352
|
compositeQ.multiply(deltaQ);
|
|
@@ -8692,7 +8355,7 @@ var _Embody = class _Embody {
|
|
|
8692
8355
|
if (config.roll && rotState.roll !== 0) {
|
|
8693
8356
|
const binding = this.getCompositeAxisBindingForNode(nodeKey, config.roll, rotState.roll);
|
|
8694
8357
|
if (binding?.maxDegrees && binding.channel) {
|
|
8695
|
-
const radians =
|
|
8358
|
+
const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.roll) * binding.scale;
|
|
8696
8359
|
const axis = getAxis(binding.channel);
|
|
8697
8360
|
const deltaQ = new three.Quaternion().setFromAxisAngle(axis, radians);
|
|
8698
8361
|
compositeQ.multiply(deltaQ);
|
|
@@ -9531,11 +9194,11 @@ function applyCharacterModelTransform(model, transform = {}) {
|
|
|
9531
9194
|
model.position.set(modelOffset.x ?? 0, modelOffset.y ?? 0, modelOffset.z ?? 0);
|
|
9532
9195
|
}
|
|
9533
9196
|
if (modelRotation) {
|
|
9534
|
-
const
|
|
9197
|
+
const deg2rad2 = Math.PI / 180;
|
|
9535
9198
|
model.rotation.set(
|
|
9536
|
-
(modelRotation.x ?? 0) *
|
|
9537
|
-
(modelRotation.y ?? 0) *
|
|
9538
|
-
(modelRotation.z ?? 0) *
|
|
9199
|
+
(modelRotation.x ?? 0) * deg2rad2,
|
|
9200
|
+
(modelRotation.y ?? 0) * deg2rad2,
|
|
9201
|
+
(modelRotation.z ?? 0) * deg2rad2
|
|
9539
9202
|
);
|
|
9540
9203
|
}
|
|
9541
9204
|
if (modelScale !== void 0 && Number.isFinite(modelScale) && modelScale > 0) {
|