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); } }
/// 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; }
/// <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 ); } } }
public NodeAnimationTrack( Animation parent ) : base( parent ) { this.target = null; }
public VertexAnimationTrack( Animation parent, ushort handle ) : base( parent, handle ) { }
/// <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; }
public NumericAnimationTrack(Animation parent) : base(parent) { }
/// Constructor public VertexAnimationTrack(Animation parent, VertexAnimationType animationType) : base(parent) { this.animationType = animationType; }
public VertexAnimationTrack(Animation parent, ushort handle) : base(parent, handle) { }
public NodeAnimationTrack(Animation parent) : base(parent) { this.target = null; }
/// <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) { }
public NodeAnimationTrack(Animation parent, ushort handle) : base(parent, handle) { }
/// <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; }
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; }
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); }
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); } }
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; } } }
/// 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; } } }
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; }
/// <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) { }
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 ); }
/// <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; }
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; }
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; } }
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 ); } } }
/// <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; }
/// <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 ) ); } } } }