/// <summary> /// Converts all meshes in the given mesh array. Each mesh is split /// up per material, the indices of the generated meshes are stored in /// the node structure. /// </summary> /// <param name="scene">The scene to construct the return data in.</param> /// <param name="node">The target node structure that references the constructed meshes.</param> /// <param name="meshes">The array of meshes to convert</param> protected void CreateMeshes(AssimpSharp.Scene scene, AssimpSharp.Node node, List<AssimpSharp.XFile.Mesh> meshes) { if (meshes.Count == 0) { return; } // create a mesh for each mesh-material combination in the source node var result = new List<AssimpSharp.Mesh>(); for (int a = 0; a < meshes.Count; a++) { var sourceMesh = meshes[a]; // first convert its materials so that we can find them with their index afterwards ConvertMaterials(scene, sourceMesh.Materials); int numMaterials = Math.Max(sourceMesh.Materials.Count, 1); for (int b = 0; b < numMaterials; b++) { // collect the faces belonging to this material var faces = new List<int>(); var numVertices = 0; if (sourceMesh.FaceMaterials.Count > 0) { // if there is a per-face material defined, select the faces with the corresponding material for (int c = 0; c < sourceMesh.FaceMaterials.Count; c++) { if (sourceMesh.FaceMaterials[c] == b) { faces.Add(c); numVertices += sourceMesh.PosFaces[c].Indices.Count; } } } else { // if there is no per-face material, place everything into one mesh for (int c = 0; c < sourceMesh.PosFaces.Count; c++) { faces.Add(c); numVertices += sourceMesh.PosFaces[c].Indices.Count; } } // no faces/vertices using this material? strange... if (numVertices == 0) { continue; } // create a submesh using this material var mesh = new AssimpSharp.Mesh(); result.Add(mesh); // find the material in the scene's material list. Either own material // or referenced material, it should already have a valid index if (sourceMesh.FaceMaterials.Count > 0) { mesh.MaterialIndex = sourceMesh.Materials[b].SceneIndex; } else { mesh.MaterialIndex = 0; } // Create properly sized data arrays in the mesh. We store unique vertices per face, // as specified mesh.NumVertices = numVertices; mesh.Vertices = new Vector3[numVertices]; mesh.NumFaces = faces.Count; mesh.Faces = new AssimpSharp.Face[mesh.NumFaces]; // normals? if (sourceMesh.Normals.Count > 0) { mesh.Normals = new Vector3[numVertices]; } // texture coords for (int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; c++) { if (sourceMesh.TexCoords[c] != null && sourceMesh.TexCoords[c].Count > 0) { mesh.TextureCoords[c] = new Vector3[numVertices]; } } // vertex colors mesh.Colors = new Color4[AI_MAX_NUMBER_OF_COLOR_SETS][]; for (int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; c++) { if (sourceMesh.Colors[c] != null && sourceMesh.Colors[c].Count > 0) { mesh.Colors[c] = new Color4[numVertices]; } } // now collect the vertex data of all data streams present in the imported mesh int newIndex = 0; var orgPoints = new int[numVertices]; for (int c = 0; c < faces.Count; c++) { int f = faces[c]; var pf = sourceMesh.PosFaces[f]; // create face. either triangle or triangle fan depending on the index count var df = mesh.Faces[c] = new AssimpSharp.Face(); df.Indices = new int[pf.Indices.Count]; // collect vertex data for indices of this face for (int d = 0; d < df.Indices.Length; d++) { df.Indices[d] = newIndex; orgPoints[newIndex] = (int)pf.Indices[d]; // Position mesh.Vertices[newIndex] = sourceMesh.Positions[(int)pf.Indices[d]]; // Normal, if present if (mesh.HasNormals) { mesh.Normals[newIndex] = sourceMesh.Normals[(int)sourceMesh.NormalFaces[f].Indices[d]]; } // texture coord sets for (int e = 0; e < AI_MAX_NUMBER_OF_TEXTURECOORDS; e++) { if (mesh.HasTextureCoords(e)) { var tex = sourceMesh.TexCoords[e][(int)pf.Indices[d]]; mesh.TextureCoords[e][newIndex] = new Vector3(tex.X, 1.0f - tex.Y, 0.0f); } } // vertex color sets for (int e = 0; e < AI_MAX_NUMBER_OF_COLOR_SETS; e++) { if (mesh.HasVertexColors(e)) { mesh.Colors[e][newIndex] = sourceMesh.Colors[e][(int)pf.Indices[d]]; } } newIndex++; } } Debug.Assert(newIndex == numVertices); var bones = sourceMesh.Bones; var newBones = new List<AssimpSharp.Bone>(); for (int c = 0; c < bones.Count; c++) { var obone = bones[c]; var oldWeights = new float[sourceMesh.Positions.Count]; for (int d = 0; d < obone.Weights.Count; d++) { oldWeights[(int)obone.Weights[d].Vertex] = obone.Weights[d].Weight; } var newWeights = new List<AssimpSharp.VertexWeight>(numVertices); for (int d = 0; d < orgPoints.Length; d++) { float w = oldWeights[orgPoints[d]]; if (w > 0.0f) { newWeights.Add(new VertexWeight(d, w)); } } if (newWeights.Count == 0) { continue; } // create var nbone = new AssimpSharp.Bone(); newBones.Add(nbone); // copy name end matrix nbone.Name = obone.Name; nbone.OffsetMatrix = obone.OffsetMatrix; nbone.NumWeights = newWeights.Count; nbone.Weights = new VertexWeight[nbone.NumWeights]; for (int d = 0; d < newWeights.Count; d++) { nbone.Weights[d] = newWeights[d]; } } mesh.NumBones = newBones.Count; if (newBones.Count > 0) { mesh.Bones = mesh.Bones.ToArray(); } } } // allocate mesh index array in the node node.Meshes.Capacity = meshes.Count; // store all meshes in the mesh library of the scene and store their indices in the node for (int a = 0; a < result.Count; a++) { scene.Meshes.Add(result[a]); node.Meshes.Add(scene.Meshes.Count - 1); } }
private void ConvertCluster(List<aiBone> bones, Model model, Cluster cl, int[] outIndices, int[] indexOutIndices, int[] countOutIndices, Matrix nodeGlobalTransform) { var bone = new aiBone(); bones.Add(bone); bone.Name = FixNodeName(cl.TargetNode.Name); bone.OffsetMatrix = cl.TransformLink; bone.OffsetMatrix.Invert(); bone.OffsetMatrix = bone.OffsetMatrix * nodeGlobalTransform; bone.NumWeights = outIndices.Length; var cursor = bone.Weights = new aiVertexWeight[outIndices.Length]; int cursor_index = 0; int noIndexSentinel = int.MaxValue; var weights = cl.Weights; int c = indexOutIndices.Length; for (int i = 0; i < c; i++) { int indexIndex = indexOutIndices[i]; if (indexIndex == noIndexSentinel) { continue; } int cc = countOutIndices[i]; for (int j = 0; j < cc; j++) { cursor[cursor_index].VertexId = outIndices[indexIndex + j]; cursor[cursor_index].Weight = weights[i]; j++; } } }