/// <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); }