SceneBuilder.Animations.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using BabylonExport.Entities;
  6. using UnityEditor;
  7. using UnityEditor.Animations;
  8. using UnityEngine;
  9. namespace Unity3D2Babylon
  10. {
  11. partial class SceneBuilder
  12. {
  13. private static void ExportAnimations(Transform transform, BabylonIAnimatable animatable)
  14. {
  15. var animator = transform.gameObject.GetComponent<Animator>();
  16. if (animator != null)
  17. {
  18. AnimatorController ac = animator.runtimeAnimatorController as AnimatorController;
  19. if (ac == null)
  20. {
  21. return;
  22. }
  23. var layer = ac.layers[0];
  24. if (layer == null)
  25. {
  26. return;
  27. }
  28. AnimatorStateMachine sm = layer.stateMachine;
  29. if (sm.states.Length > 0)
  30. {
  31. var state = sm.states[0].state; // We only support the first one
  32. AnimationClip clip = state.motion as AnimationClip;
  33. if (clip != null)
  34. {
  35. ExportAnimationClip(clip, true, animatable);
  36. }
  37. }
  38. }
  39. else
  40. {
  41. var animation = transform.gameObject.GetComponent<Animation>();
  42. if (animation != null && animation.clip != null)
  43. {
  44. ExportAnimationClip(animation.clip, animation.playAutomatically, animatable);
  45. }
  46. }
  47. }
  48. private static bool IsRotationQuaternionAnimated(BabylonIAnimatable animatable)
  49. {
  50. if (animatable.animations == null)
  51. {
  52. return false;
  53. }
  54. return animatable.animations.Any(animation => animation.property.Contains("rotationQuaternion"));
  55. }
  56. private static void ExportSkeletonAnimationClips(Animator animator, bool autoPlay, BabylonSkeleton skeleton, Transform[] bones, BabylonMesh babylonMesh)
  57. {
  58. AnimationClip clip = null;
  59. AnimatorController ac = animator.runtimeAnimatorController as AnimatorController;
  60. if (ac == null)
  61. {
  62. return;
  63. }
  64. var layer = ac.layers[0];
  65. if (layer == null)
  66. {
  67. return;
  68. }
  69. AnimatorStateMachine sm = layer.stateMachine;
  70. if (sm.states.Length > 0)
  71. {
  72. // Only the first state is supported so far.
  73. var state = sm.states[0].state;
  74. clip = state.motion as AnimationClip;
  75. }
  76. if (clip == null)
  77. {
  78. return;
  79. }
  80. ExportSkeletonAnimationClipData(animator, autoPlay, skeleton, bones, babylonMesh, clip);
  81. }
  82. private static void ExportSkeletonAnimationClipData(Animator animator, bool autoPlay, BabylonSkeleton skeleton, Transform[] bones, BabylonMesh babylonMesh, AnimationClip clip)
  83. {
  84. var frameTime = 1.0f / clip.frameRate;
  85. int animationFrameCount = (int)(clip.length * clip.frameRate);
  86. if (autoPlay)
  87. {
  88. babylonMesh.autoAnimate = true;
  89. babylonMesh.autoAnimateFrom = 0;
  90. babylonMesh.autoAnimateTo = animationFrameCount;
  91. babylonMesh.autoAnimateLoop = true;
  92. }
  93. foreach (var bone in skeleton.bones)
  94. {
  95. var keys = new List<BabylonAnimationKey>();
  96. var transform = bones.Single(b => b.name == bone.name);
  97. AnimationMode.BeginSampling();
  98. for (var i = 0; i < animationFrameCount; i++)
  99. {
  100. clip.SampleAnimation(animator.gameObject, i * frameTime);
  101. var local = (transform.parent.localToWorldMatrix.inverse * transform.localToWorldMatrix);
  102. float[] matrix = new[] {
  103. local[0, 0], local[1, 0], local[2, 0], local[3, 0],
  104. local[0, 1], local[1, 1], local[2, 1], local[3, 1],
  105. local[0, 2], local[1, 2], local[2, 2], local[3, 2],
  106. local[0, 3], local[1, 3], local[2, 3], local[3, 3]
  107. };
  108. var key = new BabylonAnimationKey
  109. {
  110. frame = i,
  111. values = matrix,
  112. };
  113. keys.Add(key);
  114. }
  115. AnimationMode.EndSampling();
  116. var babylonAnimation = new BabylonAnimation
  117. {
  118. name = bone.name + "Animation",
  119. property = "_matrix",
  120. dataType = (int)BabylonAnimation.DataType.Matrix,
  121. loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle,
  122. framePerSecond = (int)clip.frameRate,
  123. keys = keys.ToArray()
  124. };
  125. bone.animation = babylonAnimation;
  126. }
  127. }
  128. private static void ExportAnimationClip(AnimationClip clip, bool autoPlay, BabylonIAnimatable animatable)
  129. {
  130. var curveBindings = AnimationUtility.GetCurveBindings(clip);
  131. var animations = new List<BabylonAnimation>();
  132. var maxFrame = 0;
  133. foreach (var binding in curveBindings)
  134. {
  135. var curve = AnimationUtility.GetEditorCurve(clip, binding);
  136. string property;
  137. switch (binding.propertyName)
  138. {
  139. case "m_LocalPosition.x":
  140. property = "position.x";
  141. break;
  142. case "m_LocalPosition.y":
  143. property = "position.y";
  144. break;
  145. case "m_LocalPosition.z":
  146. property = "position.z";
  147. break;
  148. case "m_LocalRotation.x":
  149. property = "rotationQuaternion.x";
  150. break;
  151. case "m_LocalRotation.y":
  152. property = "rotationQuaternion.y";
  153. break;
  154. case "m_LocalRotation.z":
  155. property = "rotationQuaternion.z";
  156. break;
  157. case "m_LocalRotation.w":
  158. property = "rotationQuaternion.w";
  159. break;
  160. case "m_LocalScale.x":
  161. property = "scaling.x";
  162. break;
  163. case "m_LocalScale.y":
  164. property = "scaling.y";
  165. break;
  166. case "m_LocalScale.z":
  167. property = "scaling.z";
  168. break;
  169. default:
  170. continue;
  171. }
  172. var babylonAnimation = new BabylonAnimation
  173. {
  174. dataType = (int)BabylonAnimation.DataType.Float,
  175. name = property + " animation",
  176. keys = curve.keys.Select(keyFrame => new BabylonAnimationKey
  177. {
  178. frame = (int)(keyFrame.time * clip.frameRate),
  179. values = new[] { keyFrame.value }
  180. }).ToArray(),
  181. framePerSecond = (int)clip.frameRate,
  182. loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle,
  183. property = property
  184. };
  185. maxFrame = Math.Max(babylonAnimation.keys.Last().frame, maxFrame);
  186. animations.Add(babylonAnimation);
  187. }
  188. if (animations.Count > 0)
  189. {
  190. animatable.animations = animations.ToArray();
  191. if (autoPlay)
  192. {
  193. animatable.autoAnimate = true;
  194. animatable.autoAnimateFrom = 0;
  195. animatable.autoAnimateTo = maxFrame;
  196. animatable.autoAnimateLoop = clip.isLooping;
  197. }
  198. }
  199. }
  200. }
  201. }