public XnaBoneWeightChannel(MeshBuilder mb, VertexContainer vc, JointList joints) : base(mb) { try { _indicesChannel = (from c in vc.VertexChannels where c.Contains(VertexElementUsage.BlendIndices) select c).First(); _weightChannel = (from c in vc.VertexChannels where c.Contains(VertexElementUsage.BlendWeight) select c).First(); } catch (Exception) { throw new Exception("Missing blend indices or weights"); } _joints = joints; _vertexSize = vc.VertexSize; _indicesOffset = _indicesChannel.Source.Offset; _weightOffset = _weightChannel.Source.Offset; this.Create(); }
/// <summary> /// Creates a new vertex channel using the given MeshBuilder based on a /// Collada VertexChannel. No data is initially added to the vertex channel! /// For this, use the SetData method. /// </summary> /// <param name="meshBuilder">MeshBuilder instance to store vertex channel in</param> /// <param name="colladaVertexChannel">Original COLLADA Vertex Channel</param> public XnaVertexChannel(MeshBuilder meshBuilder, CVertexChannel colladaVertexChannel) { _colladaVertexChannel = colladaVertexChannel; _meshBuilder = meshBuilder; _vertexSize = colladaVertexChannel.Source.Stride; _offset = colladaVertexChannel.Source.Offset; Create(); }
/// <summary> /// Creates MeshContent instances for each mesh in the COLLADA model and attaches /// them to the NodeContent root. /// </summary> void CreateMeshes() { foreach (Mesh mesh in collada.Meshes) { foreach (MeshPart part in mesh.MeshParts) { var material = materials[part.MaterialName]; meshBuilder = MeshBuilder.StartMesh(mesh.Name); meshBuilder.SwapWindingOrder = false; meshBuilder.MergeDuplicatePositions = false; meshBuilder.SetMaterial(material); meshBuilder.Name = mesh.Name; // Positions CVertexChannel posChannel = part.Vertices.VertexChannels.Where(c => c.Description.VertexElementUsage == VertexElementUsage.Position). FirstOrDefault(); VertexContainer container = part.Vertices; float[] data = container.Vertices; int posOffset = posChannel.Source.Offset; for (int i = 0; i < container.Vertices.Length; i += container.VertexSize) { Vector3 pos = new Vector3(data[i + posOffset + 0], data[i + posOffset + 1], data[i + posOffset + 2]); meshBuilder.CreatePosition(pos); } // Vertex channels other than position List <XnaVertexChannel> channels = new List <XnaVertexChannel>(); foreach (CVertexChannel cvChannel in part.Vertices.VertexChannels) { switch (cvChannel.Description.VertexElementUsage) { case VertexElementUsage.Position: // Position is already created above break; case VertexElementUsage.BlendWeight: case VertexElementUsage.BlendIndices: // When bone weight collections are used these two // channels get added separately later if (UseBoneWeightCollection || excludeBlendWeights) { break; } else { goto default; } default: // standard channel like texcoord, normal etc. channels.Add(new XnaVertexChannel(meshBuilder, cvChannel)); break; } } // BoneWeightCollection vertex channel if (UseBoneWeightCollection && !excludeBlendWeights) { try { channels.Add(new XnaBoneWeightChannel(meshBuilder, part.Vertices, collada.Joints)); } catch (Exception) { importerContext.Logger.LogMessage("No skinning information found"); } } // Triangles for (int i = 0; i < part.Indices.Length; i += 3) { for (int j = i; j < i + 3; j++) { // Set channel components (other than position) foreach (var channel in channels) { channel.SetData(j); } meshBuilder.AddTriangleVertex(part.Indices[j]); } } MeshContent meshContent = meshBuilder.FinishMesh(); if (material.OpaqueData.Count > 0) { // Copy opaque data from material to mesh for convenience and // to make it compatible to Normal Mapping sample from App Hub foreach (var pair in material.OpaqueData) { meshContent.OpaqueData.Add(pair.Key, pair.Value); } } else { importerContext.Logger.LogWarning(null, null, "No opaque data in mesh"); } rootNode.Children.Add(meshContent); } } }