1
0

VRMAnimation.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import * as THREE from "three";
  2. import { VRM, VRMExpressionManager, VRMHumanBoneName } from "@pixiv/three-vrm";
  3. export class VRMAnimation {
  4. public duration: number;
  5. public restHipsPosition: THREE.Vector3;
  6. public humanoidTracks: {
  7. translation: Map<VRMHumanBoneName, THREE.VectorKeyframeTrack>;
  8. rotation: Map<VRMHumanBoneName, THREE.VectorKeyframeTrack>;
  9. };
  10. public expressionTracks: Map<string, THREE.NumberKeyframeTrack>;
  11. public lookAtTrack: THREE.QuaternionKeyframeTrack | null;
  12. public constructor() {
  13. this.duration = 0.0;
  14. this.restHipsPosition = new THREE.Vector3();
  15. this.humanoidTracks = {
  16. translation: new Map(),
  17. rotation: new Map(),
  18. };
  19. this.expressionTracks = new Map();
  20. this.lookAtTrack = null;
  21. }
  22. public createAnimationClip(vrm: VRM): THREE.AnimationClip {
  23. const tracks: THREE.KeyframeTrack[] = [];
  24. tracks.push(...this.createHumanoidTracks(vrm));
  25. if (vrm.expressionManager != null) {
  26. tracks.push(...this.createExpressionTracks(vrm.expressionManager));
  27. }
  28. if (vrm.lookAt != null) {
  29. const track = this.createLookAtTrack("lookAtTargetParent.quaternion");
  30. if (track != null) {
  31. tracks.push(track);
  32. }
  33. }
  34. return new THREE.AnimationClip("Clip", this.duration, tracks);
  35. }
  36. public createHumanoidTracks(vrm: VRM): THREE.KeyframeTrack[] {
  37. const humanoid = vrm.humanoid;
  38. const metaVersion = vrm.meta.metaVersion;
  39. const tracks: THREE.KeyframeTrack[] = [];
  40. for (const [name, origTrack] of this.humanoidTracks.rotation.entries()) {
  41. const nodeName = humanoid.getNormalizedBoneNode(name)?.name;
  42. if (nodeName != null) {
  43. const newValues: number[] = [];
  44. const metaVersionZero = metaVersion === "0";
  45. let sign = metaVersionZero ? -1 : 1;
  46. let opposite = metaVersionZero ? 1 : 1;
  47. let prevQuaternion = new THREE.Quaternion();
  48. if (origTrack.values.length % 4 !== 0) {
  49. throw new Error("Invalid origTrack values length");
  50. }
  51. for (let i = 0; i < origTrack.values.length; i += 4) {
  52. const quaternion = new THREE.Quaternion(
  53. origTrack.values[i],
  54. origTrack.values[i + 1],
  55. origTrack.values[i + 2],
  56. origTrack.values[i + 3]
  57. );
  58. if (prevQuaternion.dot(quaternion) < 0 && metaVersionZero) {
  59. sign *= -1;
  60. opposite *= -1;
  61. }
  62. newValues.push(
  63. sign * origTrack.values[i],
  64. opposite * origTrack.values[i + 1],
  65. sign * origTrack.values[i + 2],
  66. opposite * origTrack.values[i + 3]
  67. );
  68. prevQuaternion = quaternion;
  69. }
  70. const track = origTrack.clone();
  71. track.values = new Float32Array(newValues);
  72. track.name = `${nodeName}.quaternion`;
  73. /*
  74. const track = new THREE.VectorKeyframeTrack(
  75. `${nodeName}.quaternion`,
  76. origTrack.times,
  77. origTrack.values.map((v, i) =>
  78. metaVersion === "0" && i % 2 === 0 ? -v : v
  79. )
  80. );
  81. */
  82. tracks.push(track);
  83. }
  84. }
  85. for (const [name, origTrack] of this.humanoidTracks.translation.entries()) {
  86. const nodeName = humanoid.getNormalizedBoneNode(name)?.name;
  87. if (nodeName != null) {
  88. const animationY = this.restHipsPosition.y;
  89. const humanoidY =
  90. humanoid.getNormalizedAbsolutePose().hips!.position![1];
  91. const scale = humanoidY / animationY;
  92. const track = origTrack.clone();
  93. track.values = track.values.map(
  94. (v, i) => (metaVersion === "0" && i % 3 !== 1 ? -v : v) * scale
  95. );
  96. track.name = `${nodeName}.position`;
  97. tracks.push(track);
  98. }
  99. }
  100. return tracks;
  101. }
  102. public createExpressionTracks(
  103. expressionManager: VRMExpressionManager
  104. ): THREE.KeyframeTrack[] {
  105. const tracks: THREE.KeyframeTrack[] = [];
  106. for (const [name, origTrack] of this.expressionTracks.entries()) {
  107. const trackName = expressionManager.getExpressionTrackName(name);
  108. if (trackName != null) {
  109. const track = origTrack.clone();
  110. track.name = trackName;
  111. tracks.push(track);
  112. }
  113. }
  114. return tracks;
  115. }
  116. public createLookAtTrack(trackName: string): THREE.KeyframeTrack | null {
  117. if (this.lookAtTrack == null) {
  118. return null;
  119. }
  120. const track = this.lookAtTrack.clone();
  121. track.name = trackName;
  122. return track;
  123. }
  124. }