/// <summary> /// Constructs a new animation player. /// </summary> public AnimationPlayer(SkinningData skinningData) { if (skinningData == null) throw new ArgumentNullException("skinningData"); skinningDataValue = skinningData; boneTransforms = new Matrix[skinningData.BindPose.Count]; worldTransforms = new Matrix[skinningData.BindPose.Count]; skinTransforms = new Matrix[skinningData.BindPose.Count]; }
public List<string> GetBoneMapList(SkinningData skinData) { IDictionary<string, int> boneMap = skinData.BoneMap; // Convert to an array so we can loop through string[] keys = new string[boneMap.Keys.Count]; boneMap.Keys.CopyTo(keys, 0); int[] values = new int[boneMap.Values.Count]; boneMap.Values.CopyTo(values, 0); // Create the list to store the results List<string> results = new List<string>(); // Add the headings results.Add("Bone = # [ Parent = # ]"); results.Add("========================"); // Add the value pairs to the list for (int i = 0; i < boneMap.Count; i++) { int parent = skinData.SkeletonHierarchy[values[i]]; if (parent >= 0 && parent < keys.Length) { results.Add(String.Format("{0} = {1} [ {2} = {3} ]", keys[i], values[i], keys[parent], parent)); } else { results.Add(String.Format("{0} = {1} [ Root ]", keys[i], values[i])); } } return results; }
// The input only contains the local bone transform // This processor adds the bind pose private AnimationClip ProcessOneClip(string[] input, SkinningData skinningData, Matrix rotation) { // This should start at the first line FOLLOWING the clip name string[] data = ParseData.SplitNumbersAtSpaces(input[readLine]); readLine++; // This contains the number of bones in the animation... int count = ParseData.IntFromString(data[0]); // and the duration of the animation. TimeSpan duration = ParseData.TimeFromString(data[1]); // There will be no steps in a Blender Action this is just used as a placeholder List<TimeSpan> steps = new List<TimeSpan>(); // Each frame containing the bone and the transform // This contains the transform including the bind pose relative to the parent bone IList<Keyframe> poseKeyFrames = new List<Keyframe>(); if (readLine >= input.Length) { form.AddMessageLine("There are no key frames in this file!"); return null; } // To store the current pose bindTransforms = new Matrix[skinningData.BindPose.Count]; poseTransforms = new Matrix[skinningData.BindPose.Count]; // Now process add all the frames localKeyFrames.Clear(); // Start from the line following the header information while (readLine < input.Length) { // If the line starts with an "=" it is the next clip if (input[readLine].Substring(0, 1) == "=") { break; } string[] item = ParseData.SplitItemByDivision(input[readLine]); data = ParseData.SplitNumbersAtSpaces(item[0]); // The Blender Action clip exports the name of the bone not the index // this is to avoid accidentally having a different bone map order AddSortedKeyFrame(skinningData.BoneMap[data[0]], ParseData.TimeFromString(data[1]), ParseData.StringToMatrix(item[1])); readLine++; } if (localKeyFrames.Count < 1) { return null; } // Rotate /* for (int r = localKeyFrames.Count - 1; r >= 0; r--) { Matrix changed = Matrix.Identity; if (localKeyFrames[r].Bone > 0) { int parentBone = skinningData.SkeletonHierarchy[localKeyFrames[r].Bone]; Matrix parentInvert = Matrix.Invert(localKeyFrames[parentBone].Transform); // Move to parent space changed = localKeyFrames[r].Transform * parentInvert; changed = rotation * changed; } else { // Root changed = rotation * localKeyFrames[r].Transform; } localKeyFrames[r] = new Keyframe(localKeyFrames[r].Bone, localKeyFrames[r].Time, changed); } */ // Get the bind pose skinningData.BindPose.CopyTo(bindTransforms, 0); // Start the pose off in the bind pose skinningData.BindPose.CopyTo(poseTransforms, 0); // Add the bind pose to the local key frames poseKeyFrames.Clear(); // The local key frames are already sorted in to order for (int k = 0; k < localKeyFrames.Count; k++) { int boneID = localKeyFrames[k].Bone; TimeSpan time = localKeyFrames[k].Time; Matrix transform = localKeyFrames[k].Transform; poseTransforms[boneID] = transform * bindTransforms[boneID]; /* if (boneID == 0) { // Root bone poseTransforms[boneID] = transform * bindTransforms[boneID]; } else { int parentBone = skinningData.SkeletonHierarchy[boneID]; Matrix parentInvert = Matrix.Invert(rotation * bindTransforms[parentBone]); // (rotation * parent[frame]).Invert * (rotation * self[frame]) // Tried // Matrix parentInvert = Matrix.Invert(rotation * bindTransforms[parentBone]); // (parentInvert * (rotation * transform)) * bindTransforms[boneID]; //poseTransforms[boneID] = transform * bindTransforms[boneID]; poseTransforms[boneID] = (parentInvert * (rotation * transform)) * bindTransforms[boneID]; } * */ poseKeyFrames.Add(new Keyframe(boneID, time, poseTransforms[boneID])); } // Create the animation clip return new AnimationClip(count, duration, poseKeyFrames, steps); }
private Dictionary<string, AnimationClip> ProcessData(string[] input, string fullFile, SkinningData skinningData, Matrix rotation) { // If there is nothing do not process anything if (input.Length < 1) { return null; } Dictionary<string, AnimationClip> resultClips = new Dictionary<string,AnimationClip>(); form.AddMessageLine("Reading file: " + fullFile); while (readLine < input.Length) { // First line of each clip should contain the clip name // in the format "=ClipName" string clipName = input[readLine]; if (clipName.Length > 1 && clipName.Substring(0, 1) == "=") { // Remove the "=" sign clipName = clipName.Substring(1); readLine++; } else { // Unique clip name based on the current date and time clipName = DateTime.Now.ToString(GlobalSettings.timeFormat); readLine++; } // Create the animation clip form.AddMessageLine("Processing action: " + clipName); AnimationClip thisClip = ProcessOneClip(input, skinningData, rotation); if (thisClip != null) { resultClips.Add(clipName, thisClip); } } return resultClips; }