/// <summary>
        /// As an optimization, ProcessVertexChannel is overriden to remove data which
        /// is not used by the vertex shader.
        /// </summary>
        /// <param name="geometry">the geometry object which contains the
        /// vertex channel</param>
        /// <param name="vertexChannelIndex">the index of the vertex channel
        /// to operate on</param>
        /// <param name="context">the context that the processor is operating
        /// under.  in most cases, this parameter isn't necessary; but could
        /// be used to log a warning that a channel had been removed.</param>
        protected override void ProcessVertexChannel(GeometryContent geometry,
                                                     int vertexChannelIndex, ContentProcessorContext context)
        {
            String vertexChannelName =
                geometry.Vertices.Channels[vertexChannelIndex].Name;

            // if this vertex channel has an acceptable names, process it as normal.
            if (acceptableVertexChannelNames.Contains(vertexChannelName))
            {
                base.ProcessVertexChannel(geometry, vertexChannelIndex, context);
            }
            // otherwise, remove it from the vertex channels; it's just extra data
            // we don't need.
            else
            {
                geometry.Vertices.Channels.Remove(vertexChannelName);
            }

            // Remove texture channel for untextured meshes
            if (!geometry.Vertices.Channels.Contains(VertexChannelNames.TextureCoordinate(0)))
            {
                geometry.Vertices.Channels.Remove(VertexChannelNames.TextureCoordinate(0));
            }

            // Remove vertex weights for unskinned meshes
            if (!geometry.Vertices.Channels.Contains(VertexChannelNames.Weights()))
            {
                geometry.Vertices.Channels.Remove(VertexChannelNames.Weights());
            }
        }
        private bool ValidateGeometry(GeometryContent geometry, ContentProcessorContext context)
        {
            // Check if the geometry has material
            if (geometry.Material == null)
            {
                throw new InvalidContentException(string.Format(
                                                      "Mesh {0} has a geometry that does not have a material.", geometry.Parent.Name));
            }

            // Check if the geometry has skinning information
            if (!geometry.Vertices.Channels.Contains(VertexChannelNames.Weights()))
            {
                /*
                 * context.Logger.LogWarning(null, geometry.Parent.Identity,
                 *  string.Format("Mesh {0} has a geometry that does not have a skinning " +
                 *  "blend weights channel and will be skipped.", geometry.Parent.Name));
                 *
                 * geometry.Parent.Geometry.Remove(geometry);
                 */

                throw new InvalidContentException(string.Format("Mesh {0} has a geometry " +
                                                                "that does not have a skinning blend weights channel.", geometry.Parent.Name));
            }

            return(true);
        }
        private static bool MeshHasSkinning(MeshContent mesh)
        {
            bool flag;
            bool flag1;
            IEnumerator <GeometryContent> enumerator = mesh.Geometry.GetEnumerator();

            try {
                do
                {
                    flag1 = enumerator.MoveNext();
                    if (flag1)
                    {
                        GeometryContent current = enumerator.Current;
                        flag1 = current.Vertices.Channels.Contains(VertexChannelNames.Weights());
                    }
                    else
                    {
                        flag = true;
                        return(flag);
                    }
                }while (flag1);
                flag = false;
                return(flag);
            } finally {
                flag1 = enumerator == null;
                if (!flag1)
                {
                    enumerator.Dispose();
                }
            }
            flag = true;
            return(flag);
        }
Exemple #4
0
        public static bool NeedsSplitting(MeshContent mesh, int maxBones)
        {
            SortedDictionary <string, object> skinnedBones = new SortedDictionary <string, object>();

            foreach (GeometryContent geom in mesh.Geometry)
            {
                VertexChannel <BoneWeightCollection> weightChannel = null;
                foreach (VertexChannel channel in geom.Vertices.Channels)
                {
                    if (channel.Name == VertexChannelNames.Weights())
                    {
                        weightChannel = (VertexChannel <BoneWeightCollection>)channel;
                        break;
                    }
                }
                if (weightChannel != null)
                {
                    foreach (BoneWeightCollection weights in weightChannel)
                    {
                        foreach (BoneWeight weight in weights)
                        {
                            if (!skinnedBones.ContainsKey(weight.BoneName))
                            {
                                skinnedBones.Add(weight.BoneName, null);
                            }
                        }
                    }
                }
            }
            return(skinnedBones.Keys.Count > maxBones);
        }
Exemple #5
0
        public static string GetXNAName(VertexAttribute attr)
        {
            switch (attr.usage)
            {
            case COLOR:
                return(VertexChannelNames.Color(0));

            case NORMAL:
                return(VertexChannelNames.Normal());

            case TEX_COORD:
                return(VertexChannelNames.TextureCoordinate(attr.attrIndex));

            case BONE_WEIGHT:
                return(VertexChannelNames.Weights(attr.attrIndex));

            case TANGENT:
                return(VertexChannelNames.Tangent(0));

            case BINORMAL:
                return(VertexChannelNames.Binormal(0));
            }

            return(null);
        }
Exemple #6
0
        /// <summary>
        /// This function removes geometry that contains no bone weights, because the ModelProcessor
        /// will throw an exception if we give it geometry content like that.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="context"></param>
        static void RemoveInvalidGeometry(NodeContent node, ContentProcessorContext context)
        {
            MeshContent meshContent = node as MeshContent;

            if (meshContent != null)
            {
                // Maintain a list of all the geometry that was invalid that we will be removing
                List <GeometryContent> removeGeometry = new List <GeometryContent>();
                foreach (GeometryContent geometry in meshContent.Geometry)
                {
                    VertexChannelCollection channels = geometry.Vertices.Channels;

                    // Does this geometry contain bone weight information?
                    if (geometry.Vertices.Channels.Contains(VertexChannelNames.Weights(0)))
                    {
                        bool removed = false;

                        VertexChannel <BoneWeightCollection> weights = geometry.Vertices.Channels.Get <BoneWeightCollection>(VertexChannelNames.Weights(0));
                        foreach (BoneWeightCollection collection in weights)
                        {
                            // If we don't have any weights, then this isn't going to be good. The geometry has no bone weights,
                            // so lets just remove it.
                            if (collection.Count <= 0)
                            {
                                removeGeometry.Add(geometry);
                                removed = true;
                                break;
                            }
                            else
                            {
                                // Otherwise, normalize the weights. This call is probably unnecessary.
                                collection.NormalizeWeights(4);
                            }
                        }

                        //If we removed something from this geometry, just remove the whole geometry - there's no point in going farther
                        if (removed)
                        {
                            break;
                        }
                    }
                }

                // Remove all the invalid geometry we found, and log a warning.
                foreach (GeometryContent geometry in removeGeometry)
                {
                    meshContent.Geometry.Remove(geometry);
                    context.Logger.LogWarning(null, null,
                                              "Mesh part {0} has been removed because it has no bone weights associated with it.",
                                              geometry.Name);
                }
            }

            // Recursively call this function for each child
            foreach (NodeContent child in node.Children)
            {
                RemoveInvalidGeometry(child, context);
            }
        }
Exemple #7
0
 private void GetWeightChannel()
 {
     foreach (VertexChannel channel in geom.Vertices.Channels)
     {
         if (channel.Name == VertexChannelNames.Weights())
         {
             weightChannel = (VertexChannel <BoneWeightCollection>)channel;
             break;
         }
     }
 }
Exemple #8
0
 private VertexChannel <BoneWeightCollection> GetWeightChannel(GeometryContent geom)
 {
     foreach (VertexChannel channel in geom.Vertices.Channels)
     {
         if (channel.Name == VertexChannelNames.Weights())
         {
             return((VertexChannel <BoneWeightCollection>)channel);
         }
     }
     return(null);
 }
 /// <summary>
 /// Checks whether mesh contains skinning information.
 /// </summary>
 /// <param name="mesh"></param>
 /// <returns></returns>
 static bool MeshHasSkinning(MeshContent mesh)
 {
     foreach (GeometryContent geometry in mesh.Geometry)
     {
         if (!geometry.Vertices.Channels.Contains(VertexChannelNames.Weights()))
         {
             return(false);
         }
     }
     return(true);
 }
Exemple #10
0
            /// <summary>
            /// Adds all the buffered channels to the mesh and merges duplicate positions/verts
            /// </summary>
            private void AddAllChannels()
            {
                bool recalcNormal = false;

                if (model.AnimationOptions.Contains("RecalcNormals") || (normals == null && !hasNormals))
                {
                    recalcNormal = true;
                }
                else
                {
                    AddChannel <Vector3>(VertexElementUsage.Normal.ToString() + "0", normals);
                }


                if (texCoords != null)
                {
                    AddChannel <Vector2>("TextureCoordinate0", texCoords);
                }

                //for (int i = 0; i < weightIndices.Count; i++)
                //{
                //    AddChannel<Byte4>(VertexElementUsage.BlendIndices.ToString() + i.ToString(),
                //        weightIndices[i]);
                //}
                //for (int i = 0; i < weights.Count; i++)
                //{
                //    AddChannel<Vector4>(VertexElementUsage.BlendWeight.ToString() + i.ToString(),
                //        weights[i]);
                //}
                bool isSkinned = false;

                foreach (BoneWeightCollection bwc in skinInfo)
                {
                    if (bwc.Count > 0)
                    {
                        isSkinned = true;
                        break;
                    }
                }
                if (isSkinned)
                {
                    AddChannel <BoneWeightCollection>(VertexChannelNames.Weights(), skinInfo.ToArray());
                }

                MeshHelper.MergeDuplicatePositions(mesh, 0);
                MeshHelper.MergeDuplicateVertices(mesh);
                if (recalcNormal)
                {
                    MeshHelper.CalculateNormals(mesh, true);
                }
                MeshHelper.OptimizeForCache(mesh);
            }
        protected virtual void ProcessVertexChannel(
            GeometryContent geometry, int vertexChannelIndex, ContentProcessorContext context)
        {
            var channel = geometry.Vertices.Channels[vertexChannelIndex];

            // TODO: According to docs, channels with VertexElementUsage.Color -> Color

            // Channels[VertexChannelNames.Weights] -> { Byte4 boneIndices, Color boneWeights }
            if (channel.Name.StartsWith(VertexChannelNames.Weights(), StringComparison.Ordinal))
            {
                ProcessWeightsChannel(geometry, vertexChannelIndex, _identity);
            }
        }
Exemple #12
0
        static bool MeshHasSkinning(MeshContent mesh)
        {
            // Checks whether a mesh contains skininng information.

            foreach (GeometryContent geometry in mesh.Geometry)
            {
                if (!geometry.Vertices.Channels.Contains(VertexChannelNames.Weights()))
                {
                    return(false);
                }
            }

            return(true);
        }
Exemple #13
0
        protected override void ProcessVertexChannel(
            GeometryContent geometry,
            int vertexChannelIndex,
            ContentProcessorContext context)
        {
            bool isWeights = geometry.Vertices.Channels[vertexChannelIndex].Name == VertexChannelNames.Weights();

            base.ProcessVertexChannel(geometry, vertexChannelIndex, context);

            if (isWeights)
            {
                geometry.Vertices.Channels.ConvertChannelContent <Vector4>("BlendIndices0");
                geometry.Vertices.Channels.ConvertChannelContent <Vector4>("BlendWeight0");
            }
        }
Exemple #14
0
        protected virtual void ProcessVertexChannel(GeometryContent geometry,
                                                    int vertexChannelIndex,
                                                    ContentProcessorContext context)
        {
            var channel = geometry.Vertices.Channels[vertexChannelIndex];

            // TODO: According to docs, channels with VertexElementUsage.Color -> Color

            // Channels[VertexChannelNames.Weights] -> { Byte4 boneIndices, Color boneWeights }
            if (channel.Name.StartsWith(VertexChannelNames.Weights()))
            {
                ProcessWeightsChannel(geometry, vertexChannelIndex, _identity);
            }

            // Looks like XNA models usually put a default color channel in..
            if (!geometry.Vertices.Channels.Contains(VertexChannelNames.Color(0)))
            {
                geometry.Vertices.Channels.Add(VertexChannelNames.Color(0), Enumerable.Repeat(Color.White, geometry.Vertices.VertexCount));
            }
        }
 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>
 /// Return true if the vertex content contains skinning blend indices.
 /// </summary>
 /// <param name="vc">The vertex content to check.</param>
 /// <param name="context">For reporting errors.</param>
 /// <returns>true if skinning should be applied to these vertices</returns>
 protected virtual bool VerticesAreSkinned(VertexContent vc, ContentProcessorContext context)
 {
     return(vc.Channels.Contains(VertexChannelNames.Weights()));
 }
Exemple #17
0
        public override NodeContent Import(string filename, ContentImporterContext context)
        {
            context.Logger.LogMessage("Importing H3D file: {0}", filename);

            _identity = new ContentIdentity(filename, GetType().Name);
            _rootNode = new NodeContent()
            {
                Identity = _identity, Name = "RootNode"
            };

            var scene = FormatIdentifier.IdentifyAndOpen(filename);
            var model = scene.Models[0];

            if (!scene.Textures.Any())
            {
                var path = Path.Combine(Path.GetDirectoryName(filename), $"{Path.GetFileNameWithoutExtension(filename)}@Textures{Path.GetExtension(filename)}");
                if (File.Exists(path))
                {
                    context.Logger.LogMessage($"Found texture file {path}. Loading data...");
                    scene.Merge(FormatIdentifier.IdentifyAndOpen(path, model.Skeleton));
                }
                else
                {
                    context.Logger.LogMessage($"Couldn't find texture file {path}!");
                }
            }

            // Textures
            var textures = new Dictionary <string, Texture2DContent>();

            foreach (var texture in scene.Textures)
            {
                var bitmapContent = new PixelBitmapContent <Color>(texture.Width, texture.Height)
                {
                    Identity = _identity,
                    Name     = texture.Name
                };
                bitmapContent.SetPixelData(texture.ToRGBA());

                var textureContent = new Texture2DContent()
                {
                    Identity = _identity,
                    Name     = texture.Name
                };
                textureContent.Faces[0].Add(bitmapContent);
                textures.Add(textureContent.Name, textureContent);
            }

            // Materials
            var materials = new Dictionary <string, H3DMaterialContent>();

            foreach (var material in model.Materials)
            {
#if DEBUG
                var hlslCode = new HLSLShaderGenerator(material.MaterialParams)
                {
                    BoneCount = model.Skeleton.Count
                }.GetShader();
                var glslCode = new GLSLFragmentShaderGenerator(material.MaterialParams).GetFragShader();
#endif
                var materialContent = new H3DMaterialContent()
                {
                    Identity = _identity,
                    Name     = material.Name,

                    Effect = new EffectContent
                    {
                        Identity   = _identity,
                        Name       = "H3DEffect",
                        EffectCode = new HLSLShaderGenerator(material.MaterialParams)
                        {
                            BoneCount = model.Skeleton.Count
                        }.GetShader()
                    },
                    Material = material.Name,

                    FaceCulling = (H3DFaceCulling?)material.MaterialParams.FaceCulling,

                    EmissionColor      = material.MaterialParams.EmissionColor.ToXNA(),
                    AmbientColor       = material.MaterialParams.AmbientColor.ToXNA(),
                    DiffuseColor       = material.MaterialParams.DiffuseColor.ToXNA(),
                    Specular0Color     = material.MaterialParams.Specular0Color.ToXNA(),
                    Specular1Color     = material.MaterialParams.Specular1Color.ToXNA(),
                    Constant0Color     = material.MaterialParams.Constant0Color.ToXNA(),
                    Constant1Color     = material.MaterialParams.Constant1Color.ToXNA(),
                    Constant2Color     = material.MaterialParams.Constant2Color.ToXNA(),
                    Constant3Color     = material.MaterialParams.Constant3Color.ToXNA(),
                    Constant4Color     = material.MaterialParams.Constant4Color.ToXNA(),
                    Constant5Color     = material.MaterialParams.Constant5Color.ToXNA(),
                    BlendColor         = material.MaterialParams.BlendColor.ToXNA(),
                    DepthBufferRead    = material.MaterialParams.DepthBufferRead,
                    DepthBufferWrite   = material.MaterialParams.DepthBufferWrite,
                    StencilBufferRead  = material.MaterialParams.StencilBufferRead,
                    StencilBufferWrite = material.MaterialParams.StencilBufferWrite,
                };

                var texCount = 0;
                if (material.EnabledTextures[0])
                {
                    texCount++;
                }
                if (material.EnabledTextures[1])
                {
                    texCount++;
                }
                if (material.EnabledTextures[2])
                {
                    texCount++;
                }
                materialContent.TextureList = new Texture2DContent[texCount];
                if (material.EnabledTextures[0])
                {
                    materialContent.TextureList[0] = textures[material.Texture0Name];
                }
                if (material.EnabledTextures[1])
                {
                    materialContent.TextureList[1] = textures[material.Texture1Name];
                }
                if (material.EnabledTextures[2])
                {
                    materialContent.TextureList[2] = textures[material.Texture2Name];
                }

                materialContent.TextureSamplerSettings = material.TextureMappers.Select(tm => new TextureSamplerSettings()
                {
                    WrapU     = tm.WrapU.ToXNAWrap(),
                    WrapV     = tm.WrapV.ToXNAWrap(),
                    MagFilter = (TextureSamplerSettings.TextureMagFilter)tm.MagFilter,
                    MinFilter = (TextureSamplerSettings.TextureMinFilter)tm.MinFilter
                }).ToArray();

                materials.Add(material.Name, materialContent);
            }

            // Geometry
            var meshes = new List <MeshContent>();
            for (var i = 0; i < model.Meshes.Count; i++)
            {
                var modelMesh = model.Meshes[i];

                if (modelMesh.Type == H3DMeshType.Silhouette)
                {
                    continue;
                }

                var mesh = new MeshContent()
                {
                    Identity = _identity,
                    Name     = $"{model.Materials[modelMesh.MaterialIndex].Name}_node{i}",
                };
                var geometry = new GeometryContent
                {
                    Identity = _identity,
                    Material = materials[model.Materials[modelMesh.MaterialIndex].Name]
                };
                var vertices   = GetWorldSpaceVertices(model.Skeleton, modelMesh);
                var baseVertex = mesh.Positions.Count;
                foreach (var vertex in vertices)
                {
                    mesh.Positions.Add(vertex.Position.ToVector3());
                }
                geometry.Vertices.AddRange(Enumerable.Range(baseVertex, vertices.Length));

                foreach (var attribute in modelMesh.Attributes)
                {
                    if (attribute.Name >= PICAAttributeName.BoneIndex)
                    {
                        continue;
                    }

                    switch (attribute.Name)
                    {
                    case PICAAttributeName.Position: break;     // Already added

                    case PICAAttributeName.Normal:
                        geometry.Vertices.Channels.Add(VertexChannelNames.Normal(0), vertices.Select(vertex => vertex.Normal.ToVector3()));
                        break;

                    case PICAAttributeName.Tangent:
                        geometry.Vertices.Channels.Add(VertexChannelNames.Tangent(0), vertices.Select(vertex => vertex.Tangent.ToVector3()));
                        break;

                    case PICAAttributeName.Color:
                        geometry.Vertices.Channels.Add(VertexChannelNames.Color(0), vertices.Select(vertex => vertex.Color.ToColor()));
                        break;

                    case PICAAttributeName.TexCoord0:
                        geometry.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(0), vertices.Select(vertex => vertex.TexCoord0.ToVector2().ToUV()));
                        break;

                    case PICAAttributeName.TexCoord1:
                        geometry.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(1), vertices.Select(vertex => vertex.TexCoord1.ToVector2().ToUV()));
                        break;

                    case PICAAttributeName.TexCoord2:
                        geometry.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(2), vertices.Select(vertex => vertex.TexCoord2.ToVector2().ToUV()));
                        break;
                    }
                }

                var vertexOffset = 0;
                var xnaWeights   = new List <BoneWeightCollection>();
                foreach (var modelSubMesh in modelMesh.SubMeshes)
                {
                    geometry.Indices.AddRange(modelSubMesh.Indices.Select(index => (int)index));

                    var vertexCount     = modelSubMesh.MaxIndex + 1 - vertexOffset;
                    var subMeshVertices = vertices.Skip(vertexOffset).Take(vertexCount).ToList();

                    if (modelSubMesh.Skinning == H3DSubMeshSkinning.Smooth)
                    {
                        foreach (var vertex in subMeshVertices)
                        {
                            var list = new BoneWeightCollection();
                            for (var index = 0; index < 4; index++)
                            {
                                var bIndex = vertex.Indices[index];
                                var weight = vertex.Weights[index];

                                if (weight == 0)
                                {
                                    break;
                                }

                                if (bIndex < modelSubMesh.BoneIndicesCount && bIndex > -1)
                                {
                                    bIndex = modelSubMesh.BoneIndices[bIndex];
                                }
                                else
                                {
                                    bIndex = 0;
                                }

                                list.Add(new BoneWeight(model.Skeleton[bIndex].Name, weight));
                            }
                            xnaWeights.Add(list);
                        }
                    }
                    else
                    {
                        foreach (var vertex in vertices)
                        {
                            var bIndex = vertex.Indices[0];

                            if (bIndex < modelSubMesh.BoneIndices.Length && bIndex > -1)
                            {
                                bIndex = modelSubMesh.BoneIndices[bIndex];
                            }
                            else
                            {
                                bIndex = 0;
                            }

                            xnaWeights.Add(new BoneWeightCollection()
                            {
                                new BoneWeight(model.Skeleton[bIndex].Name, 0)
                            });
                        }
                    }
                    vertexOffset += vertexCount;
                }
                geometry.Vertices.Channels.Add(VertexChannelNames.Weights(0), xnaWeights);
                mesh.Geometry.Add(geometry);
                meshes.Add(mesh);
            }

            foreach (var mesh in meshes)
            {
                _rootNode.Children.Add(mesh);
            }

            var rootBone = ImportBones(model);
            _rootNode.Children.Add(rootBone);

            if (!scene.SkeletalAnimations.Any())
            {
                var path = Path.Combine(Path.GetDirectoryName(filename), $"{Path.GetFileNameWithoutExtension(filename)}@Animations{Path.GetExtension(filename)}");
                if (File.Exists(path))
                {
                    context.Logger.LogMessage($"Found animation file {path}. Loading data...");
                    scene.Merge(FormatIdentifier.IdentifyAndOpen(path, model.Skeleton));
                }
                else
                {
                    context.Logger.LogMessage($"Couldn't find animation file {path}!");
                }
            }

            foreach (var animation in ImportSkeletalAnimations(scene))
            {
                rootBone.Animations.Add(animation.Name, animation);
            }

            foreach (var animation in ImportMaterialAnimations(scene))
            {
                _rootNode.Children.Add(animation);
            }

            return(_rootNode);
        }
Exemple #18
0
        private MeshContent CreateMesh(Mesh sceneMesh)
        {
            var mesh = new MeshContent {
                Name = sceneMesh.Name
            };

            // Position vertices are shared at the mesh level
            foreach (var vert in sceneMesh.Vertices)
            {
                mesh.Positions.Add(new Vector3(vert.X, vert.Y, vert.Z));
            }

            var geom = new GeometryContent
            {
                Material = _materials[sceneMesh.MaterialIndex]
            };

            // Geometry vertices reference 1:1 with the MeshContent parent,
            // no indirection is necessary.
            //geom.Vertices.Positions.AddRange(mesh.Positions);
            geom.Vertices.AddRange(Enumerable.Range(0, sceneMesh.VertexCount));
            geom.Indices.AddRange(sceneMesh.GetIndices());

            if (sceneMesh.HasBones)
            {
                var xnaWeights = new List <BoneWeightCollection>();
                for (var i = 0; i < geom.Indices.Count; i++)
                {
                    var list = new BoneWeightCollection();
                    for (var boneIndex = 0; boneIndex < sceneMesh.BoneCount; boneIndex++)
                    {
                        var bone = sceneMesh.Bones[boneIndex];
                        foreach (var weight in bone.VertexWeights)
                        {
                            if (weight.VertexID != i)
                            {
                                continue;
                            }

                            list.Add(new BoneWeight(bone.Name, weight.Weight));
                        }
                    }
                    if (list.Count > 0)
                    {
                        xnaWeights.Add(list);
                    }
                }

                geom.Vertices.Channels.Add(VertexChannelNames.Weights(0), xnaWeights);
            }

            // Individual channels go here
            if (sceneMesh.HasNormals)
            {
                geom.Vertices.Channels.Add(VertexChannelNames.Normal(), ToXna(sceneMesh.Normals));
            }

            for (var i = 0; i < sceneMesh.TextureCoordinateChannelCount; i++)
            {
                geom.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(i),
                                           ToXnaTexCoord(sceneMesh.TextureCoordinateChannels[i]));
            }

            mesh.Geometry.Add(geom);

            return(mesh);
        }
        private MeshContent ExtractMesh(aiMesh aiMesh)
        {
            if (!String.IsNullOrEmpty(aiMesh.mName.Data))
            {
                log("modelname " + aiMesh.mName.Data);
                meshBuilder = MeshBuilder.StartMesh(aiMesh.mName.Data);
            }
            else
            {
                meshBuilder = MeshBuilder.StartMesh(Path.GetFileNameWithoutExtension(filename));
            }

            if (!aiMesh.HasPositions())
            {
                throw new Exception("MOdel does not have Position");
            }

            // Add additional vertex channels for texture coordinates and normals
            if (aiMesh.HasTextureCoords(0))
            {
                textureCoordinateDataIndex = meshBuilder.CreateVertexChannel <Vector2>(VertexChannelNames.TextureCoordinate(0));
            }
            else if (aiMesh.HasVertexColors(0))
            {
                colorCoordinateDataIndex = meshBuilder.CreateVertexChannel <Vector4>(VertexChannelNames.Color(0));
            }
            if (aiMesh.HasNormals())
            {
                normalDataIndex = meshBuilder.CreateVertexChannel <Vector3>(VertexChannelNames.Normal());
            }
            if (aiMesh.HasTangentsAndBitangents())
            {
                tangentDataIndex  = meshBuilder.CreateVertexChannel <Vector3>(VertexChannelNames.Tangent(0));
                binormalDataIndex = meshBuilder.CreateVertexChannel <Vector3>(VertexChannelNames.Binormal(0));
            }
            if (aiMesh.HasBones())
            {
                boneDataIndex = meshBuilder.CreateVertexChannel <BoneWeightCollection>(VertexChannelNames.Weights(0));
            }

            var numFaces           = (int)aiMesh.mNumFaces;
            var numVertices        = (int)aiMesh.mNumVertices;
            var aiPositions        = aiMesh.mVertices;
            var aiNormals          = aiMesh.mNormals;
            var aiTextureCoordsAll = aiMesh.mTextureCoords;
            var aiTextureCoords    = (aiTextureCoordsAll != null) ? aiTextureCoordsAll[0] : null;

            for (int j = 0; j < aiMesh.mNumVertices; j++)
            {
                meshBuilder.CreatePosition(aiMesh.mVertices[j].x, aiMesh.mVertices[j].y, aiMesh.mVertices[j].z);
            }

            meshBuilder.SetMaterial(GetMaterial(aiMesh));

            var aiFaces   = aiMesh.mFaces;
            var dxIndices = new uint[numFaces * 3];

            for (int k = 0; k < numFaces; ++k)
            {
                var aiFace    = aiFaces[k];
                var aiIndices = aiFace.mIndices;
                for (int j = 0; j < 3; ++j)
                {
                    int index = (int)aiIndices[j];
                    if (aiMesh.HasTextureCoords(0))
                    {
                        meshBuilder.SetVertexChannelData(textureCoordinateDataIndex, new Vector2(aiMesh.mTextureCoords[0][index].x, aiMesh.mTextureCoords[0][index].y));
                    }
                    else if (aiMesh.HasVertexColors(0))
                    {
                        meshBuilder.SetVertexChannelData(colorCoordinateDataIndex, new Vector4(aiMesh.mColors[0][index].r, aiMesh.mColors[0][index].g, aiMesh.mColors[0][index].b, aiMesh.mColors[0][index].a));
                    }
                    if (aiMesh.HasNormals())
                    {
                        meshBuilder.SetVertexChannelData(normalDataIndex, new Vector3(aiMesh.mNormals[index].x, aiMesh.mNormals[index].y, aiMesh.mNormals[index].z));
                    }

                    if (aiMesh.HasTangentsAndBitangents())
                    {
                        meshBuilder.SetVertexChannelData(tangentDataIndex, new Vector3(aiMesh.mTangents[index].x, aiMesh.mTangents[index].y, aiMesh.mTangents[index].z));
                        meshBuilder.SetVertexChannelData(binormalDataIndex, new Vector3(aiMesh.mBitangents[index].x, aiMesh.mBitangents[index].y, aiMesh.mBitangents[index].z));
                    }
                    if (aiMesh.HasBones())
                    {
                        BoneWeightCollection BoneWeightCollection = new BoneWeightCollection();
                        if (wbone.ContainsKey(index))
                        {
                            foreach (var item in wbone[index])
                            {
                                BoneWeightCollection.Add(new BoneWeight(item.Key, item.Value));
                            }
                        }
                        meshBuilder.SetVertexChannelData(boneDataIndex, BoneWeightCollection);
                    }

                    meshBuilder.AddTriangleVertex(index);
                }
            }

            MeshContent meshContent = meshBuilder.FinishMesh();

            return(meshContent);
        }
        public void DefaultEffectTest()
        {
            NodeContent input;
            {
                input = new NodeContent();

                var mesh = new MeshContent()
                {
                    Name = "Mesh1"
                };
                mesh.Positions.Add(new Vector3(0, 0, 0));
                mesh.Positions.Add(new Vector3(1, 0, 0));
                mesh.Positions.Add(new Vector3(1, 1, 1));

                var geom = new GeometryContent();
                geom.Vertices.Add(0);
                geom.Vertices.Add(1);
                geom.Vertices.Add(2);
                geom.Indices.Add(0);
                geom.Indices.Add(1);
                geom.Indices.Add(2);

                geom.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(0), new[]
                {
                    new Vector2(0, 0),
                    new Vector2(1, 0),
                    new Vector2(1, 1),
                });

                var wieghts = new BoneWeightCollection();
                wieghts.Add(new BoneWeight("bone1", 0.5f));
                geom.Vertices.Channels.Add(VertexChannelNames.Weights(0), new[]
                {
                    wieghts,
                    wieghts,
                    wieghts
                });

                mesh.Geometry.Add(geom);
                input.Children.Add(mesh);

                var bone1 = new BoneContent {
                    Name = "bone1", Transform = Matrix.CreateTranslation(0, 1, 0)
                };
                input.Children.Add(bone1);

                var anim = new AnimationContent()
                {
                    Name     = "anim1",
                    Duration = TimeSpan.Zero
                };
                input.Animations.Add(anim.Name, anim);
            }

            var processorContext = new ProcessorContext(TargetPlatform.Windows, "dummy.xnb");
            var processor        = new ModelProcessor
            {
                DefaultEffect = MaterialProcessorDefaultEffect.SkinnedEffect,
            };

            var output = processor.Process(input, processorContext);

            // TODO: Not sure why, but XNA always returns a BasicMaterialContent
            // even when we specify SkinnedEffect as the default.  We need to fix
            // the test first before we can enable the assert here.

            //Assert.IsInstanceOf(typeof(SkinnedMaterialContent), output.Meshes[0].MeshParts[0].Material);
        }
 /// <summary>
 /// Checks whether a mesh contains skininng information.
 /// </summary>
 private static bool MeshHasSkinning(MeshContent mesh) =>
 mesh.Geometry.All(geometry => geometry.Vertices.Channels.Contains(VertexChannelNames.Weights()) || geometry.Vertices.Channels.Contains("BlendWeight0"));
Exemple #22
0
        private GeometryContent CreateGeometry(MeshContent mesh, Mesh aiMesh)
        {
            var geom = new GeometryContent {
                Material = _materials[aiMesh.MaterialIndex]
            };

            // Vertices
            var baseVertex = mesh.Positions.Count;

            foreach (var vert in aiMesh.Vertices)
            {
                mesh.Positions.Add(ToXna(vert));
            }
            geom.Vertices.AddRange(Enumerable.Range(baseVertex, aiMesh.VertexCount));
            geom.Indices.AddRange(aiMesh.GetIndices());

            if (aiMesh.HasBones)
            {
                var xnaWeights = new List <BoneWeightCollection>();
                for (var i = 0; i < geom.Indices.Count; i++)
                {
                    var list = new BoneWeightCollection();
                    for (var boneIndex = 0; boneIndex < aiMesh.BoneCount; boneIndex++)
                    {
                        var bone = aiMesh.Bones[boneIndex];
                        foreach (var weight in bone.VertexWeights)
                        {
                            if (weight.VertexID != i)
                            {
                                continue;
                            }

                            list.Add(new BoneWeight(bone.Name, weight.Weight));
                        }
                    }
                    if (list.Count > 0)
                    {
                        xnaWeights.Add(list);
                    }
                }

                geom.Vertices.Channels.Add(VertexChannelNames.Weights(0), xnaWeights);
            }

            // Individual channels go here
            if (aiMesh.HasNormals)
            {
                geom.Vertices.Channels.Add(VertexChannelNames.Normal(), ToXna(aiMesh.Normals));
            }

            for (var i = 0; i < aiMesh.TextureCoordinateChannelCount; i++)
            {
                geom.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(i),
                                           ToXnaTexCoord(aiMesh.TextureCoordinateChannels[i]));
            }

            for (var i = 0; i < aiMesh.VertexColorChannelCount; i++)
            {
                geom.Vertices.Channels.Add(VertexChannelNames.Color(i),
                                           ToXnaColors(aiMesh.VertexColorChannels[i]));
            }

            return(geom);
        }
Exemple #23
0
        public override NodeContent Import(string filename, ContentImporterContext context)
        {
            var content = new NodeContent();

            var reader  = XmlReader.Create(filename);
            var xmlMesh = (XmlMesh) new XmlSerializer(typeof(XmlMesh)).Deserialize(reader);

            reader.Close();

            reader = XmlReader.Create(Path.Combine(Path.GetDirectoryName(filename), xmlMesh.SkeletonLink.Name + ".xml"));
            var xmlSkeleton = (XmlSkeleton) new XmlSerializer(typeof(XmlSkeleton)).Deserialize(reader);

            reader.Close();

            context.Logger.LogImportantMessage("Bones: " + xmlSkeleton.Bones.Length.ToString());

            var bones = new Dictionary <string, BoneContent>();

            foreach (var xmlBone in xmlSkeleton.Bones)
            {
                context.Logger.LogImportantMessage("{0}", "-- " + xmlBone.Name + ": " + xmlBone.Position.AsVector3().ToString() + ", " + xmlBone.Rotation.Angle.ToString() + "/" + xmlBone.Rotation.Axis.AsVector3().ToString());
                var boneContent = new BoneContent()
                {
                    Name      = xmlBone.Name,
                    Transform =
                        Matrix.CreateFromAxisAngle(xmlBone.Rotation.Axis.AsVector3(), xmlBone.Rotation.Angle) *
                        Matrix.CreateTranslation(xmlBone.Position.AsVector3())
                };
                bones.Add(xmlBone.Name, boneContent);
            }

            foreach (var boneParent in xmlSkeleton.BoneParents)
            {
                var parent = bones[boneParent.Parent];
                var bone   = bones[boneParent.Bone];
                parent.Children.Add(bone);
            }

            var rootBone = bones.Single(x => x.Value.Parent == null);

            content.Children.Add(rootBone.Value);

            context.Logger.LogImportantMessage("Submeshes: " + xmlMesh.SubMeshes.Length.ToString());

            //context.AddDependency(Path.GetFullPath("HUM_M.MATERIAL"));
            //var materialFile = File.ReadAllText("HUM_M.MATERIAL");
            ////context.Logger.LogImportantMessage("{0}", materialFile);

            foreach (var xmlSubMesh in xmlMesh.SubMeshes)
            {
                context.Logger.LogImportantMessage("Submesh: " + xmlSubMesh.Material);
                context.Logger.LogImportantMessage("-- Faces: " + xmlSubMesh.Faces.Length.ToString());
                if (xmlSubMesh.UseSharedGeometry)
                {
                    context.Logger.LogImportantMessage("-- Uses Shared Geometry");
                }
                else
                {
                    context.Logger.LogImportantMessage("-- Vertexbuffers: " + xmlSubMesh.Geometry.VertexBuffers.Length.ToString());
                    context.Logger.LogImportantMessage("-- Vertices (0): " + xmlSubMesh.Geometry.VertexBuffers[0].Vertices.Length.ToString());
                    context.Logger.LogImportantMessage("-- Vertices (1): " + xmlSubMesh.Geometry.VertexBuffers[1].Vertices.Length.ToString());
                }

                var builder = MeshBuilder.StartMesh(xmlSubMesh.Material);

                //if (xmlSubMesh.Material == "Hum_M/Chest")
                //    builder.SetMaterial(new SkinnedMaterialContent { Texture = new ExternalReference<TextureContent>("TL2_ARMORTEST_CHEST.png") });
                //else if (xmlSubMesh.Material == "Hum_M/MidLeg")
                //    builder.SetMaterial(new SkinnedMaterialContent { Texture = new ExternalReference<TextureContent>("TL2_ARMORTEST_PANTS.png") });
                //else
                builder.SetMaterial(new SkinnedMaterialContent {
                    Texture = new ExternalReference <TextureContent>("Fiend\\FIEND.dds")
                });

                var normalChannel  = builder.CreateVertexChannel <Vector3>(VertexChannelNames.Normal());
                var uvChannel      = builder.CreateVertexChannel <Vector2>(VertexChannelNames.TextureCoordinate(0));
                var weightsChannel = builder.CreateVertexChannel <BoneWeightCollection>(VertexChannelNames.Weights());

                var geometry = xmlSubMesh.Geometry;
                if (xmlSubMesh.UseSharedGeometry)
                {
                    geometry = xmlMesh.SharedGeometry;
                }

                foreach (var vertex in geometry.VertexBuffers[0].Vertices)
                {
                    builder.CreatePosition(vertex.Position.AsVector3());
                }

                foreach (var face in xmlSubMesh.Faces)
                {
                    AddTriangleVertex(builder, xmlMesh, xmlSubMesh, xmlSkeleton, face.Vertex1, normalChannel, uvChannel, weightsChannel);
                    AddTriangleVertex(builder, xmlMesh, xmlSubMesh, xmlSkeleton, face.Vertex2, normalChannel, uvChannel, weightsChannel);
                    AddTriangleVertex(builder, xmlMesh, xmlSubMesh, xmlSkeleton, face.Vertex3, normalChannel, uvChannel, weightsChannel);
                }

                content.Children.Add(builder.FinishMesh());
            }

            return(content);
        }
        private void ValidateMesh(MeshContent mesh)
        {
            foreach (var geometry in mesh.Geometry)
            {
                if (GetExternalMaterial(mesh, geometry) != null)
                {
                    // ----- External material.
                    // The material is defined in an external XML file!
                    // Ignore local material.
                    continue;
                }

                // ----- Local material.
                // Submesh uses the material included in the model.
                var material = geometry.Material;
                var channels = geometry.Vertices.Channels;

                // Check if the geometry vertices contain the right number of texture coordinates.
                if (material != null && material.Textures.ContainsKey("Texture"))
                {
                    if (!channels.Contains(VertexChannelNames.TextureCoordinate(0)))
                    {
                        string message = String.Format(
                            CultureInfo.InvariantCulture,
                            "Model \"{0}\" has texture but no texture coordinates.",
                            geometry.Parent.Name);
                        throw new InvalidContentException(message, geometry.Identity);
                    }
                }

                if (material is DualTextureMaterialContent)
                {
                    if (!channels.Contains(VertexChannelNames.TextureCoordinate(1)))
                    {
                        string message = String.Format(
                            CultureInfo.InvariantCulture,
                            "Model \"{0}\" uses DualTextureEffect but has only one set of texture coordinates.",
                            geometry.Parent.Name);
                        throw new InvalidContentException(message, geometry.Identity);
                    }
                }

                // Check if the geometry vertices contain blend weights for mesh skinning.
                if (material is SkinnedMaterialContent)
                {
                    // If the channel contains "Weights0", then we have a BoneWeightCollection that contains
                    // the necessary data.
                    if (!channels.Contains(VertexChannelNames.Weights()))
                    {
                        // Otherwise, we need "BlendIndices0" AND "BlendWeight0".
                        var blendIndicesName = VertexChannelNames.EncodeName(VertexElementUsage.BlendIndices, 0);
                        var blendWeightsName = VertexChannelNames.EncodeName(VertexElementUsage.BlendWeight, 0);

                        if (!channels.Contains(blendIndicesName) || !channels.Contains(blendWeightsName))
                        {
                            string message = String.Format(
                                CultureInfo.InvariantCulture,
                                "Model \"{0}\" uses mesh skinning but vertices do not have bone weights.",
                                geometry.Parent.Name);
                            throw new InvalidContentException(message, geometry.Identity);
                        }
                    }
                }
            }
        }
        /// <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.");
            }
        }
            protected override void Create()
            {
                String usageString = VertexChannelNames.Weights();

                _channelIndex = _meshBuilder.CreateVertexChannel <BoneWeightCollection>(usageString);
            }
Exemple #27
0
        public override NodeContent Import(string filename, ContentImporterContext context)
        {
            ContentIdentity identity = new ContentIdentity(filename, GetType().Name);

            const int MAX_BONE_WEIGHTS             = 4;
            VertexBoneWeightLimitConfig boneConfig = new VertexBoneWeightLimitConfig(MAX_BONE_WEIGHTS);

            AssimpImporter importer = new AssimpImporter();

            importer.SetConfig(boneConfig);

            importer.AttachLogStream(new LogStream((msg, userData) => context.Logger.LogMessage(msg)));
            Scene scene = importer.ImportFile(filename,
                                              PostProcessSteps.FlipUVs |
                                              PostProcessSteps.JoinIdenticalVertices |
                                              PostProcessSteps.Triangulate |
                                              PostProcessSteps.SortByPrimitiveType |
                                              PostProcessSteps.FindInvalidData |
                                              PostProcessSteps.LimitBoneWeights |
                                              PostProcessSteps.FixInFacingNormals);


            // Root node
            NodeContent rootNode = new NodeContent
            {
                Name      = scene.RootNode.Name,
                Identity  = identity,
                Transform = Matrix.Transpose(ToXna(scene.RootNode.Transform))
            };


            // Materials
            MaterialContent[] materials = new MaterialContent[scene.MaterialCount];

            for (int m = 0; m < scene.MaterialCount; m++)
            {
                materials[m] = new BasicMaterialContent();

                materials[m].Identity = identity;
                // For some reason, there is all kinds of nasty junk in this string:
                materials[m].Name = CleanInput(scene.Materials[m].Name);

                for (int t = 0; t < scene.Materials[m].GetTextureCount(TextureType.Diffuse); t++)
                {
                    TextureSlot diffuseMap = scene.Materials[m].GetTexture(TextureType.Diffuse, t);
                    if (!String.IsNullOrEmpty(diffuseMap.FilePath))
                    {
                        materials[m].Textures.Add("Texture" + (t > 0 ? t.ToString() : ""),
                                                  new ExternalReference <TextureContent>(diffuseMap.FilePath, identity));
                    }
                }
            }


            // Bones

            // We find 'mesh container' nodes with the best names for those meshes while looking for the bones,
            // and will need them later when we create the MeshContents. I have a feeling that this won't work
            // in general, and may need to be made more robust.
            Dictionary <Mesh, string>      meshNames     = new Dictionary <Mesh, string>();
            Dictionary <Node, BoneContent> nodeToBoneMap = new Dictionary <Node, BoneContent>();
            BoneContent skeleton = null;    // The root bone for the model.

            List <Node> hierarchyNodes = scene.RootNode.Children.SelectDeep(n => n.Children).ToList();

            foreach (Node node in hierarchyNodes)
            {
                BoneContent bone = new BoneContent
                {
                    Name      = node.Name,
                    Transform = Matrix.Transpose(ToXna(node.Transform))
                };


                if (node.MeshIndices != null)
                {
                    // This node is a 'mesh container' instead of a bone, so we only care about extracting the name of the mesh.
                    foreach (int meshIndex in node.MeshIndices)
                    {
                        if (!meshNames.ContainsKey(scene.Meshes[meshIndex]))
                        {
                            meshNames.Add(scene.Meshes[meshIndex], node.Name);
                        }
                    }
                }
                else if (node.Parent == scene.RootNode)
                {
                    if (skeleton == null)
                    {
                        // This will be our skeleton so put the animations here:
                        if (scene.HasAnimations)
                        {
                            foreach (Animation assimpAnim in scene.Animations)
                            {
                                if (assimpAnim.HasNodeAnimations)
                                {
                                    AnimationContent newAnim = new AnimationContent();
                                    newAnim.Identity = identity;
                                    newAnim.Duration = TimeSpan.FromSeconds(assimpAnim.DurationInTicks / assimpAnim.TicksPerSecond);
                                    newAnim.Name     = assimpAnim.Name;

                                    foreach (NodeAnimationChannel nac in assimpAnim.NodeAnimationChannels)
                                    {
                                        Node animatedNode = hierarchyNodes.Find(n => n.Name == nac.NodeName);

                                        AnimationChannel newChan = BuildAnimtionChannel(animatedNode, nac);

                                        newAnim.Channels.Add(nac.NodeName, newChan);
                                    }

                                    if (String.IsNullOrEmpty(assimpAnim.Name))
                                    {
                                        bone.Animations.Add("SkelematorNoAnimationName", newAnim);
                                    }
                                    else
                                    {
                                        bone.Animations.Add(assimpAnim.Name, newAnim);
                                    }
                                }
                            }
                        }
                        rootNode.Children.Add(bone);
                        skeleton = bone;
                    }
                    else
                    {
                        context.Logger.LogWarning(null, identity, "Found multiple skeletons in the model, throwing extras away...");
                    }
                }
                else
                {
                    BoneContent parent = nodeToBoneMap[node.Parent];
                    parent.Children.Add(bone);
                }

                nodeToBoneMap.Add(node, bone);
            }


            // Meshes
            Dictionary <Mesh, MeshContent> meshes = new Dictionary <Mesh, MeshContent>();

            foreach (Mesh sceneMesh in scene.Meshes)
            {
                // See comment about meshNames at the beginning of the bone section.
                MeshBuilder mb = MeshBuilder.StartMesh(meshNames[sceneMesh]);

                mb.SwapWindingOrder = true; // Appears to require this...

                int positionIndex = -1;

                for (int v = 0; v < sceneMesh.VertexCount; v++)
                {
                    Vector3D vert = sceneMesh.Vertices[v];

                    // CreatePosition should just return a 0-based index of the newly added vertex.
                    positionIndex = mb.CreatePosition(new Vector3(vert.X, vert.Y, vert.Z));

                    if (positionIndex != v)
                    {
                        throw new InvalidContentException("Something unexpected happened while building a MeshContent from the Assimp scene mesh's vertices.  The scene mesh may contains duplicate vertices.");
                    }
                }

                if (positionIndex + 1 < 3)
                {
                    throw new InvalidContentException("There were not enough vertices in the Assimp scene mesh.");
                }



                // Create vertex channels
                int normalVertexChannelIndex = mb.CreateVertexChannel <Vector3>(VertexChannelNames.Normal());

                int[] texCoordVertexChannelIndex = new int[sceneMesh.TextureCoordsChannelCount];
                for (int x = 0; x < sceneMesh.TextureCoordsChannelCount; x++)
                {
                    texCoordVertexChannelIndex[x] = mb.CreateVertexChannel <Vector2>(VertexChannelNames.TextureCoordinate(x));
                }

                int boneWeightVertexChannelIndex = -1;

                if (sceneMesh.HasBones)
                {
                    boneWeightVertexChannelIndex = mb.CreateVertexChannel <BoneWeightCollection>(VertexChannelNames.Weights());
                }


                // Prepare vertex channel data
                BoneWeightCollection[] boneWeightData = null;
                if (sceneMesh.HasBones)
                {
                    boneWeightData = new BoneWeightCollection[sceneMesh.VertexCount];

                    for (int v = 0; v < sceneMesh.VertexCount; v++)
                    {
                        boneWeightData[v] = new BoneWeightCollection();
                    }

                    foreach (Bone sceneMeshBone in sceneMesh.Bones)
                    {
                        // We have to assume that the bone's name matches up with a node, and therefore one of our BoneContents.
                        foreach (VertexWeight sceneMeshBoneWeight in sceneMeshBone.VertexWeights)
                        {
                            boneWeightData[sceneMeshBoneWeight.VertexID].Add(new BoneWeight(sceneMeshBone.Name, sceneMeshBoneWeight.Weight));
                        }
                    }

                    for (int v = 0; v < sceneMesh.VertexCount; v++)
                    {
                        if (boneWeightData[v].Count <= 0)
                        {
                            throw new InvalidContentException("Encountered vertices without bone weights.");
                        }

                        boneWeightData[v].NormalizeWeights();
                    }
                }

                // Set the per-geometry data
                mb.SetMaterial(materials[sceneMesh.MaterialIndex]);
                mb.SetOpaqueData(new OpaqueDataDictionary());

                // Add each vertex
                for (int f = 0; f < sceneMesh.FaceCount; f++)
                {
                    if (sceneMesh.Faces[f].IndexCount != 3)
                    {
                        throw new InvalidContentException("Only triangular faces allowed.");
                    }

                    for (int t = 0; t < 3; t++)
                    {
                        mb.SetVertexChannelData(normalVertexChannelIndex, ToXna(sceneMesh.Normals[sceneMesh.Faces[f].Indices[t]]));

                        for (int x = 0; x < sceneMesh.TextureCoordsChannelCount; x++)
                        {
                            mb.SetVertexChannelData(texCoordVertexChannelIndex[x], ToXnaVector2((sceneMesh.GetTextureCoords(x))[sceneMesh.Faces[f].Indices[t]]));
                        }

                        if (sceneMesh.HasBones)
                        {
                            mb.SetVertexChannelData(boneWeightVertexChannelIndex, boneWeightData[sceneMesh.Faces[f].Indices[t]]);
                        }

                        mb.AddTriangleVertex((int)(sceneMesh.Faces[f].Indices[t]));
                    }
                }

                MeshContent mesh = mb.FinishMesh();
                rootNode.Children.Add(mesh);
                meshes.Add(sceneMesh, mesh);
            }

            return(rootNode);
        }