Assists in creating palette indices for mesh bones.
Beispiel #1
0
        // returns true if the model contains meshes that have a parent bone as a child of
        // a bone in the skeleton attached to the mesh.
        private bool ValidateMeshSkeleton(MeshContent meshContent)
        {
            List <string> meshParentHierarchy = new List <string>();
            int           meshIndex           = (int)meshContent.OpaqueData["MeshIndex"];
            BoneIndexer   indexer             = indexers[meshIndex];

            if (meshContent.Parent != null && indexer.SkinnedBoneNames.Contains(meshContent.Parent.Name))
            {
                // Warning
                return(false);
            }
            // skeleton is fine
            return(true);
        }
Beispiel #2
0
 private void CreatePaletteIndices(MeshContent mesh)
 {
     foreach (GeometryContent meshPart in mesh.Geometry)
     {
         int         meshIndex = (int)mesh.OpaqueData["MeshIndex"];
         BoneIndexer indexer   = indexers[meshIndex];
         foreach (VertexChannel channel in meshPart.Vertices.Channels)
         {
             if (channel.Name == VertexChannelNames.Weights())
             {
                 VertexChannel <BoneWeightCollection> vc =
                     (VertexChannel <BoneWeightCollection>)channel;
                 foreach (BoneWeightCollection boneWeights in vc)
                 {
                     foreach (BoneWeight weight in boneWeights)
                     {
                         indexer.GetBoneIndex(weight.BoneName);
                     }
                 }
             }
         }
     }
 }
        /// <summary>Processes a SkinnedModelImporter NodeContent root</summary>
        /// <param name="input">The root of the X file tree</param>
        /// <param name="context">The context for this processor</param>
        /// <returns>A model with animation data on its tag</returns>
        public override ModelContent Process(NodeContent input, ContentProcessorContext context)
        {
            //try
            //{
                ModelSplitter splitter;
                if (context.TargetPlatform != TargetPlatform.Xbox360)
                {
                    splitter = new ModelSplitter(input, maximumNumberOfPCBones);
                }
                else
                {
                    splitter = new ModelSplitter(input, maximumNumberOfWiiBones);
                }
                modelSplit = splitter.Split();
                splitter = null;
                this.input = input;
                this.context = context;
                FindMeshes(input);
                indexers = new BoneIndexer[numMeshes];
                for (int i = 0; i < indexers.Length; i++)
                {
                    indexers[i] = new BoneIndexer();
                }
                foreach (MeshContent meshContent in meshes)
                {
                    CreatePaletteIndices(meshContent);
                }

                // Get the process model minus the animation data
                ModelContent c = base.Process(input, context);

                if (!modelSplit && input.OpaqueData.ContainsKey("AbsoluteMeshTransforms"))
                {
                    absoluteMeshTransforms =
                        (List<Matrix>)input.OpaqueData["AbsoluteMeshTransforms"];
                }
                else
                {

                    foreach (MeshContent mesh in meshes)
                    {
                        if (!ValidateMeshSkeleton(mesh))
                        {
                            context.Logger.LogWarning(null, mesh.Identity, "Warning: Mesh found that has a parent that exists as "
                                + "one of the bones in the skeleton attached to the mesh.  Change the mesh "
                                + "skeleton structure or use X - File Animation Library importer if transforms are incorrect.");
                        }
                    }

                }

                Dictionary<string, object> dict = new Dictionary<string, object>();



                // Attach the animation and skinning data to the models tag
                FindAnimations(input);
                // Test to see if any animations have zero duration
                foreach (AnimationContent anim in animations.Values)
                {
                    string errorMsg = "One or more AnimationContent objects have an extremely small duration.  If the animation "
                            + "was intended to last more than one frame, please add \n AnimTicksPerSecond \n{0} \nY; \n{1}\n to your .X "
                            + "file, where Y is a positive integer.";
                    if (anim.Duration.Ticks < ContentUtil.TICKS_PER_60FPS)
                    {
                        context.Logger.LogWarning("", anim.Identity, errorMsg, "{", "}");

                        break;
                    }
                }

                XmlDocument xmlDoc = ReadAnimationXML(input);

                if (xmlDoc != null)
                {
                    SubdivideAnimations(animations, xmlDoc);
                }

                AnimationContentDictionary processedAnims
                    = new AnimationContentDictionary();
                try
                {
                    foreach (KeyValuePair<string, AnimationContent> animKey in animations)
                    {
                        AnimationContent processedAnim = ProcessAnimation(animKey.Value);
                        processedAnims.Add(animKey.Key, processedAnim);

                    }
                    dict.Add("Animations", processedAnims);
                }
                catch
                {
                    throw new Exception("Error processing animations.");
                }

                foreach (ModelMeshContent meshContent in c.Meshes)
                    ReplaceBasicEffects(meshContent);
                skinInfo = ProcessSkinInfo(c);
                dict.Add("SkinInfo", skinInfo);
                c.Tag = dict;

                return c;
            //}
            //catch (Exception e)
            //{
            //    System.IO.File.WriteAllText(@"AnimatedModelProcessorError.txt", e.Message);
            //    throw e;
            //}

            return null;
        }
Beispiel #4
0
        /// <summary>
        /// Go through the vertex channels in the geometry and replace the
        /// BoneWeightCollection objects with weight and index channels.
        /// </summary>
        /// <param name="geometry">The geometry to process.</param>
        /// <param name="vertexChannelIndex">The index of the vertex channel to process.</param>
        /// <param name="context">The processor context.</param>
        protected override void ProcessVertexChannel(GeometryContent geometry, int vertexChannelIndex, ContentProcessorContext context)
        {
            bool boneCollectionsWithZeroWeights = false;

            if (geometry.Vertices.Channels[vertexChannelIndex].Name == VertexChannelNames.Weights())
            {
                int         meshIndex = (int)geometry.Parent.OpaqueData["MeshIndex"];
                BoneIndexer indexer   = indexers[meshIndex];
                // Skin channels are passed in from importers as BoneWeightCollection objects
                VertexChannel <BoneWeightCollection> vc =
                    (VertexChannel <BoneWeightCollection>)
                    geometry.Vertices.Channels[vertexChannelIndex];
                int maxBonesPerVertex = 0;
                for (int i = 0; i < vc.Count; i++)
                {
                    int count = vc[i].Count;
                    if (count > maxBonesPerVertex)
                    {
                        maxBonesPerVertex = count;
                    }
                }

                // Add weights as colors (Converts well to 4 floats)
                // and indices as packed 4byte vectors.
                Color[] weightsToAdd = new Color[vc.Count];
                Byte4[] indicesToAdd = new Byte4[vc.Count];

                // Go through the BoneWeightCollections and create a new
                // weightsToAdd and indicesToAdd array for each BoneWeightCollection.
                for (int i = 0; i < vc.Count; i++)
                {
                    BoneWeightCollection bwc = vc[i];

                    if (bwc.Count == 0)
                    {
                        boneCollectionsWithZeroWeights = true;
                        continue;
                    }

                    bwc.NormalizeWeights(4);
                    int count = bwc.Count;
                    if (count > maxBonesPerVertex)
                    {
                        maxBonesPerVertex = count;
                    }

                    // Add the appropriate bone indices based on the bone names in the
                    // BoneWeightCollection
                    Vector4 bi = new Vector4();
                    bi.X = count > 0 ? indexer.GetBoneIndex(bwc[0].BoneName) : (byte)0;
                    bi.Y = count > 1 ? indexer.GetBoneIndex(bwc[1].BoneName) : (byte)0;
                    bi.Z = count > 2 ? indexer.GetBoneIndex(bwc[2].BoneName) : (byte)0;
                    bi.W = count > 3 ? indexer.GetBoneIndex(bwc[3].BoneName) : (byte)0;


                    indicesToAdd[i] = new Byte4(bi);
                    Vector4 bw = new Vector4();
                    bw.X            = count > 0 ? bwc[0].Weight : 0;
                    bw.Y            = count > 1 ? bwc[1].Weight : 0;
                    bw.Z            = count > 2 ? bwc[2].Weight : 0;
                    bw.W            = count > 3 ? bwc[3].Weight : 0;
                    weightsToAdd[i] = new Color(bw);
                }

                // Remove the old BoneWeightCollection channel
                geometry.Vertices.Channels.Remove(vc);
                // Add the new channels
                geometry.Vertices.Channels.Add <Byte4>(VertexElementUsage.BlendIndices.ToString(), indicesToAdd);
                geometry.Vertices.Channels.Add <Color>(VertexElementUsage.BlendWeight.ToString(), weightsToAdd);
            }
            else
            {
                // No skinning info, so we let the base class process the channel
                base.ProcessVertexChannel(geometry, vertexChannelIndex, context);
            }
            if (boneCollectionsWithZeroWeights)
            {
                context.Logger.LogWarning("", geometry.Identity,
                                          "BonesWeightCollections with zero weights found in geometry.");
            }
        }
Beispiel #5
0
        /// <summary>Processes a SkinnedModelImporter NodeContent root</summary>
        /// <param name="input">The root of the X file tree</param>
        /// <param name="context">The context for this processor</param>
        /// <returns>A model with animation data on its tag</returns>
        public override ModelContent Process(NodeContent input, ContentProcessorContext context)
        {
            //try
            //{
            ModelSplitter splitter;

            if (context.TargetPlatform != TargetPlatform.Xbox360)
            {
                splitter = new ModelSplitter(input, maximumNumberOfPCBones);
            }
            else
            {
                splitter = new ModelSplitter(input, maximumNumberOfWiiBones);
            }
            modelSplit   = splitter.Split();
            splitter     = null;
            this.input   = input;
            this.context = context;
            FindMeshes(input);
            indexers = new BoneIndexer[numMeshes];
            for (int i = 0; i < indexers.Length; i++)
            {
                indexers[i] = new BoneIndexer();
            }
            foreach (MeshContent meshContent in meshes)
            {
                CreatePaletteIndices(meshContent);
            }

            // Get the process model minus the animation data
            ModelContent c = base.Process(input, context);

            if (!modelSplit && input.OpaqueData.ContainsKey("AbsoluteMeshTransforms"))
            {
                absoluteMeshTransforms =
                    (List <Matrix>)input.OpaqueData["AbsoluteMeshTransforms"];
            }
            else
            {
                foreach (MeshContent mesh in meshes)
                {
                    if (!ValidateMeshSkeleton(mesh))
                    {
                        context.Logger.LogWarning(null, mesh.Identity, "Warning: Mesh found that has a parent that exists as "
                                                  + "one of the bones in the skeleton attached to the mesh.  Change the mesh "
                                                  + "skeleton structure or use X - File Animation Library importer if transforms are incorrect.");
                    }
                }
            }

            Dictionary <string, object> dict = new Dictionary <string, object>();



            // Attach the animation and skinning data to the models tag
            FindAnimations(input);
            // Test to see if any animations have zero duration
            foreach (AnimationContent anim in animations.Values)
            {
                string errorMsg = "One or more AnimationContent objects have an extremely small duration.  If the animation "
                                  + "was intended to last more than one frame, please add \n AnimTicksPerSecond \n{0} \nY; \n{1}\n to your .X "
                                  + "file, where Y is a positive integer.";
                if (anim.Duration.Ticks < ContentUtil.TICKS_PER_60FPS)
                {
                    context.Logger.LogWarning("", anim.Identity, errorMsg, "{", "}");

                    break;
                }
            }

            XmlDocument xmlDoc = ReadAnimationXML(input);

            if (xmlDoc != null)
            {
                SubdivideAnimations(animations, xmlDoc);
            }

            AnimationContentDictionary processedAnims
                = new AnimationContentDictionary();

            try
            {
                foreach (KeyValuePair <string, AnimationContent> animKey in animations)
                {
                    AnimationContent processedAnim = ProcessAnimation(animKey.Value);
                    processedAnims.Add(animKey.Key, processedAnim);
                }
                dict.Add("Animations", processedAnims);
            }
            catch
            {
                throw new Exception("Error processing animations.");
            }

            foreach (ModelMeshContent meshContent in c.Meshes)
            {
                ReplaceBasicEffects(meshContent);
            }
            skinInfo = ProcessSkinInfo(c);
            dict.Add("SkinInfo", skinInfo);
            c.Tag = dict;

            return(c);

            //}
            //catch (Exception e)
            //{
            //    System.IO.File.WriteAllText(@"AnimatedModelProcessorError.txt", e.Message);
            //    throw e;
            //}

            return(null);
        }
Beispiel #6
0
        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);
        }