@lovelace_lol/embody 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/WasmRuntimeCore.d.ts +10 -24
- package/dist/core/index.d.ts +2 -4
- package/dist/core.cjs +27 -739
- package/dist/core.cjs.map +1 -1
- package/dist/core.js +28 -735
- package/dist/core.js.map +1 -1
- package/dist/engines/three/Embody.d.ts +1 -2
- package/dist/index.cjs +164 -729
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -4
- package/dist/index.js +166 -726
- 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.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
import { Vector3, NoBlending, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NormalBlending, PropertyBinding, NumberKeyframeTrack, QuaternionKeyframeTrack, VectorKeyframeTrack, AnimationClip, AnimationUtils, AdditiveAnimationBlendMode, NormalAnimationBlendMode, LoopPingPong, LoopOnce, LoopRepeat, Quaternion, AnimationMixer, Box3, Mesh, Clock, BufferAttribute, PlaneGeometry, ShadowMaterial, PMREMGenerator, WebGLRenderer, PCFSoftShadowMap, Scene, Color, PerspectiveCamera, HemisphereLight, DirectionalLight, MathUtils, SRGBColorSpace, ACESFilmicToneMapping } from 'three';
|
|
3
|
-
import { initEmbodyCore, HAIR_MORPH_OUTPUT_FIELDS, HAIR_CONFIG_STRIDE, HAIR_HEAD_STATE_STRIDE, HAIR_MORPH_OUTPUT_STRIDE, HAIR_STATE_STRIDE } from '@lovelace_lol/embody/wasm';
|
|
3
|
+
import { initEmbodyCore, requireInitializedEmbodyCore, HAIR_MORPH_OUTPUT_FIELDS, HAIR_CONFIG_STRIDE, HAIR_HEAD_STATE_STRIDE, HAIR_MORPH_OUTPUT_STRIDE, HAIR_STATE_STRIDE } from '@lovelace_lol/embody/wasm';
|
|
4
4
|
export { EMBODY_CORE_ABI_VERSION, HAIR_CONFIG_FIELDS, HAIR_CONFIG_STRIDE, HAIR_HEAD_STATE_FIELDS, HAIR_HEAD_STATE_STRIDE, HAIR_MORPH_OUTPUT_FIELDS, HAIR_MORPH_OUTPUT_STRIDE, HAIR_STATE_FIELDS, HAIR_STATE_STRIDE, MESH_PROPORTIONS_FIELDS, MESH_PROPORTIONS_STRIDE, PACKED_BONE_FRAME_DELTA_FIELDS, PACKED_BONE_FRAME_DELTA_STRIDE, PACKED_MORPH_FRAME_DELTA_FIELDS, PACKED_MORPH_FRAME_DELTA_STRIDE, TEMPLATE_SKELETON_FIT_SOLUTION_FIELDS, TEMPLATE_SKELETON_FIT_SOLUTION_STRIDE, TEMPLATE_SKELETON_FIT_TRANSFORM_FIELDS, TEMPLATE_SKELETON_FIT_TRANSFORM_STRIDE, getEmbodyCore, initEmbodyCore, requireInitializedEmbodyCore, resetEmbodyCoreForTests } from '@lovelace_lol/embody/wasm';
|
|
5
5
|
import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js';
|
|
6
6
|
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
|
@@ -3676,410 +3676,6 @@ function getBlendingName(value) {
|
|
|
3676
3676
|
return "Normal";
|
|
3677
3677
|
}
|
|
3678
3678
|
|
|
3679
|
-
// src/core/TsRuntimeCore.ts
|
|
3680
|
-
var identityQuat = { x: 0, y: 0, z: 0, w: 1 };
|
|
3681
|
-
function isRotationBoneBinding2(binding) {
|
|
3682
|
-
return binding?.channel === "rx" || binding?.channel === "ry" || binding?.channel === "rz";
|
|
3683
|
-
}
|
|
3684
|
-
var TsRuntimeCore = class {
|
|
3685
|
-
constructor(options) {
|
|
3686
|
-
__publicField(this, "profile");
|
|
3687
|
-
__publicField(this, "model");
|
|
3688
|
-
__publicField(this, "auValues", {});
|
|
3689
|
-
__publicField(this, "auBalances", {});
|
|
3690
|
-
__publicField(this, "visemeValues");
|
|
3691
|
-
__publicField(this, "visemeJawScales");
|
|
3692
|
-
__publicField(this, "mixWeights");
|
|
3693
|
-
this.profile = options.profile;
|
|
3694
|
-
this.model = options.model;
|
|
3695
|
-
this.visemeValues = new Array(getProfileVisemeSlots(this.profile).length).fill(0);
|
|
3696
|
-
this.visemeJawScales = new Array(this.visemeValues.length).fill(1);
|
|
3697
|
-
this.mixWeights = { ...this.profile.auMixDefaults };
|
|
3698
|
-
}
|
|
3699
|
-
setProfile(profile) {
|
|
3700
|
-
this.profile = profile;
|
|
3701
|
-
this.visemeValues = new Array(getProfileVisemeSlots(this.profile).length).fill(0);
|
|
3702
|
-
this.visemeJawScales = new Array(this.visemeValues.length).fill(1);
|
|
3703
|
-
this.mixWeights = { ...this.profile.auMixDefaults };
|
|
3704
|
-
}
|
|
3705
|
-
setModelDescriptor(model) {
|
|
3706
|
-
this.model = model;
|
|
3707
|
-
}
|
|
3708
|
-
setAU(id, value, balance) {
|
|
3709
|
-
if (value < 0 && this.profile.continuumPairs) {
|
|
3710
|
-
const pairInfo = this.profile.continuumPairs[id];
|
|
3711
|
-
if (pairInfo) {
|
|
3712
|
-
const negAU = pairInfo.isNegative ? id : pairInfo.pairId;
|
|
3713
|
-
const posAU = pairInfo.isNegative ? pairInfo.pairId : id;
|
|
3714
|
-
this.setContinuum(negAU, posAU, pairInfo.isNegative ? -value : value, balance);
|
|
3715
|
-
return;
|
|
3716
|
-
}
|
|
3717
|
-
}
|
|
3718
|
-
this.auValues[id] = clamp01(value);
|
|
3719
|
-
if (balance !== void 0) {
|
|
3720
|
-
this.auBalances[id] = clampBalance2(balance);
|
|
3721
|
-
}
|
|
3722
|
-
}
|
|
3723
|
-
getAU(id) {
|
|
3724
|
-
return this.auValues[id] ?? 0;
|
|
3725
|
-
}
|
|
3726
|
-
setContinuum(negAU, posAU, continuumValue, balance) {
|
|
3727
|
-
const value = Math.max(-1, Math.min(1, continuumValue));
|
|
3728
|
-
if (value < 0) {
|
|
3729
|
-
this.setAU(posAU, 0, balance);
|
|
3730
|
-
this.setAU(negAU, Math.abs(value), balance);
|
|
3731
|
-
return;
|
|
3732
|
-
}
|
|
3733
|
-
if (value > 0) {
|
|
3734
|
-
this.setAU(negAU, 0, balance);
|
|
3735
|
-
this.setAU(posAU, value, balance);
|
|
3736
|
-
return;
|
|
3737
|
-
}
|
|
3738
|
-
this.setAU(negAU, 0, balance);
|
|
3739
|
-
this.setAU(posAU, 0, balance);
|
|
3740
|
-
}
|
|
3741
|
-
setViseme(visemeIndex, value, jawScale = 1) {
|
|
3742
|
-
if (visemeIndex < 0 || visemeIndex >= this.visemeValues.length) return;
|
|
3743
|
-
this.visemeValues[visemeIndex] = clamp01(value);
|
|
3744
|
-
this.visemeJawScales[visemeIndex] = jawScale;
|
|
3745
|
-
}
|
|
3746
|
-
setVisemeById(slotId, value, jawScale = 1) {
|
|
3747
|
-
const index = getVisemeSlotIndex(this.profile, slotId);
|
|
3748
|
-
if (index < 0) return;
|
|
3749
|
-
this.setViseme(index, value, jawScale);
|
|
3750
|
-
}
|
|
3751
|
-
setAUMixWeight(id, weight) {
|
|
3752
|
-
this.mixWeights[id] = clamp01(weight);
|
|
3753
|
-
}
|
|
3754
|
-
evaluateFrameDelta(deltaSeconds) {
|
|
3755
|
-
const morphWrites = /* @__PURE__ */ new Map();
|
|
3756
|
-
this.collectAUWrites(morphWrites);
|
|
3757
|
-
this.collectVisemeWrites(morphWrites);
|
|
3758
|
-
return {
|
|
3759
|
-
deltaSeconds,
|
|
3760
|
-
morphTargets: Array.from(morphWrites.values()),
|
|
3761
|
-
bones: this.collectBoneWrites()
|
|
3762
|
-
};
|
|
3763
|
-
}
|
|
3764
|
-
collectAUWrites(morphWrites) {
|
|
3765
|
-
for (const [auIdText, entry] of Object.entries(this.profile.auToMorphs || {})) {
|
|
3766
|
-
const auId = Number(auIdText);
|
|
3767
|
-
if (Number.isNaN(auId) || !entry) continue;
|
|
3768
|
-
const mixWeight = this.isMixedAU(auId) ? this.getAUMixWeight(auId) : 1;
|
|
3769
|
-
const base = clamp01(this.auValues[auId] ?? 0) * mixWeight;
|
|
3770
|
-
const { left, right } = computeSideValues(base, this.auBalances[auId]);
|
|
3771
|
-
const meshNames = getMeshNamesForAUProfile(this.profile, auId);
|
|
3772
|
-
for (const morph of entry.left || []) {
|
|
3773
|
-
this.addMorphWrites(morphWrites, morph, meshNames, left);
|
|
3774
|
-
}
|
|
3775
|
-
for (const morph of entry.right || []) {
|
|
3776
|
-
this.addMorphWrites(morphWrites, morph, meshNames, right);
|
|
3777
|
-
}
|
|
3778
|
-
for (const morph of entry.center || []) {
|
|
3779
|
-
this.addMorphWrites(morphWrites, morph, meshNames, base);
|
|
3780
|
-
}
|
|
3781
|
-
}
|
|
3782
|
-
}
|
|
3783
|
-
collectVisemeWrites(morphWrites) {
|
|
3784
|
-
const meshNames = getMeshNamesForVisemeProfile(this.profile);
|
|
3785
|
-
const localMax = /* @__PURE__ */ new Map();
|
|
3786
|
-
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
3787
|
-
const value = clamp01(this.visemeValues[index] ?? 0);
|
|
3788
|
-
for (const bindingTarget of getVisemeBindingTargets(this.profile, index)) {
|
|
3789
|
-
const weighted = clamp01(value * bindingTarget.weight);
|
|
3790
|
-
for (const resolved of this.resolveMorphTargets(bindingTarget.morph, meshNames)) {
|
|
3791
|
-
const key = morphWriteKey(resolved.mesh.id, resolved.morphTarget.id);
|
|
3792
|
-
const existing = localMax.get(key);
|
|
3793
|
-
if (!existing || weighted > existing.value) {
|
|
3794
|
-
localMax.set(key, {
|
|
3795
|
-
meshId: resolved.mesh.id,
|
|
3796
|
-
morphTargetId: resolved.morphTarget.id,
|
|
3797
|
-
value: weighted,
|
|
3798
|
-
mode: "absolute"
|
|
3799
|
-
});
|
|
3800
|
-
}
|
|
3801
|
-
}
|
|
3802
|
-
}
|
|
3803
|
-
}
|
|
3804
|
-
for (const [key, write] of localMax) {
|
|
3805
|
-
const existing = morphWrites.get(key);
|
|
3806
|
-
if (!existing || write.value > existing.value) {
|
|
3807
|
-
morphWrites.set(key, write);
|
|
3808
|
-
}
|
|
3809
|
-
}
|
|
3810
|
-
}
|
|
3811
|
-
collectBoneWrites() {
|
|
3812
|
-
const writes = [];
|
|
3813
|
-
const rotations = this.computeRotationState();
|
|
3814
|
-
for (const composite of this.profile.compositeRotations || []) {
|
|
3815
|
-
const bone = this.findBoneDescriptor(composite.node);
|
|
3816
|
-
if (!bone) continue;
|
|
3817
|
-
const transform = this.evaluateCompositeTransform(bone, composite, rotations[composite.node]);
|
|
3818
|
-
if (transform) {
|
|
3819
|
-
writes.push({
|
|
3820
|
-
boneId: bone.id,
|
|
3821
|
-
transform,
|
|
3822
|
-
mode: "absolute",
|
|
3823
|
-
space: "local"
|
|
3824
|
-
});
|
|
3825
|
-
}
|
|
3826
|
-
}
|
|
3827
|
-
for (const [nodeKey, translation] of Object.entries(this.computeTranslations())) {
|
|
3828
|
-
const bone = this.findBoneDescriptor(nodeKey);
|
|
3829
|
-
if (!bone) continue;
|
|
3830
|
-
const position = addVec3(bone.restTransform?.position, translation);
|
|
3831
|
-
upsertBoneWrite(writes, bone.id, { position });
|
|
3832
|
-
}
|
|
3833
|
-
const jawAmount = this.getActiveVisemeJawAmount();
|
|
3834
|
-
const jawBinding = this.findAutoVisemeJawBinding();
|
|
3835
|
-
const jawBone = jawBinding ? this.findBoneDescriptor(jawBinding.node) : void 0;
|
|
3836
|
-
if (jawBone && jawBinding?.maxDegrees && jawBinding.channel) {
|
|
3837
|
-
const current = writes.find((write) => write.boneId === jawBone.id);
|
|
3838
|
-
if (jawAmount > 1e-6 || !current?.transform.rotation) {
|
|
3839
|
-
const rest = jawBone.restTransform?.rotation ?? identityQuat;
|
|
3840
|
-
const rotation = jawAmount > 1e-6 ? multiplyQuat(
|
|
3841
|
-
rest,
|
|
3842
|
-
quatFromChannel(jawBinding.channel, deg2rad(jawBinding.maxDegrees) * jawAmount * jawBinding.scale)
|
|
3843
|
-
) : rest;
|
|
3844
|
-
upsertBoneWrite(writes, jawBone.id, { rotation });
|
|
3845
|
-
}
|
|
3846
|
-
}
|
|
3847
|
-
return writes;
|
|
3848
|
-
}
|
|
3849
|
-
computeRotationState() {
|
|
3850
|
-
const rotations = {};
|
|
3851
|
-
for (const composite of this.profile.compositeRotations || []) {
|
|
3852
|
-
rotations[composite.node] = {
|
|
3853
|
-
pitch: this.getCompositeAxisValueForNode(composite.node, composite.pitch),
|
|
3854
|
-
yaw: this.getCompositeAxisValueForNode(composite.node, composite.yaw),
|
|
3855
|
-
roll: this.getCompositeAxisValueForNode(composite.node, composite.roll)
|
|
3856
|
-
};
|
|
3857
|
-
}
|
|
3858
|
-
return rotations;
|
|
3859
|
-
}
|
|
3860
|
-
evaluateCompositeTransform(bone, composite, state) {
|
|
3861
|
-
if (!state) return null;
|
|
3862
|
-
let rotation = bone.restTransform?.rotation ?? identityQuat;
|
|
3863
|
-
const applyAxis = (axisConfig, direction) => {
|
|
3864
|
-
if (!axisConfig || Math.abs(direction) <= 1e-6) return;
|
|
3865
|
-
const binding = getCompositeAxisBinding(
|
|
3866
|
-
composite.node,
|
|
3867
|
-
axisConfig,
|
|
3868
|
-
direction,
|
|
3869
|
-
(auId) => this.getEffectiveBoneAUValue(auId, composite.node),
|
|
3870
|
-
this.profile.auToBones
|
|
3871
|
-
);
|
|
3872
|
-
if (!binding?.maxDegrees || !binding.channel) return;
|
|
3873
|
-
rotation = multiplyQuat(
|
|
3874
|
-
rotation,
|
|
3875
|
-
quatFromChannel(binding.channel, deg2rad(binding.maxDegrees) * Math.abs(direction) * binding.scale)
|
|
3876
|
-
);
|
|
3877
|
-
};
|
|
3878
|
-
applyAxis(composite.yaw, state.yaw);
|
|
3879
|
-
applyAxis(composite.pitch, state.pitch);
|
|
3880
|
-
applyAxis(composite.roll, state.roll);
|
|
3881
|
-
return { rotation };
|
|
3882
|
-
}
|
|
3883
|
-
computeTranslations() {
|
|
3884
|
-
const translations = {};
|
|
3885
|
-
for (const [auIdText, bindings] of Object.entries(this.profile.auToBones || {})) {
|
|
3886
|
-
const auId = Number(auIdText);
|
|
3887
|
-
if (Number.isNaN(auId)) continue;
|
|
3888
|
-
const value = clamp01(this.auValues[auId] ?? 0);
|
|
3889
|
-
for (const binding of bindings || []) {
|
|
3890
|
-
if (binding.channel !== "tx" && binding.channel !== "ty" && binding.channel !== "tz") continue;
|
|
3891
|
-
if (binding.maxUnits === void 0) continue;
|
|
3892
|
-
const current = translations[binding.node] ?? { x: 0, y: 0, z: 0 };
|
|
3893
|
-
translations[binding.node] = current;
|
|
3894
|
-
if (value <= 1e-6) continue;
|
|
3895
|
-
const offset = clampSigned(value * binding.scale) * binding.maxUnits;
|
|
3896
|
-
translations[binding.node] = {
|
|
3897
|
-
x: binding.channel === "tx" ? offset : current.x,
|
|
3898
|
-
y: binding.channel === "ty" ? offset : current.y,
|
|
3899
|
-
z: binding.channel === "tz" ? offset : current.z
|
|
3900
|
-
};
|
|
3901
|
-
}
|
|
3902
|
-
}
|
|
3903
|
-
return translations;
|
|
3904
|
-
}
|
|
3905
|
-
addMorphWrites(morphWrites, morph, meshNames, value) {
|
|
3906
|
-
for (const resolved of this.resolveMorphTargets(morph, meshNames)) {
|
|
3907
|
-
const key = morphWriteKey(resolved.mesh.id, resolved.morphTarget.id);
|
|
3908
|
-
const existing = morphWrites.get(key);
|
|
3909
|
-
if (existing && existing.value >= value) continue;
|
|
3910
|
-
morphWrites.set(key, {
|
|
3911
|
-
meshId: resolved.mesh.id,
|
|
3912
|
-
morphTargetId: resolved.morphTarget.id,
|
|
3913
|
-
value,
|
|
3914
|
-
mode: "absolute"
|
|
3915
|
-
});
|
|
3916
|
-
}
|
|
3917
|
-
}
|
|
3918
|
-
resolveMorphTargets(morph, meshNames) {
|
|
3919
|
-
const result = [];
|
|
3920
|
-
for (const meshName of meshNames) {
|
|
3921
|
-
const mesh = this.model.meshes.find((candidate) => candidate.name === meshName);
|
|
3922
|
-
if (!mesh) continue;
|
|
3923
|
-
const morphTargets = mesh.morphTargetIds.map((id) => this.model.morphTargets.find((candidate) => candidate.id === id)).filter((target2) => !!target2);
|
|
3924
|
-
const target = typeof morph === "number" ? morphTargets.find((candidate) => candidate.hostIndex === morph) : resolveMorphTargetByName(morphTargets, morph, this.profile);
|
|
3925
|
-
if (target) {
|
|
3926
|
-
result.push({ mesh, morphTarget: target });
|
|
3927
|
-
}
|
|
3928
|
-
}
|
|
3929
|
-
return result;
|
|
3930
|
-
}
|
|
3931
|
-
findBoneDescriptor(nodeKey) {
|
|
3932
|
-
const configuredName = this.profile.boneNodes[nodeKey] || nodeKey;
|
|
3933
|
-
const prefix = this.profile.bonePrefix ?? "";
|
|
3934
|
-
const suffix = this.profile.boneSuffix ?? "";
|
|
3935
|
-
const prefixedName = prefix && !configuredName.startsWith(prefix) ? `${prefix}${configuredName}` : configuredName;
|
|
3936
|
-
const fullName = suffix && !prefixedName.endsWith(suffix) ? `${prefixedName}${suffix}` : prefixedName;
|
|
3937
|
-
const candidates = /* @__PURE__ */ new Set([nodeKey, configuredName, fullName]);
|
|
3938
|
-
return this.model.bones.find((bone) => candidates.has(bone.name));
|
|
3939
|
-
}
|
|
3940
|
-
findAutoVisemeJawBinding() {
|
|
3941
|
-
const candidates = [
|
|
3942
|
-
this.profile.auToBones[103]?.find(isRotationBoneBinding2),
|
|
3943
|
-
this.profile.auToBones[26]?.find(isRotationBoneBinding2)
|
|
3944
|
-
].filter((binding) => !!binding);
|
|
3945
|
-
return candidates.find((binding) => !!this.findBoneDescriptor(binding.node)) ?? candidates[0] ?? null;
|
|
3946
|
-
}
|
|
3947
|
-
getActiveVisemeJawAmount() {
|
|
3948
|
-
const jawAmounts = getVisemeJawAmounts(this.profile) ?? [];
|
|
3949
|
-
let jawAmount = 0;
|
|
3950
|
-
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
3951
|
-
const value = clamp01(this.visemeValues[index] ?? 0);
|
|
3952
|
-
if (value <= 1e-6) continue;
|
|
3953
|
-
const jawScale = this.visemeJawScales[index] ?? 1;
|
|
3954
|
-
if (Math.abs(jawScale) <= 1e-6) continue;
|
|
3955
|
-
jawAmount = Math.max(jawAmount, (jawAmounts[index] ?? 0) * value * jawScale);
|
|
3956
|
-
}
|
|
3957
|
-
return jawAmount;
|
|
3958
|
-
}
|
|
3959
|
-
getCompositeAxisValueForNode(nodeKey, axisConfig) {
|
|
3960
|
-
return getCompositeAxisValue(axisConfig, (auId) => this.getEffectiveBoneAUValue(auId, nodeKey));
|
|
3961
|
-
}
|
|
3962
|
-
getEffectiveBoneAUValue(auId, nodeKey) {
|
|
3963
|
-
const rawValue = clamp01(this.auValues[auId] ?? 0);
|
|
3964
|
-
if (rawValue <= 1e-6) return 0;
|
|
3965
|
-
const binding = this.profile.auToBones[auId]?.find((candidate) => candidate.node === nodeKey) ?? null;
|
|
3966
|
-
if (!binding?.side) return rawValue;
|
|
3967
|
-
return rawValue * getSideScale2(this.auBalances[auId] ?? 0, binding.side);
|
|
3968
|
-
}
|
|
3969
|
-
getAUMixWeight(auId) {
|
|
3970
|
-
return this.mixWeights[auId] ?? this.profile.auMixDefaults?.[auId] ?? 1;
|
|
3971
|
-
}
|
|
3972
|
-
isMixedAU(auId) {
|
|
3973
|
-
const morphs = this.profile.auToMorphs[auId];
|
|
3974
|
-
const hasMorphs = !!(morphs?.left?.length || morphs?.right?.length || morphs?.center?.length);
|
|
3975
|
-
return !!(hasMorphs && this.profile.auToBones[auId]?.length);
|
|
3976
|
-
}
|
|
3977
|
-
};
|
|
3978
|
-
function resolveMorphTargetByName(targets, key, profile) {
|
|
3979
|
-
const prefix = profile.morphPrefix || "";
|
|
3980
|
-
const suffix = profile.morphSuffix || "";
|
|
3981
|
-
const fullName = prefix + key + suffix;
|
|
3982
|
-
const exact = targets.find((target) => target.name === fullName);
|
|
3983
|
-
if (exact) return exact;
|
|
3984
|
-
const suffixRegex = profile.suffixPattern ? new RegExp(profile.suffixPattern) : null;
|
|
3985
|
-
if (!suffixRegex) return void 0;
|
|
3986
|
-
return targets.find((target) => {
|
|
3987
|
-
if (!target.name.startsWith(fullName)) return false;
|
|
3988
|
-
const candidateSuffix = target.name.slice(fullName.length);
|
|
3989
|
-
return candidateSuffix === "" || suffixRegex.test(candidateSuffix);
|
|
3990
|
-
});
|
|
3991
|
-
}
|
|
3992
|
-
function computeSideValues(base, balance) {
|
|
3993
|
-
const b = clampBalance2(balance ?? 0);
|
|
3994
|
-
if (b === 0) return { left: base, right: base };
|
|
3995
|
-
if (b < 0) return { left: base, right: base * (1 + b) };
|
|
3996
|
-
return { left: base * (1 - b), right: base };
|
|
3997
|
-
}
|
|
3998
|
-
function getSideScale2(balance, side) {
|
|
3999
|
-
if (side !== "left" && side !== "right") return 1;
|
|
4000
|
-
const b = clampBalance2(balance);
|
|
4001
|
-
if (side === "left") return b > 0 ? 1 - b : 1;
|
|
4002
|
-
return b < 0 ? 1 + b : 1;
|
|
4003
|
-
}
|
|
4004
|
-
function addVec3(base, offset) {
|
|
4005
|
-
return {
|
|
4006
|
-
x: (base?.x ?? 0) + offset.x,
|
|
4007
|
-
y: (base?.y ?? 0) + offset.y,
|
|
4008
|
-
z: (base?.z ?? 0) + offset.z
|
|
4009
|
-
};
|
|
4010
|
-
}
|
|
4011
|
-
function upsertBoneWrite(writes, boneId2, transform) {
|
|
4012
|
-
const existingIndex = writes.findIndex((write) => write.boneId === boneId2);
|
|
4013
|
-
if (existingIndex >= 0) {
|
|
4014
|
-
const existing = writes[existingIndex];
|
|
4015
|
-
writes[existingIndex] = {
|
|
4016
|
-
...existing,
|
|
4017
|
-
transform: {
|
|
4018
|
-
...existing.transform,
|
|
4019
|
-
...transform
|
|
4020
|
-
}
|
|
4021
|
-
};
|
|
4022
|
-
return;
|
|
4023
|
-
}
|
|
4024
|
-
writes.push({
|
|
4025
|
-
boneId: boneId2,
|
|
4026
|
-
transform,
|
|
4027
|
-
mode: "absolute",
|
|
4028
|
-
space: "local"
|
|
4029
|
-
});
|
|
4030
|
-
}
|
|
4031
|
-
function quatFromChannel(channel, radians) {
|
|
4032
|
-
if (channel === "rx") return quatFromAxis({ x: 1, y: 0, z: 0 }, radians);
|
|
4033
|
-
if (channel === "ry") return quatFromAxis({ x: 0, y: 1, z: 0 }, radians);
|
|
4034
|
-
return quatFromAxis({ x: 0, y: 0, z: 1 }, radians);
|
|
4035
|
-
}
|
|
4036
|
-
function quatFromAxis(axis, radians) {
|
|
4037
|
-
const half = radians / 2;
|
|
4038
|
-
const s = Math.sin(half);
|
|
4039
|
-
return normalizeQuat({
|
|
4040
|
-
x: axis.x * s,
|
|
4041
|
-
y: axis.y * s,
|
|
4042
|
-
z: axis.z * s,
|
|
4043
|
-
w: Math.cos(half)
|
|
4044
|
-
});
|
|
4045
|
-
}
|
|
4046
|
-
function multiplyQuat(a, b) {
|
|
4047
|
-
return normalizeQuat({
|
|
4048
|
-
x: a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
|
|
4049
|
-
y: a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
|
|
4050
|
-
z: a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
|
|
4051
|
-
w: a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z
|
|
4052
|
-
});
|
|
4053
|
-
}
|
|
4054
|
-
function normalizeQuat(q) {
|
|
4055
|
-
const len = Math.hypot(q.x, q.y, q.z, q.w);
|
|
4056
|
-
if (len <= 1e-12) return identityQuat;
|
|
4057
|
-
return {
|
|
4058
|
-
x: q.x / len,
|
|
4059
|
-
y: q.y / len,
|
|
4060
|
-
z: q.z / len,
|
|
4061
|
-
w: q.w / len
|
|
4062
|
-
};
|
|
4063
|
-
}
|
|
4064
|
-
function deg2rad(degrees) {
|
|
4065
|
-
return degrees * Math.PI / 180;
|
|
4066
|
-
}
|
|
4067
|
-
function clamp01(value) {
|
|
4068
|
-
if (!Number.isFinite(value)) return 0;
|
|
4069
|
-
return value < 0 ? 0 : value > 1 ? 1 : value;
|
|
4070
|
-
}
|
|
4071
|
-
function clampSigned(value) {
|
|
4072
|
-
if (!Number.isFinite(value)) return 0;
|
|
4073
|
-
return value < -1 ? -1 : value > 1 ? 1 : value;
|
|
4074
|
-
}
|
|
4075
|
-
function clampBalance2(value) {
|
|
4076
|
-
if (!Number.isFinite(value)) return 0;
|
|
4077
|
-
return Math.max(-1, Math.min(1, value));
|
|
4078
|
-
}
|
|
4079
|
-
function morphWriteKey(meshId2, morphTargetId2) {
|
|
4080
|
-
return `${meshId2}:${morphTargetId2}`;
|
|
4081
|
-
}
|
|
4082
|
-
|
|
4083
3679
|
// src/core/contracts/abi.ts
|
|
4084
3680
|
var PACKED_MORPH_FRAME_DELTA_STRIDE = 4;
|
|
4085
3681
|
var PACKED_BONE_FRAME_DELTA_STRIDE = 9;
|
|
@@ -4209,25 +3805,17 @@ function positiveFiniteOr(value, fallback) {
|
|
|
4209
3805
|
}
|
|
4210
3806
|
|
|
4211
3807
|
// src/core/WasmRuntimeCore.ts
|
|
4212
|
-
var AU_MORPH_BINDING_STRIDE = 5;
|
|
4213
|
-
var VISEME_MORPH_BINDING_STRIDE = 4;
|
|
4214
|
-
var AXIS_GROUP_NEGATIVE = 0;
|
|
4215
|
-
var AXIS_GROUP_POSITIVE = 1;
|
|
4216
|
-
var AXIS_GROUP_PLAIN = 2;
|
|
4217
|
-
var BONE_SIDE_NONE = 0;
|
|
4218
|
-
var BONE_SIDE_LEFT = 1;
|
|
4219
|
-
var BONE_SIDE_RIGHT = 2;
|
|
4220
|
-
var ROTATION_CHANNELS = { rx: 0, ry: 1, rz: 2 };
|
|
4221
|
-
var TRANSLATION_CHANNELS = { tx: 0, ty: 1, tz: 2 };
|
|
4222
3808
|
var WasmRuntimeCore = class {
|
|
4223
3809
|
constructor(options) {
|
|
4224
3810
|
__publicField(this, "wasm");
|
|
4225
3811
|
__publicField(this, "core");
|
|
3812
|
+
__publicField(this, "allowEmptyBindings");
|
|
4226
3813
|
__publicField(this, "profile");
|
|
4227
3814
|
__publicField(this, "model");
|
|
4228
3815
|
this.wasm = options.wasm;
|
|
4229
3816
|
this.profile = options.profile;
|
|
4230
3817
|
this.model = options.model;
|
|
3818
|
+
this.allowEmptyBindings = options.allowEmptyBindings ?? false;
|
|
4231
3819
|
const RuntimeCtor = options.wasm.RuntimeCore;
|
|
4232
3820
|
if (!RuntimeCtor) {
|
|
4233
3821
|
throw new Error("Embody Wasm module does not export RuntimeCore");
|
|
@@ -4246,6 +3834,24 @@ var WasmRuntimeCore = class {
|
|
|
4246
3834
|
setAU(id, value, balance = 0) {
|
|
4247
3835
|
this.core.set_au(id >>> 0, value, balance);
|
|
4248
3836
|
}
|
|
3837
|
+
setContinuum(negativeAU, positiveAU, value, balance = 0) {
|
|
3838
|
+
this.core.set_continuum(negativeAU >>> 0, positiveAU >>> 0, value, balance);
|
|
3839
|
+
}
|
|
3840
|
+
transitionAU(id, to, durationMs, balance = Number.NaN) {
|
|
3841
|
+
this.core.transition_au(id >>> 0, to, durationMs, balance);
|
|
3842
|
+
}
|
|
3843
|
+
transitionViseme(visemeIndex, to, durationMs, jawScale = 1) {
|
|
3844
|
+
this.core.transition_viseme(visemeIndex >>> 0, to, durationMs, jawScale);
|
|
3845
|
+
}
|
|
3846
|
+
update(deltaSeconds) {
|
|
3847
|
+
return this.core.update(deltaSeconds);
|
|
3848
|
+
}
|
|
3849
|
+
activeTransitionCount() {
|
|
3850
|
+
return this.core.active_transition_count();
|
|
3851
|
+
}
|
|
3852
|
+
clearTransitions() {
|
|
3853
|
+
this.core.clear_transitions();
|
|
3854
|
+
}
|
|
4249
3855
|
getAU(id) {
|
|
4250
3856
|
return this.core.get_au(id >>> 0);
|
|
4251
3857
|
}
|
|
@@ -4281,182 +3887,15 @@ var WasmRuntimeCore = class {
|
|
|
4281
3887
|
};
|
|
4282
3888
|
}
|
|
4283
3889
|
reloadBindings() {
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
for (const [auIdText, entry] of Object.entries(profile.auToMorphs || {})) {
|
|
4291
|
-
const auId = Number(auIdText);
|
|
4292
|
-
if (Number.isNaN(auId) || !entry) continue;
|
|
4293
|
-
const meshNames = getMeshNamesForAUProfile(profile, auId);
|
|
4294
|
-
const hasMorphs = !!(entry.left?.length || entry.right?.length || entry.center?.length);
|
|
4295
|
-
if (hasMorphs && profile.auToBones?.[auId]?.length) {
|
|
4296
|
-
mixed.push(auId);
|
|
4297
|
-
}
|
|
4298
|
-
pushAuSide(auRows, auId, 0, entry.left || [], meshNames, model, profile);
|
|
4299
|
-
pushAuSide(auRows, auId, 1, entry.right || [], meshNames, model, profile);
|
|
4300
|
-
pushAuSide(auRows, auId, 2, entry.center || [], meshNames, model, profile);
|
|
4301
|
-
}
|
|
4302
|
-
const visemeRows = [];
|
|
4303
|
-
const visemeMeshNames = getMeshNamesForVisemeProfile(profile);
|
|
4304
|
-
const slotCount = getProfileVisemeSlots(profile).length;
|
|
4305
|
-
for (let index = 0; index < slotCount; index += 1) {
|
|
4306
|
-
for (const bindingTarget of getVisemeBindingTargets(profile, index)) {
|
|
4307
|
-
for (const resolved of resolveMorphTargets(model, profile, bindingTarget.morph, visemeMeshNames)) {
|
|
4308
|
-
visemeRows.push(
|
|
4309
|
-
index,
|
|
4310
|
-
Number(resolved.mesh.id),
|
|
4311
|
-
Number(resolved.morphTarget.id),
|
|
4312
|
-
bindingTarget.weight
|
|
4313
|
-
);
|
|
4314
|
-
}
|
|
3890
|
+
const profileJson = JSON.stringify(this.profile);
|
|
3891
|
+
const modelJson = JSON.stringify(this.model);
|
|
3892
|
+
if (this.allowEmptyBindings) {
|
|
3893
|
+
this.core.configure(profileJson, modelJson);
|
|
3894
|
+
} else {
|
|
3895
|
+
this.core.configure_with_profile(profileJson, modelJson);
|
|
4315
3896
|
}
|
|
4316
3897
|
}
|
|
4317
|
-
|
|
4318
|
-
auBindings: Float32Array.from(auRows),
|
|
4319
|
-
visemeBindings: Float32Array.from(visemeRows),
|
|
4320
|
-
mixedAus: Uint32Array.from(mixed)
|
|
4321
|
-
};
|
|
4322
|
-
}
|
|
4323
|
-
function compileBoneBindings(profile, model) {
|
|
4324
|
-
const referencedBones = /* @__PURE__ */ new Map();
|
|
4325
|
-
const findBone = (nodeKey) => {
|
|
4326
|
-
const bone = findBoneDescriptor(profile, model, nodeKey);
|
|
4327
|
-
if (bone) referencedBones.set(bone.id, bone);
|
|
4328
|
-
return bone;
|
|
4329
|
-
};
|
|
4330
|
-
const boneSideForAU = (auId, nodeKey) => {
|
|
4331
|
-
const side = profile.auToBones?.[auId]?.find((candidate) => candidate.node === nodeKey)?.side;
|
|
4332
|
-
if (side === "left") return BONE_SIDE_LEFT;
|
|
4333
|
-
if (side === "right") return BONE_SIDE_RIGHT;
|
|
4334
|
-
return BONE_SIDE_NONE;
|
|
4335
|
-
};
|
|
4336
|
-
const compositeRows = [];
|
|
4337
|
-
for (const composite of profile.compositeRotations || []) {
|
|
4338
|
-
const bone = findBone(composite.node);
|
|
4339
|
-
if (!bone) continue;
|
|
4340
|
-
const axes = [
|
|
4341
|
-
{ axis: 1, config: composite.yaw },
|
|
4342
|
-
{ axis: 0, config: composite.pitch },
|
|
4343
|
-
{ axis: 2, config: composite.roll }
|
|
4344
|
-
];
|
|
4345
|
-
for (const { axis, config } of axes) {
|
|
4346
|
-
if (!config) continue;
|
|
4347
|
-
const negativeAUs = toAUList(config.negative);
|
|
4348
|
-
const positiveAUs = toAUList(config.positive);
|
|
4349
|
-
const hasDirectional = negativeAUs.length > 0 && positiveAUs.length > 0;
|
|
4350
|
-
const valueRows = [];
|
|
4351
|
-
if (hasDirectional) {
|
|
4352
|
-
for (const auId of negativeAUs) {
|
|
4353
|
-
valueRows.push([auId, AXIS_GROUP_NEGATIVE, boneSideForAU(auId, composite.node)]);
|
|
4354
|
-
}
|
|
4355
|
-
for (const auId of positiveAUs) {
|
|
4356
|
-
valueRows.push([auId, AXIS_GROUP_POSITIVE, boneSideForAU(auId, composite.node)]);
|
|
4357
|
-
}
|
|
4358
|
-
} else {
|
|
4359
|
-
for (const auId of config.aus) {
|
|
4360
|
-
valueRows.push([auId, AXIS_GROUP_PLAIN, boneSideForAU(auId, composite.node)]);
|
|
4361
|
-
}
|
|
4362
|
-
}
|
|
4363
|
-
const bindingRows = [];
|
|
4364
|
-
const pushBindingRows = (auIds, group) => {
|
|
4365
|
-
for (const auId of auIds) {
|
|
4366
|
-
const binding = profile.auToBones?.[auId]?.find(
|
|
4367
|
-
(candidate) => candidate.node === composite.node
|
|
4368
|
-
);
|
|
4369
|
-
if (!binding?.maxDegrees) continue;
|
|
4370
|
-
const channel = ROTATION_CHANNELS[binding.channel];
|
|
4371
|
-
if (channel === void 0) continue;
|
|
4372
|
-
bindingRows.push([
|
|
4373
|
-
auId,
|
|
4374
|
-
group,
|
|
4375
|
-
boneSideForAU(auId, composite.node),
|
|
4376
|
-
channel,
|
|
4377
|
-
binding.scale,
|
|
4378
|
-
binding.maxDegrees
|
|
4379
|
-
]);
|
|
4380
|
-
}
|
|
4381
|
-
};
|
|
4382
|
-
pushBindingRows(negativeAUs, AXIS_GROUP_NEGATIVE);
|
|
4383
|
-
pushBindingRows(positiveAUs, AXIS_GROUP_POSITIVE);
|
|
4384
|
-
pushBindingRows(config.aus, AXIS_GROUP_PLAIN);
|
|
4385
|
-
compositeRows.push(
|
|
4386
|
-
Number(bone.id),
|
|
4387
|
-
axis,
|
|
4388
|
-
hasDirectional ? 1 : 0,
|
|
4389
|
-
valueRows.length,
|
|
4390
|
-
bindingRows.length,
|
|
4391
|
-
0,
|
|
4392
|
-
0,
|
|
4393
|
-
0
|
|
4394
|
-
);
|
|
4395
|
-
for (const row of valueRows) compositeRows.push(...row);
|
|
4396
|
-
for (const row of bindingRows) compositeRows.push(...row);
|
|
4397
|
-
}
|
|
4398
|
-
}
|
|
4399
|
-
const translationRows = [];
|
|
4400
|
-
for (const [auIdText, bindings] of Object.entries(profile.auToBones || {})) {
|
|
4401
|
-
const auId = Number(auIdText);
|
|
4402
|
-
if (Number.isNaN(auId)) continue;
|
|
4403
|
-
for (const binding of bindings || []) {
|
|
4404
|
-
const channel = TRANSLATION_CHANNELS[binding.channel];
|
|
4405
|
-
if (channel === void 0 || binding.maxUnits === void 0) continue;
|
|
4406
|
-
const bone = findBone(binding.node);
|
|
4407
|
-
if (!bone) continue;
|
|
4408
|
-
translationRows.push(auId, Number(bone.id), channel, binding.scale, binding.maxUnits);
|
|
4409
|
-
}
|
|
4410
|
-
}
|
|
4411
|
-
const jawRow = [];
|
|
4412
|
-
const jawBinding = findAutoVisemeJawBinding(profile, model);
|
|
4413
|
-
if (jawBinding?.maxDegrees) {
|
|
4414
|
-
const bone = findBone(jawBinding.node);
|
|
4415
|
-
const channel = ROTATION_CHANNELS[jawBinding.channel];
|
|
4416
|
-
if (bone && channel !== void 0) {
|
|
4417
|
-
jawRow.push(Number(bone.id), channel, jawBinding.scale, jawBinding.maxDegrees);
|
|
4418
|
-
}
|
|
4419
|
-
}
|
|
4420
|
-
const restRows = [];
|
|
4421
|
-
for (const bone of referencedBones.values()) {
|
|
4422
|
-
const position = bone.restTransform?.position;
|
|
4423
|
-
const rotation = bone.restTransform?.rotation;
|
|
4424
|
-
restRows.push(
|
|
4425
|
-
Number(bone.id),
|
|
4426
|
-
position?.x ?? 0,
|
|
4427
|
-
position?.y ?? 0,
|
|
4428
|
-
position?.z ?? 0,
|
|
4429
|
-
rotation?.x ?? 0,
|
|
4430
|
-
rotation?.y ?? 0,
|
|
4431
|
-
rotation?.z ?? 0,
|
|
4432
|
-
rotation?.w ?? 1
|
|
4433
|
-
);
|
|
4434
|
-
}
|
|
4435
|
-
return {
|
|
4436
|
-
restTransforms: Float32Array.from(restRows),
|
|
4437
|
-
compositeAxes: Float32Array.from(compositeRows),
|
|
4438
|
-
translations: Float32Array.from(translationRows),
|
|
4439
|
-
jawBinding: Float32Array.from(jawRow),
|
|
4440
|
-
visemeJawAmounts: Float32Array.from(getVisemeJawAmounts(profile) ?? [])
|
|
4441
|
-
};
|
|
4442
|
-
}
|
|
4443
|
-
function findBoneDescriptor(profile, model, nodeKey) {
|
|
4444
|
-
const configuredName = profile.boneNodes?.[nodeKey] || nodeKey;
|
|
4445
|
-
const prefix = profile.bonePrefix ?? "";
|
|
4446
|
-
const suffix = profile.boneSuffix ?? "";
|
|
4447
|
-
const prefixedName = prefix && !configuredName.startsWith(prefix) ? `${prefix}${configuredName}` : configuredName;
|
|
4448
|
-
const fullName = suffix && !prefixedName.endsWith(suffix) ? `${prefixedName}${suffix}` : prefixedName;
|
|
4449
|
-
const candidates = /* @__PURE__ */ new Set([nodeKey, configuredName, fullName]);
|
|
4450
|
-
return model.bones.find((bone) => candidates.has(bone.name));
|
|
4451
|
-
}
|
|
4452
|
-
function findAutoVisemeJawBinding(profile, model) {
|
|
4453
|
-
const isRotation = (binding) => binding?.channel === "rx" || binding?.channel === "ry" || binding?.channel === "rz";
|
|
4454
|
-
const candidates = [
|
|
4455
|
-
profile.auToBones?.[103]?.find(isRotation),
|
|
4456
|
-
profile.auToBones?.[26]?.find(isRotation)
|
|
4457
|
-
].filter((binding) => !!binding);
|
|
4458
|
-
return candidates.find((binding) => !!findBoneDescriptor(profile, model, binding.node)) ?? candidates[0] ?? null;
|
|
4459
|
-
}
|
|
3898
|
+
};
|
|
4460
3899
|
function unpackBoneFrameDelta(values) {
|
|
4461
3900
|
const stride = PACKED_BONE_FRAME_DELTA_STRIDE;
|
|
4462
3901
|
const writes = [];
|
|
@@ -4497,46 +3936,6 @@ function unpackMorphFrameDelta(values) {
|
|
|
4497
3936
|
}
|
|
4498
3937
|
return writes;
|
|
4499
3938
|
}
|
|
4500
|
-
function pushAuSide(rows, auId, side, morphs, meshNames, model, profile) {
|
|
4501
|
-
for (const morph of morphs) {
|
|
4502
|
-
for (const resolved of resolveMorphTargets(model, profile, morph, meshNames)) {
|
|
4503
|
-
rows.push(
|
|
4504
|
-
auId,
|
|
4505
|
-
side,
|
|
4506
|
-
Number(resolved.mesh.id),
|
|
4507
|
-
Number(resolved.morphTarget.id),
|
|
4508
|
-
1
|
|
4509
|
-
);
|
|
4510
|
-
}
|
|
4511
|
-
}
|
|
4512
|
-
}
|
|
4513
|
-
function resolveMorphTargets(model, profile, morph, meshNames) {
|
|
4514
|
-
const result = [];
|
|
4515
|
-
for (const meshName of meshNames) {
|
|
4516
|
-
const mesh = model.meshes.find((candidate) => candidate.name === meshName);
|
|
4517
|
-
if (!mesh) continue;
|
|
4518
|
-
const morphTargets = mesh.morphTargetIds.map((id) => model.morphTargets.find((candidate) => candidate.id === id)).filter((target2) => !!target2);
|
|
4519
|
-
const target = typeof morph === "number" ? morphTargets.find((candidate) => candidate.hostIndex === morph) : resolveMorphTargetByName2(morphTargets, morph, profile);
|
|
4520
|
-
if (target) {
|
|
4521
|
-
result.push({ mesh, morphTarget: target });
|
|
4522
|
-
}
|
|
4523
|
-
}
|
|
4524
|
-
return result;
|
|
4525
|
-
}
|
|
4526
|
-
function resolveMorphTargetByName2(targets, key, profile) {
|
|
4527
|
-
const prefix = profile.morphPrefix || "";
|
|
4528
|
-
const suffix = profile.morphSuffix || "";
|
|
4529
|
-
const fullName = prefix + key + suffix;
|
|
4530
|
-
const exact = targets.find((target) => target.name === fullName);
|
|
4531
|
-
if (exact) return exact;
|
|
4532
|
-
const suffixRegex = profile.suffixPattern ? new RegExp(profile.suffixPattern) : null;
|
|
4533
|
-
if (!suffixRegex) return void 0;
|
|
4534
|
-
return targets.find((target) => {
|
|
4535
|
-
if (!target.name.startsWith(fullName)) return false;
|
|
4536
|
-
const candidateSuffix = target.name.slice(fullName.length);
|
|
4537
|
-
return candidateSuffix === "" || suffixRegex.test(candidateSuffix);
|
|
4538
|
-
});
|
|
4539
|
-
}
|
|
4540
3939
|
|
|
4541
3940
|
// src/hair/appearance.ts
|
|
4542
3941
|
var HAIR_COLOR_PRESETS = {
|
|
@@ -5852,7 +5251,7 @@ var CC4_PRESET = {
|
|
|
5852
5251
|
};
|
|
5853
5252
|
|
|
5854
5253
|
// src/engines/three/hair/HairPhysicsController.ts
|
|
5855
|
-
var
|
|
5254
|
+
var clamp01 = (value) => value < 0 ? 0 : value > 1 ? 1 : value;
|
|
5856
5255
|
var HairPhysicsController = class {
|
|
5857
5256
|
constructor(host) {
|
|
5858
5257
|
__publicField(this, "host");
|
|
@@ -6350,7 +5749,7 @@ var HairPhysicsController = class {
|
|
|
6350
5749
|
}
|
|
6351
5750
|
}
|
|
6352
5751
|
setMorphOnMeshes(meshNames, morphKey, value) {
|
|
6353
|
-
const val =
|
|
5752
|
+
const val = clamp01(value);
|
|
6354
5753
|
for (const name of meshNames) {
|
|
6355
5754
|
const mesh = this.registeredHairObjects.get(name) || this.host.getMeshByName(name);
|
|
6356
5755
|
if (!mesh) continue;
|
|
@@ -6594,9 +5993,9 @@ var HairPhysicsController = class {
|
|
|
6594
5993
|
const deltaVertical = vertical - this.lastHeadVertical;
|
|
6595
5994
|
this.lastHeadHorizontal = horizontal;
|
|
6596
5995
|
this.lastHeadVertical = vertical;
|
|
6597
|
-
const leftWeight =
|
|
6598
|
-
const rightWeight =
|
|
6599
|
-
const frontWeight =
|
|
5996
|
+
const leftWeight = clamp01(deltaHorizontal > 0 ? deltaHorizontal : 0);
|
|
5997
|
+
const rightWeight = clamp01(deltaHorizontal < 0 ? -deltaHorizontal : 0);
|
|
5998
|
+
const frontWeight = clamp01(deltaVertical > 0 ? deltaVertical : 0);
|
|
6600
5999
|
const minTrigger = 0.01;
|
|
6601
6000
|
if (leftWeight <= minTrigger && rightWeight <= minTrigger && frontWeight <= minTrigger) return;
|
|
6602
6001
|
if (this.impulseClipDirty) {
|
|
@@ -7566,7 +6965,7 @@ async function getPresetWithProfile(presetType, profile) {
|
|
|
7566
6965
|
var resolvePresetWithOverrides = getPresetWithProfile;
|
|
7567
6966
|
|
|
7568
6967
|
// src/engines/three/Embody.ts
|
|
7569
|
-
var
|
|
6968
|
+
var deg2rad = (d) => d * Math.PI / 180;
|
|
7570
6969
|
var X_AXIS2 = new Vector3(1, 0, 0);
|
|
7571
6970
|
var Y_AXIS2 = new Vector3(0, 1, 0);
|
|
7572
6971
|
var Z_AXIS2 = new Vector3(0, 0, 1);
|
|
@@ -7589,9 +6988,18 @@ function buildAUToCompositeMap(composites) {
|
|
|
7589
6988
|
});
|
|
7590
6989
|
return map;
|
|
7591
6990
|
}
|
|
7592
|
-
function
|
|
6991
|
+
function clamp012(x) {
|
|
7593
6992
|
return x < 0 ? 0 : x > 1 ? 1 : x;
|
|
7594
6993
|
}
|
|
6994
|
+
var RESOLVED_TRANSITION_HANDLE = {
|
|
6995
|
+
promise: Promise.resolve(),
|
|
6996
|
+
pause: () => {
|
|
6997
|
+
},
|
|
6998
|
+
resume: () => {
|
|
6999
|
+
},
|
|
7000
|
+
cancel: () => {
|
|
7001
|
+
}
|
|
7002
|
+
};
|
|
7595
7003
|
var _Embody = class _Embody {
|
|
7596
7004
|
constructor(config = {}, animation) {
|
|
7597
7005
|
// Optional hook for animation schedulers.
|
|
@@ -7635,7 +7043,6 @@ var _Embody = class _Embody {
|
|
|
7635
7043
|
__publicField(this, "modelInspector", new ThreeModelInspector());
|
|
7636
7044
|
__publicField(this, "frameApplier", new ThreeFrameApplier());
|
|
7637
7045
|
__publicField(this, "modelDescriptor", null);
|
|
7638
|
-
__publicField(this, "tsRuntimeCore", null);
|
|
7639
7046
|
__publicField(this, "wasmRuntimeCore", null);
|
|
7640
7047
|
__publicField(this, "framePathReady", false);
|
|
7641
7048
|
// Internal animation loop
|
|
@@ -7748,48 +7155,21 @@ var _Embody = class _Embody {
|
|
|
7748
7155
|
bindHostNeutralRuntime(inspection) {
|
|
7749
7156
|
this.modelDescriptor = inspection.descriptor;
|
|
7750
7157
|
this.frameApplier.setBindings(buildFrameApplierBindings(inspection));
|
|
7751
|
-
|
|
7158
|
+
const wasm = requireInitializedEmbodyCore();
|
|
7159
|
+
this.attachWasmCore(wasm);
|
|
7160
|
+
this.wasmRuntimeCore = new WasmRuntimeCore({
|
|
7752
7161
|
profile: this.config,
|
|
7753
|
-
model: inspection.descriptor
|
|
7162
|
+
model: inspection.descriptor,
|
|
7163
|
+
wasm,
|
|
7164
|
+
allowEmptyBindings: true
|
|
7754
7165
|
});
|
|
7755
7166
|
this.syncRuntimeCoreState();
|
|
7756
7167
|
this.framePathReady = true;
|
|
7757
|
-
void initEmbodyCore().then((wasm) => {
|
|
7758
|
-
if (!this.modelDescriptor) return;
|
|
7759
|
-
this.attachWasmCore(wasm);
|
|
7760
|
-
this.wasmRuntimeCore = new WasmRuntimeCore({
|
|
7761
|
-
profile: this.config,
|
|
7762
|
-
model: this.modelDescriptor,
|
|
7763
|
-
wasm
|
|
7764
|
-
});
|
|
7765
|
-
this.syncRuntimeCoreState();
|
|
7766
|
-
}).catch(() => {
|
|
7767
|
-
this.wasmRuntimeCore = null;
|
|
7768
|
-
});
|
|
7769
7168
|
}
|
|
7770
7169
|
attachWasmCore(core) {
|
|
7771
7170
|
this.hairPhysics.setCore(core);
|
|
7772
7171
|
}
|
|
7773
7172
|
syncRuntimeCoreState() {
|
|
7774
|
-
if (this.tsRuntimeCore) {
|
|
7775
|
-
this.tsRuntimeCore.setProfile(this.config);
|
|
7776
|
-
if (this.modelDescriptor) {
|
|
7777
|
-
this.tsRuntimeCore.setModelDescriptor(this.modelDescriptor);
|
|
7778
|
-
}
|
|
7779
|
-
for (const [auIdText, value] of Object.entries(this.auValues)) {
|
|
7780
|
-
const auId = Number(auIdText);
|
|
7781
|
-
if (Number.isNaN(auId)) continue;
|
|
7782
|
-
this.tsRuntimeCore.setAU(auId, value, this.auBalances[auId]);
|
|
7783
|
-
}
|
|
7784
|
-
for (const [auIdText, weight] of Object.entries(this.mixWeights)) {
|
|
7785
|
-
const auId = Number(auIdText);
|
|
7786
|
-
if (Number.isNaN(auId)) continue;
|
|
7787
|
-
this.tsRuntimeCore.setAUMixWeight(auId, weight);
|
|
7788
|
-
}
|
|
7789
|
-
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
7790
|
-
this.tsRuntimeCore.setViseme(index, this.visemeValues[index] ?? 0, this.visemeJawScales[index] ?? 1);
|
|
7791
|
-
}
|
|
7792
|
-
}
|
|
7793
7173
|
if (this.wasmRuntimeCore) {
|
|
7794
7174
|
this.wasmRuntimeCore.setProfile(this.config);
|
|
7795
7175
|
if (this.modelDescriptor) {
|
|
@@ -7807,7 +7187,7 @@ var _Embody = class _Embody {
|
|
|
7807
7187
|
this.wasmRuntimeCore.setAUMixWeight(auId, weight);
|
|
7808
7188
|
}
|
|
7809
7189
|
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
7810
|
-
this.wasmRuntimeCore.setViseme(index, this.visemeValues[index] ?? 0);
|
|
7190
|
+
this.wasmRuntimeCore.setViseme(index, this.visemeValues[index] ?? 0, this.visemeJawScales[index] ?? 1);
|
|
7811
7191
|
}
|
|
7812
7192
|
}
|
|
7813
7193
|
}
|
|
@@ -7825,25 +7205,13 @@ var _Embody = class _Embody {
|
|
|
7825
7205
|
});
|
|
7826
7206
|
this.modelDescriptor = inspection.descriptor;
|
|
7827
7207
|
this.frameApplier.setBindings(buildFrameApplierBindings(inspection));
|
|
7828
|
-
this.tsRuntimeCore?.setModelDescriptor(inspection.descriptor);
|
|
7829
7208
|
this.wasmRuntimeCore?.setModelDescriptor(inspection.descriptor);
|
|
7830
7209
|
}
|
|
7831
|
-
|
|
7832
|
-
if (!this.framePathReady || !this.model) return false;
|
|
7833
|
-
|
|
7834
|
-
|
|
7835
|
-
|
|
7836
|
-
);
|
|
7837
|
-
return true;
|
|
7838
|
-
}
|
|
7839
|
-
if (this.tsRuntimeCore) {
|
|
7840
|
-
const frame = this.tsRuntimeCore.evaluateFrameDelta();
|
|
7841
|
-
this.frameApplier.applyFrameDelta(this.model, {
|
|
7842
|
-
morphTargets: frame.morphTargets
|
|
7843
|
-
});
|
|
7844
|
-
return true;
|
|
7845
|
-
}
|
|
7846
|
-
return false;
|
|
7210
|
+
applyLiveFrameDelta() {
|
|
7211
|
+
if (!this.framePathReady || !this.model || !this.wasmRuntimeCore) return false;
|
|
7212
|
+
this.frameApplier.applyFrameDelta(this.model, this.wasmRuntimeCore.evaluateFrameDelta());
|
|
7213
|
+
this.pendingCompositeNodes.clear();
|
|
7214
|
+
return true;
|
|
7847
7215
|
}
|
|
7848
7216
|
rebuildMorphTargetsCache() {
|
|
7849
7217
|
this.morphKeyCache.clear();
|
|
@@ -7945,6 +7313,11 @@ var _Embody = class _Embody {
|
|
|
7945
7313
|
const dtSeconds = Math.max(0, deltaSeconds || 0);
|
|
7946
7314
|
if (dtSeconds <= 0 || this.isPaused) return;
|
|
7947
7315
|
this.animation.tick(dtSeconds);
|
|
7316
|
+
const wasmTransitionCount = this.wasmRuntimeCore?.activeTransitionCount() ?? 0;
|
|
7317
|
+
const remainingWasmTransitions = this.wasmRuntimeCore?.update(dtSeconds) ?? 0;
|
|
7318
|
+
if (wasmTransitionCount > 0 || remainingWasmTransitions > 0) {
|
|
7319
|
+
this.applyLiveFrameDelta();
|
|
7320
|
+
}
|
|
7948
7321
|
this.flushPendingComposites();
|
|
7949
7322
|
this.animationController.update(dtSeconds);
|
|
7950
7323
|
this.hairPhysics.update(dtSeconds);
|
|
@@ -7979,7 +7352,6 @@ var _Embody = class _Embody {
|
|
|
7979
7352
|
this.model = null;
|
|
7980
7353
|
this.bones = {};
|
|
7981
7354
|
this.modelDescriptor = null;
|
|
7982
|
-
this.tsRuntimeCore = null;
|
|
7983
7355
|
this.wasmRuntimeCore = null;
|
|
7984
7356
|
this.framePathReady = false;
|
|
7985
7357
|
}
|
|
@@ -8016,15 +7388,14 @@ var _Embody = class _Embody {
|
|
|
8016
7388
|
if (balance !== void 0) {
|
|
8017
7389
|
this.auBalances[id] = balance;
|
|
8018
7390
|
}
|
|
8019
|
-
this.tsRuntimeCore?.setAU(id, v, balance);
|
|
8020
7391
|
this.wasmRuntimeCore?.setAU(id, v, balance ?? this.auBalances[id] ?? 0);
|
|
8021
|
-
const appliedViaFrame = this.
|
|
7392
|
+
const appliedViaFrame = this.applyLiveFrameDelta();
|
|
8022
7393
|
if (!appliedViaFrame) {
|
|
8023
7394
|
const resolvedMorphTargets = this.resolvedAUMorphTargets.get(id);
|
|
8024
7395
|
const { left: leftKeys, right: rightKeys, center: centerKeys } = this.getAUMorphsBySide(id);
|
|
8025
7396
|
if (resolvedMorphTargets) {
|
|
8026
7397
|
const mixWeight = this.isMixedAU(id) ? this.getAUMixWeight(id) : 1;
|
|
8027
|
-
const base =
|
|
7398
|
+
const base = clamp012(v) * mixWeight;
|
|
8028
7399
|
const { left: leftVal, right: rightVal } = this.computeSideValues(base, balance);
|
|
8029
7400
|
if (resolvedMorphTargets.left.length || resolvedMorphTargets.right.length) {
|
|
8030
7401
|
this.applyMorphTargets(resolvedMorphTargets.left, leftVal);
|
|
@@ -8033,7 +7404,7 @@ var _Embody = class _Embody {
|
|
|
8033
7404
|
this.applyMorphTargets(resolvedMorphTargets.center, base);
|
|
8034
7405
|
} else if (leftKeys.length || rightKeys.length || centerKeys.length) {
|
|
8035
7406
|
const mixWeight = this.isMixedAU(id) ? this.getAUMixWeight(id) : 1;
|
|
8036
|
-
const base =
|
|
7407
|
+
const base = clamp012(v) * mixWeight;
|
|
8037
7408
|
const meshNames = this.getMeshNamesForAU(id);
|
|
8038
7409
|
const { left: leftVal, right: rightVal } = this.computeSideValues(base, balance);
|
|
8039
7410
|
if (leftKeys.length || rightKeys.length) {
|
|
@@ -8052,6 +7423,7 @@ var _Embody = class _Embody {
|
|
|
8052
7423
|
}
|
|
8053
7424
|
}
|
|
8054
7425
|
}
|
|
7426
|
+
if (appliedViaFrame) return;
|
|
8055
7427
|
const compositeInfo = this.auToCompositeMap.get(id);
|
|
8056
7428
|
if (compositeInfo) {
|
|
8057
7429
|
for (const nodeKey of compositeInfo.nodes) {
|
|
@@ -8086,7 +7458,7 @@ var _Embody = class _Embody {
|
|
|
8086
7458
|
return this.transitionContinuum(negAU, posAU, continuumValue, durationMs, balance);
|
|
8087
7459
|
}
|
|
8088
7460
|
}
|
|
8089
|
-
const target =
|
|
7461
|
+
const target = clamp012(to);
|
|
8090
7462
|
if (balance !== void 0) {
|
|
8091
7463
|
this.auBalances[numId] = balance;
|
|
8092
7464
|
}
|
|
@@ -8097,6 +7469,19 @@ var _Embody = class _Embody {
|
|
|
8097
7469
|
const base = target * mixWeight;
|
|
8098
7470
|
const { left: leftVal, right: rightVal } = this.computeSideValues(base, storedBalance);
|
|
8099
7471
|
this.auValues[numId] = target;
|
|
7472
|
+
if (this.wasmRuntimeCore) {
|
|
7473
|
+
this.wasmRuntimeCore.transitionAU(
|
|
7474
|
+
numId,
|
|
7475
|
+
target,
|
|
7476
|
+
durationMs,
|
|
7477
|
+
balance ?? this.auBalances[numId] ?? Number.NaN
|
|
7478
|
+
);
|
|
7479
|
+
this.update(0);
|
|
7480
|
+
if (durationMs <= 0) {
|
|
7481
|
+
this.applyLiveFrameDelta();
|
|
7482
|
+
}
|
|
7483
|
+
return RESOLVED_TRANSITION_HANDLE;
|
|
7484
|
+
}
|
|
8100
7485
|
const handles = [];
|
|
8101
7486
|
const meshNames = this.getMeshNamesForAU(numId);
|
|
8102
7487
|
if (leftKeys.length || rightKeys.length) {
|
|
@@ -8159,6 +7544,17 @@ var _Embody = class _Embody {
|
|
|
8159
7544
|
*/
|
|
8160
7545
|
setContinuum(negAU, posAU, continuumValue, balance) {
|
|
8161
7546
|
const value = Math.max(-1, Math.min(1, continuumValue));
|
|
7547
|
+
this.auValues[negAU] = value < 0 ? Math.abs(value) : 0;
|
|
7548
|
+
this.auValues[posAU] = value > 0 ? value : 0;
|
|
7549
|
+
if (balance !== void 0) {
|
|
7550
|
+
this.auBalances[negAU] = balance;
|
|
7551
|
+
this.auBalances[posAU] = balance;
|
|
7552
|
+
}
|
|
7553
|
+
if (this.wasmRuntimeCore) {
|
|
7554
|
+
this.wasmRuntimeCore.setContinuum(negAU, posAU, value, balance ?? 0);
|
|
7555
|
+
this.applyLiveFrameDelta();
|
|
7556
|
+
return;
|
|
7557
|
+
}
|
|
8162
7558
|
if (value < 0) {
|
|
8163
7559
|
this.setAU(posAU, 0, balance);
|
|
8164
7560
|
this.setAU(negAU, Math.abs(value), balance);
|
|
@@ -8184,10 +7580,32 @@ var _Embody = class _Embody {
|
|
|
8184
7580
|
*/
|
|
8185
7581
|
transitionContinuum(negAU, posAU, continuumValue, durationMs = 200, balance) {
|
|
8186
7582
|
const target = Math.max(-1, Math.min(1, continuumValue));
|
|
8187
|
-
const driverKey = `continuum_${negAU}_${posAU}`;
|
|
8188
7583
|
const currentNeg = this.auValues[negAU] ?? 0;
|
|
8189
7584
|
const currentPos = this.auValues[posAU] ?? 0;
|
|
8190
7585
|
const currentContinuum = currentPos - currentNeg;
|
|
7586
|
+
this.auValues[negAU] = target < 0 ? Math.abs(target) : 0;
|
|
7587
|
+
this.auValues[posAU] = target > 0 ? target : 0;
|
|
7588
|
+
if (balance !== void 0) {
|
|
7589
|
+
this.auBalances[negAU] = balance;
|
|
7590
|
+
this.auBalances[posAU] = balance;
|
|
7591
|
+
}
|
|
7592
|
+
if (this.wasmRuntimeCore) {
|
|
7593
|
+
if (target < 0) {
|
|
7594
|
+
this.wasmRuntimeCore.transitionAU(posAU, 0, durationMs, balance ?? this.auBalances[posAU] ?? Number.NaN);
|
|
7595
|
+
this.wasmRuntimeCore.transitionAU(negAU, Math.abs(target), durationMs, balance ?? this.auBalances[negAU] ?? Number.NaN);
|
|
7596
|
+
} else if (target > 0) {
|
|
7597
|
+
this.wasmRuntimeCore.transitionAU(negAU, 0, durationMs, balance ?? this.auBalances[negAU] ?? Number.NaN);
|
|
7598
|
+
this.wasmRuntimeCore.transitionAU(posAU, target, durationMs, balance ?? this.auBalances[posAU] ?? Number.NaN);
|
|
7599
|
+
} else {
|
|
7600
|
+
this.wasmRuntimeCore.transitionAU(negAU, 0, durationMs, balance ?? this.auBalances[negAU] ?? Number.NaN);
|
|
7601
|
+
this.wasmRuntimeCore.transitionAU(posAU, 0, durationMs, balance ?? this.auBalances[posAU] ?? Number.NaN);
|
|
7602
|
+
}
|
|
7603
|
+
if (durationMs <= 0) {
|
|
7604
|
+
this.applyLiveFrameDelta();
|
|
7605
|
+
}
|
|
7606
|
+
return RESOLVED_TRANSITION_HANDLE;
|
|
7607
|
+
}
|
|
7608
|
+
const driverKey = `continuum_${negAU}_${posAU}`;
|
|
8191
7609
|
return this.animation.addTransition(driverKey, currentContinuum, target, durationMs, (value) => this.setContinuum(negAU, posAU, value, balance));
|
|
8192
7610
|
}
|
|
8193
7611
|
// ============================================================================
|
|
@@ -8269,7 +7687,7 @@ var _Embody = class _Embody {
|
|
|
8269
7687
|
this.hairPhysics.refreshMeshSelection();
|
|
8270
7688
|
}
|
|
8271
7689
|
setMorph(key, v, meshNamesOrTargets) {
|
|
8272
|
-
const val =
|
|
7690
|
+
const val = clamp012(v);
|
|
8273
7691
|
if (Array.isArray(meshNamesOrTargets) && meshNamesOrTargets.length > 0 && typeof meshNamesOrTargets[0] === "object" && "infl" in meshNamesOrTargets[0]) {
|
|
8274
7692
|
const targets2 = meshNamesOrTargets;
|
|
8275
7693
|
this.applyMorphTargets(targets2, val);
|
|
@@ -8281,7 +7699,7 @@ var _Embody = class _Embody {
|
|
|
8281
7699
|
this.applyMorphTargets(targets, val);
|
|
8282
7700
|
}
|
|
8283
7701
|
setMorphInfluence(index, v, meshNames) {
|
|
8284
|
-
const val =
|
|
7702
|
+
const val = clamp012(v);
|
|
8285
7703
|
const targets = this.resolveMorphTargetsByIndex(index, meshNames);
|
|
8286
7704
|
if (targets.length === 0) return;
|
|
8287
7705
|
this.applyMorphTargets(targets, val);
|
|
@@ -8356,21 +7774,21 @@ var _Embody = class _Embody {
|
|
|
8356
7774
|
}
|
|
8357
7775
|
transitionMorph(key, to, durationMs = 120, meshNames) {
|
|
8358
7776
|
const transitionKey = meshNames?.length ? `morph_${this.getMorphKeyCacheKey(key, meshNames)}` : `morph_${this.getMorphKeyCacheKey(key)}`;
|
|
8359
|
-
const target =
|
|
7777
|
+
const target = clamp012(to);
|
|
8360
7778
|
const targets = this.resolveMorphTargets(key, meshNames);
|
|
8361
7779
|
const from = targets.length > 0 ? targets[0].infl[targets[0].idx] ?? 0 : this.getMorphValue(key);
|
|
8362
7780
|
return this.animation.addTransition(transitionKey, from, target, durationMs, (value) => {
|
|
8363
|
-
const val =
|
|
7781
|
+
const val = clamp012(value);
|
|
8364
7782
|
this.applyMorphTargets(targets, val);
|
|
8365
7783
|
});
|
|
8366
7784
|
}
|
|
8367
7785
|
transitionMorphInfluence(index, to, durationMs = 120, meshNames) {
|
|
8368
7786
|
const transitionKey = meshNames?.length ? `morph_${this.getMorphIndexCacheKey(index, meshNames)}` : `morph_${this.getMorphIndexCacheKey(index)}`;
|
|
8369
|
-
const target =
|
|
7787
|
+
const target = clamp012(to);
|
|
8370
7788
|
const targets = this.resolveMorphTargetsByIndex(index, meshNames);
|
|
8371
7789
|
const from = targets.length > 0 ? targets[0].infl[targets[0].idx] ?? 0 : this.getMorphValueByIndex(index);
|
|
8372
7790
|
return this.animation.addTransition(transitionKey, from, target, durationMs, (value) => {
|
|
8373
|
-
const val =
|
|
7791
|
+
const val = clamp012(value);
|
|
8374
7792
|
this.applyMorphTargets(targets, val);
|
|
8375
7793
|
});
|
|
8376
7794
|
}
|
|
@@ -8379,7 +7797,7 @@ var _Embody = class _Embody {
|
|
|
8379
7797
|
// ============================================================================
|
|
8380
7798
|
setViseme(visemeIndex, value, jawScale = 1) {
|
|
8381
7799
|
if (visemeIndex < 0 || visemeIndex >= this.visemeValues.length) return;
|
|
8382
|
-
const val =
|
|
7800
|
+
const val = clamp012(value);
|
|
8383
7801
|
this.visemeValues[visemeIndex] = val;
|
|
8384
7802
|
this.visemeJawScales[visemeIndex] = jawScale;
|
|
8385
7803
|
this.applyVisemeRuntimeState();
|
|
@@ -8391,16 +7809,24 @@ var _Embody = class _Embody {
|
|
|
8391
7809
|
}, cancel: () => {
|
|
8392
7810
|
} };
|
|
8393
7811
|
}
|
|
8394
|
-
const target =
|
|
7812
|
+
const target = clamp012(to);
|
|
8395
7813
|
const from = this.visemeValues[visemeIndex] ?? 0;
|
|
8396
7814
|
this.visemeJawScales[visemeIndex] = jawScale;
|
|
7815
|
+
if (this.wasmRuntimeCore) {
|
|
7816
|
+
this.visemeValues[visemeIndex] = target;
|
|
7817
|
+
this.wasmRuntimeCore.transitionViseme(visemeIndex, target, durationMs, jawScale);
|
|
7818
|
+
if (durationMs <= 0) {
|
|
7819
|
+
this.applyLiveFrameDelta();
|
|
7820
|
+
}
|
|
7821
|
+
return RESOLVED_TRANSITION_HANDLE;
|
|
7822
|
+
}
|
|
8397
7823
|
return this.animation.addTransition(
|
|
8398
7824
|
`viseme_value_${visemeIndex}`,
|
|
8399
7825
|
from,
|
|
8400
7826
|
target,
|
|
8401
7827
|
durationMs,
|
|
8402
7828
|
(value) => {
|
|
8403
|
-
this.visemeValues[visemeIndex] =
|
|
7829
|
+
this.visemeValues[visemeIndex] = clamp012(value);
|
|
8404
7830
|
this.visemeJawScales[visemeIndex] = jawScale;
|
|
8405
7831
|
this.applyVisemeRuntimeState();
|
|
8406
7832
|
}
|
|
@@ -8425,8 +7851,7 @@ var _Embody = class _Embody {
|
|
|
8425
7851
|
// MIX WEIGHT CONTROL
|
|
8426
7852
|
// ============================================================================
|
|
8427
7853
|
setAUMixWeight(id, weight) {
|
|
8428
|
-
this.mixWeights[id] =
|
|
8429
|
-
this.tsRuntimeCore?.setAUMixWeight(id, weight);
|
|
7854
|
+
this.mixWeights[id] = clamp012(weight);
|
|
8430
7855
|
this.wasmRuntimeCore?.setAUMixWeight(id, weight);
|
|
8431
7856
|
const v = this.auValues[id] ?? 0;
|
|
8432
7857
|
if (v > 0) this.setAU(id, v);
|
|
@@ -8464,9 +7889,10 @@ var _Embody = class _Embody {
|
|
|
8464
7889
|
}
|
|
8465
7890
|
clearTransitions() {
|
|
8466
7891
|
this.animation.clearTransitions();
|
|
7892
|
+
this.wasmRuntimeCore?.clearTransitions();
|
|
8467
7893
|
}
|
|
8468
7894
|
getActiveTransitionCount() {
|
|
8469
|
-
return this.animation.getActiveTransitionCount();
|
|
7895
|
+
return this.animation.getActiveTransitionCount() + (this.wasmRuntimeCore?.activeTransitionCount() ?? 0);
|
|
8470
7896
|
}
|
|
8471
7897
|
resetToNeutral() {
|
|
8472
7898
|
this.auValues = {};
|
|
@@ -8476,6 +7902,7 @@ var _Embody = class _Embody {
|
|
|
8476
7902
|
this.translations = {};
|
|
8477
7903
|
this.initBoneRotations();
|
|
8478
7904
|
this.clearTransitions();
|
|
7905
|
+
this.wasmRuntimeCore?.clear();
|
|
8479
7906
|
const morphTargetsToReset = [];
|
|
8480
7907
|
for (const m of this.meshes) {
|
|
8481
7908
|
const infl = m.morphTargetInfluences;
|
|
@@ -8654,7 +8081,18 @@ var _Embody = class _Embody {
|
|
|
8654
8081
|
this.bones = this.resolveBones(this.model);
|
|
8655
8082
|
this.missingBoneWarnings.clear();
|
|
8656
8083
|
this.rebuildMorphTargetsCache();
|
|
8657
|
-
|
|
8084
|
+
Object.values(this.bones).forEach((entry) => {
|
|
8085
|
+
if (!entry) return;
|
|
8086
|
+
this.frameApplier.applyObjectTransform(entry.obj, {
|
|
8087
|
+
position: { x: entry.basePos.x, y: entry.basePos.y, z: entry.basePos.z },
|
|
8088
|
+
rotation: {
|
|
8089
|
+
x: entry.baseQuat.x,
|
|
8090
|
+
y: entry.baseQuat.y,
|
|
8091
|
+
z: entry.baseQuat.z,
|
|
8092
|
+
w: entry.baseQuat.w
|
|
8093
|
+
}
|
|
8094
|
+
});
|
|
8095
|
+
});
|
|
8658
8096
|
this.wasmRuntimeCore?.setProfile(this.config);
|
|
8659
8097
|
this.refreshHostNeutralModelDescriptor();
|
|
8660
8098
|
}
|
|
@@ -8771,20 +8209,20 @@ var _Embody = class _Embody {
|
|
|
8771
8209
|
}
|
|
8772
8210
|
applyVisemeRuntimeState() {
|
|
8773
8211
|
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
8774
|
-
this.
|
|
8775
|
-
this.wasmRuntimeCore?.setViseme(index, this.visemeValues[index] ?? 0);
|
|
8212
|
+
this.wasmRuntimeCore?.setViseme(index, this.visemeValues[index] ?? 0, this.visemeJawScales[index] ?? 1);
|
|
8776
8213
|
}
|
|
8777
|
-
|
|
8214
|
+
const appliedViaFrame = this.applyLiveFrameDelta();
|
|
8215
|
+
if (!appliedViaFrame) {
|
|
8778
8216
|
for (const targets of this.resolvedVisemeTargets) {
|
|
8779
8217
|
this.frameApplier.resetMorphTargets(targets || []);
|
|
8780
8218
|
}
|
|
8781
8219
|
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
8782
|
-
const value =
|
|
8220
|
+
const value = clamp012(this.visemeValues[index] ?? 0);
|
|
8783
8221
|
if (value <= 1e-6) continue;
|
|
8784
8222
|
const targets = this.resolvedVisemeTargets[index] || [];
|
|
8785
8223
|
for (const target of targets) {
|
|
8786
8224
|
if (target.idx >= target.infl.length) continue;
|
|
8787
|
-
const weighted =
|
|
8225
|
+
const weighted = clamp012(value * target.weight);
|
|
8788
8226
|
this.frameApplier.applyMorphTargets(
|
|
8789
8227
|
[target],
|
|
8790
8228
|
Math.max(target.infl[target.idx] ?? 0, weighted)
|
|
@@ -8792,7 +8230,9 @@ var _Embody = class _Embody {
|
|
|
8792
8230
|
}
|
|
8793
8231
|
}
|
|
8794
8232
|
}
|
|
8795
|
-
|
|
8233
|
+
if (!appliedViaFrame) {
|
|
8234
|
+
this.updateBoneRotation(this.getJawBoneNodeKey(), "pitch", this.getActiveVisemeJawAmount());
|
|
8235
|
+
}
|
|
8796
8236
|
}
|
|
8797
8237
|
getJawBoneNodeKey() {
|
|
8798
8238
|
const candidates = [
|
|
@@ -8814,7 +8254,7 @@ var _Embody = class _Embody {
|
|
|
8814
8254
|
getActiveVisemeJawAmount() {
|
|
8815
8255
|
let jawAmount = 0;
|
|
8816
8256
|
for (let index = 0; index < this.visemeValues.length; index += 1) {
|
|
8817
|
-
const value =
|
|
8257
|
+
const value = clamp012(this.visemeValues[index] ?? 0);
|
|
8818
8258
|
if (value <= 1e-6) continue;
|
|
8819
8259
|
const jawScale = this.visemeJawScales[index] ?? 1;
|
|
8820
8260
|
if (Math.abs(jawScale) <= 1e-6) continue;
|
|
@@ -9097,7 +8537,7 @@ var _Embody = class _Embody {
|
|
|
9097
8537
|
return !!(hasMorphs && this.config.auToBones[id]?.length);
|
|
9098
8538
|
}
|
|
9099
8539
|
getEffectiveBoneAUValue(auId, nodeKey) {
|
|
9100
|
-
const rawValue =
|
|
8540
|
+
const rawValue = clamp012(this.auValues[auId] ?? 0);
|
|
9101
8541
|
if (rawValue <= 1e-6) return 0;
|
|
9102
8542
|
const binding = this.config.auToBones[auId]?.find((candidate) => candidate.node === nodeKey) ?? null;
|
|
9103
8543
|
if (!binding?.side) return rawValue;
|
|
@@ -9197,7 +8637,7 @@ var _Embody = class _Embody {
|
|
|
9197
8637
|
if (config.yaw && rotState.yaw !== 0) {
|
|
9198
8638
|
const binding = this.getCompositeAxisBindingForNode(nodeKey, config.yaw, rotState.yaw);
|
|
9199
8639
|
if (binding?.maxDegrees && binding.channel) {
|
|
9200
|
-
const radians =
|
|
8640
|
+
const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.yaw) * binding.scale;
|
|
9201
8641
|
const axis = getAxis(binding.channel);
|
|
9202
8642
|
const deltaQ = new Quaternion().setFromAxisAngle(axis, radians);
|
|
9203
8643
|
compositeQ.multiply(deltaQ);
|
|
@@ -9206,7 +8646,7 @@ var _Embody = class _Embody {
|
|
|
9206
8646
|
if (config.pitch && rotState.pitch !== 0) {
|
|
9207
8647
|
const binding = this.getCompositeAxisBindingForNode(nodeKey, config.pitch, rotState.pitch);
|
|
9208
8648
|
if (binding?.maxDegrees && binding.channel) {
|
|
9209
|
-
const radians =
|
|
8649
|
+
const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.pitch) * binding.scale;
|
|
9210
8650
|
const axis = getAxis(binding.channel);
|
|
9211
8651
|
const deltaQ = new Quaternion().setFromAxisAngle(axis, radians);
|
|
9212
8652
|
compositeQ.multiply(deltaQ);
|
|
@@ -9215,7 +8655,7 @@ var _Embody = class _Embody {
|
|
|
9215
8655
|
if (config.roll && rotState.roll !== 0) {
|
|
9216
8656
|
const binding = this.getCompositeAxisBindingForNode(nodeKey, config.roll, rotState.roll);
|
|
9217
8657
|
if (binding?.maxDegrees && binding.channel) {
|
|
9218
|
-
const radians =
|
|
8658
|
+
const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.roll) * binding.scale;
|
|
9219
8659
|
const axis = getAxis(binding.channel);
|
|
9220
8660
|
const deltaQ = new Quaternion().setFromAxisAngle(axis, radians);
|
|
9221
8661
|
compositeQ.multiply(deltaQ);
|
|
@@ -10054,11 +9494,11 @@ function applyCharacterModelTransform(model, transform = {}) {
|
|
|
10054
9494
|
model.position.set(modelOffset.x ?? 0, modelOffset.y ?? 0, modelOffset.z ?? 0);
|
|
10055
9495
|
}
|
|
10056
9496
|
if (modelRotation) {
|
|
10057
|
-
const
|
|
9497
|
+
const deg2rad2 = Math.PI / 180;
|
|
10058
9498
|
model.rotation.set(
|
|
10059
|
-
(modelRotation.x ?? 0) *
|
|
10060
|
-
(modelRotation.y ?? 0) *
|
|
10061
|
-
(modelRotation.z ?? 0) *
|
|
9499
|
+
(modelRotation.x ?? 0) * deg2rad2,
|
|
9500
|
+
(modelRotation.y ?? 0) * deg2rad2,
|
|
9501
|
+
(modelRotation.z ?? 0) * deg2rad2
|
|
10062
9502
|
);
|
|
10063
9503
|
}
|
|
10064
9504
|
if (modelScale !== void 0 && Number.isFinite(modelScale) && modelScale > 0) {
|
|
@@ -15074,7 +14514,7 @@ function computeHumanoidSkeletonTemplateRestBounds(template) {
|
|
|
15074
14514
|
}
|
|
15075
14515
|
const parentPosition = worldPositions.get(bone.parent);
|
|
15076
14516
|
if (!parentPosition) continue;
|
|
15077
|
-
worldPositions.set(bone.name,
|
|
14517
|
+
worldPositions.set(bone.name, addVec3(parentPosition, bone.translation));
|
|
15078
14518
|
unresolved.delete(bone.name);
|
|
15079
14519
|
resolvedThisPass += 1;
|
|
15080
14520
|
}
|
|
@@ -15135,10 +14575,10 @@ function assertNonEmptyString(value, fieldName) {
|
|
|
15135
14575
|
throw new Error(`${fieldName} must be a non-empty string`);
|
|
15136
14576
|
}
|
|
15137
14577
|
}
|
|
15138
|
-
function
|
|
14578
|
+
function addVec3(a, b) {
|
|
15139
14579
|
return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];
|
|
15140
14580
|
}
|
|
15141
14581
|
|
|
15142
|
-
export { AU_INFO, AU_MAPPING_CONFIG, AU_MIX_DEFAULTS,
|
|
14582
|
+
export { AU_INFO, AU_MAPPING_CONFIG, AU_MIX_DEFAULTS, AU_TO_MORPHS, ThreeAnimationSystem as AnimationController, BETTA_FISH_PRESET, BLENDING_MODES, BONE_AU_TO_BINDINGS, ThreeAnimationSystem as BakedAnimationController, CC4_BONES, CC4_BONE_NODES, CC4_BONE_PREFIX, CC4_EYE_MESH_NODES, CC4_MAPPING_SECTIONS, CC4_MESHES, CC4_PRESET, CC4_PROFILE_BONE_BINDINGS, CC4_SUFFIX_PATTERN, CC4_VISEME_SLOTS, CC4_VISEME_SYSTEM_ID, CHARACTER_SCENE_TYPES, CHARACTER_SCENE_TYPE_IDS, COMPOSITE_ROTATIONS, CONTINUUM_LABELS, CONTINUUM_PAIRS_MAP, DEFAULT_AXIS_TO_CHANNEL, DEFAULT_BONE_MAX_DEGREES, DEFAULT_CHARACTER_LIGHTING_PRESETS, DEFAULT_CHARACTER_LIGHTING_PRESET_ID, DEFAULT_CHARACTER_LIGHTING_PRESET_IDS, DEFAULT_CHARACTER_LIGHTING_SETTINGS, DEFAULT_CHARACTER_SCENE_TYPE_ID, DEFAULT_HAIR_COLOR_APPEARANCE, DEFAULT_HAIR_PHYSICS_CONFIG, Embody, FISH_AU_MAPPING_CONFIG, HAIR_COLOR_PRESETS, HUMANOID_SKELETON_TEMPLATES, HairPhysics, HairPhysicsController, JOINT_CONTROL_SECTION, JONATHAN_HUMANOID_SKELETON_TEMPLATE, LIP_SYNC_CONTROL_TO_BINDINGS, MORPH_TO_MESH, RustAnnotationCameraCore, RustCameraFlight, RustCameraOrbit, RustHairPhysics, TEMPLATE_SKELETON_FIT_METADATA_KIND, TEMPLATE_SKELETON_FIT_METADATA_VERSION, TEMPLATE_SKELETON_FIT_STATUSES, TEMPLATE_SKELETON_FIT_VERTICAL_ANCHORS, TEMPLATE_SKELETON_FIT_VERTICAL_AXES, THREE_BLENDING_MODES, ThreeAnimationRuntime, ThreeAnimationSystem, ThreeClipAdapter, ThreeFrameApplier, ThreeModelInspector, TsClipCompiler, VISEME_JAW_AMOUNTS, VISEME_KEYS, WasmRuntimeCore, analyzeModel, applyAUBoneBindingUpdate, applyBilateralAxisBindingUpdate, applyBoneAxisBindingUpdate, applyCharacterModelTransform, applyCharacterProfileToPreset, buildBoneAuOptions, buildFrameApplierBindings, buildMappingEditorModel, classifyAuAsJointControl, collectMorphMeshes2 as collectMorphMeshes, compileVisemeKeys, composeTemplateSkeletonFitTransform, computeCameraRelativeGazeOffset, computeHumanoidSkeletonTemplateRestBounds, createBilateralBoneAxisAu, createBoneAxisAu, createCharacterHost, createDefaultCharacterLighting, createDefaultCharacterScene, createRustAnnotationCameraCore, createRustHairPhysics, createShadowPlane, createValidationSkeletonFromHumanoidTemplate, detectAnnotationLaterality, detectFacingDirection, disposeCharacterModel, ensureBilateralBoneNodeKeys, ensureBoneNodeKey, extendCharacterConfigWithPreset, extendPresetWithProfile, extendProfileConfigWithPreset, extractFromGLTF, extractHumanoidSkeletonTemplateFromModel, extractLegacyCharacterProfileOverrides, extractModelData, extractProfileOverrides, findFaceCenter, findNodeKeyForBone, formatAxisDirectionLabel, formatAxisLabel, fuzzyNameMatch, generateMappingCorrections, getAUBoneBindingState, getAxisFromChannel, getBilateralAxisBindingState, getBoneAxisBindingState, getDefaultAnnotationLaterality, getHumanoidSkeletonTemplate, getHumanoidSkeletonTemplateBoneNames, getMeshNamesForAUProfile, getMeshNamesForVisemeProfile, getModelForwardDirection, getModelLocalOrbitAngle, getPreset, getPresetWithProfile, getProfilePresetId, getProfileVisemeSlots, getRegionSemanticSide, getSemanticHorizontalSign, getSemanticHorizontalSignForSide, getVisemeBindingTargets, getVisemeJawAmounts, getVisemeSlotIndex, getWorldDirectionForCameraAngle, hasLeftRightMorphs, inferChiralBoneNamePair, inferEyeControlFamily, inferEyeControlScope, isJointControlAuInfo, isMaxDegreesOnlyAxisBindingUpdate, isMixedAU, isPresetCompatible, isTemplateSkeletonFitStatus, loadCharacterModel, mapProviderVisemeToSlot, mergeRegionsByName as mergeCharacterRegionsByName, mergePresetWithProfile, mergeProfileRegionsByName, normalizeCameraAngle, normalizeDefaultCharacterLightingSettings, normalizeHairColorAppearance, numericArrayToNumbers, packHairConfig, packHeadState, parseCharacterModel, passesMarkerCameraAngleGate, resolveBoneAxisChannel, resolveBoneName, resolveBoneNameForNodeKey, resolveBoneNames, resolveContinuumDisplayLabel, resolveFaceCenter, resolvePreset, resolvePresetWithOverrides, resolveProfileFromPreset, resolveRegionCameraAngle, resolveRegionVisibilityCameraAngle, resolveRustEmbeddedProfileView, resolveRustProfileView, resolveVisemeMeshCategory, stripConfiguredBoneAffixes, suggestBestPreset, toModelLocalDirection2 as toModelLocalDirection, toWorldDirection, unpackBoneFrameDelta, unpackHairConfig, unpackHairMorphOutput, unpackHairState, unpackMorphFrameDelta, validateMappingConfig, validateMappings, validateTemplateSkeletonFitMetadata };
|
|
15143
14583
|
//# sourceMappingURL=index.js.map
|
|
15144
14584
|
//# sourceMappingURL=index.js.map
|