@lovelace_lol/embody 0.0.9 → 0.0.10

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.
@@ -1,5 +1,10 @@
1
1
  import type { AnimationClip } from 'three';
2
2
  import type { ClipIRTrack, ThreeModelInspection } from './index';
3
+ /**
4
+ * Packed morphs must share PropertyMixers with indexed compiled tracks. Euler
5
+ * components avoid Euler.fromArray's incompatible mixer-buffer offset/order.
6
+ */
7
+ export declare function withComponentTracks(clip: AnimationClip): AnimationClip;
3
8
  /** One PropertyMixer cache key for every concrete renderer destination. */
4
9
  export declare function concreteTrackName(target: ClipIRTrack['target'] | undefined, inspection: ThreeModelInspection): string | undefined;
5
10
  /** Retain authored samples and interpolants; normalize only cloned binding names. */
package/dist/three.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as THREE3 from 'three';
2
- import { NoBlending, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NormalBlending, Vector3, Box3, Timer, Matrix4, AnimationMixer, AdditiveAnimationBlendMode, NormalAnimationBlendMode, LoopOnce, LoopRepeat, LoopPingPong, PropertyBinding, Quaternion, AnimationUtils, InterpolateDiscrete, InterpolateLinear, MathUtils, Mesh, PlaneGeometry, ShadowMaterial, HemisphereLight, DirectionalLight, SRGBColorSpace, ACESFilmicToneMapping, WebGLRenderer, Scene, Color, PerspectiveCamera, PCFShadowMap, PCFSoftShadowMap, NumberKeyframeTrack, QuaternionKeyframeTrack, VectorKeyframeTrack, AnimationClip, PMREMGenerator, FloatType, Float32BufferAttribute, Euler, BufferAttribute, WebGPUCoordinateSystem, WebGLCoordinateSystem } from 'three';
2
+ import { NoBlending, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NormalBlending, Vector3, Box3, Timer, Matrix4, AnimationMixer, AdditiveAnimationBlendMode, NormalAnimationBlendMode, LoopOnce, LoopRepeat, LoopPingPong, PropertyBinding, Euler, Quaternion, AnimationUtils, InterpolateDiscrete, InterpolateLinear, MathUtils, Mesh, PlaneGeometry, ShadowMaterial, HemisphereLight, DirectionalLight, SRGBColorSpace, ACESFilmicToneMapping, WebGLRenderer, Scene, Color, PerspectiveCamera, PCFShadowMap, PCFSoftShadowMap, NumberKeyframeTrack, QuaternionKeyframeTrack, VectorKeyframeTrack, AnimationClip, PMREMGenerator, FloatType, Float32BufferAttribute, BufferAttribute, WebGPUCoordinateSystem, WebGLCoordinateSystem } from 'three';
3
3
  import { CC4_HUMANOID_SKELETON_TEMPLATE, HUMANOID_SKELETON_TEMPLATES, DEFAULT_HAIR_COLOR_APPEARANCE, initEmbodyCore, requireInitializedEmbodyCore } from '@lovelace_lol/embody/wasm';
4
4
  export { CC4_HUMANOID_SKELETON_TEMPLATE, DEFAULT_AXIS_TO_CHANNEL, DEFAULT_BONE_MAX_DEGREES, DEFAULT_HAIR_COLOR_APPEARANCE, HAIR_COLOR_PRESETS, HUMANOID_SKELETON_TEMPLATES, JOINT_CONTROL_SECTION, VISEME_KEYS } from '@lovelace_lol/embody/wasm';
5
5
  import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
@@ -6732,8 +6732,30 @@ function bindModelReferencePose(model, referencePose) {
6732
6732
  if (index !== referencePose.nodes.length) throw new Error("Incompatible reference pose hierarchy: extra captured nodes");
6733
6733
  return bindings2;
6734
6734
  }
6735
-
6736
- // three/clipBindings.ts
6735
+ function withComponentTracks(clip) {
6736
+ let expanded = false;
6737
+ const tracks = clip.tracks.flatMap((track) => {
6738
+ const parsed = PropertyBinding.parseTrackName(track.name);
6739
+ const euler = parsed.propertyName === "rotation";
6740
+ if (!euler && !["morphTargetInfluences", "weights"].includes(parsed.propertyName) || parsed.propertyIndex !== void 0) return [track];
6741
+ const cubic = track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline === true;
6742
+ const parts = cubic ? 3 : 1;
6743
+ const width = track.getValueSize() / parts;
6744
+ if (!Number.isInteger(width) || width < 1 || euler && width !== 3) throw new Error(`Invalid component track ${JSON.stringify(track.name)}.`);
6745
+ expanded = true;
6746
+ return Array.from({ length: width }, (_, component) => {
6747
+ const scalar = track.clone();
6748
+ scalar.name = `${track.name}[${euler ? ["x", "y", "z"][component] : component}]`;
6749
+ scalar.values = track.values.slice(0, track.times.length * parts);
6750
+ for (let sample = 0; sample < scalar.values.length; sample += 1) scalar.values[sample] = track.values[sample * width + component];
6751
+ return scalar;
6752
+ });
6753
+ });
6754
+ if (!expanded) return clip;
6755
+ const indexed = clip.clone();
6756
+ indexed.tracks = tracks;
6757
+ return indexed;
6758
+ }
6737
6759
  function concreteTrackName(target, inspection) {
6738
6760
  if (!target) return void 0;
6739
6761
  if (target.kind === "morphTarget") {
@@ -6745,6 +6767,7 @@ function concreteTrackName(target, inspection) {
6745
6767
  const property = target.property ?? "rotation";
6746
6768
  if (!object) return void 0;
6747
6769
  if (property === "rotation" || property === "quaternion") return `${object.uuid}.quaternion`;
6770
+ if (property === "eulerX" || property === "eulerY" || property === "eulerZ") return `${object.uuid}.rotation[${property.slice(-1).toLowerCase()}]`;
6748
6771
  if (property === "position" || property === "scale") return `${object.uuid}.${property}`;
6749
6772
  }
6750
6773
  if (target.kind === "meshVisibility") {
@@ -6855,6 +6878,7 @@ var ThreeNativePlaybackConnector = class {
6855
6878
  */
6856
6879
  playNativeClip(clip, options = {}) {
6857
6880
  this.beforeOperation();
6881
+ clip = withComponentTracks(clip);
6858
6882
  const [ir] = serializeAnimationClips(this.binding.model, [clip], this.binding.inspection);
6859
6883
  if (ir.tracks.length !== clip.tracks.length) {
6860
6884
  throw new Error("Every native playback track must serialize against the bound model.");
@@ -6902,6 +6926,7 @@ var ThreeNativePlaybackConnector = class {
6902
6926
  /** Edit authored samples, retaining the native action and its loop/fade progress. */
6903
6927
  replaceClip(handle, clip) {
6904
6928
  this.beforeOperation();
6929
+ clip = withComponentTracks(clip);
6905
6930
  const resource = this.resources.get(handle);
6906
6931
  if (!resource) throw new Error("Unknown, foreign or stale playback handle.");
6907
6932
  const [ir] = serializeAnimationClips(this.binding.model, [clip], this.binding.inspection);
@@ -7410,10 +7435,17 @@ var Embody = class _Embody {
7410
7435
  switch (parsed.propertyName) {
7411
7436
  case "quaternion":
7412
7437
  return Object.values(reference.transform.rotation);
7438
+ case "rotation": {
7439
+ const rotation = reference.transform.rotation;
7440
+ const euler = reference.rotationEuler ?? new Euler().setFromQuaternion(new Quaternion(rotation.x, rotation.y, rotation.z, rotation.w), reference.rotationOrder);
7441
+ const axis = parsed.propertyIndex;
7442
+ return axis === "x" || axis === "y" || axis === "z" ? [euler[axis]] : [euler.x, euler.y, euler.z];
7443
+ }
7413
7444
  case "position":
7414
7445
  return Object.values(reference.transform.position);
7415
7446
  case "scale":
7416
7447
  return Object.values(reference.transform.scale);
7448
+ case "weights":
7417
7449
  case "morphTargetInfluences": {
7418
7450
  const mesh = object;
7419
7451
  const index = typeof parsed.propertyIndex === "string" && !/^\d+$/.test(parsed.propertyIndex) ? mesh.morphTargetDictionary?.[parsed.propertyIndex] : Number(parsed.propertyIndex);
@@ -7430,7 +7462,7 @@ var Embody = class _Embody {
7430
7462
  if (!nativeSource) {
7431
7463
  ir = this.compile(source, options);
7432
7464
  }
7433
- const clip = nativeSource ? source.clip.clone() : createAnimationClipFromClipIR(ir, this.inspection);
7465
+ const clip = nativeSource ? withComponentTracks(source.clip).clone() : createAnimationClipFromClipIR(ir, this.inspection);
7434
7466
  if (ir) {
7435
7467
  const predecessor = this.current.get(source.name);
7436
7468
  const outgoing = predecessor?.connector.getAction(predecessor.id);
@@ -9589,6 +9621,10 @@ function createAnimationClipFromClipIR(clip, inspection) {
9589
9621
  if (property === "rotation" || property === "quaternion") {
9590
9622
  if (track.inheritStart) object.quaternion.toArray(values, 0);
9591
9623
  tracks.push(new QuaternionKeyframeTrack(trackName, times, values, interpolation));
9624
+ } else if (property === "eulerX" || property === "eulerY" || property === "eulerZ") {
9625
+ const axis = property.slice(-1).toLowerCase();
9626
+ if (track.inheritStart) values[0] = object.rotation[axis];
9627
+ tracks.push(new NumberKeyframeTrack(trackName, times, values, interpolation));
9592
9628
  } else if (property === "position") {
9593
9629
  if (track.inheritStart) object.position.toArray(values, 0);
9594
9630
  tracks.push(new VectorKeyframeTrack(trackName, times, values, interpolation));
@@ -9622,7 +9658,7 @@ function serializeAnimationClips(model, clips, inspection) {
9622
9658
  channelKinds.set(kind, id);
9623
9659
  return id;
9624
9660
  };
9625
- clip.tracks.forEach((track, index) => {
9661
+ withComponentTracks(clip).tracks.forEach((track, index) => {
9626
9662
  const found = findTrackTarget(model, track);
9627
9663
  if (!found?.object) return;
9628
9664
  const { parsed, object } = found;
@@ -9637,7 +9673,7 @@ function serializeAnimationClips(model, clips, inspection) {
9637
9673
  } else if (property === "visible" && object.isMesh) {
9638
9674
  target = { kind: "meshVisibility", meshId: meshIds.get(object) };
9639
9675
  } else {
9640
- const transformProperty = property === "quaternion" || property === "rotation" ? "rotation" : property === "position" ? "position" : property === "scale" ? "scale" : null;
9676
+ const transformProperty = property === "rotation" && ["x", "y", "z"].includes(String(parsed.propertyIndex)) ? `euler${String(parsed.propertyIndex).toUpperCase()}` : property === "quaternion" ? "rotation" : property === "position" ? "position" : property === "scale" ? "scale" : null;
9641
9677
  if (transformProperty) {
9642
9678
  const boneId = boneIds.get(object);
9643
9679
  target = boneId ? { kind: "boneTransform", boneId, property: transformProperty } : { kind: "objectTransform", objectId: objectIds.get(object), property: transformProperty };