/// <summary> /// Reads animation information from the file. /// </summary> protected void ReadAnimation(BinaryMemoryReader reader) { // name of the animation string name = ReadString(reader); // length in seconds of the animation float length = ReadFloat(reader); // create an animation from the skeleton Animation anim = skeleton.CreateAnimation(name, length); // keep reading all keyframes for this track if (!IsEOF(reader)) { SkeletonChunkID chunkID = ReadChunk(reader); while (!IsEOF(reader) && (chunkID == SkeletonChunkID.AnimationTrack)) { // read the animation track ReadAnimationTrack(reader, anim); // read the next chunk id // If we're not end of file get the next chunk ID if (!IsEOF(reader)) { chunkID = ReadChunk(reader); } } // backpedal to the start of the chunk if (!IsEOF(reader)) { Seek(reader, -ChunkOverheadSize); } } }
protected void TransformSkeleton(Matrix4 exportTransform) { Matrix4 invExportTransform = exportTransform.Inverse(); Dictionary <string, Matrix4> fullInverseBoneTransforms = new Dictionary <string, Matrix4>(); Skeleton newSkeleton = new Skeleton(skeleton.Name); // Construct new versions of the bones, and build // the inverse bind matrix that will be needed. for (ushort i = 0; i < skeleton.BoneCount; ++i) { Bone bone = skeleton.GetBone(i); Bone newBone = newSkeleton.CreateBone(bone.Name, bone.Handle); fullInverseBoneTransforms[bone.Name] = bone.BindDerivedInverseTransform; } // Build the parenting relationship for the new skeleton for (ushort i = 0; i < skeleton.BoneCount; ++i) { Bone bone = skeleton.GetBone(i); Bone newBone = newSkeleton.GetBone(i); Bone parentBone = (Bone)bone.Parent; if (parentBone != null) { Bone newParentBone = newSkeleton.GetBone(parentBone.Handle); newParentBone.AddChild(newBone); } } // Set the orientation and position for the various bones // B' = T * B * Tinv for (ushort i = 0; i < newSkeleton.BoneCount; ++i) { Bone bone = skeleton.GetBone(i); string boneName = bone.Name; string parentName = (bone.Parent == null) ? null : bone.Parent.Name; Matrix4 transform = GetLocalBindMatrix(fullInverseBoneTransforms, boneName, parentName, true); transform = exportTransform * transform * invExportTransform; Quaternion orientation = GetRotation(transform); Bone newBone = newSkeleton.GetBone(i); newBone.Orientation = orientation; newBone.Position = transform.Translation; //if (newBone.Name == "Lower_Torso_BIND_jjj") { // log.DebugFormat("New Bone Position: {0}", transform.Translation); //} } newSkeleton.SetBindingPose(); for (int i = 0; i < skeleton.AnimationCount; ++i) { Animation anim = skeleton.GetAnimation(i); Animation newAnim = newSkeleton.CreateAnimation(anim.Name, anim.Length); TransformAnimation(exportTransform, newAnim, anim, newSkeleton); } skeleton = newSkeleton; }
protected void ReadAnimation(XmlNode node) { string name = node.Attributes["name"].Value; float length = float.Parse(node.Attributes["length"].Value); // create an animation from the skeleton Animation anim = skeleton.CreateAnimation(name, length); foreach (XmlNode childNode in node.ChildNodes) { switch (childNode.Name) { case "tracks": ReadTracks(childNode, anim); break; default: DebugMessage(childNode); break; } } }
public static void CleanupAnimation(Skeleton skel, Animation anim) { Animation newAnim = skel.CreateAnimation("_replacement", anim.Length); Animation tmpAnim = skel.CreateAnimation("_temporary", anim.Length); foreach (NodeAnimationTrack track in anim.NodeTracks.Values) { Bone bone = skel.GetBone((ushort)track.Handle); NodeAnimationTrack newTrack = newAnim.CreateNodeTrack(track.Handle, bone); NodeAnimationTrack tmpTrack = tmpAnim.CreateNodeTrack(track.Handle, bone); int maxFrame = track.KeyFrames.Count; int lastKeyFrame = -1; for (int keyFrameIndex = 0; keyFrameIndex < track.KeyFrames.Count; ++keyFrameIndex) { if (anim.InterpolationMode == InterpolationMode.Linear) { // Linear is based on one point before and one after. TransformKeyFrame cur = track.GetTransformKeyFrame(keyFrameIndex); if (keyFrameIndex == 0 || keyFrameIndex == (track.KeyFrames.Count - 1)) { // Add the key frame if it is the first or last keyframe. lastKeyFrame = keyFrameIndex; DuplicateKeyFrame(newTrack, cur); } else { // Make sure tmpTrack is clean.. we just use it for interpolation tmpTrack.RemoveAllKeyFrames(); TransformKeyFrame prior = track.GetTransformKeyFrame(lastKeyFrame); TransformKeyFrame next = track.GetTransformKeyFrame(keyFrameIndex + 1); DuplicateKeyFrame(tmpTrack, prior); DuplicateKeyFrame(tmpTrack, next); // Check to see if removing this last keyframe will throw off // any of the other keyframes that were considered redundant. bool needKeyFrame = false; for (int i = lastKeyFrame + 1; i <= keyFrameIndex; ++i) { TransformKeyFrame orig = track.GetTransformKeyFrame(i); TransformKeyFrame interp = new TransformKeyFrame(tmpTrack, orig.Time); tmpTrack.GetInterpolatedKeyFrame(orig.Time, interp); // Is this interpolated frame useful or redundant? if (!CompareKeyFrames(interp, cur)) { needKeyFrame = true; break; } } if (needKeyFrame) { lastKeyFrame = keyFrameIndex; DuplicateKeyFrame(newTrack, cur); } } } else if (anim.InterpolationMode == InterpolationMode.Spline) { // Spline is based on two points before and two after. TransformKeyFrame cur = track.GetTransformKeyFrame(keyFrameIndex); #if DISABLED_CODE if (keyFrameIndex == 0 || keyFrameIndex == 1 || keyFrameIndex == (track.KeyFrames.Count - 1) || keyFrameIndex == (track.KeyFrames.Count - 2)) { // Add the key frame if it is the first, second, last or second to last keyframe. DuplicateKeyFrame(newTrack, cur); } else { // Make sure tmpTrack is clean.. we just use it for interpolation tmpTrack.RemoveAllKeyFrames(); TransformKeyFrame prior1 = track.GetTransformKeyFrame(keyFrameIndex - 2); TransformKeyFrame prior2 = track.GetTransformKeyFrame(keyFrameIndex - 1); TransformKeyFrame next1 = track.GetTransformKeyFrame(keyFrameIndex + 1); TransformKeyFrame next2 = track.GetTransformKeyFrame(keyFrameIndex + 2); DuplicateKeyFrame(tmpTrack, prior1); DuplicateKeyFrame(tmpTrack, prior2); DuplicateKeyFrame(tmpTrack, next1); DuplicateKeyFrame(tmpTrack, next2); TransformKeyFrame interp = new TransformKeyFrame(tmpTrack, cur.Time); tmpTrack.GetInterpolatedKeyFrame(cur.Time, interp); // Is this interpolated frame useful or redundant? if (!CompareKeyFrames(interp, cur)) { DuplicateKeyFrame(newTrack, cur); } } #else DuplicateKeyFrame(newTrack, cur); #endif } else { System.Diagnostics.Debug.Assert(false, "Invalid InterpolationMode: " + anim.InterpolationMode); } } } skel.RemoveAnimation(tmpAnim.Name); skel.RemoveAnimation(newAnim.Name); skel.RemoveAnimation(anim.Name); // Recreate the animation with the proper name (awkward) anim = skel.CreateAnimation(anim.Name, anim.Length); foreach (NodeAnimationTrack track in newAnim.NodeTracks.Values) { Bone bone = skel.GetBone((ushort)track.Handle); NodeAnimationTrack newTrack = anim.CreateNodeTrack(track.Handle, bone); foreach (KeyFrame keyFrame in track.KeyFrames) { DuplicateKeyFrame(newTrack, (TransformKeyFrame)keyFrame); } } }