Advertisement
JCBDigger

Blend Method

Apr 27th, 2011
493
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 12.66 KB | None | 0 0
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // Author: JCBDigger
  4. // URL: http://Games.DiscoverThat.co.uk
  5. //-----------------------------------------------------------------------------
  6. // Central store for animation clips used by all models
  7. //-----------------------------------------------------------------------------
  8. // Read the separate document describing what each animation does.
  9. // See the enums for the list of animations used.
  10. // .clip animations move the body and legs
  11. // .head animations only move the head and neck for looking round
  12. // .arms animations only move the arms to hold weapons
  13. //-----------------------------------------------------------------------------
  14. #endregion
  15.  
  16. #region Using Statements
  17. using System;
  18. using System.IO;
  19. using System.Collections.Generic;
  20. using Microsoft.Xna.Framework;
  21. using Microsoft.Xna.Framework.Content;
  22. using AssetData;
  23. #endregion
  24.  
  25. namespace Engine
  26. {
  27.     /// <summary>
  28.     /// Central store for animation clips
  29.     /// </summary>
  30.     public class AnimationManager
  31.     {
  32.         // The rig type is for human or droid or whatever bone layout is used by the model
  33.         // It is multiplied by a number so it can be added to the Clip and part type numbers
  34.         // to create a unique number to represent the clip or the part.
  35.         private const int rigTypeMultiplier = 100;
  36.         private enum RigType
  37.         {
  38.             Alien,
  39.             Human,
  40.             LocalHuman
  41.         }
  42.         // Every rig type must have all of the following animation clips (.clip) and parts
  43.         public enum ClipType
  44.         {
  45.             Alert,
  46.             Charge,
  47.             Crouch,
  48.             Patrol,
  49.             Shuffle,
  50.             Spin,
  51.             Walk
  52.         }
  53.         // Arms (.arms):
  54.         // HoldRifle, AimRifle, HoldPistol, AimPistol
  55.         // ReloadRifle, ReloadPistol, MeleeRifle, MeleePistol
  56.         // Head (.head):
  57.         // Look, Aim
  58.         public enum PartType
  59.         {
  60.             HoldRifle,
  61.             AimRifle,
  62.             Look,
  63.             Aim
  64.         }
  65.  
  66.         // To avoid garbage collection the strings are converted to unique numbers
  67.         private Dictionary<string, int> rigNumbers = new Dictionary<string, int>();
  68.         private Dictionary<string, int> clipNumbers = new Dictionary<string, int>();
  69.         private Dictionary<string, int> partNumbers = new Dictionary<string, int>();
  70.  
  71.         // Animation clips used by all the models
  72.         private Dictionary<int, AnimationClip> animationClips = new Dictionary<int, AnimationClip>();
  73.         // Animation parts that can be used to blend some bones in to other animations
  74.         private Dictionary<int, AnimationPart> animationParts = new Dictionary<int, AnimationPart>();
  75.  
  76.         private ContentManager Content;
  77.         public volatile bool Ready = false;
  78.  
  79.         public AnimationManager(ContentManager content)
  80.         {
  81.             Content = content;
  82.             //LoadAnimations();
  83.         }
  84.  
  85.         // Load animationClips and animationParts from the storage manager thread
  86.         public void LoadAnimations()
  87.         {
  88.             Ready = false;
  89.             ClearClips();
  90.             ClearParts();
  91.             FillLookupTables();
  92.             // Convert lookups back to text for use as filenames
  93.             string[] rigNames = new string[rigNumbers.Keys.Count];
  94.             rigNumbers.Keys.CopyTo(rigNames, 0);
  95.             string[] clipNames = new string[clipNumbers.Keys.Count];
  96.             clipNumbers.Keys.CopyTo(clipNames, 0);
  97.             string[] partNames = new string[partNumbers.Keys.Count];
  98.             partNumbers.Keys.CopyTo(partNames, 0);
  99.             // Load Clips
  100.             foreach (string rig in rigNames)
  101.             {
  102.                 foreach (string name in clipNames)
  103.                 {
  104.                     string filename = rig + "-" + name;
  105.                     string path = Path.Combine(GameSettings.pathAnimationFolder, filename);
  106.                     int unique = rigNumbers[rig] + clipNumbers[name];
  107.                     AddClip(unique, Content.Load<AnimationClip>(path));
  108.                 }
  109.             }
  110.             // Load Parts
  111.             foreach (string rig in rigNames)
  112.             {
  113.                 foreach (string name in partNames)
  114.                 {
  115.                     string filename = rig + "-" + name;
  116.                     string path = Path.Combine(GameSettings.pathAnimationFolder, filename);
  117.                     int unique = rigNumbers[rig] + partNumbers[name];
  118.                     AddPart(unique, Content.Load<AnimationPart>(path));
  119.                 }
  120.             }
  121.             Ready = true;
  122.         }
  123.  
  124.         // Convert string to unique numbers to avoid garbage collection when joining the
  125.         // rig to the clip or part to get the desired animation to play.
  126.         private void FillLookupTables()
  127.         {
  128.             // The rig is the type of bone structure used by the model
  129.             rigNumbers.Clear();
  130.             // Create numbers to add to the clip and part numbers to give unique results
  131.             rigNumbers.Add("alien", (int)RigType.Alien * rigTypeMultiplier);
  132.             rigNumbers.Add("human", (int)RigType.Human * rigTypeMultiplier);
  133.             // The local player is the 3rd person view.  It uses different animations
  134.             rigNumbers.Add(GameSettings.localPlayerAnimationPrefix + "human", (int)RigType.LocalHuman * rigTypeMultiplier);
  135.             // Clips move the whole body
  136.             clipNumbers.Clear();
  137.             clipNumbers.Add("Alert", (int)ClipType.Alert);
  138.             clipNumbers.Add("Charge", (int)ClipType.Charge);
  139.             clipNumbers.Add("Crouch", (int)ClipType.Crouch);
  140.             clipNumbers.Add("Patrol", (int)ClipType.Patrol);
  141.             clipNumbers.Add("Shuffle", (int)ClipType.Shuffle);
  142.             clipNumbers.Add("Spin", (int)ClipType.Spin);
  143.             clipNumbers.Add("Walk", (int)ClipType.Walk);
  144.             // Parts move separate bones such as the arms for aiming the weapon
  145.             partNumbers.Clear();
  146.             partNumbers.Add("HoldRifle", (int)PartType.HoldRifle);
  147.             partNumbers.Add("AimRifle", (int)PartType.AimRifle);
  148.             partNumbers.Add("Look", (int)PartType.Look);
  149.             partNumbers.Add("Aim", (int)PartType.Aim);
  150.         }
  151.  
  152.  
  153.         #region Use
  154.  
  155.         // checkBoneCount is the number of bones in the character model
  156.         public AnimationClip GetAnimationClip(int take, int checkBoneCount)
  157.         {
  158.             if (IsClipBoneCountOK(take, checkBoneCount))
  159.             {
  160.                 return GetClip(take);
  161.             }
  162.             else
  163.             {
  164.                 return null;
  165.             }
  166.         }
  167.  
  168.         // checkBoneCount is the number of bones in the character model
  169.         public AnimationPart GetAnimationPart(int partNum, int checkBoneCount)
  170.         {
  171.             if (IsPartBoneCountOK(partNum, checkBoneCount))
  172.             {
  173.                 return GetPart(partNum);
  174.             }
  175.             else
  176.             {
  177.                 return null;
  178.             }
  179.         }
  180.  
  181.         /// <summary>
  182.         /// Return true if the number of bones in the model is the same as the number
  183.         /// required to use the clip.  Animations are unlikely to work unless the rigs
  184.         /// are identical.  The clip must also exist.
  185.         /// </summary>
  186.         /// <param name="clipName">The name of the animation clip, e.g. "Walk" or "Run" etc.</param>
  187.         /// <param name="modelBoneCount">The number of bones in the calling model</param>
  188.         public bool IsClipBoneCountOK(int clipNum, int modelBoneCount)
  189.         {
  190.             if (ClipExists(clipNum) && animationClips[clipNum].BoneCount == modelBoneCount)
  191.             {
  192.                 return true;
  193.             }
  194.             else
  195.             {
  196.                 return false;
  197.             }
  198.         }
  199.  
  200.         public bool ClipExists(int clipNum)
  201.         {
  202.             if (animationClips.ContainsKey(clipNum))
  203.             {
  204.                 return true;
  205.             }
  206.             else
  207.             {
  208.                 return false;
  209.             }
  210.         }
  211.  
  212.         public AnimationClip GetClip(int clipNum)
  213.         {
  214.             if (ClipExists(clipNum))
  215.             {
  216.                 return animationClips[clipNum];
  217.             }
  218.             else
  219.             {
  220.                 return null;
  221.             }
  222.         }
  223.  
  224.         /// <summary>
  225.         /// Return true if the number of bones in the model is the same as the number
  226.         /// required to use the part clip.  Animations are unlikely to work unless the rigs
  227.         /// are identical.  The part must also exist.
  228.         /// </summary>
  229.         public bool IsPartBoneCountOK(int partNum, int modelBoneCount)
  230.         {
  231.             if (PartExists(partNum) && animationParts[partNum].BoneCount == modelBoneCount)
  232.             {
  233.                 return true;
  234.             }
  235.             else
  236.             {
  237.                 return false;
  238.             }
  239.         }
  240.  
  241.         public bool PartExists(int partNum)
  242.         {
  243.             if (animationParts.ContainsKey(partNum))
  244.             {
  245.                 return true;
  246.             }
  247.             else
  248.             {
  249.                 return false;
  250.             }
  251.         }
  252.  
  253.         public AnimationPart GetPart(int partNum)
  254.         {
  255.             if (PartExists(partNum))
  256.             {
  257.                 return animationParts[partNum];
  258.             }
  259.             else
  260.             {
  261.                 return null;
  262.             }
  263.         }
  264.  
  265.         /// <summary>
  266.         /// Calculate a bone transform part way between two other transforms.
  267.         /// </summary>
  268.         /// <param name="blendFactor">Fraction from 0.0f closest to blendFrom
  269.         /// up to 1.0f closest to blendTo</param>
  270.         public static Matrix Blend(Matrix blendFrom, Matrix blendTo, float blendFactor)
  271.         {
  272.             // From the AvatarAnimationBlending sample
  273.             // Variables to hold the rotations and translations for the
  274.             // current, target, and blended transforms
  275.             Quaternion currentRotation, targetRotation, finalRotation;
  276.             Vector3 currentTranslation, targetTranslation, finalTranslation;
  277.             // Find the rotation of the current and target bone transforms
  278.             currentRotation =
  279.                    Quaternion.CreateFromRotationMatrix(blendFrom);
  280.             targetRotation =
  281.                     Quaternion.CreateFromRotationMatrix(blendTo);
  282.  
  283.             // Calculate the blended rotation from the current to the target
  284.             Quaternion.Slerp(ref currentRotation, ref targetRotation,
  285.                                                  blendFactor, out finalRotation);
  286.  
  287.             // Find the translation of the current and target bone transforms
  288.             currentTranslation = blendFrom.Translation;
  289.             targetTranslation = blendTo.Translation;
  290.  
  291.             // Calculate the blended translation from the current to the target
  292.             Vector3.Lerp(ref currentTranslation, ref targetTranslation,
  293.                                               blendFactor, out finalTranslation);
  294.  
  295.             // Build the final bone transform
  296.             return Matrix.CreateFromQuaternion(finalRotation) *
  297.                              Matrix.CreateTranslation(finalTranslation);
  298.         }
  299.  
  300.         #endregion
  301.  
  302.         #region Load and Save
  303.  
  304.         public void ClearClips()
  305.         {
  306.             animationClips.Clear();
  307.         }
  308.  
  309.         public void AddClip(int takeNum, AnimationClip clip)
  310.         {
  311.             if (clip != null && takeNum > -1)
  312.             {
  313.                 animationClips.Add(takeNum, clip);
  314.             }
  315.         }
  316.  
  317.         public void ClearParts()
  318.         {
  319.             animationParts.Clear();
  320.         }
  321.  
  322.         public void AddPart(int partNum, AnimationPart part)
  323.         {
  324.             if (part != null && partNum > -1)
  325.             {
  326.                 animationParts.Add(partNum, part);
  327.             }
  328.         }
  329.  
  330.         // The character calls this when loading to get the rig type numbers for that character
  331.         public int GetRigTypeNumber(string rigTypeName)
  332.         {
  333.             if (rigNumbers.ContainsKey(rigTypeName))
  334.             {
  335.                 return rigNumbers[rigTypeName];
  336.             }
  337.             // No matching number so return anything negative
  338.             return -1 * rigTypeMultiplier;
  339.         }
  340.  
  341.         public int GetClipNumber(int rigNum, string clipName)
  342.         {
  343.             if (clipNumbers.ContainsKey(clipName) && rigNum > -1)
  344.             {
  345.                 return rigNum + clipNumbers[clipName];
  346.             }
  347.             else
  348.             {
  349.                 return -1;
  350.             }
  351.         }
  352.  
  353.         #endregion
  354.  
  355.     }
  356. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement