AnimationBlender.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // AnimationBlender.cs
  4. //
  5. // Microsoft XNA Community Game Platform
  6. // Copyright (C) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #endregion
  9. #region Using Statements
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Text;
  13. using Microsoft.Xna.Framework;
  14. using RobotGameData.GameInterface;
  15. #endregion
  16. namespace RobotGameData.GameObject
  17. {
  18. /// <summary>
  19. /// this class blends two animation key frames.
  20. /// However, even when the animation blend is not carried out,
  21. /// there must be AnimationBinder with one or more key frame in order
  22. /// to play animation.
  23. /// Each bone of character corresponds to an AnimationBlender and
  24. /// may have one or two AnimationBinder.
  25. /// </summary>
  26. public class AnimationBlender : INamed
  27. {
  28. #region Fields
  29. /// <summary>
  30. /// animation binder 1
  31. /// </summary>
  32. AnimationBinder firstBinder = null;
  33. /// <summary>
  34. /// animation binder 2
  35. /// </summary>
  36. AnimationBinder secondBinder = null;
  37. string name = String.Empty;
  38. int bindCount = 0;
  39. float blendTime = 0.0f;
  40. float elapsedTime = 0.0f;
  41. #endregion
  42. #region Properties
  43. public string Name
  44. {
  45. get { return name; }
  46. set { name = value; }
  47. }
  48. public float BlendTime
  49. {
  50. get { return blendTime; }
  51. }
  52. public AnimationBinder AnimationBinder
  53. {
  54. get { return firstBinder; }
  55. }
  56. public int BindCount
  57. {
  58. get { return bindCount; }
  59. }
  60. public bool IsEmpty
  61. {
  62. get { return (BindCount == 0); }
  63. }
  64. #endregion
  65. /// <summary>
  66. /// Constructor.
  67. /// </summary>
  68. public AnimationBlender()
  69. {
  70. this.firstBinder = new AnimationBinder();
  71. this.secondBinder = new AnimationBinder();
  72. this.bindCount = 0;
  73. }
  74. /// <summary>
  75. /// inserts the new KeyFrameSequence, which is specified in the Binder.
  76. /// If there are two Binder’s, the first Binder will be gone and
  77. /// the second Binder will be moved as the first Binder,
  78. /// and the new KeyFrameSequence will be inserted into the second Binder.
  79. /// When the every Binder is empty, it will then insert to the first Binder
  80. /// </summary>
  81. /// <param name="keyFrame">Animation key frame sequence</param>
  82. /// <param name="startTime">Start time of the animaton</param>
  83. /// <param name="blendTime">Blend time of two the animaton</param>
  84. /// <param name="timeScaleFactor">Time scale of the animaton</param>
  85. /// <param name="mode">Play mode of the animaton</param>
  86. public void AddKeyFrameSequence(KeyFrameSequence keyFrame,
  87. float startTime,
  88. float blendTime,
  89. float timeScaleFactor,
  90. AnimPlayMode mode)
  91. {
  92. this.blendTime = blendTime;
  93. this.elapsedTime = startTime;
  94. if (this.BlendTime == 0.0f)
  95. {
  96. ClearAllBinder();
  97. firstBinder.BindKeyFrameSequence(keyFrame, startTime,
  98. timeScaleFactor, mode);
  99. }
  100. else
  101. {
  102. // If binding above two binders, push out one binder
  103. if (this.bindCount == 2)
  104. ShiftBinder();
  105. if (this.bindCount == 0)
  106. {
  107. firstBinder.BindKeyFrameSequence(keyFrame, startTime,
  108. timeScaleFactor, mode);
  109. }
  110. else if (this.bindCount == 1)
  111. {
  112. secondBinder.BindKeyFrameSequence(keyFrame, startTime,
  113. timeScaleFactor, mode);
  114. }
  115. }
  116. this.bindCount++;
  117. }
  118. /// <summary>
  119. /// calculates the key frame of the animation of the specified time.
  120. /// If there are two bound animations, it will calculate by blending.
  121. /// </summary>
  122. /// <param name="time">animation time</param>
  123. /// <returns>Matrix of the animation key frame</returns>
  124. public Matrix GetKeyFrameMatrix(float time)
  125. {
  126. Matrix keyFrameMatrix = Matrix.Identity;
  127. if (firstBinder == null)
  128. return keyFrameMatrix;
  129. this.elapsedTime += time;
  130. // We have to blend animations, if it has multiple binders
  131. if (bindCount > 1)
  132. {
  133. float t = this.elapsedTime / this.blendTime;
  134. // Blending finished
  135. if (t > 1.0f)
  136. {
  137. keyFrameMatrix = secondBinder.GetKeyFrameMatrix(time);
  138. ShiftBinder();
  139. }
  140. // Calculate blending matrix
  141. else
  142. {
  143. KeyFrame[] sourceKeyFrame = new KeyFrame[2];
  144. KeyFrame targetKeyFrame = new KeyFrame();
  145. // Calculate two keyFrame
  146. sourceKeyFrame[0] = firstBinder.GetKeyFrame(time);
  147. sourceKeyFrame[1] = secondBinder.GetKeyFrame(time);
  148. // Calculate blending key frame
  149. {
  150. // Interpolate translation using two key frame
  151. if (sourceKeyFrame[0].HasTranslation &&
  152. sourceKeyFrame[1].HasTranslation)
  153. {
  154. targetKeyFrame.Translation = Vector3.Lerp(
  155. sourceKeyFrame[0].Translation,
  156. sourceKeyFrame[1].Translation,
  157. t);
  158. targetKeyFrame.HasTranslation = true;
  159. }
  160. else if (sourceKeyFrame[0].HasTranslation)
  161. {
  162. targetKeyFrame.Translation = sourceKeyFrame[0].Translation;
  163. targetKeyFrame.HasTranslation = true;
  164. }
  165. else if (sourceKeyFrame[1].HasTranslation)
  166. {
  167. targetKeyFrame.Translation = sourceKeyFrame[1].Translation;
  168. targetKeyFrame.HasTranslation = true;
  169. }
  170. // Interpolate scale using two key frame
  171. if (sourceKeyFrame[0].HasScale && sourceKeyFrame[1].HasScale)
  172. {
  173. targetKeyFrame.Scale = Vector3.Lerp(
  174. sourceKeyFrame[0].Scale,
  175. sourceKeyFrame[1].Scale,
  176. t);
  177. targetKeyFrame.HasScale = true;
  178. }
  179. else if (sourceKeyFrame[0].HasScale)
  180. {
  181. targetKeyFrame.Scale = sourceKeyFrame[0].Scale;
  182. targetKeyFrame.HasScale = true;
  183. }
  184. else if (sourceKeyFrame[1].HasScale)
  185. {
  186. targetKeyFrame.Scale = sourceKeyFrame[1].Scale;
  187. targetKeyFrame.HasScale = true;
  188. }
  189. // Interpolate rotation using two key frame
  190. if (sourceKeyFrame[0].HasRotation &&
  191. sourceKeyFrame[1].HasRotation)
  192. {
  193. targetKeyFrame.Rotation = Quaternion.Slerp(
  194. sourceKeyFrame[0].Rotation,
  195. sourceKeyFrame[1].Rotation,
  196. t);
  197. targetKeyFrame.HasRotation = true;
  198. }
  199. else if (sourceKeyFrame[0].HasRotation)
  200. {
  201. targetKeyFrame.Rotation = sourceKeyFrame[0].Rotation;
  202. targetKeyFrame.HasRotation = true;
  203. }
  204. else if (sourceKeyFrame[1].HasRotation)
  205. {
  206. targetKeyFrame.Rotation = sourceKeyFrame[1].Rotation;
  207. targetKeyFrame.HasRotation = true;
  208. }
  209. }
  210. // Final, creates a frame matrix using blending key frame
  211. {
  212. // Has Rotation ?
  213. if (targetKeyFrame.HasRotation)
  214. {
  215. // Calculates rotation matrix using the quaternion
  216. keyFrameMatrix = Matrix.CreateFromQuaternion(
  217. targetKeyFrame.Rotation);
  218. }
  219. // Has translation ?
  220. if (targetKeyFrame.HasTranslation)
  221. {
  222. // Calculates position using keyframe
  223. keyFrameMatrix.Translation = targetKeyFrame.Translation;
  224. }
  225. // Has scale ?
  226. if (targetKeyFrame.HasScale)
  227. {
  228. // Calculates scale value using keyframe
  229. keyFrameMatrix = keyFrameMatrix *
  230. Matrix.CreateScale(targetKeyFrame.Scale);
  231. }
  232. }
  233. return keyFrameMatrix;
  234. }
  235. }
  236. else
  237. {
  238. // No blending, or finished blending
  239. keyFrameMatrix = firstBinder.GetKeyFrameMatrix(time);
  240. }
  241. return keyFrameMatrix;
  242. }
  243. /// <summary>
  244. /// moves the position of the Binder.
  245. /// If there are two binders already,
  246. /// the first Binder will be gone and the second Binder will be moved
  247. /// to the first Binder.
  248. /// </summary>
  249. private void ShiftBinder()
  250. {
  251. this.firstBinder.Initialize();
  252. this.secondBinder.CopyTo(firstBinder);
  253. this.secondBinder.Initialize();
  254. this.bindCount--;
  255. }
  256. private void ClearAllBinder()
  257. {
  258. this.firstBinder.Initialize();
  259. this.secondBinder.Initialize();
  260. this.bindCount = 0;
  261. }
  262. }
  263. }