public void ExportAssImp(string fileName, string modelType, ExportSettings settings, Arguments cmdargs) { fileName = Path.GetFullPath(fileName); // Get absolute path instead of relative string outDir = Path.GetDirectoryName(fileName); string fileNameNoExt = Path.GetFileNameWithoutExtension(fileName); if (modelType == "obj") { fileName = Path.Combine(outDir, fileNameNoExt + ".obj"); } else { fileName = Path.Combine(outDir, fileNameNoExt + ".dae"); } Scene outScene = new Scene { RootNode = new Node("RootNode") }; Console.WriteLine(); Console.WriteLine("Processing Materials ->"); Materials.FillScene(outScene, Textures, outDir); Console.WriteLine(); Console.WriteLine("Processing Meshes ->"); Shapes.FillScene(outScene, VertexData.Attributes, Joints.FlatSkeleton, SkinningEnvelopes.InverseBindMatrices); Console.WriteLine(); Console.Write("Processing Skeleton"); Scenegraph.FillScene(outScene, Joints.FlatSkeleton, settings.UseSkeletonRoot); Scenegraph.CorrectMaterialIndices(outScene, Materials); Console.WriteLine(); Console.WriteLine(); Console.WriteLine("Processing Textures ->"); Textures.DumpTextures(outDir, fileNameNoExt + "_tex_headers.json", true, cmdargs.readMipmaps); string infPath = Path.Combine(outDir, fileNameNoExt + "_hierarchy.json"); this.Scenegraph.DumpJson(infPath); Console.WriteLine(); Console.WriteLine("Removing Duplicate Verticies ->"); foreach (Mesh mesh in outScene.Meshes) { Console.Write(mesh.Name.Replace('_', ' ') + ": "); // Assimp has a JoinIdenticalVertices post process step, but we can't use that or the skinning info we manually add won't take it into account. RemoveDuplicateVertices(mesh); Console.Write("✓"); Console.WriteLine(); } AssimpContext cont = new AssimpContext(); if (modelType == "obj") { Console.WriteLine("Writing the OBJ file..."); cont.ExportFile(outScene, fileName, "obj");//, PostProcessSteps.ValidateDataStructure); using (System.IO.StreamWriter file = new System.IO.StreamWriter(fileName)) { string mtllibname = fileName.Split(new char[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries).Last() + ".mtl"; file.WriteLine(String.Format("mtllib {0}", mtllibname)); foreach (Assimp.Mesh mesh in outScene.Meshes) { foreach (Assimp.Vector3D vertex in mesh.Vertices) { file.WriteLine(String.Format("v {0} {1} {2}", vertex.X, vertex.Y, vertex.Z)); } } foreach (Assimp.Mesh mesh in outScene.Meshes) { foreach (Assimp.Vector3D normal in mesh.Normals) { file.WriteLine(String.Format("vn {0} {1} {2}", normal.X, normal.Y, normal.Z)); } } foreach (Assimp.Mesh mesh in outScene.Meshes) { if (mesh.HasTextureCoords(0)) { foreach (Assimp.Vector3D uv in mesh.TextureCoordinateChannels[0]) { file.WriteLine(String.Format("vt {0} {1}", uv.X, uv.Y)); } } } int vertex_offset = 1; foreach (Assimp.Mesh mesh in outScene.Meshes) { string material_name = outScene.Materials[mesh.MaterialIndex].Name; file.WriteLine(String.Format("usemtl {0}", material_name)); foreach (Assimp.Face face in mesh.Faces) { file.Write("f "); foreach (int index in face.Indices) { file.Write(index + vertex_offset); if (mesh.HasTextureCoords(0)) { file.Write("/"); file.Write(index + vertex_offset); } if (!mesh.HasTextureCoords(0) && mesh.HasNormals) { file.Write("//"); file.Write(index + vertex_offset); } else if (mesh.HasNormals) { file.Write("/"); file.Write(index + vertex_offset); } file.Write(" "); } file.Write("\n"); } vertex_offset += mesh.VertexCount; } } return; } else { cont.ExportFile(outScene, fileName, "collada", PostProcessSteps.ValidateDataStructure); } //if (SkinningEnvelopes.Weights.Count == 0) // return; // There's no skinning information, so we can stop here // Now we need to add some skinning info, since AssImp doesn't do it for some bizarre reason StreamWriter test = new StreamWriter(fileName + ".tmp"); StreamReader dae = File.OpenText(fileName); Console.WriteLine(); Console.Write("Finalizing the Mesh"); while (!dae.EndOfStream) { string line = dae.ReadLine(); if (line == " <library_visual_scenes>") { AddControllerLibrary(outScene, test); test.WriteLine(line); test.Flush(); } else if (line.Contains("<node")) { string[] testLn = line.Split('\"'); string name = testLn[3]; if (Joints.FlatSkeleton.Exists(x => x.Name == name)) { string jointLine = line.Replace(">", $" sid=\"{ name }\" type=\"JOINT\">"); test.WriteLine(jointLine); test.Flush(); } else { test.WriteLine(line); test.Flush(); } } else if (line.Contains("</visual_scene>")) { foreach (Mesh mesh in outScene.Meshes) { string matname = "mat"; bool keepmatnames = false; if (keepmatnames == true) { matname = AssimpMatnameSanitize(mesh.MaterialIndex, outScene.Materials[mesh.MaterialIndex].Name); } else { matname = AssimpMatnameSanitize(mesh.MaterialIndex, Materials.m_Materials[mesh.MaterialIndex].Name); } test.WriteLine($" <node id=\"{ mesh.Name }\" name=\"{ mesh.Name }\" type=\"NODE\">"); test.WriteLine($" <instance_controller url=\"#{ mesh.Name }-skin\">"); test.WriteLine(" <skeleton>#skeleton_root</skeleton>"); test.WriteLine(" <bind_material>"); test.WriteLine(" <technique_common>"); test.WriteLine($" <instance_material symbol=\"m{matname}\" target=\"#{matname}\" />"); test.WriteLine(" </technique_common>"); test.WriteLine(" </bind_material>"); test.WriteLine(" </instance_controller>"); test.WriteLine(" </node>"); test.Flush(); } test.WriteLine(line); test.Flush(); } else if (line.Contains("<matrix")) { string matLine = line.Replace("<matrix>", "<matrix sid=\"matrix\">"); test.WriteLine(matLine); test.Flush(); } else { test.WriteLine(line); test.Flush(); } Console.Write("."); } Console.Write("✓"); Console.WriteLine(); test.Close(); dae.Close(); File.Copy(fileName + ".tmp", fileName, true); File.Delete(fileName + ".tmp"); }