Пример #1
0
        /// <summary>
        /// Imports a piece of geometry, but does only support meshes, no NURBS.
        /// </summary>
        /// <param name="xmlGeometryNode">XML node of the geometry</param>
        /// <exception cref="Exception">Only works with meshes</exception>
        Mesh ImportGeometry(XmlNode xmlGeometryNode, ColladaModel model)
        {
            // Find the mesh node
            XmlNode xmlMeshNode = xmlGeometryNode.SelectSingleNode(".//mesh");

            if (xmlMeshNode == null)
            {
                throw new Exception("No supported geometry (Mesh) found");
            }

            // Determine number of mesh parts
            XmlNodeList xmlTriangles = xmlMeshNode.SelectNodes("triangles|polygons|polylist");

            if (xmlTriangles.Count == 0)
            {
                throw new Exception("No triangles found in mesh. Only triangles are supported");
            }

            if (xmlTriangles[0].Name != "triangles")
            {
                // If there are polygons or a polylist, check that all of them are triangles
                if (xmlTriangles[0].Attributes["vcount"] != null)
                {
                    var vcounts      = XmlUtil.ParseInts(xmlTriangles[0].Attributes["vcount"].Value);
                    var nonTriangles = vcounts.Where(count => count != 3);
                    if (nonTriangles.Any())
                    {
                        throw new Exception("Found polygon with " + nonTriangles.First() +
                                            " elements. Only triangles are supported");
                    }
                }
            }

            // Source data for this mesh used by all mesh parts.
            List <VertexSource> sources = ReadSources(xmlMeshNode);

            Vector4[] jointIndices;
            Vector3[] jointWeights;

            // Skinning Information, if available
            GetJointWeightsAndIndices(xmlMeshNode, model, out jointIndices, out jointWeights);

            if (sources.Count == 0)
            {
                throw new Exception("No data found");
            }

            //-------------------------------------------------------
            // Create Mesh
            //-------------------------------------------------------
            Mesh mesh = new Mesh();

            mesh.Name      = XmlUtil.GetName(xmlGeometryNode);
            mesh.MeshParts = new MeshPart[xmlTriangles.Count];

            // A mesh container for every mesh part, since every mesh part may use different
            // vertex types. This can be optimized in the content processor, if needed
            mesh.VertexContainers = new VertexContainer[xmlTriangles.Count];

            string[] semantics = new string[] { "VERTEX", "COLOR", "NORMAL", "TEXCOORD", "TEXTANGENT", "TEXBINORMAL" };

            //-------------------------------------------------------
            // Create Mesh Parts
            //-------------------------------------------------------
            for (int i = 0; i < xmlTriangles.Count; i++)
            {
                XmlNode    xmlPart      = xmlTriangles[i];
                int        numTriangles = int.Parse(xmlPart.Attributes["count"].Value);
                List <int> indexStream  = new List <int>(numTriangles * 3);

                var pNodes = xmlPart.SelectNodes("p");
                if (pNodes.Count > 1)
                {
                    // Indices are scattered among numTriangles <p> tags
                    foreach (XmlNode p in pNodes)
                    {
                        indexStream.AddRange(XmlUtil.ParseInts(p.InnerText));
                    }
                }
                else
                {
                    // Indices are contained in one <p> tag
                    indexStream.AddRange(XmlUtil.ParseInts(pNodes[0].InnerText));
                }

                int[]    indices = indexStream.ToArray();
                MeshPart part    = new MeshPart();

                try
                {
                    if (xmlPart.Attributes["material"] == null)
                    {
                        throw new Exception("no material attribute found");
                    }
                    part.MaterialName = FindMaterial(xmlGeometryNode, xmlPart.Attributes["material"].Value);
                }
                catch (Exception)
                {
                    // No Material found
                    part.MaterialName = null;
                }

                // Read Vertex Channels
                List <VertexChannel> vertexChannels = new List <VertexChannel>();

                foreach (String semantic in semantics)
                {
                    XmlNode input = xmlPart.SelectSingleNode(".//input[@semantic='" + semantic + "']");
                    if (input == null)
                    {
                        continue;                // no such vertex channel defined
                    }
                    int    offset;
                    String sourceId;

                    if (!input.TryGetAttribute("source", out sourceId))
                    {
                        throw new Exception("Referenced source of input with '" + semantic + "' semantic not found");
                    }
                    if (!input.TryGetAttribute("offset", out offset))
                    {
                        throw new Exception("No offset attribute of input with '" + semantic + "' semantic found");
                    }

                    sourceId = sourceId.Replace("#", "");
                    VertexSource source = sources.Where(s => s.GlobalID.Equals(sourceId)).FirstOrDefault();
                    if (source == null)
                    {
                        if (semantic.Equals("VERTEX"))
                        {
                            sourceId = xmlGeometryNode.SelectSingleNode(".//input[@semantic='POSITION']/@source").InnerText.Substring(1);
                            source   = sources.Where(s => s.GlobalID.Equals(sourceId)).FirstOrDefault();
                        }

                        if (source == null)
                        {
                            throw new Exception("Source '" + sourceId + "' not found");
                        }
                    }

                    VertexElement desc = new VertexElement();
                    desc.Offset              = offset;
                    desc.UsageIndex          = 0;
                    desc.VertexElementFormat = GetVertexElementFormat(source, semantic);
                    desc.VertexElementUsage  = GetVertexElementUsage(semantic);

                    VertexChannel channel = new VertexChannel(source, desc);
                    channel.CopyIndices(indices, offset, numTriangles * 3);
                    vertexChannels.Add(channel);
                }

                var jointChannels = GenerateJointChannels(jointIndices, jointWeights,
                                                          vertexChannels.Where(c => c.Description.VertexElementUsage ==
                                                                               VertexElementUsage.Position).First().Indices);

                if (jointChannels != null)
                {
                    vertexChannels.Add(jointChannels.Item1);
                    vertexChannels.Add(jointChannels.Item2);
                }

                part.Vertices = new VertexContainer(vertexChannels);
                part.Indices  = part.Vertices.Indices;

                mesh.VertexContainers[i] = part.Vertices;
                mesh.MeshParts[i]        = part;
            }

            return(mesh);
        }