internal SkinnedModelContent(ModelContent model, SkinnedModelBoneContentCollection skeleton,
     AnimationClipContentDictionary animationClips)
 {
     this.model = model;
     this.skeleton = skeleton;
     this.animationClips = animationClips;
 }
Example #2
0
		public HeightMapInfoContent(ModelContent model, MeshContent terrainMesh, float terrainScale, int terrainWidth, int terrainLength) {
			Model = model;
			if (terrainMesh == null) {
				throw new ArgumentNullException("terrainMesh");
			}

			if (terrainWidth <= 0) {
				throw new ArgumentOutOfRangeException("terrainWidth");
			}
			if (terrainLength <= 0) {
				throw new ArgumentOutOfRangeException("terrainLength");
			}

			TerrainScale = terrainScale;
			Height = new float[terrainWidth, terrainLength];
			Normals = new Vector3[terrainWidth, terrainLength];
			GeometryContent item = terrainMesh.Geometry[0];
			for (int i = 0; i < item.Vertices.VertexCount; i++) {
				Vector3 vector3 = item.Vertices.Positions[i];
				Vector3 item1 = (Vector3)item.Vertices.Channels[VertexChannelNames.Normal()][i];
				int x = (int)(vector3.X / terrainScale + (terrainWidth - 1) / 2f);
				int z = (int)(vector3.Z / terrainScale + (terrainLength - 1) / 2f);
				Height[x, z] = vector3.Y;
				Normals[x, z] = item1;
			}
		}
Example #3
0
        public override ModelContent Process(NodeContent input, ContentProcessorContext context)
        {
            CompileRegularExpressions();
            context.Logger.LogMessage("Output Platform: {0}", context.TargetPlatform);

            maxScale_  = 0;
            maxOffset_ = 0;
            BoneContent skeleton = MeshHelper.FindSkeleton(input);

            FlattenTransforms(input, skeleton, context);
            SkinnedBone[] inverseBindPose = GetInverseBindPose(input, context, skeleton);
            context.Logger.LogMessage("Found {0} skinned bones in skeleton.", (inverseBindPose == null) ? 0 : inverseBindPose.Length);

            ModelContent output = base.Process(input, context);

            if (output.Tag == null)
            {
                output.Tag = new Dictionary <string, object>();
            }

            if (FoundSkinning)
            {
#if DEBUG
                StringBuilder strb = new StringBuilder();
#endif
                if (inverseBindPose == null)
                {
                    throw new System.Exception("Could not find skeleton although there is skinned data.");
                }
                for (int i = 0; i != inverseBindPose.Length; ++i)
                {
                    SkinnedBone sb = inverseBindPose[i];
                    int         q  = 0;
                    sb.Index = -1;
                    foreach (ModelBoneContent mbc in output.Bones)
                    {
                        if (mbc.Name == sb.Name)
                        {
                            sb.Index = mbc.Index;
                            break;
                        }
                        ++q;
                    }
                    if (sb.Index == -1)
                    {
                        throw new System.ArgumentException(
                                  String.Format("Can't find the index for animated bone named {0}.", sb.Name));
                    }
                    inverseBindPose[i] = sb;
                }
                ((Dictionary <string, object>)output.Tag).Add("InverseBindPose", inverseBindPose);
            }

            ((Dictionary <string, object>)output.Tag).Add("AnimationSet",
                                                          BuildAnimationSet(input, ref output, context));

            ((Dictionary <string, object>)output.Tag).Add("BoundsInfo",
                                                          new BoundsInfo(maxScale_, maxOffset_));
            return(output);
        }
 public override ModelContent Process(NodeContent input, ContentProcessorContext context)
 {
     model = base.Process(input, context);
     AnimationClips clips = ProcessAnimations(model, input, context);
     model.Tag = clips;
     return model;
 }
 /// <summary>
 /// Calculate a bounding box for the model.
 /// </summary>
 /// <param name="model">The model to calculate AABBs for</param>
 public static void CalculateBoundingBox(NodeContent input, ModelContent model)
 {
   BoundingBox box = new BoundingBox();
   CalculateBoundingBox(input, ref box);
   if (model.Tag == null)
     model.Tag = new Dictionary<string, object>();
   (model.Tag as Dictionary<string, object>).Add("BoundingBox", box);
 }
        public override ModelContent Process(NodeContent input, ContentProcessorContext context)
        {
            BoneContent skeleton = ProcessSkeleton(input);

            SwapSkinMaterials(input);

            model = base.Process(input, context);

            ProcessAnimations(model, input, context);

            // Add the extra content to the model 
            model.Tag = modelExtra;

            return model;
        }
        /// <summary>
        /// The function to process a model from original content into model content for export
        /// </summary>
        /// <param name="input"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override ModelContent Process(NodeContent input, ContentProcessorContext context)
        {
            // Process the skeleton for skinned character animation
            BoneContent skeleton = ProcessSkeleton(input);

            SwapSkinnedMaterial(input);

            model = base.Process(input, context);

            ProcessAnimations(model, input, context,input.Identity);

            // Add the extra content to the model
            model.Tag = modelExtra;

            return model;
        }
Example #8
0
        private BoundingBox GetBoundingBox(ModelContent model)
        {
            Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
            Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);

            foreach (ModelMeshContent mesh in model.Meshes)
            {
                foreach (ModelMeshPartContent part in mesh.MeshParts)
                {
                    for (int i = 0; i < part.NumVertices; i++)
                    {
                        Vector3 pos = GetVertexPosition(part.VertexBuffer, i);
                        min = Vector3.Min(min, pos);
                        max = Vector3.Max(max, pos);
                    }
                }
            }

            return(new BoundingBox(min, max));
        }
        /// <summary>
        /// Entry point for animation processing. 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="input"></param>
        /// <param name="context"></param>
        private void ProcessAnimations(ModelContent model, NodeContent input, ContentProcessorContext context)
        {
            // First build a lookup table so we can determine the 
            // index into the list of bones from a bone name.
            for (int i = 0; i < model.Bones.Count; i++)
            {
                bones[model.Bones[i].Name] = i;
            }

            // For saving the bone transforms
            boneTransforms = new Matrix[model.Bones.Count];

            //
            // Collect up all of the animation data
            //

            ProcessAnimationsRecursive(input);

            // Ensure there is always a clip, even if none is included in the FBX
            // That way we can create poses using FBX files as one-frame 
            // animation clips
            if (modelExtra.Clips.Count == 0)
            {
                AnimationClip clip = new AnimationClip();
                modelExtra.Clips.Add(clip);

                string clipName = "Take 001";

                // Retain by name
                clips[clipName] = clip;

                clip.Name = clipName;
                foreach (ModelBoneContent bone in model.Bones)
                {
                    AnimationClip.Bone clipBone = new AnimationClip.Bone();
                    clipBone.Name = bone.Name;

                    clip.Bones.Add(clipBone);
                }
            }

            // Ensure all animations have a first key frame for every bone
            foreach (AnimationClip clip in modelExtra.Clips)
            {
               
                foreach (int b in bones.Values)
                {
                    List<AnimationClip.Keyframe> keyframes = clip.Bones[b].Keyframes;
                    if (keyframes.Count == 0 || keyframes[0].Time > 0)
                    {
                        AnimationClip.Keyframe keyframe = new AnimationClip.Keyframe();
                        keyframe.Time = 0;
                        keyframe.SetTransform(boneTransforms[b]);
                        keyframes.Insert(0, keyframe);
                    }
                }
            }
        }
        private ModelContent SkinnedData(ModelContent model, NodeContent input, ContentProcessorContext context, MeshMetaData metadata)
        {
            // Find the skeleton
            BoneContent skeleton = MeshHelper.FindSkeleton(input);

            if (skeleton != null)
            {
                // Read the bind pose and skeleton hierarchy data.
                IList<BoneContent> bones = MeshHelper.FlattenSkeleton(skeleton);

                // Set up the bone matrices and index lists
                List<Matrix> bindPose = new List<Matrix>();
                List<Matrix> inverseBindPose = new List<Matrix>();
                List<int> skeletonHierarchy = new List<int>();
                Dictionary<String, int> boneIndices = new Dictionary<String, int>();
                Dictionary<String, AnimationClip> animationClips = new Dictionary<String, AnimationClip>();

                // Extract the bind pose transforms, inverse bind pose transforms,
                // and parent bone index of each bone in order
                foreach (BoneContent bone in bones)
                {
                    bindPose.Add(bone.Transform);
                    inverseBindPose.Add(Matrix.Invert(bone.AbsoluteTransform));
                    skeletonHierarchy.Add(bones.IndexOf(bone.Parent as BoneContent));
                    boneIndices.Add(bone.Name, boneIndices.Count);
                }

                // Convert animation data to our runtime format.
                animationClips = ProcessAnimations(skeleton.Animations, bones);

                // Save skinndd data
                metadata.SkinningData = new SkinningData(animationClips, bindPose, inverseBindPose, skeletonHierarchy, boneIndices);
            }

            // Save meta data
            model.Tag = metadata;

            // Return the model with the custom animation data
            return model;
        }
Example #11
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);
        }
        private SkinInfoContentCollection[] ProcessSkinInfo(ModelContent model)
        {
            SkinInfoContentCollection[] info = new SkinInfoContentCollection[model.Meshes.Count];
            Dictionary<string, int> boneDict = new Dictionary<string,int>();
            foreach (ModelBoneContent b in model.Bones)
            {
                if (b.Name != null && !boneDict.ContainsKey(b.Name))
                    boneDict.Add(b.Name, b.Index);
            }

            for (int i = 0; i < info.Length; i++)
            {
                info[i] = new SkinInfoContentCollection();
                BoneIndexer indexer = indexers[i];
                ReadOnlyCollection<string> skinnedBoneNames = indexer.SkinnedBoneNames;

                Matrix[] absoluteTransforms = new Matrix[model.Bones.Count];
                CalculateAbsoluteTransforms(model.Bones[0], absoluteTransforms);

                Matrix absoluteMeshTransform;
                if (absoluteMeshTransforms == null)
                {
                    absoluteMeshTransform = absoluteTransforms[model.Meshes[i].ParentBone.Index];
                }
                else
                {
                    absoluteMeshTransform = absoluteMeshTransforms[i];
                }

                for (int j = 0; j < skinnedBoneNames.Count; j++)
                {
                    string name = skinnedBoneNames[j];
                    SkinInfoContent content = new SkinInfoContent();
                    content.BoneIndex = boneDict[name];
                    content.PaletteIndex = indexer.GetBoneIndex(name);
                    content.InverseBindPoseTransform = absoluteMeshTransform *
                        Matrix.Invert(absoluteTransforms[boneDict[name]]);
                    content.BoneName = name;
                    info[i].Add(content);
                }

            }
            return info;
        }
        private SkinInfoContentCollection[] ProcessSkinInfo(ModelContent model)
        {
            SkinInfoContentCollection[] info = new SkinInfoContentCollection[model.Meshes.Count];
            Dictionary<string, int> boneDict = new Dictionary<string,int>();

            //if (model.Bones.Count > maximumNumberOfPCBones)
            //{
            //    throw new Exception("There are too many bones! You have " + model.Bones.Count + " and you can only have " + maximumNumberOfPCBones);
            //}

            foreach (ModelBoneContent b in model.Bones)
            {
                if (b.Name != null && !boneDict.ContainsKey(b.Name))
                    boneDict.Add(b.Name, b.Index);
            }

            for (int i = 0; i < info.Length; i++)
            {
                info[i] = new SkinInfoContentCollection();
                BoneIndexer indexer = indexers[i];
                ReadOnlyCollection<string> skinnedBoneNames = indexer.SkinnedBoneNames;

                Matrix[] absoluteTransforms = new Matrix[model.Bones.Count];
                CalculateAbsoluteTransforms(model.Bones[0], absoluteTransforms);

                Matrix absoluteMeshTransform;
                if (absoluteMeshTransforms == null)
                {
                    absoluteMeshTransform = absoluteTransforms[model.Meshes[i].ParentBone.Index];
                }
                else
                {
                    absoluteMeshTransform = absoluteMeshTransforms[i];
                }

                for (int j = 0; j < skinnedBoneNames.Count; j++)
                {
                    string name = skinnedBoneNames[j];
                    SkinInfoContent content = new SkinInfoContent();

                    try
                    {
                        content.BoneIndex = boneDict[name];
                    }
                    catch (KeyNotFoundException knfe)
                    {
                        string error = "Could not find a bone by the name of " + name + ".  This is skinned bone index " + j + ".";

                        error += "\nThere are " + skinnedBoneNames.Count + " skinned bones:";

                        for (int boneIndex = 0; boneIndex < skinnedBoneNames.Count; boneIndex++)
                        {
                            error += "\n " + skinnedBoneNames[boneIndex];
                        }

                        error += "\nThere are " + model.Bones.Count + " bones:";

                        foreach (ModelBoneContent b in model.Bones)
                        {
                            error += "\n " + b.Name;
                        }

                        throw new KeyNotFoundException(error);
                    }
                        
                    content.PaletteIndex = indexer.GetBoneIndex(name);
                    content.InverseBindPoseTransform = absoluteMeshTransform *
                        Matrix.Invert(absoluteTransforms[boneDict[name]]);
                    content.BoneName = name;
                    info[i].Add(content);
                }

            }
            return info;
        }
        /// <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();
            TimeSpan longestUniqueDuration = new TimeSpan(0);
            foreach (string name in acdict.Keys)
            {
              if (!IncludeTrack(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);
              Debug.Assert(name != null);
              at.Name = name;
              tracks.Add(bix, at);
            }
            if (ShouldTrimAnimation(ac))
            {
              TrimAnimationTracks(ac.Name, tracks, context);
            }

            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)
              {
            if (!IncludeTrack(nip.Key))
              continue;
            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);
            at_id.Name = nip.Key;
            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);
            at_bind.Name = nip.Key;
            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;
        }
 public InstancedSkinnedModelContent(ModelContent model, 
     InstancedSkinningDataContent instancedSkinningInfo)
 {
     this.modelContent = model;
     this.instancedSkinningData = instancedSkinningInfo;
 }
Example #16
0
        /// <summary>
        /// The function to process a model from original content into model content for export
        /// </summary>
        /// <param name="input"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override ModelContent Process(NodeContent input, ContentProcessorContext context)
        {
            if (input == null) throw new ArgumentNullException("input");

            directory = Path.GetDirectoryName(input.Identity.SourceFilename);

            LookUpTextures(input);
            // Process the skeleton for skinned character animation
            BoneContent skeleton = ProcessSkeleton(input);

            SwapSkinnedMaterial(input);

            model = base.Process(input, context);

            ProcessAnimations(model, input, context,input.Identity);

            List<Vector3> vertices = new List<Vector3>();
            AddVerticesToList(input, vertices);
            modelExtra.boundingBox = BoundingBox.CreateFromPoints(vertices);
            modelExtra.boundingSphere = BoundingSphere.CreateFromPoints(vertices);

            // Add the extra content to the model
            model.Tag = modelExtra;

            List<Vector3[]> meshVertices = new List<Vector3[]>();
            meshVertices = AddModelMeshVertexArrayToList(input, meshVertices);

            int i = 0;
            foreach (ModelMeshContent mesh in model.Meshes)
            {
                List<Vector3> modelMeshVertices = new List<Vector3>();
                foreach (ModelMeshPartContent part in mesh.MeshParts)
                    {
                        if (i < meshVertices.Count)
                        modelMeshVertices.AddRange(meshVertices[i++]);
                    }
                mesh.Tag = modelMeshVertices.ToArray();
            }

            return model;
        }
        public override ModelContent Process(NodeContent input, ContentProcessorContext context)
        {
            if (skinned)
            {
                ProcessSkeleton(input);
            }
            model = base.Process(input, context);
            AnimationClips clips = ProcessAnimations(model, input, context);
            clips.SkelToBone = skelToBone;
            model.Tag = clips;

            return model;
        }
        private AnimationClips ProcessAnimations(ModelContent model, NodeContent input, ContentProcessorContext context)
        {
            //first build a lookup table so we can determine the index into the list of bones from a bone name
            for (int i = 0; i < model.Bones.Count; i++)
            {
                bones[model.Bones[i].Name] = i;
            }

            AnimationClips animationClips = new AnimationClips();
            ProcessAnimationRecursive(input, animationClips);
            return animationClips;
        }
        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContent
        /// object to our runtime AnimationClip format.
        /// </summary>
        static ModelAnimationClip ProcessAnimation(
            string animationName,
            Dictionary<string, int> boneMap,
            NodeContent input,
            ModelContent model)
        {
            List<ModelKeyframe> keyframes = new List<ModelKeyframe>();
            TimeSpan duration = TimeSpan.Zero;

            AddTransformationNodes(animationName, boneMap, input, keyframes, ref duration);

            // Sort the merged keyframes by time.
            keyframes.Sort(CompareKeyframeTimes);

            if (keyframes.Count == 0)
                throw new InvalidContentException("Animation has no keyframes.");

            if (duration <= TimeSpan.Zero)
                throw new InvalidContentException("Animation has a zero duration.");

            return new ModelAnimationClip(duration, keyframes);
        }
        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContentDictionary
        /// object to our runtime AnimationClip format.
        /// </summary>
        static void ProcessAnimations(
            NodeContent input,
            ModelContent model,
            Dictionary<string, ModelAnimationClip> animationClips,
            Dictionary<string, ModelAnimationClip> rootClips)
        {
            // Build up a table mapping bone names to indices.
            Dictionary<string, int> boneMap = new Dictionary<string, int>();
            for (int i = 0; i < model.Bones.Count; i++)
            {
                string boneName = model.Bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                    boneMap.Add(boneName, i);
            }

            // Convert each animation in the root of the object
            foreach (KeyValuePair<string, AnimationContent> animation in input.Animations)
            {
                ModelAnimationClip processed = ProcessRootAnimation(animation.Value, model.Bones[0].Name);

                rootClips.Add(animation.Key, processed);
            }

            // Get the unique names of the animations on the mesh children
            List<string> animationNames = new List<string>();
            AddAnimationNodes(animationNames, input);

            // Now create those animations
            foreach (string key in animationNames)
            {
                ModelAnimationClip processed = ProcessAnimation(key, boneMap, input, model);

                animationClips.Add(key, processed);
            }
        }
        private AnimationClips ProcessAnimations(ModelContent model,
                                         NodeContent input, ContentProcessorContext context)
        {
            // First build a lookup table so we can determine the
            // index into the list of bones from a bone name.
            for (int i = 0; i < model.Bones.Count; i++)
            {
                bones[model.Bones[i].Name] = i;
            }

            AnimationClips animationClips = new AnimationClips();

            ProcessAnimationsRecursive(input, animationClips);

            // Ensure all animations have a first key frame for every bone
            foreach (AnimationClips.Clip clip in animationClips.Clips.Values)
            {
                for (int b = 0; b < bones.Count; b++)
                {
                    List<AnimationClips.Keyframe> keyframes = clip.Keyframes[b];
                    if (keyframes.Count == 0 || keyframes[0].Time > 0)
                    {
                        AnimationClips.Keyframe keyframe = new AnimationClips.Keyframe();
                        keyframe.Time = 0;

                        Matrix transform = model.Bones[b].Transform;
                        transform.Right = Vector3.Normalize(transform.Right);
                        transform.Up = Vector3.Normalize(transform.Up);
                        transform.Backward = Vector3.Normalize(transform.Backward);
                        keyframe.Rotation = Quaternion.CreateFromRotationMatrix(transform);
                        keyframe.Translation = transform.Translation;

                        keyframes.Insert(0, keyframe);
                    }
                }
            }

            return animationClips;
        }
Example #22
0
        private void FlattenNormals(ModelContent model)
        {
            //This stuff re-calculates surface normals to give a low-poly flat shading effect
            foreach (ModelMeshContent mesh in model.Meshes)
            {
                foreach (ModelMeshPartContent part in mesh.MeshParts)
                {
                    IndexCollection indices = part.IndexBuffer;
                    for (int i = 0; i < indices.Count; i += 3)
                    {
                        Vector3 p1 = GetVertexPosition(part.VertexBuffer, indices[i + 0]);
                        Vector3 p2 = GetVertexPosition(part.VertexBuffer, indices[i + 1]);
                        Vector3 p3 = GetVertexPosition(part.VertexBuffer, indices[i + 2]);

                        Vector3 v1     = p2 - p1;
                        Vector3 v2     = p3 - p1;
                        Vector3 normal = Vector3.Cross(v1, v2);

                        normal.Normalize();

                        for (int j = 0; j < 3; j++)
                        {
                            for (int k = 0; k < 3; k++)
                            {
                                SetVertexNormalCoord(part.VertexBuffer, i + j, normal, k);
                            }
                        }
                    }

                    /*
                     *                  byte[] vertices = part.VertexBuffer.VertexData;
                     *                  //We only have the packed vertex data available so we need to parse the individual bytes
                     *                  for (int i = 0; i < part.NumVertices; i++)
                     *                  {
                     *                          float[] pos = new float[3];
                     *                          float[] normal = new float[3];
                     *
                     *                          for (int j = 0; j < 3; j++)
                     *                          {
                     *                                  int posOffset = i * (int)part.VertexBuffer.VertexDeclaration.VertexStride + j * 4; //4 bytes per float
                     *                                  int normalOffset = posOffset + 12; //Normal is after the 3 position words
                     *
                     *                                  pos[j] = System.BitConverter.ToSingle(vertices, posOffset);
                     *                                  normal[j] = System.BitConverter.ToSingle(vertices, normalOffset);
                     *                          }
                     *
                     *                          Console.WriteLine("=====");
                     *                  }*/


                    //byte[] newArray = new[] { vertices[3], vertices[2], vertices[1], vertices[0] };


                    /*short[] indices = new short[part.IndexBuffer.IndexCount];
                     *                  part.IndexBuffer.GetData<short>(indices);
                     *
                     *                  for (int i = 0; i < indices.Length; i += 3)
                     *                  {
                     *                          Vector3 p1 = vertices[indices[i]].Position;
                     *                          Vector3 p2 = vertices[indices[i + 1]].Position;
                     *                          Vector3 p3 = vertices[indices[i + 2]].Position;
                     *
                     *                          Vector3 v1 = p2 - p1;
                     *                          Vector3 v2 = p3 - p1;
                     *                          Vector3 normal = Vector3.Cross(v1, v2);
                     *
                     *                          normal.Normalize();
                     *
                     *                          vertices[indices[i]].Normal = normal;
                     *                          vertices[indices[i + 1]].Normal = normal;
                     *                          vertices[indices[i + 2]].Normal = normal;
                     *                  }
                     *
                     *                  part.VertexBuffer.SetData<VertexPositionNormalTexture>(vertices);*/
                }
            }
        }
Example #23
0
        /// <summary>
        /// Entry point for animation processing. 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="input"></param>
        /// <param name="context"></param>
        private void ProcessAnimations(ModelContent model, NodeContent input, ContentProcessorContext context, ContentIdentity sourceIdentity)
        {
            // First build a lookup table so we can determine the
            // index into the list of bones from a bone name.
            for (int i = 0; i < model.Bones.Count; i++)
            {
                bones[model.Bones[i].Name] = i;
            }

            // For saving the bone transforms
            boneTransforms = new Matrix[model.Bones.Count];

            //
            // Collect up all of the animation data
            //

            ProcessAnimationsRecursive(input);

            // Check to see if there's an animation clip definition
            // Here, we're checking for a file with the _Anims suffix.
            // So, if your model is named dude.fbx, we'd add dude_Anims.xml in the same folder
            // and the pipeline will see the file and use it to override the animations in the
            // original model file.
            string SourceModelFile = sourceIdentity.SourceFilename;
            string SourcePath = Path.GetDirectoryName(SourceModelFile);
            string AnimFilename = Path.GetFileNameWithoutExtension(SourceModelFile);
            AnimFilename += "_Anims.xml";
            string AnimPath = Path.Combine(SourcePath, AnimFilename);
            if (File.Exists(AnimPath))
            {
                // Add the filename as a dependency, so if it changes, the model is rebuilt
                context.AddDependency(AnimPath);

                // Load the animation definition from the XML file
                AnimationDefinition AnimDef = context.BuildAndLoadAsset<XmlImporter, AnimationDefinition>(new ExternalReference<XmlImporter>(AnimPath), null);

                if (modelExtra.Clips.Count > 0) //if there are some animations in our model
                {
                    foreach (AnimationDefinition.ClipPart Part in AnimDef.ClipParts)
                    {
                        // Grab the main clip that we are using and copy to MainClip

                        AnimationClip MainClip = new AnimationClip();

                        float StartTime = GetTimeSpanForFrame(Part.StartFrame, AnimDef.OriginalFrameCount, modelExtra.Clips[AnimDef.OriginalClipName].Duration);
                        float EndTime = GetTimeSpanForFrame(Part.EndFrame, AnimDef.OriginalFrameCount, modelExtra.Clips[AnimDef.OriginalClipName].Duration);

                        MainClip.Duration = EndTime-StartTime;
                        MainClip.Name = modelExtra.Clips[AnimDef.OriginalClipName].Name;

                        // Process each of our new animation clip parts
                        for (int i = 0; i < modelExtra.Clips[AnimDef.OriginalClipName].Bones.Count; i++)
                        {
                            AnimationClip.Bone clipBone = new AnimationClip.Bone();
                            clipBone.Name = modelExtra.Clips[AnimDef.OriginalClipName].Bones[i].Name;
                            LinkedList<AnimationClip.Keyframe> keyframes = new LinkedList<AnimationClip.Keyframe>();

                            if (modelExtra.Clips[AnimDef.OriginalClipName].Bones[i].Keyframes.Count != 0)
                            {

                                for (int j = 0; j < modelExtra.Clips[AnimDef.OriginalClipName].Bones[i].Keyframes.Count; j++)
                                {

                                    if ((modelExtra.Clips[AnimDef.OriginalClipName].Bones[i].Keyframes[j].Time >= StartTime) && (modelExtra.Clips[AnimDef.OriginalClipName].Bones[i].Keyframes[j].Time <= EndTime))
                                    {
                                        AnimationClip.Keyframe frame = new AnimationClip.Keyframe();
                                        frame.Rotation = modelExtra.Clips[AnimDef.OriginalClipName].Bones[i].Keyframes[j].Rotation;
                                        frame.Time = modelExtra.Clips[AnimDef.OriginalClipName].Bones[i].Keyframes[j].Time - StartTime;
                                        frame.Translation = modelExtra.Clips[AnimDef.OriginalClipName].Bones[i].Keyframes[j].Translation;
                                        keyframes.AddLast(frame);
                                       //clipBone.Keyframes.Add(frame);
                                    }

                                }
                            }
                           // LinearKeyframeReduction(keyframes);
                            clipBone.Keyframes = keyframes.ToList<AnimationClip.Keyframe>();
                            MainClip.Bones.Add(clipBone);

                        }
                        modelExtra.Clips.Add(Part.ClipName, MainClip);

                    }
                }
            }

            // Ensure there is always a clip, even if none is included in the FBX
            // That way we can create poses using FBX files as one-frame
            // animation clips
            if (modelExtra.Clips.Count == 0)
            {
                AnimationClip clip = new AnimationClip();
                modelExtra.Clips.Add("Take 001",clip);

                string clipName = "Take 001";

                // Retain by name
                clips[clipName] = clip;

                clip.Name = clipName;
                foreach (ModelBoneContent bone in model.Bones)
                {
                    AnimationClip.Bone clipBone = new AnimationClip.Bone();
                    clipBone.Name = bone.Name;

                    clip.Bones.Add(clipBone);
                }
            }

            //Ensure all animations have a first key frame for every bone
            foreach (KeyValuePair<string,AnimationClip> clip in modelExtra.Clips)
            {
                for (int b = 0; b < bones.Count; b++)
                {
                    List<AnimationClip.Keyframe> keyframes = clip.Value.Bones[b].Keyframes;
                    if (keyframes.Count == 0 || keyframes[0].Time > 0)
                    {
                        AnimationClip.Keyframe keyframe = new AnimationClip.Keyframe();
                        keyframe.Time = 0;
                        keyframe.Transform = boneTransforms[b];
                        keyframes.Insert(0, keyframe);
                    }
                }
            }
        }
Example #24
0
        private static void FindTextureName(ModelContent model, ContentProcessorContext context, MeshData meshData)
        {
            string[] dirSeparators = { context.OutputDirectory };

            int counter = 0;
            for (int i = 0; i < model.Meshes.Count; i++)
            {
                ModelMeshContent mesh = model.Meshes[i];
                for (int j = 0; j < mesh.MeshParts.Count; j++)
                {
                    ModelMeshPartContent part = mesh.MeshParts[j];
                    SubMeshData subData = meshData.SubMeshDatas[counter];
                    foreach (KeyValuePair<string, ExternalReference<TextureContent>> textureRef in part.Material.Textures)
                    {
                        ExternalReference<TextureContent> texture = textureRef.Value;
                        string textureName = texture.Filename.Split(dirSeparators, StringSplitOptions.RemoveEmptyEntries)[0];
                        string finalName = textureName.Split(ExtensionSeparators, StringSplitOptions.RemoveEmptyEntries)[0];
                        subData.TexturesName.Add(textureRef.Key, finalName);
                    }

                    counter++;
                }
            }
        }