示例#1
0
 /// <summary>
 /// Decompose the given matrix into a scale/rotation/translation
 /// keyframe.
 /// </summary>
 /// <param name="xform">The transform to decompose.</param>
 /// <param name="ret">The keyframe to decompose into.</param>
 /// <returns>ret (for convenience)</returns>
 protected Keyframe KeyframeFromMatrix(Matrix xform, Keyframe ret)
 {
     return(Keyframe.CreateFromMatrix(ref xform, ret));
 }
示例#2
0
        /// <summary>
        /// The workhorse of the animation processor. It loops through all
        /// animations, all tracks, and all keyframes, and converts to the format
        /// expected by the runtime animation classes.
        /// </summary>
        /// <param name="input">The NodeContent to process. Comes from the base ModelProcessor.</param>
        /// <param name="output">The ModelContent that was produced. You don't typically change this.</param>
        /// <param name="context">The build context (logger, etc).</param>
        /// <returns>An allocated AnimationSet with the animations to include.</returns>
        public virtual AnimationSet BuildAnimationSet(NodeContent input, ref ModelContent output,
                                                      ContentProcessorContext context)
        {
            AnimationSet ret = new AnimationSet();

            if (!DoAnimations)
            {
                context.Logger.LogImportantMessage("DoAnimation is set to false for {0}; not generating animations.", input.Name);
                return(ret);
            }

            //  go from name to index
            Dictionary <string, ModelBoneContent> nameToIndex = new Dictionary <string, ModelBoneContent>();

            foreach (ModelBoneContent mbc in output.Bones)
            {
                nameToIndex.Add(GetBoneName(mbc), mbc);
            }

            AnimationContentDictionary adict = MergeAnimatedBones(input);

            if (adict == null || adict.Count == 0)
            {
                context.Logger.LogWarning("http://kwxport.sourceforge.net/", input.Identity,
                                          "Model processed with AnimationProcessor has no animations.");
                return(ret);
            }

            foreach (AnimationContent ac in adict.Values)
            {
                if (!IncludeAnimation(ac))
                {
                    context.Logger.LogImportantMessage(String.Format("Not including animation named {0}.", ac.Name));
                    continue;
                }
                context.Logger.LogImportantMessage(
                    "Processing animation {0} duration {1} sample rate {2} reduction tolerance {3}.",
                    ac.Name, ac.Duration, SampleRate, Tolerance);
                AnimationChannelDictionary acdict = ac.Channels;
                AnimationTrackDictionary   tracks = new AnimationTrackDictionary();
                foreach (string name in acdict.Keys)
                {
                    if (!IncludeTrack(ac, name))
                    {
                        context.Logger.LogImportantMessage(String.Format("Not including track named {0}.", name));
                        continue;
                    }

                    int ix = 0;
                    AnimationChannel achan = acdict[name];
                    int bix = nameToIndex[name].Index;
                    context.Logger.LogMessage("Processing bone {0}:{1}.", name, bix);
                    AnimationTrack at;
                    if (tracks.TryGetValue(bix, out at))
                    {
                        throw new System.ArgumentException(
                                  String.Format("Bone index {0} is used by multiple animations in the same clip (name {1}).",
                                                bix, name));
                    }

                    //  Sample at given frame rate from 0 .. Duration
                    List <Keyframe> kfl     = new List <Keyframe>();
                    int             nFrames = (int)Math.Floor(ac.Duration.TotalSeconds * SampleRate + 0.5);
                    for (int i = 0; i < nFrames; ++i)
                    {
                        Keyframe k = SampleChannel(achan, i / SampleRate, ref ix);
                        kfl.Add(k);
                    }

                    //  Run keyframe elimitation
                    Keyframe[] frames   = kfl.ToArray();
                    int        nReduced = 0;
                    if (tolerance_ > 0)
                    {
                        nReduced = ReduceKeyframes(frames, tolerance_);
                    }
                    if (nReduced > 0)
                    {
                        context.Logger.LogMessage("Reduced '{2}' from {0} to {1} frames.",
                                                  frames.Length, frames.Length - nReduced, name);
                    }

                    //  Create an AnimationTrack
                    at = new AnimationTrack(bix, frames);
                    tracks.Add(bix, at);
                }

                Animation a = new Animation(ac.Name, tracks, SampleRate);
                ret.AddAnimation(a);
            }

            //  build the special "identity" and "bind pose" animations
            AnimationTrackDictionary atd_id   = new AnimationTrackDictionary();
            AnimationTrackDictionary atd_bind = new AnimationTrackDictionary();

            foreach (KeyValuePair <string, ModelBoneContent> nip in nameToIndex)
            {
                Keyframe[] frames_id = new Keyframe[2];
                frames_id[0] = new Keyframe();
                frames_id[1] = new Keyframe();
                AnimationTrack at_id = new AnimationTrack(nip.Value.Index, frames_id);
                atd_id.Add(nip.Value.Index, at_id);

                Keyframe[] frames_bind = new Keyframe[2];
                Matrix     mat         = nip.Value.Transform;
                frames_bind[0] = Keyframe.CreateFromMatrix(mat);
                frames_bind[1] = new Keyframe();
                frames_bind[1].CopyFrom(frames_bind[0]);
                AnimationTrack at_bind = new AnimationTrack(nip.Value.Index, frames_bind);
                atd_bind.Add(nip.Value.Index, at_bind);
            }
            ret.AddAnimation(new Animation("$id$", atd_id, 1.0f));
            ret.AddAnimation(new Animation("$bind$", atd_bind, 1.0f));

            return(ret);
        }