@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/index.cjs
CHANGED
|
@@ -3696,410 +3696,6 @@ function getBlendingName(value) {
|
|
|
3696
3696
|
return "Normal";
|
|
3697
3697
|
}
|
|
3698
3698
|
|
|
3699
|
-
// src/core/TsRuntimeCore.ts
|
|
3700
|
-
var identityQuat = { x: 0, y: 0, z: 0, w: 1 };
|
|
3701
|
-
function isRotationBoneBinding2(binding) {
|
|
3702
|
-
return binding?.channel === "rx" || binding?.channel === "ry" || binding?.channel === "rz";
|
|
3703
|
-
}
|
|
3704
|
-
var TsRuntimeCore = class {
|
|
3705
|
-
constructor(options) {
|
|
3706
|
-
__publicField(this, "profile");
|
|
3707
|
-
__publicField(this, "model");
|
|
3708
|
-
__publicField(this, "auValues", {});
|
|
3709
|
-
__publicField(this, "auBalances", {});
|
|
3710
|
-
__publicField(this, "visemeValues");
|
|
3711
|
-
__publicField(this, "visemeJawScales");
|
|
3712
|
-
__publicField(this, "mixWeights");
|
|
3713
|
-
this.profile = options.profile;
|
|
3714
|
-
this.model = options.model;
|
|
3715
|
-
this.visemeValues = new Array(getProfileVisemeSlots(this.profile).length).fill(0);
|
|
3716
|
-
this.visemeJawScales = new Array(this.visemeValues.length).fill(1);
|
|
3717
|
-
this.mixWeights = { ...this.profile.auMixDefaults };
|
|
3718
|
-
}
|
|
3719
|
-
setProfile(profile) {
|
|
3720
|
-
this.profile = profile;
|
|
3721
|
-
this.visemeValues = new Array(getProfileVisemeSlots(this.profile).length).fill(0);
|
|
3722
|
-
this.visemeJawScales = new Array(this.visemeValues.length).fill(1);
|
|
3723
|
-
this.mixWeights = { ...this.profile.auMixDefaults };
|
|
3724
|
-
}
|
|
3725
|
-
setModelDescriptor(model) {
|
|
3726
|
-
this.model = model;
|
|
3727
|
-
}
|
|
3728
|
-
setAU(id, value, balance) {
|
|
3729
|
-
if (value < 0 && this.profile.continuumPairs) {
|
|
3730
|
-
const pairInfo = this.profile.continuumPairs[id];
|
|
3731
|
-
if (pairInfo) {
|
|
3732
|
-
const negAU = pairInfo.isNegative ? id : pairInfo.pairId;
|
|
3733
|
-
const posAU = pairInfo.isNegative ? pairInfo.pairId : id;
|
|
3734
|
-
this.setContinuum(negAU, posAU, pairInfo.isNegative ? -value : value, balance);
|
|
3735
|
-
return;
|
|
3736
|
-
}
|
|
3737
|
-
}
|
|
3738
|
-
this.auValues[id] = clamp01(value);
|
|
3739
|
-
if (balance !== void 0) {
|
|
3740
|
-
this.auBalances[id] = clampBalance2(balance);
|
|
3741
|
-
}
|
|
3742
|
-
}
|
|
3743
|
-
getAU(id) {
|
|
3744
|
-
return this.auValues[id] ?? 0;
|
|
3745
|
-
}
|
|
3746
|
-
setContinuum(negAU, posAU, continuumValue, balance) {
|
|
3747
|
-
const value = Math.max(-1, Math.min(1, continuumValue));
|
|
3748
|
-
if (value < 0) {
|
|
3749
|
-
this.setAU(posAU, 0, balance);
|
|
3750
|
-
this.setAU(negAU, Math.abs(value), balance);
|
|
3751
|
-
return;
|
|
3752
|
-
}
|
|
3753
|
-
if (value > 0) {
|
|
3754
|
-
this.setAU(negAU, 0, balance);
|
|
3755
|
-
this.setAU(posAU, value, balance);
|
|
3756
|
-
return;
|
|
3757
|
-
}
|
|
3758
|
-
this.setAU(negAU, 0, balance);
|
|
3759
|
-
this.setAU(posAU, 0, balance);
|
|
3760
|
-
}
|
|
3761
|
-
setViseme(visemeIndex, value, jawScale = 1) {
|
|
3762
|
-
if (visemeIndex < 0 || visemeIndex >= this.visemeValues.length) return;
|
|
3763
|
-
this.visemeValues[visemeIndex] = clamp01(value);
|
|
3764
|
-
this.visemeJawScales[visemeIndex] = jawScale;
|
|
3765
|
-
}
|
|
3766
|
-
setVisemeById(slotId, value, jawScale = 1) {
|
|
3767
|
-
const index = getVisemeSlotIndex(this.profile, slotId);
|
|
3768
|
-
if (index < 0) return;
|
|
3769
|
-
this.setViseme(index, value, jawScale);
|
|
3770
|
-
}
|
|
3771
|
-
setAUMixWeight(id, weight) {
|
|
3772
|
-
this.mixWeights[id] = clamp01(weight);
|
|
3773
|
-
}
|
|
3774
|
-
evaluateFrameDelta(deltaSeconds) {
|
|
3775
|
-
const morphWrites = /* @__PURE__ */ new Map();
|
|
3776
|
-
this.collectAUWrites(morphWrites);
|
|
3777
|
-
this.collectVisemeWrites(morphWrites);
|
|
3778
|
-
return {
|
|
3779
|
-
deltaSeconds,
|
|
3780
|
-
morphTargets: Array.from(morphWrites.values()),
|
|
3781
|
-
bones: this.collectBoneWrites()
|
|
3782
|
-
};
|
|
3783
|
-
}
|
|
3784
|
-
collectAUWrites(morphWrites) {
|
|
3785
|
-
for (const [auIdText, entry] of Object.entries(this.profile.auToMorphs || {})) {
|
|
3786
|
-
const auId = Number(auIdText);
|
|
3787
|
-
if (Number.isNaN(auId) || !entry) continue;
|
|
3788
|
-
const mixWeight = this.isMixedAU(auId) ? this.getAUMixWeight(auId) : 1;
|
|
3789
|
-
const base = clamp01(this.auValues[auId] ?? 0) * mixWeight;
|
|
3790
|
-
const { left, right } = computeSideValues(base, this.auBalances[auId]);
|
|
3791
|
-
const meshNames = getMeshNamesForAUProfile(this.profile, auId);
|
|
3792
|
-
for (const morph of entry.left || []) {
|
|
3793
|
-
this.addMorphWrites(morphWrites, morph, meshNames, left);
|
|
3794
|
-
}
|
|
3795
|
-
for (const morph of entry.right || []) {
|
|
3796
|
-
this.addMorphWrites(morphWrites, morph, meshNames, right);
|
|
3797
|
-
}
|
|
3798
|
-
for (const morph of entry.center || []) {
|
|
3799
|
-
this.addMorphWrites(morphWrites, morph, meshNames, base);
|
|
3800
|
-
}
|
|
3801
|
-
}
|
|
3802
|
-
}
|
|
3803
|
-
collectVisemeWrites(morphWrites) {
|
|
3804
|
-
const meshNames = getMeshNamesForVisemeProfile(this.profile);
|
|
3805
|
-
const localMax = /* @__PURE__ */ new Map();
|
|
3806
|
-
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
3807
|
-
const value = clamp01(this.visemeValues[index] ?? 0);
|
|
3808
|
-
for (const bindingTarget of getVisemeBindingTargets(this.profile, index)) {
|
|
3809
|
-
const weighted = clamp01(value * bindingTarget.weight);
|
|
3810
|
-
for (const resolved of this.resolveMorphTargets(bindingTarget.morph, meshNames)) {
|
|
3811
|
-
const key = morphWriteKey(resolved.mesh.id, resolved.morphTarget.id);
|
|
3812
|
-
const existing = localMax.get(key);
|
|
3813
|
-
if (!existing || weighted > existing.value) {
|
|
3814
|
-
localMax.set(key, {
|
|
3815
|
-
meshId: resolved.mesh.id,
|
|
3816
|
-
morphTargetId: resolved.morphTarget.id,
|
|
3817
|
-
value: weighted,
|
|
3818
|
-
mode: "absolute"
|
|
3819
|
-
});
|
|
3820
|
-
}
|
|
3821
|
-
}
|
|
3822
|
-
}
|
|
3823
|
-
}
|
|
3824
|
-
for (const [key, write] of localMax) {
|
|
3825
|
-
const existing = morphWrites.get(key);
|
|
3826
|
-
if (!existing || write.value > existing.value) {
|
|
3827
|
-
morphWrites.set(key, write);
|
|
3828
|
-
}
|
|
3829
|
-
}
|
|
3830
|
-
}
|
|
3831
|
-
collectBoneWrites() {
|
|
3832
|
-
const writes = [];
|
|
3833
|
-
const rotations = this.computeRotationState();
|
|
3834
|
-
for (const composite of this.profile.compositeRotations || []) {
|
|
3835
|
-
const bone = this.findBoneDescriptor(composite.node);
|
|
3836
|
-
if (!bone) continue;
|
|
3837
|
-
const transform = this.evaluateCompositeTransform(bone, composite, rotations[composite.node]);
|
|
3838
|
-
if (transform) {
|
|
3839
|
-
writes.push({
|
|
3840
|
-
boneId: bone.id,
|
|
3841
|
-
transform,
|
|
3842
|
-
mode: "absolute",
|
|
3843
|
-
space: "local"
|
|
3844
|
-
});
|
|
3845
|
-
}
|
|
3846
|
-
}
|
|
3847
|
-
for (const [nodeKey, translation] of Object.entries(this.computeTranslations())) {
|
|
3848
|
-
const bone = this.findBoneDescriptor(nodeKey);
|
|
3849
|
-
if (!bone) continue;
|
|
3850
|
-
const position = addVec3(bone.restTransform?.position, translation);
|
|
3851
|
-
upsertBoneWrite(writes, bone.id, { position });
|
|
3852
|
-
}
|
|
3853
|
-
const jawAmount = this.getActiveVisemeJawAmount();
|
|
3854
|
-
const jawBinding = this.findAutoVisemeJawBinding();
|
|
3855
|
-
const jawBone = jawBinding ? this.findBoneDescriptor(jawBinding.node) : void 0;
|
|
3856
|
-
if (jawBone && jawBinding?.maxDegrees && jawBinding.channel) {
|
|
3857
|
-
const current = writes.find((write) => write.boneId === jawBone.id);
|
|
3858
|
-
if (jawAmount > 1e-6 || !current?.transform.rotation) {
|
|
3859
|
-
const rest = jawBone.restTransform?.rotation ?? identityQuat;
|
|
3860
|
-
const rotation = jawAmount > 1e-6 ? multiplyQuat(
|
|
3861
|
-
rest,
|
|
3862
|
-
quatFromChannel(jawBinding.channel, deg2rad(jawBinding.maxDegrees) * jawAmount * jawBinding.scale)
|
|
3863
|
-
) : rest;
|
|
3864
|
-
upsertBoneWrite(writes, jawBone.id, { rotation });
|
|
3865
|
-
}
|
|
3866
|
-
}
|
|
3867
|
-
return writes;
|
|
3868
|
-
}
|
|
3869
|
-
computeRotationState() {
|
|
3870
|
-
const rotations = {};
|
|
3871
|
-
for (const composite of this.profile.compositeRotations || []) {
|
|
3872
|
-
rotations[composite.node] = {
|
|
3873
|
-
pitch: this.getCompositeAxisValueForNode(composite.node, composite.pitch),
|
|
3874
|
-
yaw: this.getCompositeAxisValueForNode(composite.node, composite.yaw),
|
|
3875
|
-
roll: this.getCompositeAxisValueForNode(composite.node, composite.roll)
|
|
3876
|
-
};
|
|
3877
|
-
}
|
|
3878
|
-
return rotations;
|
|
3879
|
-
}
|
|
3880
|
-
evaluateCompositeTransform(bone, composite, state) {
|
|
3881
|
-
if (!state) return null;
|
|
3882
|
-
let rotation = bone.restTransform?.rotation ?? identityQuat;
|
|
3883
|
-
const applyAxis = (axisConfig, direction) => {
|
|
3884
|
-
if (!axisConfig || Math.abs(direction) <= 1e-6) return;
|
|
3885
|
-
const binding = getCompositeAxisBinding(
|
|
3886
|
-
composite.node,
|
|
3887
|
-
axisConfig,
|
|
3888
|
-
direction,
|
|
3889
|
-
(auId) => this.getEffectiveBoneAUValue(auId, composite.node),
|
|
3890
|
-
this.profile.auToBones
|
|
3891
|
-
);
|
|
3892
|
-
if (!binding?.maxDegrees || !binding.channel) return;
|
|
3893
|
-
rotation = multiplyQuat(
|
|
3894
|
-
rotation,
|
|
3895
|
-
quatFromChannel(binding.channel, deg2rad(binding.maxDegrees) * Math.abs(direction) * binding.scale)
|
|
3896
|
-
);
|
|
3897
|
-
};
|
|
3898
|
-
applyAxis(composite.yaw, state.yaw);
|
|
3899
|
-
applyAxis(composite.pitch, state.pitch);
|
|
3900
|
-
applyAxis(composite.roll, state.roll);
|
|
3901
|
-
return { rotation };
|
|
3902
|
-
}
|
|
3903
|
-
computeTranslations() {
|
|
3904
|
-
const translations = {};
|
|
3905
|
-
for (const [auIdText, bindings] of Object.entries(this.profile.auToBones || {})) {
|
|
3906
|
-
const auId = Number(auIdText);
|
|
3907
|
-
if (Number.isNaN(auId)) continue;
|
|
3908
|
-
const value = clamp01(this.auValues[auId] ?? 0);
|
|
3909
|
-
for (const binding of bindings || []) {
|
|
3910
|
-
if (binding.channel !== "tx" && binding.channel !== "ty" && binding.channel !== "tz") continue;
|
|
3911
|
-
if (binding.maxUnits === void 0) continue;
|
|
3912
|
-
const current = translations[binding.node] ?? { x: 0, y: 0, z: 0 };
|
|
3913
|
-
translations[binding.node] = current;
|
|
3914
|
-
if (value <= 1e-6) continue;
|
|
3915
|
-
const offset = clampSigned(value * binding.scale) * binding.maxUnits;
|
|
3916
|
-
translations[binding.node] = {
|
|
3917
|
-
x: binding.channel === "tx" ? offset : current.x,
|
|
3918
|
-
y: binding.channel === "ty" ? offset : current.y,
|
|
3919
|
-
z: binding.channel === "tz" ? offset : current.z
|
|
3920
|
-
};
|
|
3921
|
-
}
|
|
3922
|
-
}
|
|
3923
|
-
return translations;
|
|
3924
|
-
}
|
|
3925
|
-
addMorphWrites(morphWrites, morph, meshNames, value) {
|
|
3926
|
-
for (const resolved of this.resolveMorphTargets(morph, meshNames)) {
|
|
3927
|
-
const key = morphWriteKey(resolved.mesh.id, resolved.morphTarget.id);
|
|
3928
|
-
const existing = morphWrites.get(key);
|
|
3929
|
-
if (existing && existing.value >= value) continue;
|
|
3930
|
-
morphWrites.set(key, {
|
|
3931
|
-
meshId: resolved.mesh.id,
|
|
3932
|
-
morphTargetId: resolved.morphTarget.id,
|
|
3933
|
-
value,
|
|
3934
|
-
mode: "absolute"
|
|
3935
|
-
});
|
|
3936
|
-
}
|
|
3937
|
-
}
|
|
3938
|
-
resolveMorphTargets(morph, meshNames) {
|
|
3939
|
-
const result = [];
|
|
3940
|
-
for (const meshName of meshNames) {
|
|
3941
|
-
const mesh = this.model.meshes.find((candidate) => candidate.name === meshName);
|
|
3942
|
-
if (!mesh) continue;
|
|
3943
|
-
const morphTargets = mesh.morphTargetIds.map((id) => this.model.morphTargets.find((candidate) => candidate.id === id)).filter((target2) => !!target2);
|
|
3944
|
-
const target = typeof morph === "number" ? morphTargets.find((candidate) => candidate.hostIndex === morph) : resolveMorphTargetByName(morphTargets, morph, this.profile);
|
|
3945
|
-
if (target) {
|
|
3946
|
-
result.push({ mesh, morphTarget: target });
|
|
3947
|
-
}
|
|
3948
|
-
}
|
|
3949
|
-
return result;
|
|
3950
|
-
}
|
|
3951
|
-
findBoneDescriptor(nodeKey) {
|
|
3952
|
-
const configuredName = this.profile.boneNodes[nodeKey] || nodeKey;
|
|
3953
|
-
const prefix = this.profile.bonePrefix ?? "";
|
|
3954
|
-
const suffix = this.profile.boneSuffix ?? "";
|
|
3955
|
-
const prefixedName = prefix && !configuredName.startsWith(prefix) ? `${prefix}${configuredName}` : configuredName;
|
|
3956
|
-
const fullName = suffix && !prefixedName.endsWith(suffix) ? `${prefixedName}${suffix}` : prefixedName;
|
|
3957
|
-
const candidates = /* @__PURE__ */ new Set([nodeKey, configuredName, fullName]);
|
|
3958
|
-
return this.model.bones.find((bone) => candidates.has(bone.name));
|
|
3959
|
-
}
|
|
3960
|
-
findAutoVisemeJawBinding() {
|
|
3961
|
-
const candidates = [
|
|
3962
|
-
this.profile.auToBones[103]?.find(isRotationBoneBinding2),
|
|
3963
|
-
this.profile.auToBones[26]?.find(isRotationBoneBinding2)
|
|
3964
|
-
].filter((binding) => !!binding);
|
|
3965
|
-
return candidates.find((binding) => !!this.findBoneDescriptor(binding.node)) ?? candidates[0] ?? null;
|
|
3966
|
-
}
|
|
3967
|
-
getActiveVisemeJawAmount() {
|
|
3968
|
-
const jawAmounts = getVisemeJawAmounts(this.profile) ?? [];
|
|
3969
|
-
let jawAmount = 0;
|
|
3970
|
-
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
3971
|
-
const value = clamp01(this.visemeValues[index] ?? 0);
|
|
3972
|
-
if (value <= 1e-6) continue;
|
|
3973
|
-
const jawScale = this.visemeJawScales[index] ?? 1;
|
|
3974
|
-
if (Math.abs(jawScale) <= 1e-6) continue;
|
|
3975
|
-
jawAmount = Math.max(jawAmount, (jawAmounts[index] ?? 0) * value * jawScale);
|
|
3976
|
-
}
|
|
3977
|
-
return jawAmount;
|
|
3978
|
-
}
|
|
3979
|
-
getCompositeAxisValueForNode(nodeKey, axisConfig) {
|
|
3980
|
-
return getCompositeAxisValue(axisConfig, (auId) => this.getEffectiveBoneAUValue(auId, nodeKey));
|
|
3981
|
-
}
|
|
3982
|
-
getEffectiveBoneAUValue(auId, nodeKey) {
|
|
3983
|
-
const rawValue = clamp01(this.auValues[auId] ?? 0);
|
|
3984
|
-
if (rawValue <= 1e-6) return 0;
|
|
3985
|
-
const binding = this.profile.auToBones[auId]?.find((candidate) => candidate.node === nodeKey) ?? null;
|
|
3986
|
-
if (!binding?.side) return rawValue;
|
|
3987
|
-
return rawValue * getSideScale2(this.auBalances[auId] ?? 0, binding.side);
|
|
3988
|
-
}
|
|
3989
|
-
getAUMixWeight(auId) {
|
|
3990
|
-
return this.mixWeights[auId] ?? this.profile.auMixDefaults?.[auId] ?? 1;
|
|
3991
|
-
}
|
|
3992
|
-
isMixedAU(auId) {
|
|
3993
|
-
const morphs = this.profile.auToMorphs[auId];
|
|
3994
|
-
const hasMorphs = !!(morphs?.left?.length || morphs?.right?.length || morphs?.center?.length);
|
|
3995
|
-
return !!(hasMorphs && this.profile.auToBones[auId]?.length);
|
|
3996
|
-
}
|
|
3997
|
-
};
|
|
3998
|
-
function resolveMorphTargetByName(targets, key, profile) {
|
|
3999
|
-
const prefix = profile.morphPrefix || "";
|
|
4000
|
-
const suffix = profile.morphSuffix || "";
|
|
4001
|
-
const fullName = prefix + key + suffix;
|
|
4002
|
-
const exact = targets.find((target) => target.name === fullName);
|
|
4003
|
-
if (exact) return exact;
|
|
4004
|
-
const suffixRegex = profile.suffixPattern ? new RegExp(profile.suffixPattern) : null;
|
|
4005
|
-
if (!suffixRegex) return void 0;
|
|
4006
|
-
return targets.find((target) => {
|
|
4007
|
-
if (!target.name.startsWith(fullName)) return false;
|
|
4008
|
-
const candidateSuffix = target.name.slice(fullName.length);
|
|
4009
|
-
return candidateSuffix === "" || suffixRegex.test(candidateSuffix);
|
|
4010
|
-
});
|
|
4011
|
-
}
|
|
4012
|
-
function computeSideValues(base, balance) {
|
|
4013
|
-
const b = clampBalance2(balance ?? 0);
|
|
4014
|
-
if (b === 0) return { left: base, right: base };
|
|
4015
|
-
if (b < 0) return { left: base, right: base * (1 + b) };
|
|
4016
|
-
return { left: base * (1 - b), right: base };
|
|
4017
|
-
}
|
|
4018
|
-
function getSideScale2(balance, side) {
|
|
4019
|
-
if (side !== "left" && side !== "right") return 1;
|
|
4020
|
-
const b = clampBalance2(balance);
|
|
4021
|
-
if (side === "left") return b > 0 ? 1 - b : 1;
|
|
4022
|
-
return b < 0 ? 1 + b : 1;
|
|
4023
|
-
}
|
|
4024
|
-
function addVec3(base, offset) {
|
|
4025
|
-
return {
|
|
4026
|
-
x: (base?.x ?? 0) + offset.x,
|
|
4027
|
-
y: (base?.y ?? 0) + offset.y,
|
|
4028
|
-
z: (base?.z ?? 0) + offset.z
|
|
4029
|
-
};
|
|
4030
|
-
}
|
|
4031
|
-
function upsertBoneWrite(writes, boneId2, transform) {
|
|
4032
|
-
const existingIndex = writes.findIndex((write) => write.boneId === boneId2);
|
|
4033
|
-
if (existingIndex >= 0) {
|
|
4034
|
-
const existing = writes[existingIndex];
|
|
4035
|
-
writes[existingIndex] = {
|
|
4036
|
-
...existing,
|
|
4037
|
-
transform: {
|
|
4038
|
-
...existing.transform,
|
|
4039
|
-
...transform
|
|
4040
|
-
}
|
|
4041
|
-
};
|
|
4042
|
-
return;
|
|
4043
|
-
}
|
|
4044
|
-
writes.push({
|
|
4045
|
-
boneId: boneId2,
|
|
4046
|
-
transform,
|
|
4047
|
-
mode: "absolute",
|
|
4048
|
-
space: "local"
|
|
4049
|
-
});
|
|
4050
|
-
}
|
|
4051
|
-
function quatFromChannel(channel, radians) {
|
|
4052
|
-
if (channel === "rx") return quatFromAxis({ x: 1, y: 0, z: 0 }, radians);
|
|
4053
|
-
if (channel === "ry") return quatFromAxis({ x: 0, y: 1, z: 0 }, radians);
|
|
4054
|
-
return quatFromAxis({ x: 0, y: 0, z: 1 }, radians);
|
|
4055
|
-
}
|
|
4056
|
-
function quatFromAxis(axis, radians) {
|
|
4057
|
-
const half = radians / 2;
|
|
4058
|
-
const s = Math.sin(half);
|
|
4059
|
-
return normalizeQuat({
|
|
4060
|
-
x: axis.x * s,
|
|
4061
|
-
y: axis.y * s,
|
|
4062
|
-
z: axis.z * s,
|
|
4063
|
-
w: Math.cos(half)
|
|
4064
|
-
});
|
|
4065
|
-
}
|
|
4066
|
-
function multiplyQuat(a, b) {
|
|
4067
|
-
return normalizeQuat({
|
|
4068
|
-
x: a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
|
|
4069
|
-
y: a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
|
|
4070
|
-
z: a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
|
|
4071
|
-
w: a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z
|
|
4072
|
-
});
|
|
4073
|
-
}
|
|
4074
|
-
function normalizeQuat(q) {
|
|
4075
|
-
const len = Math.hypot(q.x, q.y, q.z, q.w);
|
|
4076
|
-
if (len <= 1e-12) return identityQuat;
|
|
4077
|
-
return {
|
|
4078
|
-
x: q.x / len,
|
|
4079
|
-
y: q.y / len,
|
|
4080
|
-
z: q.z / len,
|
|
4081
|
-
w: q.w / len
|
|
4082
|
-
};
|
|
4083
|
-
}
|
|
4084
|
-
function deg2rad(degrees) {
|
|
4085
|
-
return degrees * Math.PI / 180;
|
|
4086
|
-
}
|
|
4087
|
-
function clamp01(value) {
|
|
4088
|
-
if (!Number.isFinite(value)) return 0;
|
|
4089
|
-
return value < 0 ? 0 : value > 1 ? 1 : value;
|
|
4090
|
-
}
|
|
4091
|
-
function clampSigned(value) {
|
|
4092
|
-
if (!Number.isFinite(value)) return 0;
|
|
4093
|
-
return value < -1 ? -1 : value > 1 ? 1 : value;
|
|
4094
|
-
}
|
|
4095
|
-
function clampBalance2(value) {
|
|
4096
|
-
if (!Number.isFinite(value)) return 0;
|
|
4097
|
-
return Math.max(-1, Math.min(1, value));
|
|
4098
|
-
}
|
|
4099
|
-
function morphWriteKey(meshId2, morphTargetId2) {
|
|
4100
|
-
return `${meshId2}:${morphTargetId2}`;
|
|
4101
|
-
}
|
|
4102
|
-
|
|
4103
3699
|
// src/core/contracts/abi.ts
|
|
4104
3700
|
var PACKED_MORPH_FRAME_DELTA_STRIDE = 4;
|
|
4105
3701
|
var PACKED_BONE_FRAME_DELTA_STRIDE = 9;
|
|
@@ -4233,11 +3829,13 @@ var WasmRuntimeCore = class {
|
|
|
4233
3829
|
constructor(options) {
|
|
4234
3830
|
__publicField(this, "wasm");
|
|
4235
3831
|
__publicField(this, "core");
|
|
3832
|
+
__publicField(this, "allowEmptyBindings");
|
|
4236
3833
|
__publicField(this, "profile");
|
|
4237
3834
|
__publicField(this, "model");
|
|
4238
3835
|
this.wasm = options.wasm;
|
|
4239
3836
|
this.profile = options.profile;
|
|
4240
3837
|
this.model = options.model;
|
|
3838
|
+
this.allowEmptyBindings = options.allowEmptyBindings ?? false;
|
|
4241
3839
|
const RuntimeCtor = options.wasm.RuntimeCore;
|
|
4242
3840
|
if (!RuntimeCtor) {
|
|
4243
3841
|
throw new Error("Embody Wasm module does not export RuntimeCore");
|
|
@@ -4256,6 +3854,24 @@ var WasmRuntimeCore = class {
|
|
|
4256
3854
|
setAU(id, value, balance = 0) {
|
|
4257
3855
|
this.core.set_au(id >>> 0, value, balance);
|
|
4258
3856
|
}
|
|
3857
|
+
setContinuum(negativeAU, positiveAU, value, balance = 0) {
|
|
3858
|
+
this.core.set_continuum(negativeAU >>> 0, positiveAU >>> 0, value, balance);
|
|
3859
|
+
}
|
|
3860
|
+
transitionAU(id, to, durationMs, balance = Number.NaN) {
|
|
3861
|
+
this.core.transition_au(id >>> 0, to, durationMs, balance);
|
|
3862
|
+
}
|
|
3863
|
+
transitionViseme(visemeIndex, to, durationMs, jawScale = 1) {
|
|
3864
|
+
this.core.transition_viseme(visemeIndex >>> 0, to, durationMs, jawScale);
|
|
3865
|
+
}
|
|
3866
|
+
update(deltaSeconds) {
|
|
3867
|
+
return this.core.update(deltaSeconds);
|
|
3868
|
+
}
|
|
3869
|
+
activeTransitionCount() {
|
|
3870
|
+
return this.core.active_transition_count();
|
|
3871
|
+
}
|
|
3872
|
+
clearTransitions() {
|
|
3873
|
+
this.core.clear_transitions();
|
|
3874
|
+
}
|
|
4259
3875
|
getAU(id) {
|
|
4260
3876
|
return this.core.get_au(id >>> 0);
|
|
4261
3877
|
}
|
|
@@ -4291,7 +3907,13 @@ var WasmRuntimeCore = class {
|
|
|
4291
3907
|
};
|
|
4292
3908
|
}
|
|
4293
3909
|
reloadBindings() {
|
|
4294
|
-
|
|
3910
|
+
const profileJson = JSON.stringify(this.profile);
|
|
3911
|
+
const modelJson = JSON.stringify(this.model);
|
|
3912
|
+
if (this.allowEmptyBindings) {
|
|
3913
|
+
this.core.configure(profileJson, modelJson);
|
|
3914
|
+
} else {
|
|
3915
|
+
this.core.configure_with_profile(profileJson, modelJson);
|
|
3916
|
+
}
|
|
4295
3917
|
}
|
|
4296
3918
|
};
|
|
4297
3919
|
function unpackBoneFrameDelta(values) {
|
|
@@ -5649,7 +5271,7 @@ var CC4_PRESET = {
|
|
|
5649
5271
|
};
|
|
5650
5272
|
|
|
5651
5273
|
// src/engines/three/hair/HairPhysicsController.ts
|
|
5652
|
-
var
|
|
5274
|
+
var clamp01 = (value) => value < 0 ? 0 : value > 1 ? 1 : value;
|
|
5653
5275
|
var HairPhysicsController = class {
|
|
5654
5276
|
constructor(host) {
|
|
5655
5277
|
__publicField(this, "host");
|
|
@@ -6147,7 +5769,7 @@ var HairPhysicsController = class {
|
|
|
6147
5769
|
}
|
|
6148
5770
|
}
|
|
6149
5771
|
setMorphOnMeshes(meshNames, morphKey, value) {
|
|
6150
|
-
const val =
|
|
5772
|
+
const val = clamp01(value);
|
|
6151
5773
|
for (const name of meshNames) {
|
|
6152
5774
|
const mesh = this.registeredHairObjects.get(name) || this.host.getMeshByName(name);
|
|
6153
5775
|
if (!mesh) continue;
|
|
@@ -6391,9 +6013,9 @@ var HairPhysicsController = class {
|
|
|
6391
6013
|
const deltaVertical = vertical - this.lastHeadVertical;
|
|
6392
6014
|
this.lastHeadHorizontal = horizontal;
|
|
6393
6015
|
this.lastHeadVertical = vertical;
|
|
6394
|
-
const leftWeight =
|
|
6395
|
-
const rightWeight =
|
|
6396
|
-
const frontWeight =
|
|
6016
|
+
const leftWeight = clamp01(deltaHorizontal > 0 ? deltaHorizontal : 0);
|
|
6017
|
+
const rightWeight = clamp01(deltaHorizontal < 0 ? -deltaHorizontal : 0);
|
|
6018
|
+
const frontWeight = clamp01(deltaVertical > 0 ? deltaVertical : 0);
|
|
6397
6019
|
const minTrigger = 0.01;
|
|
6398
6020
|
if (leftWeight <= minTrigger && rightWeight <= minTrigger && frontWeight <= minTrigger) return;
|
|
6399
6021
|
if (this.impulseClipDirty) {
|
|
@@ -7363,7 +6985,7 @@ async function getPresetWithProfile(presetType, profile) {
|
|
|
7363
6985
|
var resolvePresetWithOverrides = getPresetWithProfile;
|
|
7364
6986
|
|
|
7365
6987
|
// src/engines/three/Embody.ts
|
|
7366
|
-
var
|
|
6988
|
+
var deg2rad = (d) => d * Math.PI / 180;
|
|
7367
6989
|
var X_AXIS2 = new THREE.Vector3(1, 0, 0);
|
|
7368
6990
|
var Y_AXIS2 = new THREE.Vector3(0, 1, 0);
|
|
7369
6991
|
var Z_AXIS2 = new THREE.Vector3(0, 0, 1);
|
|
@@ -7386,9 +7008,18 @@ function buildAUToCompositeMap(composites) {
|
|
|
7386
7008
|
});
|
|
7387
7009
|
return map;
|
|
7388
7010
|
}
|
|
7389
|
-
function
|
|
7011
|
+
function clamp012(x) {
|
|
7390
7012
|
return x < 0 ? 0 : x > 1 ? 1 : x;
|
|
7391
7013
|
}
|
|
7014
|
+
var RESOLVED_TRANSITION_HANDLE = {
|
|
7015
|
+
promise: Promise.resolve(),
|
|
7016
|
+
pause: () => {
|
|
7017
|
+
},
|
|
7018
|
+
resume: () => {
|
|
7019
|
+
},
|
|
7020
|
+
cancel: () => {
|
|
7021
|
+
}
|
|
7022
|
+
};
|
|
7392
7023
|
var _Embody = class _Embody {
|
|
7393
7024
|
constructor(config = {}, animation) {
|
|
7394
7025
|
// Optional hook for animation schedulers.
|
|
@@ -7432,7 +7063,6 @@ var _Embody = class _Embody {
|
|
|
7432
7063
|
__publicField(this, "modelInspector", new ThreeModelInspector());
|
|
7433
7064
|
__publicField(this, "frameApplier", new ThreeFrameApplier());
|
|
7434
7065
|
__publicField(this, "modelDescriptor", null);
|
|
7435
|
-
__publicField(this, "tsRuntimeCore", null);
|
|
7436
7066
|
__publicField(this, "wasmRuntimeCore", null);
|
|
7437
7067
|
__publicField(this, "framePathReady", false);
|
|
7438
7068
|
// Internal animation loop
|
|
@@ -7545,48 +7175,21 @@ var _Embody = class _Embody {
|
|
|
7545
7175
|
bindHostNeutralRuntime(inspection) {
|
|
7546
7176
|
this.modelDescriptor = inspection.descriptor;
|
|
7547
7177
|
this.frameApplier.setBindings(buildFrameApplierBindings(inspection));
|
|
7548
|
-
|
|
7178
|
+
const wasm$1 = wasm.requireInitializedEmbodyCore();
|
|
7179
|
+
this.attachWasmCore(wasm$1);
|
|
7180
|
+
this.wasmRuntimeCore = new WasmRuntimeCore({
|
|
7549
7181
|
profile: this.config,
|
|
7550
|
-
model: inspection.descriptor
|
|
7182
|
+
model: inspection.descriptor,
|
|
7183
|
+
wasm: wasm$1,
|
|
7184
|
+
allowEmptyBindings: true
|
|
7551
7185
|
});
|
|
7552
7186
|
this.syncRuntimeCoreState();
|
|
7553
7187
|
this.framePathReady = true;
|
|
7554
|
-
void wasm.initEmbodyCore().then((wasm) => {
|
|
7555
|
-
if (!this.modelDescriptor) return;
|
|
7556
|
-
this.attachWasmCore(wasm);
|
|
7557
|
-
this.wasmRuntimeCore = new WasmRuntimeCore({
|
|
7558
|
-
profile: this.config,
|
|
7559
|
-
model: this.modelDescriptor,
|
|
7560
|
-
wasm
|
|
7561
|
-
});
|
|
7562
|
-
this.syncRuntimeCoreState();
|
|
7563
|
-
}).catch(() => {
|
|
7564
|
-
this.wasmRuntimeCore = null;
|
|
7565
|
-
});
|
|
7566
7188
|
}
|
|
7567
7189
|
attachWasmCore(core) {
|
|
7568
7190
|
this.hairPhysics.setCore(core);
|
|
7569
7191
|
}
|
|
7570
7192
|
syncRuntimeCoreState() {
|
|
7571
|
-
if (this.tsRuntimeCore) {
|
|
7572
|
-
this.tsRuntimeCore.setProfile(this.config);
|
|
7573
|
-
if (this.modelDescriptor) {
|
|
7574
|
-
this.tsRuntimeCore.setModelDescriptor(this.modelDescriptor);
|
|
7575
|
-
}
|
|
7576
|
-
for (const [auIdText, value] of Object.entries(this.auValues)) {
|
|
7577
|
-
const auId = Number(auIdText);
|
|
7578
|
-
if (Number.isNaN(auId)) continue;
|
|
7579
|
-
this.tsRuntimeCore.setAU(auId, value, this.auBalances[auId]);
|
|
7580
|
-
}
|
|
7581
|
-
for (const [auIdText, weight] of Object.entries(this.mixWeights)) {
|
|
7582
|
-
const auId = Number(auIdText);
|
|
7583
|
-
if (Number.isNaN(auId)) continue;
|
|
7584
|
-
this.tsRuntimeCore.setAUMixWeight(auId, weight);
|
|
7585
|
-
}
|
|
7586
|
-
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
7587
|
-
this.tsRuntimeCore.setViseme(index, this.visemeValues[index] ?? 0, this.visemeJawScales[index] ?? 1);
|
|
7588
|
-
}
|
|
7589
|
-
}
|
|
7590
7193
|
if (this.wasmRuntimeCore) {
|
|
7591
7194
|
this.wasmRuntimeCore.setProfile(this.config);
|
|
7592
7195
|
if (this.modelDescriptor) {
|
|
@@ -7604,7 +7207,7 @@ var _Embody = class _Embody {
|
|
|
7604
7207
|
this.wasmRuntimeCore.setAUMixWeight(auId, weight);
|
|
7605
7208
|
}
|
|
7606
7209
|
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
7607
|
-
this.wasmRuntimeCore.setViseme(index, this.visemeValues[index] ?? 0);
|
|
7210
|
+
this.wasmRuntimeCore.setViseme(index, this.visemeValues[index] ?? 0, this.visemeJawScales[index] ?? 1);
|
|
7608
7211
|
}
|
|
7609
7212
|
}
|
|
7610
7213
|
}
|
|
@@ -7622,25 +7225,13 @@ var _Embody = class _Embody {
|
|
|
7622
7225
|
});
|
|
7623
7226
|
this.modelDescriptor = inspection.descriptor;
|
|
7624
7227
|
this.frameApplier.setBindings(buildFrameApplierBindings(inspection));
|
|
7625
|
-
this.tsRuntimeCore?.setModelDescriptor(inspection.descriptor);
|
|
7626
7228
|
this.wasmRuntimeCore?.setModelDescriptor(inspection.descriptor);
|
|
7627
7229
|
}
|
|
7628
|
-
|
|
7629
|
-
if (!this.framePathReady || !this.model) return false;
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
);
|
|
7634
|
-
return true;
|
|
7635
|
-
}
|
|
7636
|
-
if (this.tsRuntimeCore) {
|
|
7637
|
-
const frame = this.tsRuntimeCore.evaluateFrameDelta();
|
|
7638
|
-
this.frameApplier.applyFrameDelta(this.model, {
|
|
7639
|
-
morphTargets: frame.morphTargets
|
|
7640
|
-
});
|
|
7641
|
-
return true;
|
|
7642
|
-
}
|
|
7643
|
-
return false;
|
|
7230
|
+
applyLiveFrameDelta() {
|
|
7231
|
+
if (!this.framePathReady || !this.model || !this.wasmRuntimeCore) return false;
|
|
7232
|
+
this.frameApplier.applyFrameDelta(this.model, this.wasmRuntimeCore.evaluateFrameDelta());
|
|
7233
|
+
this.pendingCompositeNodes.clear();
|
|
7234
|
+
return true;
|
|
7644
7235
|
}
|
|
7645
7236
|
rebuildMorphTargetsCache() {
|
|
7646
7237
|
this.morphKeyCache.clear();
|
|
@@ -7742,6 +7333,11 @@ var _Embody = class _Embody {
|
|
|
7742
7333
|
const dtSeconds = Math.max(0, deltaSeconds || 0);
|
|
7743
7334
|
if (dtSeconds <= 0 || this.isPaused) return;
|
|
7744
7335
|
this.animation.tick(dtSeconds);
|
|
7336
|
+
const wasmTransitionCount = this.wasmRuntimeCore?.activeTransitionCount() ?? 0;
|
|
7337
|
+
const remainingWasmTransitions = this.wasmRuntimeCore?.update(dtSeconds) ?? 0;
|
|
7338
|
+
if (wasmTransitionCount > 0 || remainingWasmTransitions > 0) {
|
|
7339
|
+
this.applyLiveFrameDelta();
|
|
7340
|
+
}
|
|
7745
7341
|
this.flushPendingComposites();
|
|
7746
7342
|
this.animationController.update(dtSeconds);
|
|
7747
7343
|
this.hairPhysics.update(dtSeconds);
|
|
@@ -7776,7 +7372,6 @@ var _Embody = class _Embody {
|
|
|
7776
7372
|
this.model = null;
|
|
7777
7373
|
this.bones = {};
|
|
7778
7374
|
this.modelDescriptor = null;
|
|
7779
|
-
this.tsRuntimeCore = null;
|
|
7780
7375
|
this.wasmRuntimeCore = null;
|
|
7781
7376
|
this.framePathReady = false;
|
|
7782
7377
|
}
|
|
@@ -7813,15 +7408,14 @@ var _Embody = class _Embody {
|
|
|
7813
7408
|
if (balance !== void 0) {
|
|
7814
7409
|
this.auBalances[id] = balance;
|
|
7815
7410
|
}
|
|
7816
|
-
this.tsRuntimeCore?.setAU(id, v, balance);
|
|
7817
7411
|
this.wasmRuntimeCore?.setAU(id, v, balance ?? this.auBalances[id] ?? 0);
|
|
7818
|
-
const appliedViaFrame = this.
|
|
7412
|
+
const appliedViaFrame = this.applyLiveFrameDelta();
|
|
7819
7413
|
if (!appliedViaFrame) {
|
|
7820
7414
|
const resolvedMorphTargets = this.resolvedAUMorphTargets.get(id);
|
|
7821
7415
|
const { left: leftKeys, right: rightKeys, center: centerKeys } = this.getAUMorphsBySide(id);
|
|
7822
7416
|
if (resolvedMorphTargets) {
|
|
7823
7417
|
const mixWeight = this.isMixedAU(id) ? this.getAUMixWeight(id) : 1;
|
|
7824
|
-
const base =
|
|
7418
|
+
const base = clamp012(v) * mixWeight;
|
|
7825
7419
|
const { left: leftVal, right: rightVal } = this.computeSideValues(base, balance);
|
|
7826
7420
|
if (resolvedMorphTargets.left.length || resolvedMorphTargets.right.length) {
|
|
7827
7421
|
this.applyMorphTargets(resolvedMorphTargets.left, leftVal);
|
|
@@ -7830,7 +7424,7 @@ var _Embody = class _Embody {
|
|
|
7830
7424
|
this.applyMorphTargets(resolvedMorphTargets.center, base);
|
|
7831
7425
|
} else if (leftKeys.length || rightKeys.length || centerKeys.length) {
|
|
7832
7426
|
const mixWeight = this.isMixedAU(id) ? this.getAUMixWeight(id) : 1;
|
|
7833
|
-
const base =
|
|
7427
|
+
const base = clamp012(v) * mixWeight;
|
|
7834
7428
|
const meshNames = this.getMeshNamesForAU(id);
|
|
7835
7429
|
const { left: leftVal, right: rightVal } = this.computeSideValues(base, balance);
|
|
7836
7430
|
if (leftKeys.length || rightKeys.length) {
|
|
@@ -7849,6 +7443,7 @@ var _Embody = class _Embody {
|
|
|
7849
7443
|
}
|
|
7850
7444
|
}
|
|
7851
7445
|
}
|
|
7446
|
+
if (appliedViaFrame) return;
|
|
7852
7447
|
const compositeInfo = this.auToCompositeMap.get(id);
|
|
7853
7448
|
if (compositeInfo) {
|
|
7854
7449
|
for (const nodeKey of compositeInfo.nodes) {
|
|
@@ -7883,7 +7478,7 @@ var _Embody = class _Embody {
|
|
|
7883
7478
|
return this.transitionContinuum(negAU, posAU, continuumValue, durationMs, balance);
|
|
7884
7479
|
}
|
|
7885
7480
|
}
|
|
7886
|
-
const target =
|
|
7481
|
+
const target = clamp012(to);
|
|
7887
7482
|
if (balance !== void 0) {
|
|
7888
7483
|
this.auBalances[numId] = balance;
|
|
7889
7484
|
}
|
|
@@ -7894,6 +7489,19 @@ var _Embody = class _Embody {
|
|
|
7894
7489
|
const base = target * mixWeight;
|
|
7895
7490
|
const { left: leftVal, right: rightVal } = this.computeSideValues(base, storedBalance);
|
|
7896
7491
|
this.auValues[numId] = target;
|
|
7492
|
+
if (this.wasmRuntimeCore) {
|
|
7493
|
+
this.wasmRuntimeCore.transitionAU(
|
|
7494
|
+
numId,
|
|
7495
|
+
target,
|
|
7496
|
+
durationMs,
|
|
7497
|
+
balance ?? this.auBalances[numId] ?? Number.NaN
|
|
7498
|
+
);
|
|
7499
|
+
this.update(0);
|
|
7500
|
+
if (durationMs <= 0) {
|
|
7501
|
+
this.applyLiveFrameDelta();
|
|
7502
|
+
}
|
|
7503
|
+
return RESOLVED_TRANSITION_HANDLE;
|
|
7504
|
+
}
|
|
7897
7505
|
const handles = [];
|
|
7898
7506
|
const meshNames = this.getMeshNamesForAU(numId);
|
|
7899
7507
|
if (leftKeys.length || rightKeys.length) {
|
|
@@ -7956,6 +7564,17 @@ var _Embody = class _Embody {
|
|
|
7956
7564
|
*/
|
|
7957
7565
|
setContinuum(negAU, posAU, continuumValue, balance) {
|
|
7958
7566
|
const value = Math.max(-1, Math.min(1, continuumValue));
|
|
7567
|
+
this.auValues[negAU] = value < 0 ? Math.abs(value) : 0;
|
|
7568
|
+
this.auValues[posAU] = value > 0 ? value : 0;
|
|
7569
|
+
if (balance !== void 0) {
|
|
7570
|
+
this.auBalances[negAU] = balance;
|
|
7571
|
+
this.auBalances[posAU] = balance;
|
|
7572
|
+
}
|
|
7573
|
+
if (this.wasmRuntimeCore) {
|
|
7574
|
+
this.wasmRuntimeCore.setContinuum(negAU, posAU, value, balance ?? 0);
|
|
7575
|
+
this.applyLiveFrameDelta();
|
|
7576
|
+
return;
|
|
7577
|
+
}
|
|
7959
7578
|
if (value < 0) {
|
|
7960
7579
|
this.setAU(posAU, 0, balance);
|
|
7961
7580
|
this.setAU(negAU, Math.abs(value), balance);
|
|
@@ -7981,10 +7600,32 @@ var _Embody = class _Embody {
|
|
|
7981
7600
|
*/
|
|
7982
7601
|
transitionContinuum(negAU, posAU, continuumValue, durationMs = 200, balance) {
|
|
7983
7602
|
const target = Math.max(-1, Math.min(1, continuumValue));
|
|
7984
|
-
const driverKey = `continuum_${negAU}_${posAU}`;
|
|
7985
7603
|
const currentNeg = this.auValues[negAU] ?? 0;
|
|
7986
7604
|
const currentPos = this.auValues[posAU] ?? 0;
|
|
7987
7605
|
const currentContinuum = currentPos - currentNeg;
|
|
7606
|
+
this.auValues[negAU] = target < 0 ? Math.abs(target) : 0;
|
|
7607
|
+
this.auValues[posAU] = target > 0 ? target : 0;
|
|
7608
|
+
if (balance !== void 0) {
|
|
7609
|
+
this.auBalances[negAU] = balance;
|
|
7610
|
+
this.auBalances[posAU] = balance;
|
|
7611
|
+
}
|
|
7612
|
+
if (this.wasmRuntimeCore) {
|
|
7613
|
+
if (target < 0) {
|
|
7614
|
+
this.wasmRuntimeCore.transitionAU(posAU, 0, durationMs, balance ?? this.auBalances[posAU] ?? Number.NaN);
|
|
7615
|
+
this.wasmRuntimeCore.transitionAU(negAU, Math.abs(target), durationMs, balance ?? this.auBalances[negAU] ?? Number.NaN);
|
|
7616
|
+
} else if (target > 0) {
|
|
7617
|
+
this.wasmRuntimeCore.transitionAU(negAU, 0, durationMs, balance ?? this.auBalances[negAU] ?? Number.NaN);
|
|
7618
|
+
this.wasmRuntimeCore.transitionAU(posAU, target, durationMs, balance ?? this.auBalances[posAU] ?? Number.NaN);
|
|
7619
|
+
} else {
|
|
7620
|
+
this.wasmRuntimeCore.transitionAU(negAU, 0, durationMs, balance ?? this.auBalances[negAU] ?? Number.NaN);
|
|
7621
|
+
this.wasmRuntimeCore.transitionAU(posAU, 0, durationMs, balance ?? this.auBalances[posAU] ?? Number.NaN);
|
|
7622
|
+
}
|
|
7623
|
+
if (durationMs <= 0) {
|
|
7624
|
+
this.applyLiveFrameDelta();
|
|
7625
|
+
}
|
|
7626
|
+
return RESOLVED_TRANSITION_HANDLE;
|
|
7627
|
+
}
|
|
7628
|
+
const driverKey = `continuum_${negAU}_${posAU}`;
|
|
7988
7629
|
return this.animation.addTransition(driverKey, currentContinuum, target, durationMs, (value) => this.setContinuum(negAU, posAU, value, balance));
|
|
7989
7630
|
}
|
|
7990
7631
|
// ============================================================================
|
|
@@ -8066,7 +7707,7 @@ var _Embody = class _Embody {
|
|
|
8066
7707
|
this.hairPhysics.refreshMeshSelection();
|
|
8067
7708
|
}
|
|
8068
7709
|
setMorph(key, v, meshNamesOrTargets) {
|
|
8069
|
-
const val =
|
|
7710
|
+
const val = clamp012(v);
|
|
8070
7711
|
if (Array.isArray(meshNamesOrTargets) && meshNamesOrTargets.length > 0 && typeof meshNamesOrTargets[0] === "object" && "infl" in meshNamesOrTargets[0]) {
|
|
8071
7712
|
const targets2 = meshNamesOrTargets;
|
|
8072
7713
|
this.applyMorphTargets(targets2, val);
|
|
@@ -8078,7 +7719,7 @@ var _Embody = class _Embody {
|
|
|
8078
7719
|
this.applyMorphTargets(targets, val);
|
|
8079
7720
|
}
|
|
8080
7721
|
setMorphInfluence(index, v, meshNames) {
|
|
8081
|
-
const val =
|
|
7722
|
+
const val = clamp012(v);
|
|
8082
7723
|
const targets = this.resolveMorphTargetsByIndex(index, meshNames);
|
|
8083
7724
|
if (targets.length === 0) return;
|
|
8084
7725
|
this.applyMorphTargets(targets, val);
|
|
@@ -8153,21 +7794,21 @@ var _Embody = class _Embody {
|
|
|
8153
7794
|
}
|
|
8154
7795
|
transitionMorph(key, to, durationMs = 120, meshNames) {
|
|
8155
7796
|
const transitionKey = meshNames?.length ? `morph_${this.getMorphKeyCacheKey(key, meshNames)}` : `morph_${this.getMorphKeyCacheKey(key)}`;
|
|
8156
|
-
const target =
|
|
7797
|
+
const target = clamp012(to);
|
|
8157
7798
|
const targets = this.resolveMorphTargets(key, meshNames);
|
|
8158
7799
|
const from = targets.length > 0 ? targets[0].infl[targets[0].idx] ?? 0 : this.getMorphValue(key);
|
|
8159
7800
|
return this.animation.addTransition(transitionKey, from, target, durationMs, (value) => {
|
|
8160
|
-
const val =
|
|
7801
|
+
const val = clamp012(value);
|
|
8161
7802
|
this.applyMorphTargets(targets, val);
|
|
8162
7803
|
});
|
|
8163
7804
|
}
|
|
8164
7805
|
transitionMorphInfluence(index, to, durationMs = 120, meshNames) {
|
|
8165
7806
|
const transitionKey = meshNames?.length ? `morph_${this.getMorphIndexCacheKey(index, meshNames)}` : `morph_${this.getMorphIndexCacheKey(index)}`;
|
|
8166
|
-
const target =
|
|
7807
|
+
const target = clamp012(to);
|
|
8167
7808
|
const targets = this.resolveMorphTargetsByIndex(index, meshNames);
|
|
8168
7809
|
const from = targets.length > 0 ? targets[0].infl[targets[0].idx] ?? 0 : this.getMorphValueByIndex(index);
|
|
8169
7810
|
return this.animation.addTransition(transitionKey, from, target, durationMs, (value) => {
|
|
8170
|
-
const val =
|
|
7811
|
+
const val = clamp012(value);
|
|
8171
7812
|
this.applyMorphTargets(targets, val);
|
|
8172
7813
|
});
|
|
8173
7814
|
}
|
|
@@ -8176,7 +7817,7 @@ var _Embody = class _Embody {
|
|
|
8176
7817
|
// ============================================================================
|
|
8177
7818
|
setViseme(visemeIndex, value, jawScale = 1) {
|
|
8178
7819
|
if (visemeIndex < 0 || visemeIndex >= this.visemeValues.length) return;
|
|
8179
|
-
const val =
|
|
7820
|
+
const val = clamp012(value);
|
|
8180
7821
|
this.visemeValues[visemeIndex] = val;
|
|
8181
7822
|
this.visemeJawScales[visemeIndex] = jawScale;
|
|
8182
7823
|
this.applyVisemeRuntimeState();
|
|
@@ -8188,16 +7829,24 @@ var _Embody = class _Embody {
|
|
|
8188
7829
|
}, cancel: () => {
|
|
8189
7830
|
} };
|
|
8190
7831
|
}
|
|
8191
|
-
const target =
|
|
7832
|
+
const target = clamp012(to);
|
|
8192
7833
|
const from = this.visemeValues[visemeIndex] ?? 0;
|
|
8193
7834
|
this.visemeJawScales[visemeIndex] = jawScale;
|
|
7835
|
+
if (this.wasmRuntimeCore) {
|
|
7836
|
+
this.visemeValues[visemeIndex] = target;
|
|
7837
|
+
this.wasmRuntimeCore.transitionViseme(visemeIndex, target, durationMs, jawScale);
|
|
7838
|
+
if (durationMs <= 0) {
|
|
7839
|
+
this.applyLiveFrameDelta();
|
|
7840
|
+
}
|
|
7841
|
+
return RESOLVED_TRANSITION_HANDLE;
|
|
7842
|
+
}
|
|
8194
7843
|
return this.animation.addTransition(
|
|
8195
7844
|
`viseme_value_${visemeIndex}`,
|
|
8196
7845
|
from,
|
|
8197
7846
|
target,
|
|
8198
7847
|
durationMs,
|
|
8199
7848
|
(value) => {
|
|
8200
|
-
this.visemeValues[visemeIndex] =
|
|
7849
|
+
this.visemeValues[visemeIndex] = clamp012(value);
|
|
8201
7850
|
this.visemeJawScales[visemeIndex] = jawScale;
|
|
8202
7851
|
this.applyVisemeRuntimeState();
|
|
8203
7852
|
}
|
|
@@ -8222,8 +7871,7 @@ var _Embody = class _Embody {
|
|
|
8222
7871
|
// MIX WEIGHT CONTROL
|
|
8223
7872
|
// ============================================================================
|
|
8224
7873
|
setAUMixWeight(id, weight) {
|
|
8225
|
-
this.mixWeights[id] =
|
|
8226
|
-
this.tsRuntimeCore?.setAUMixWeight(id, weight);
|
|
7874
|
+
this.mixWeights[id] = clamp012(weight);
|
|
8227
7875
|
this.wasmRuntimeCore?.setAUMixWeight(id, weight);
|
|
8228
7876
|
const v = this.auValues[id] ?? 0;
|
|
8229
7877
|
if (v > 0) this.setAU(id, v);
|
|
@@ -8261,9 +7909,10 @@ var _Embody = class _Embody {
|
|
|
8261
7909
|
}
|
|
8262
7910
|
clearTransitions() {
|
|
8263
7911
|
this.animation.clearTransitions();
|
|
7912
|
+
this.wasmRuntimeCore?.clearTransitions();
|
|
8264
7913
|
}
|
|
8265
7914
|
getActiveTransitionCount() {
|
|
8266
|
-
return this.animation.getActiveTransitionCount();
|
|
7915
|
+
return this.animation.getActiveTransitionCount() + (this.wasmRuntimeCore?.activeTransitionCount() ?? 0);
|
|
8267
7916
|
}
|
|
8268
7917
|
resetToNeutral() {
|
|
8269
7918
|
this.auValues = {};
|
|
@@ -8273,6 +7922,7 @@ var _Embody = class _Embody {
|
|
|
8273
7922
|
this.translations = {};
|
|
8274
7923
|
this.initBoneRotations();
|
|
8275
7924
|
this.clearTransitions();
|
|
7925
|
+
this.wasmRuntimeCore?.clear();
|
|
8276
7926
|
const morphTargetsToReset = [];
|
|
8277
7927
|
for (const m of this.meshes) {
|
|
8278
7928
|
const infl = m.morphTargetInfluences;
|
|
@@ -8451,7 +8101,18 @@ var _Embody = class _Embody {
|
|
|
8451
8101
|
this.bones = this.resolveBones(this.model);
|
|
8452
8102
|
this.missingBoneWarnings.clear();
|
|
8453
8103
|
this.rebuildMorphTargetsCache();
|
|
8454
|
-
|
|
8104
|
+
Object.values(this.bones).forEach((entry) => {
|
|
8105
|
+
if (!entry) return;
|
|
8106
|
+
this.frameApplier.applyObjectTransform(entry.obj, {
|
|
8107
|
+
position: { x: entry.basePos.x, y: entry.basePos.y, z: entry.basePos.z },
|
|
8108
|
+
rotation: {
|
|
8109
|
+
x: entry.baseQuat.x,
|
|
8110
|
+
y: entry.baseQuat.y,
|
|
8111
|
+
z: entry.baseQuat.z,
|
|
8112
|
+
w: entry.baseQuat.w
|
|
8113
|
+
}
|
|
8114
|
+
});
|
|
8115
|
+
});
|
|
8455
8116
|
this.wasmRuntimeCore?.setProfile(this.config);
|
|
8456
8117
|
this.refreshHostNeutralModelDescriptor();
|
|
8457
8118
|
}
|
|
@@ -8568,20 +8229,20 @@ var _Embody = class _Embody {
|
|
|
8568
8229
|
}
|
|
8569
8230
|
applyVisemeRuntimeState() {
|
|
8570
8231
|
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
8571
|
-
this.
|
|
8572
|
-
this.wasmRuntimeCore?.setViseme(index, this.visemeValues[index] ?? 0);
|
|
8232
|
+
this.wasmRuntimeCore?.setViseme(index, this.visemeValues[index] ?? 0, this.visemeJawScales[index] ?? 1);
|
|
8573
8233
|
}
|
|
8574
|
-
|
|
8234
|
+
const appliedViaFrame = this.applyLiveFrameDelta();
|
|
8235
|
+
if (!appliedViaFrame) {
|
|
8575
8236
|
for (const targets of this.resolvedVisemeTargets) {
|
|
8576
8237
|
this.frameApplier.resetMorphTargets(targets || []);
|
|
8577
8238
|
}
|
|
8578
8239
|
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
8579
|
-
const value =
|
|
8240
|
+
const value = clamp012(this.visemeValues[index] ?? 0);
|
|
8580
8241
|
if (value <= 1e-6) continue;
|
|
8581
8242
|
const targets = this.resolvedVisemeTargets[index] || [];
|
|
8582
8243
|
for (const target of targets) {
|
|
8583
8244
|
if (target.idx >= target.infl.length) continue;
|
|
8584
|
-
const weighted =
|
|
8245
|
+
const weighted = clamp012(value * target.weight);
|
|
8585
8246
|
this.frameApplier.applyMorphTargets(
|
|
8586
8247
|
[target],
|
|
8587
8248
|
Math.max(target.infl[target.idx] ?? 0, weighted)
|
|
@@ -8589,7 +8250,9 @@ var _Embody = class _Embody {
|
|
|
8589
8250
|
}
|
|
8590
8251
|
}
|
|
8591
8252
|
}
|
|
8592
|
-
|
|
8253
|
+
if (!appliedViaFrame) {
|
|
8254
|
+
this.updateBoneRotation(this.getJawBoneNodeKey(), "pitch", this.getActiveVisemeJawAmount());
|
|
8255
|
+
}
|
|
8593
8256
|
}
|
|
8594
8257
|
getJawBoneNodeKey() {
|
|
8595
8258
|
const candidates = [
|
|
@@ -8611,7 +8274,7 @@ var _Embody = class _Embody {
|
|
|
8611
8274
|
getActiveVisemeJawAmount() {
|
|
8612
8275
|
let jawAmount = 0;
|
|
8613
8276
|
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
8614
|
-
const value =
|
|
8277
|
+
const value = clamp012(this.visemeValues[index] ?? 0);
|
|
8615
8278
|
if (value <= 1e-6) continue;
|
|
8616
8279
|
const jawScale = this.visemeJawScales[index] ?? 1;
|
|
8617
8280
|
if (Math.abs(jawScale) <= 1e-6) continue;
|
|
@@ -8894,7 +8557,7 @@ var _Embody = class _Embody {
|
|
|
8894
8557
|
return !!(hasMorphs && this.config.auToBones[id]?.length);
|
|
8895
8558
|
}
|
|
8896
8559
|
getEffectiveBoneAUValue(auId, nodeKey) {
|
|
8897
|
-
const rawValue =
|
|
8560
|
+
const rawValue = clamp012(this.auValues[auId] ?? 0);
|
|
8898
8561
|
if (rawValue <= 1e-6) return 0;
|
|
8899
8562
|
const binding = this.config.auToBones[auId]?.find((candidate) => candidate.node === nodeKey) ?? null;
|
|
8900
8563
|
if (!binding?.side) return rawValue;
|
|
@@ -8994,7 +8657,7 @@ var _Embody = class _Embody {
|
|
|
8994
8657
|
if (config.yaw && rotState.yaw !== 0) {
|
|
8995
8658
|
const binding = this.getCompositeAxisBindingForNode(nodeKey, config.yaw, rotState.yaw);
|
|
8996
8659
|
if (binding?.maxDegrees && binding.channel) {
|
|
8997
|
-
const radians =
|
|
8660
|
+
const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.yaw) * binding.scale;
|
|
8998
8661
|
const axis = getAxis(binding.channel);
|
|
8999
8662
|
const deltaQ = new THREE.Quaternion().setFromAxisAngle(axis, radians);
|
|
9000
8663
|
compositeQ.multiply(deltaQ);
|
|
@@ -9003,7 +8666,7 @@ var _Embody = class _Embody {
|
|
|
9003
8666
|
if (config.pitch && rotState.pitch !== 0) {
|
|
9004
8667
|
const binding = this.getCompositeAxisBindingForNode(nodeKey, config.pitch, rotState.pitch);
|
|
9005
8668
|
if (binding?.maxDegrees && binding.channel) {
|
|
9006
|
-
const radians =
|
|
8669
|
+
const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.pitch) * binding.scale;
|
|
9007
8670
|
const axis = getAxis(binding.channel);
|
|
9008
8671
|
const deltaQ = new THREE.Quaternion().setFromAxisAngle(axis, radians);
|
|
9009
8672
|
compositeQ.multiply(deltaQ);
|
|
@@ -9012,7 +8675,7 @@ var _Embody = class _Embody {
|
|
|
9012
8675
|
if (config.roll && rotState.roll !== 0) {
|
|
9013
8676
|
const binding = this.getCompositeAxisBindingForNode(nodeKey, config.roll, rotState.roll);
|
|
9014
8677
|
if (binding?.maxDegrees && binding.channel) {
|
|
9015
|
-
const radians =
|
|
8678
|
+
const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.roll) * binding.scale;
|
|
9016
8679
|
const axis = getAxis(binding.channel);
|
|
9017
8680
|
const deltaQ = new THREE.Quaternion().setFromAxisAngle(axis, radians);
|
|
9018
8681
|
compositeQ.multiply(deltaQ);
|
|
@@ -9851,11 +9514,11 @@ function applyCharacterModelTransform(model, transform = {}) {
|
|
|
9851
9514
|
model.position.set(modelOffset.x ?? 0, modelOffset.y ?? 0, modelOffset.z ?? 0);
|
|
9852
9515
|
}
|
|
9853
9516
|
if (modelRotation) {
|
|
9854
|
-
const
|
|
9517
|
+
const deg2rad2 = Math.PI / 180;
|
|
9855
9518
|
model.rotation.set(
|
|
9856
|
-
(modelRotation.x ?? 0) *
|
|
9857
|
-
(modelRotation.y ?? 0) *
|
|
9858
|
-
(modelRotation.z ?? 0) *
|
|
9519
|
+
(modelRotation.x ?? 0) * deg2rad2,
|
|
9520
|
+
(modelRotation.y ?? 0) * deg2rad2,
|
|
9521
|
+
(modelRotation.z ?? 0) * deg2rad2
|
|
9859
9522
|
);
|
|
9860
9523
|
}
|
|
9861
9524
|
if (modelScale !== void 0 && Number.isFinite(modelScale) && modelScale > 0) {
|
|
@@ -14871,7 +14534,7 @@ function computeHumanoidSkeletonTemplateRestBounds(template) {
|
|
|
14871
14534
|
}
|
|
14872
14535
|
const parentPosition = worldPositions.get(bone.parent);
|
|
14873
14536
|
if (!parentPosition) continue;
|
|
14874
|
-
worldPositions.set(bone.name,
|
|
14537
|
+
worldPositions.set(bone.name, addVec3(parentPosition, bone.translation));
|
|
14875
14538
|
unresolved.delete(bone.name);
|
|
14876
14539
|
resolvedThisPass += 1;
|
|
14877
14540
|
}
|
|
@@ -14932,7 +14595,7 @@ function assertNonEmptyString(value, fieldName) {
|
|
|
14932
14595
|
throw new Error(`${fieldName} must be a non-empty string`);
|
|
14933
14596
|
}
|
|
14934
14597
|
}
|
|
14935
|
-
function
|
|
14598
|
+
function addVec3(a, b) {
|
|
14936
14599
|
return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];
|
|
14937
14600
|
}
|
|
14938
14601
|
|
|
@@ -15088,7 +14751,6 @@ exports.ThreeClipAdapter = ThreeClipAdapter;
|
|
|
15088
14751
|
exports.ThreeFrameApplier = ThreeFrameApplier;
|
|
15089
14752
|
exports.ThreeModelInspector = ThreeModelInspector;
|
|
15090
14753
|
exports.TsClipCompiler = TsClipCompiler;
|
|
15091
|
-
exports.TsRuntimeCore = TsRuntimeCore;
|
|
15092
14754
|
exports.VISEME_JAW_AMOUNTS = VISEME_JAW_AMOUNTS;
|
|
15093
14755
|
exports.VISEME_KEYS = VISEME_KEYS;
|
|
15094
14756
|
exports.WasmRuntimeCore = WasmRuntimeCore;
|