An animation sequence.
This class defines the interface for a sequence of animation, whether that be animation of a mesh, a path along a spline, or possibly more than one type of animation in one. An animation is made up of many 'tracks', which are the more specific types of animation.

You should not create these animations directly. They will be created via a parent object which owns the animation, e.g. Skeleton, SceneManager, etc.

        protected void TransformAnimation(Matrix4 exportTransform, 
										  Animation newAnim, Animation anim,
										  Skeleton newSkeleton)
        {
            foreach (NodeAnimationTrack track in anim.NodeTracks.Values) {
                NodeAnimationTrack newTrack = newAnim.CreateNodeTrack(track.Handle);
                Bone targetBone = (Bone)track.TargetNode;
                newTrack.TargetNode = newSkeleton.GetBone(targetBone.Handle);
                TransformTrack(exportTransform, newTrack, track, targetBone);
            }
        }
Beispiel #2
0
		/// Constructor, associates with target VertexData and temp buffer (for software)
		public VertexAnimationTrack( Animation parent, VertexAnimationType animationType,
									VertexData targetVertexData, VertexAnimationTargetMode targetMode )
			: base( parent )
		{
			this.animationType = animationType;
			this.targetVertexData = targetVertexData;
			this.targetMode = targetMode;
		}
Beispiel #3
0
		/// <summary>
		///    Reads an animation track.
		/// </summary>
		protected void ReadAnimationTrack( BinaryReader reader, Animation anim )
		{
			// read the bone handle to apply this track to
			ushort boneHandle = ReadUShort( reader );

			// get a reference to the target bone
			Bone targetBone = skeleton.GetBone( boneHandle );

			// create an animation track for this bone
			NodeAnimationTrack track = anim.CreateNodeTrack( boneHandle, targetBone );

			// keep reading all keyframes for this track
			if ( !IsEOF( reader ) )
			{
				SkeletonChunkID chunkID = ReadChunk( reader );
				while ( !IsEOF( reader ) && ( chunkID == SkeletonChunkID.KeyFrame ) )
				{
					// read the key frame
					ReadKeyFrame( reader, track );
					// 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 );
				}
			}
		}
Beispiel #4
0
		public NodeAnimationTrack( Animation parent )
			: base( parent )
		{
			this.target = null;
		}
Beispiel #5
0
		public VertexAnimationTrack( Animation parent, ushort handle )
			: base( parent, handle )
		{
		}
Beispiel #6
0
		/// <summary>
		///     Creates a new Animation object for vertex animating this mesh.
		/// </summary>
		/// <param name="name">The name of this animation</param>
		/// <param name="length">The length of the animation in seconds</param>
		public Animation CreateAnimation( string name, float length )
		{
			// Check name not used
			if ( this._animationsList.ContainsKey( name ) )
			{
				throw new Exception( "An animation with the name " + name + " already exists" + ", in Mesh.CreateAnimation" );
			}
			var ret = new Animation( name, length );
			// Add to list
			this._animationsList[ name ] = ret;
			// Mark animation types dirty
			this._animationTypesDirty = true;
			return ret;
		}
Beispiel #7
0
 public NumericAnimationTrack(Animation parent) : base(parent)
 {
 }
Beispiel #8
0
 /// Constructor
 public VertexAnimationTrack(Animation parent, VertexAnimationType animationType) : base(parent)
 {
     this.animationType = animationType;
 }
Beispiel #9
0
 public VertexAnimationTrack(Animation parent, ushort handle) : base(parent, handle)
 {
 }
Beispiel #10
0
 public NodeAnimationTrack(Animation parent) : base(parent)
 {
     this.target = null;
 }
Beispiel #11
0
 /// <summary>
 ///		Internal constructor, to prevent direction instantiation.  Should be created
 ///		via a call to the CreateTrack method of an Animation.
 /// </summary>
 internal AnimationTrack(Animation parent) : this(parent, 0)
 {
 }
Beispiel #12
0
 public NodeAnimationTrack(Animation parent, ushort handle) : base(parent, handle)
 {
 }
Beispiel #13
0
 /// <summary>
 ///		Internal constructor, to prevent direction instantiation.  Should be created
 ///		via a call to the CreateTrack method of an Animation.
 /// </summary>
 public NodeAnimationTrack(Animation parent, Node target) : base(parent)
 {
     this.target = target;
 }
Beispiel #14
0
 public NumericAnimationTrack(Animation parent, AnimableValue targetAnimable) : base(parent)
 {
     this.targetAnimable = targetAnimable;
 }
 protected AnimationTrack GetBoneTrack(Animation anim, ushort boneHandle)
 {
     for (int i = 0; i < anim.Tracks.Count; ++i) {
         AnimationTrack track = anim.Tracks[i];
         Bone bone = (Bone)track.TargetNode;
         if (bone.Handle == boneHandle)
             return track;
     }
     return null;
 }
Beispiel #16
0
 public VertexAnimationTrack(Animation parent, ushort handle, VertexAnimationType animationType)
     : base(parent, handle)
 {
     this.animationType = animationType;
 }
        protected void TransformAnimation(Matrix4 unscaledTransform, float scale,
										  Animation newAnim, Animation anim,
										  Skeleton newSkeleton)
        {
            // With the new idea I had for transforming these, I need the tracks
            // set up for the parent bones before I can handle the child bones.
            for (int i = 0; i < anim.Tracks.Count; ++i) {
                AnimationTrack track = anim.Tracks[i];
                AnimationTrack newTrack = newAnim.CreateTrack(track.Handle);
                Bone targetBone = (Bone)track.TargetNode;
                newTrack.TargetNode = newSkeleton.GetBone(targetBone.Handle);
            }
            // This gets the ordered bone list, and transforms the tracks in
            // that order instead.
            List<Bone> orderedBoneList = GetOrderedBoneList(null, newSkeleton);
            foreach (Bone bone in orderedBoneList)
                TransformTrack(unscaledTransform, scale, newAnim, anim, bone);
        }
Beispiel #18
0
 internal AnimationTrack(Animation parent, ushort handle)
 {
     this.parent     = parent;
     this.handle     = handle;
     maxKeyFrameTime = float.MinValue;
 }
		protected void WriteAnimation( BinaryWriter writer, Animation anim )
		{
			var start_offset = writer.Seek( 0, SeekOrigin.Current );
			WriteChunk( writer, MeshChunkID.Animation, 0 );

			WriteString( writer, anim.Name );
			WriteFloat( writer, anim.Length );
			foreach ( var track in anim.VertexTracks.Values )
			{
				WriteAnimationTrack( writer, track );
			}

			var end_offset = writer.Seek( 0, SeekOrigin.Current );
			writer.Seek( (int)start_offset, SeekOrigin.Begin );
			WriteChunk( writer, MeshChunkID.Animation, (int)( end_offset - start_offset ) );
			writer.Seek( (int)end_offset, SeekOrigin.Begin );
		}
        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);
            }
        }
Beispiel #21
0
		public NodeAnimationTrack( Animation parent, ushort handle )
			: base( parent, handle )
		{
		}
        protected void ReadTrack(XmlNode node, Animation anim)
        {
            string boneName = node.Attributes["bone"].Value;
            // get a reference to the target bone
            Bone targetBone = skeleton.GetBone(boneName);
            // create an animation track for this bone
            NodeAnimationTrack track = anim.CreateNodeTrack(targetBone.Handle, targetBone);

            foreach (XmlNode childNode in node.ChildNodes) {
                switch (childNode.Name) {
                    case "keyframes":
                        ReadKeyFrames(childNode, track);
                        break;
                    default:
                        DebugMessage(childNode);
                        break;
                }
            }
        }
Beispiel #23
0
		/// Constructor
		public VertexAnimationTrack( Animation parent, VertexAnimationType animationType )
			: base( parent )
		{
			this.animationType = animationType;
		}
 protected void ReadTracks(XmlNode node, Animation anim)
 {
     foreach (XmlNode childNode in node.ChildNodes) {
         switch (childNode.Name) {
             case "track":
                 ReadTrack(childNode, anim);
                 break;
             default:
                 DebugMessage(childNode);
                 break;
         }
     }
 }
Beispiel #25
0
		public VertexAnimationTrack( Animation parent, ushort handle, VertexAnimationType animationType )
			: base( parent, handle )
		{
			this.animationType = animationType;
		}
 internal AnimationTrack(Animation parent, ushort handle)
 {
     this.parent = parent;
     this.handle = handle;
     maxKeyFrameTime = float.MinValue;
 }
Beispiel #27
0
		/// <summary>
		///    Creates a new Animation object for animating this skeleton.
		/// </summary>
		/// <param name="name">The name of this animation</param>
		/// <param name="length">The length of the animation in seconds</param>
		/// <returns></returns>
		public virtual Animation CreateAnimation( string name, float length )
		{
			// Check name not used
			if ( this.animationList.ContainsKey( name ) )
			{
				throw new Exception( "An animation with the name already exists" );
			}

			var anim = new Animation( name, length );

			this.animationList.Add( name, anim );

			return anim;
		}
 /// <summary>
 ///		Internal constructor, to prevent direction instantiation.  Should be created
 ///		via a call to the CreateTrack method of an Animation.
 /// </summary>
 internal AnimationTrack(Animation parent)
     : this(parent, 0)
 {
 }
Beispiel #29
0
		protected void WriteAnimation( BinaryWriter writer, Animation anim )
		{
			long start_offset = writer.Seek( 0, SeekOrigin.Current );
			WriteChunk( writer, SkeletonChunkID.Animation, 0 );

			WriteString( writer, anim.Name );
			WriteFloat( writer, anim.Length );

			foreach ( NodeAnimationTrack track in anim.NodeTracks.Values )
				WriteAnimationTrack( writer, track );

			long end_offset = writer.Seek( 0, SeekOrigin.Current );
			writer.Seek( (int)start_offset, SeekOrigin.Begin );
			WriteChunk( writer, SkeletonChunkID.Animation, (int)( end_offset - start_offset ) );
			writer.Seek( (int)end_offset, SeekOrigin.Begin );
		}
Beispiel #30
0
		/// <summary>
		///		Internal constructor, to prevent direction instantiation.  Should be created
		///		via a call to the CreateTrack method of an Animation.
		/// </summary>
		internal AnimationTrack( Animation parent )
		{
			this.parent = parent;
			maxKeyFrameTime = -1;
		}
 protected XmlElement WriteAnimation(Animation anim)
 {
     XmlElement node = document.CreateElement("animation");
     XmlAttribute attr;
     attr = document.CreateAttribute("name");
     attr.Value = anim.Name;
     node.Attributes.Append(attr);
     attr = document.CreateAttribute("length");
     attr.Value = anim.Length.ToString();
     node.Attributes.Append(attr);
     XmlElement tracksNode = document.CreateElement("tracks");
     foreach (NodeAnimationTrack track in anim.NodeTracks.Values) {
         XmlElement trackNode = WriteTrack(track);
         tracksNode.AppendChild(trackNode);
     }
     node.AppendChild(tracksNode);
     return node;
 }
Beispiel #32
0
		internal AnimationTrack( Animation parent, ushort handle )
		{
			this.parent = parent;
			this.handle = handle;
			maxKeyFrameTime = -1;
		}
        protected void GetCompositeTransform(ref Quaternion orientation,
											 ref Vector3 translation,
											 Bone bone, Animation anim, int keyFrameIndex)
        {
            if (bone == null)
                return;
            Quaternion tmpOrient = Quaternion.Identity;
            Vector3 tmpTranslate = Vector3.Zero;
            GetCompositeTransform(ref tmpOrient, ref tmpTranslate, (Bone)bone.Parent, anim, keyFrameIndex);
            AnimationTrack track = GetBoneTrack(anim, bone.Handle);
            KeyFrame keyFrame = track.KeyFrames[keyFrameIndex];
            orientation = tmpOrient * bone.Orientation * keyFrame.Rotation;
            translation = tmpTranslate + bone.Position + keyFrame.Translate;
        }
Beispiel #34
0
		public NumericAnimationTrack( Animation parent )
			: base( parent )
		{
		}
        protected void TransformTrack(Matrix4 unscaledTransform, float scale,
									  Animation newAnim, Animation anim, Bone bone)
        {
            AnimationTrack track = GetBoneTrack(anim, bone.Handle);
            AnimationTrack newTrack = GetBoneTrack(newAnim, bone.Handle);
            Bone oldNode = (Bone)track.TargetNode;
            Bone newNode = (Bone)newTrack.TargetNode;
            Quaternion exportRotation = GetRotation(unscaledTransform);
            Vector3 exportTranslation = unscaledTransform.Translation;
            for (int i = 0; i < track.KeyFrames.Count; ++i) {
                KeyFrame keyFrame = track.KeyFrames[i];
                Quaternion oldOrientation = Quaternion.Identity;
                Vector3 oldTranslation = Vector3.Zero;
                // Now build the composite transform for the old node
                GetCompositeTransform(ref oldOrientation, ref oldTranslation, oldNode, anim, i);
                Quaternion targetOrientation = exportRotation * oldOrientation;
                Vector3 targetTranslation = exportTranslation + scale * (exportRotation * oldTranslation);
                KeyFrame newKeyFrame = newTrack.CreateKeyFrame(keyFrame.Time);
                // we have a parent - where is it?
                Quaternion parentOrientation = Quaternion.Identity;
                Vector3 parentTranslation = Vector3.Zero;
                GetCompositeTransform(ref parentOrientation, ref parentTranslation, (Bone)newNode.Parent, newAnim, i);
                newKeyFrame.Rotation = newNode.Orientation.Inverse() * parentOrientation.Inverse() * targetOrientation;
                newKeyFrame.Translate = (-1 * newNode.Position) + (-1 * parentTranslation) + targetTranslation;
            }
        }
Beispiel #36
0
		public NumericAnimationTrack( Animation parent, AnimableValue targetAnimable )
			: base( parent )
		{
			this.targetAnimable = targetAnimable;
		}
		protected void ReadAnimationTrack( BinaryReader reader, Animation anim )
		{
			var type = ReadUShort( reader );
			var target = ReadUShort( reader );

			var track = anim.CreateVertexTrack( target, this.mesh.GetVertexDataByTrackHandle( target ), (VertexAnimationType)type );
			// Now read the key frames for this track
			if ( !IsEOF( reader ) )
			{
				var chunkID = ReadChunk( reader );
				while ( !IsEOF( reader ) &&
				        ( chunkID == MeshChunkID.AnimationMorphKeyframe || chunkID == MeshChunkID.AnimationPoseKeyframe ) )
				{
					switch ( chunkID )
					{
						case MeshChunkID.AnimationMorphKeyframe:
							ReadMorphKeyframe( reader, track );
							break;
						case MeshChunkID.AnimationPoseKeyframe:
							ReadPoseKeyframe( reader, track );
							break;
					}
					if ( !IsEOF( reader ) )
					{
						chunkID = ReadChunk( reader );
					}
				}
				if ( !IsEOF( reader ) )
				{
					// backpedal to the start of chunk
					Seek( reader, -ChunkOverheadSize );
				}
			}
		}
Beispiel #38
0
		/// <summary>
		///		Internal constructor, to prevent direction instantiation.  Should be created
		///		via a call to the CreateTrack method of an Animation.
		/// </summary>
		public NodeAnimationTrack( Animation parent, Node target )
			: base( parent )
		{
			this.target = target;
		}
Beispiel #39
0
		/// <summary>
		///		Creates an animation which can be used to animate scene nodes.
		/// </summary>
		/// <remarks>
		///		An animation is a collection of 'tracks' which over time change the position / orientation
		///		of Node objects. In this case, the animation will likely have tracks to modify the position
		///		/ orientation of SceneNode objects, e.g. to make objects move along a path.
		///		<p/>
		///		You don't need to use an Animation object to move objects around - you can do it yourself
		///		using the methods of the Node in your application. However, when you need relatively
		///		complex scripted animation, this is the class to use since it will interpolate between
		///		keyframes for you and generally make the whole process easier to manage.
		///		<p/>
		///		A single animation can affect multiple Node objects (each AnimationTrack affects a single Node).
		///		In addition, through animation blending a single Node can be affected by multiple animations,
		///		although this is more useful when performing skeletal animation (see Skeleton.CreateAnimation).
		/// </remarks>
		/// <param name="name"></param>
		/// <param name="length"></param>
		/// <returns></returns>
		public virtual Animation CreateAnimation( string name, float length )
		{
			if ( this.animationList.ContainsKey( name ) )
			{
				throw new AxiomException( string.Format(
											  "An animation with the name '{0}' already exists in the scene.", name ) );
			}

			// create a new animation and record it locally
			Animation anim = new Animation( name, length );
			this.animationList.Add( name, anim );

			return anim;
		}
 protected void BuildInitialPoseInfo( Dictionary<MeshGeometry, List<PoseRef>> initialPoses,
                                     Dictionary<MeshGeometry, VertexAnimationTrack> tracks,
                                     Animation anim, MorphController morphController )
 {
     InputSource morphTargetSource = morphController.GetInputSourceBySemantic( "MORPH_TARGET" );
     InputSource morphWeightSource = morphController.GetInputSourceBySemantic( "MORPH_WEIGHT" );
     List<MeshGeometry> initialGeometries = morphController.Target;
     for( int geoIndex = 0; geoIndex < initialGeometries.Count; ++geoIndex )
     {
         MeshGeometry geometry = initialGeometries[ geoIndex ];
         // These geometry.Id are the submesh names (e.g. head01-mesh.0)
         for( ushort i = 0; i < m_AxiomMesh.SubMeshCount; ++i )
         {
             SubMesh subMesh = m_AxiomMesh.GetSubMesh( i );
             if( subMesh.Name != geometry.Id )
                 continue;
             VertexData vData = null;
             ushort target;
             if( subMesh.useSharedVertices )
             {
                 target = 0;
                 vData = m_AxiomMesh.SharedVertexData;
             }
             else
             {
                 target = (ushort) (i + 1);
                 vData = subMesh.vertexData;
             }
             VertexAnimationTrack track =
                 anim.CreateVertexTrack( target, vData, VertexAnimationType.Pose );
             tracks[ geometry ] = track;
             // This is the initial set of influences on the geometry
             List<PoseRef> initialPoseInfo = new List<PoseRef>();
             initialPoses[ geometry ] = initialPoseInfo;
             for( int k = 0; k < morphTargetSource.Accessor.Count; ++k )
             {
                 // morphTargetName is the id of the mesh we are blending in (e.g. head02-mesh)
                 string morphTargetName = (string) morphTargetSource.Accessor.GetParam( "MORPH_TARGET", k );
                 float influence = (float) morphWeightSource.Accessor.GetParam( "MORPH_WEIGHT", k );
                 GeometrySet morphDest = Geometries[ morphTargetName ];
                 // Get the pose index for the target submesh
                 // First find the PoseInfo object that is about this combination
                 PoseInfo poseInfo = GetPoseInfo( morphController.Target, morphDest );
                 // Now that I have the pose info for this combination,
                 // I still need to find the pose index for the portion
                 // that is associated with my MeshGeometry (instead of
                 // the GeometrySet).  Since I added these in order, I
                 // should be able to retrieve it in order as well.
                 ushort poseIndex = (ushort) poseInfo.poseIndices[ geoIndex ];
                 initialPoseInfo.Add( new PoseRef( poseIndex, influence ) );
             }
         }
     }
 }