public static void ToAssimp(Module.Export.Assimp.Context context, Scene scene) { if (context.meshes != null && context.meshes.Count > 0) { using (aiMeshArray meshes = context.scene.Meshes) { uint count = (uint)context.meshes.Count; meshes.Reserve(count, true); foreach (KeyValuePair <Module.Export.Assimp.Mesh, uint> indexes in context.meshes) { if (indexes.Value >= 0 && indexes.Value < count) { // Save the values to local variables to avoid the problem of variables passed by reference to lambda functions. Module.Export.Assimp.Mesh mesh_indexes = indexes.Key; aiMesh assimp_mesh = new aiMesh(); // Allocation in another thread fails so we must do it before starting the task meshes.Set(indexes.Value, assimp_mesh.Unmanaged()); context.threads.AddTask(() => ToAssimp(context, scene, mesh_indexes, assimp_mesh)); } } } } }
private static void InitProgress(Module.Export.Assimp.Context context, Module.ProgressCallback callback, Scene scene) { uint nb_steps = Node.ASSIMP_PROGRESS_FACTOR * CountNodes(scene.root_node); nb_steps += Mesh.ASSIMP_PROGRESS_FACTOR * (uint)(scene.meshes != null ? scene.meshes.Length : 0); nb_steps += Material.ASSIMP_PROGRESS_FACTOR * (uint)(scene.materials != null ? scene.materials.Length : 0); nb_steps += Texture.ASSIMP_PROGRESS_FACTOR * (uint)(scene.textures != null ? scene.textures.Length : 0); context.progress.Init(nb_steps, callback); }
public static void ToAssimp(Module.Export.Assimp.Context context, Scene scene) { if (scene.materials != null && scene.materials.Length > 0) { using (aiMaterialArray materials = context.scene.Materials) { uint count = (uint)scene.materials.Length; materials.Reserve(count, true); for (uint i = 0; i < count; i++) { uint index = i; // To avoid problems of lambda expression getting 'for' variable by reference (even if uint are not ref normaly!) aiMaterial assimp_material = new aiMaterial(); // Allocation in another thread fails so we must do it before starting the task materials.Set(index, assimp_material.Unmanaged()); context.threads.AddTask(() => scene.materials[index].ToAssimp(context, scene, assimp_material)); } } } }
public IEnumerator ToAssimp(Module.Export.Assimp.Context context, string filename, aiPostProcessSteps steps, Module.ExporterSuccessCallback return_callback, Module.ProgressCallback progress_callback) { bool success = false; string extension = System.IO.Path.GetExtension(filename).Remove(0, 1).ToLower(); uint export_format_count = context.exporter.GetExportFormatCount(); bool found_exporter = false; for (uint i = 0; i < export_format_count; i++) { using (aiExportFormatDesc desc = context.exporter.GetExportFormatDescription(i)) { if (extension == desc.fileExtension.ToLower()) { using (aiScene scene = new aiScene()) { InitProgress(context, progress_callback, this); context.scene = scene; // Export nodes IResult nodes_result = context.threads.AddTask(() => { using (aiNode root = root_node.ToAssimp(context, this, null)) { scene.mRootNode = root.Unmanaged(); } }); // Export materials. context.threads.AddTask(() => Material.ToAssimp(context, this)); // We must wait for all the nodes to be processed before exporting meshes because indexes are computed during parsing. while (!nodes_result.Done) { context.progress.Display(); yield return(null); } // Export meshes context.threads.AddTask(() => Mesh.ToAssimp(context, this)); // Wait for all tasks to be completed IEnumerator it = context.threads.WaitForTasksCompletion(); while (it.MoveNext()) { context.progress.Display(); yield return(it.Current); } // Do the final export using Assimp now that we created the complete structure in the C++ DLL. Result <aiReturn> status = context.threads.AddTask(() => context.exporter.Export(scene, desc.id, filename, steps)); // Wait for export to complete while (!status.Done) { context.progress.Display(); yield return(null); } if (progress_callback != null) { progress_callback(1f); } context.Clean(); // Check export status if (status.Success && status.Value == aiReturn.aiReturn_SUCCESS) { success = true; } else { Debug.LogErrorFormat("Failed to export to: {0}. \nThe exporter reported the following error: {1}", filename, context.exporter.GetErrorString()); } } found_exporter = true; break; } } } if (!found_exporter) { Debug.LogErrorFormat("No exporter for format '{0}' was found in Assimp.", extension); } if (return_callback != null) { return_callback(success); } }
private void ToAssimp(Module.Export.Assimp.Context context, Scene scene, aiMaterial assimp_material) { // Name if (!string.IsNullOrEmpty(name)) { using (aiString assimp_material_name = new aiString(name)) { assimp_material.SetName(assimp_material_name.Unmanaged()); } } // Set flag for transparent texture if the shader use transparency if (renderQueue == (int)UnityEngine.Rendering.RenderQueue.Transparent) { assimp_material.SetTextureFlags(aiTextureType.aiTextureType_DIFFUSE, 0, aiTextureFlags.aiTextureFlags_UseAlpha); } // Reflectivity float reflectivity; if (floats == null || !floats.TryGetValue("_Metallic", out reflectivity)) { reflectivity = 0f; } assimp_material.SetReflectivity(reflectivity); // Shininess float smoothness; if (floats == null || !floats.TryGetValue("_Glossiness", out smoothness)) { smoothness = 0f; } float shininess = 2.0f * smoothness - (reflectivity > 0.0f ? reflectivity : 0.0f); if (shininess > 0.0f) { const int factor = 128; // unity shader factor assimp_material.SetShadingModel(aiShadingMode.aiShadingMode_Phong); assimp_material.SetShininess(shininess * factor); assimp_material.SetShininessStrength(1.0f); } else { assimp_material.SetShadingModel(aiShadingMode.aiShadingMode_Gouraud); } // Colors if (colors != null) { foreach (KeyValuePair <string, Assimp.Convert.SetColor> pair in Assimp.Convert.SetColors(assimp_material)) { if (colors.ContainsKey(pair.Key)) { Color unity_color = colors[pair.Key]; switch (pair.Key) { case Assimp.Convert.unityDiffuseColorName: if (unity_color.a < 1.0f) { assimp_material.SetOpacity(unity_color.a); } break; case Assimp.Convert.unitySpecularColorName: // Revert specular color to original value unity_color = 10.0f * unity_color; break; default: break; } using (aiColor4D color = Assimp.Convert.UnityToAssimp.Color(unity_color)) { pair.Value(color); } } } } // Textures if (textures != null) { Dictionary <Texture, aiTextureType> textures_types = new Dictionary <Texture, aiTextureType>(); // Get supported textures foreach (KeyValuePair <string, aiTextureType> pair in Assimp.Convert.textureTypes) { if (textures.ContainsKey(pair.Key)) { Texture texture = scene.textures[textures[pair.Key].index]; if (texture != null) { textures_types.Add(texture, pair.Value); } } } // Export each supported textures foreach (KeyValuePair <Texture, aiTextureType> texture_pair in textures_types) { // Make a copy to avoid problem of loop variable captured by reference by lambda expression Texture texture = texture_pair.Key; aiTextureType texture_type = texture_pair.Value; context.threads.AddTask(() => texture.ToAssimp(context, texture_type, assimp_material)); } } context.progress.Update(ASSIMP_PROGRESS_FACTOR); }
public aiNode ToAssimp(Module.Export.Assimp.Context context, Scene scene, aiNode parent) { uint index = 0; aiNode node_object = new aiNode(name); // Set parent node_object.mParent = parent; // Set transform using (aiVector3D assimp_scale = Assimp.Convert.UnityToAssimp.Vector3(scale)) { using (aiQuaternion assimp_rotation = Assimp.Convert.UnityToAssimp.Quaternion(rotation)) { using (aiVector3D assimp_position = Assimp.Convert.UnityToAssimp.Vector3(position)) { using (aiMatrix4x4 matrix = new aiMatrix4x4(assimp_scale, assimp_rotation, assimp_position)) { node_object.mTransformation = matrix.Unmanaged(); } } } } // Parse the children nodes if (children != null && children.Length > 0) { using (aiNodeArray assimp_children = node_object.Children) { assimp_children.Reserve((uint)children.Length, true); index = 0; foreach (Node child in children) { using (aiNode assimp_child = child.ToAssimp(context, scene, node_object)) { if (assimp_child != null) { assimp_children.Set(index++, assimp_child.Unmanaged()); } } } } } // Parse the mesh objects if (meshes != null && meshes.Length > 0) { using (aiUIntArray assimp_meshes = node_object.Meshes) { assimp_meshes.Reserve((uint)meshes.Length, true); index = 0; foreach (GraphicMesh graphic_mesh in meshes) { Mesh mesh = scene.meshes[graphic_mesh.meshIndex]; int nb_materials = (graphic_mesh.materialsIndexes != null ? graphic_mesh.materialsIndexes.Length : 0); // Handle unity submeshes by creating new meshes for each submesh for (int i = 0; i < mesh.SubMeshesCount; i++) { // Assimp meshes can only have one material. Therefore, mutliple instances of one mesh // using different materials must be detected and replaced by different output meshes. uint assimp_mesh_index; int mat_index = (i < nb_materials ? graphic_mesh.materialsIndexes[i] : 0 /*Assimp default*/); Module.Export.Assimp.Mesh key = new Module.Export.Assimp.Mesh(graphic_mesh.meshIndex, i, mat_index); if (!context.meshes.TryGetValue(key, out assimp_mesh_index)) { assimp_mesh_index = (uint)context.meshes.Count; context.meshes.Add(key, assimp_mesh_index); } assimp_meshes.Set(index++, assimp_mesh_index); } } } } // Parse the node metadata if (components != null) { foreach (UnityComponent component in components) { aiMetadata assimp_meta = component.ToAssimpMetadata(); if (assimp_meta != null) { node_object.mMetaData = assimp_meta.Unmanaged(); break; } } } context.progress.Update(ASSIMP_PROGRESS_FACTOR); return(node_object); }
private void ToAssimp(Module.Export.Assimp.Context context, string texture_name, aiTextureType texture_type, aiMaterial material) { if (!string.IsNullOrEmpty(texture_name)) { string final_texture_name = null; if (texture_name.Length >= 1 && texture_name[0] == '*') { // Special textures if (texture_name.Length >= 3 && texture_name[1] == '*') { switch (texture_name[2]) { case 'N': // New normal texture generated from height map texture_type = aiTextureType.aiTextureType_HEIGHT; final_texture_name = texture_name.Substring(3); break; case 'A': // Secondary texture encoded in alpha channel string[] textures = texture_name.Substring(3).Split('|'); if (textures.Length == 2) { ToAssimp(context, textures[0], texture_type, material); switch (texture_type) { case aiTextureType.aiTextureType_DIFFUSE: texture_type = aiTextureType.aiTextureType_OPACITY; break; case aiTextureType.aiTextureType_SPECULAR: texture_type = aiTextureType.aiTextureType_SHININESS; break; default: break; } ToAssimp(context, textures[1], texture_type, material); } else { throw new FormatException("The texture + alpha should contain identifiers to only two original textures"); } break; case 'E': // Empty texture break; default: break; } } else // Embeded texture { if (unityTexture != null) { using (aiTextureArray textures = context.scene.Textures) { uint index = textures.Size(); final_texture_name = "*" + index; using (aiTexture texture = new aiTexture()) { texture.data = unityTexture.EncodeToPNG(); texture.achFormatHint = "png"; textures.Set(index, texture.Unmanaged()); } } } } } else { final_texture_name = texture_name; } if (final_texture_name != null) { using (aiString assimp_texture_name = new aiString(final_texture_name)) { lock (material) { material.SetTexturePath(texture_type, 0, assimp_texture_name.Unmanaged()); } } context.progress.Update(ASSIMP_PROGRESS_FACTOR); } } }
public void ToAssimp(Module.Export.Assimp.Context context, aiTextureType texture_type, aiMaterial material) { ToAssimp(context, filename, texture_type, material); }
private static void ToAssimp(Module.Export.Assimp.Context context, Scene scene, Module.Export.Assimp.Mesh mesh_indexes, aiMesh assimp_mesh) { Mesh mesh = scene.meshes[mesh_indexes.mesh]; assimp_mesh.mMaterialIndex = (uint)mesh_indexes.material; using (aiString assimp_mesh_name = new aiString(mesh.name)) { assimp_mesh.mName = assimp_mesh_name.Unmanaged(); } if (mesh.vertices.Length > 0) { using (aiVector3DArray vertices = assimp_mesh.Vertices) { Assimp.Convert.UnityToAssimp.Array(Assimp.Convert.UnityToAssimp.Vector3, mesh.vertices, vertices); } } if (mesh.normals.Length > 0) { using (aiVector3DArray normals = assimp_mesh.Normals) { Assimp.Convert.UnityToAssimp.Array(Assimp.Convert.UnityToAssimp.Vector3, mesh.normals, normals); } } if (mesh.tangents.Length > 0) { using (aiVector3DArray tangents = assimp_mesh.Tangents) { Assimp.Convert.UnityToAssimp.Array(Assimp.Convert.UnityToAssimp.Tangent, mesh.tangents, tangents); } } if (mesh_indexes.submesh < mesh.submeshes.Length) { // Support for submeshes: this mesh represent only one submesh of the original mesh SubMesh sub_mesh = mesh.submeshes[mesh_indexes.submesh]; if (sub_mesh != null && sub_mesh.triangles != null && sub_mesh.triangles.Length > 0) { using (aiFaceArray faces = assimp_mesh.Faces) { Assimp.Convert.UnityToAssimp.Face(sub_mesh.triangles, sub_mesh.topology, faces); } } } if (mesh.uv1.Length > 0 || mesh.uv2.Length > 0) { using (aiVector3DMultiArray texture_coords = assimp_mesh.TextureCoords) { if (mesh.uv1.Length > 0) { using (aiVector3DArray texture_coords0 = texture_coords.Get(0)) { Assimp.Convert.UnityToAssimp.Array(Assimp.Convert.UnityToAssimp.UV, mesh.uv1, texture_coords0); } } if (mesh.uv2.Length > 0) { using (aiVector3DArray texture_coords1 = texture_coords.Get(1)) { Assimp.Convert.UnityToAssimp.Array(Assimp.Convert.UnityToAssimp.UV, mesh.uv2, texture_coords1); } } } } if (mesh.colors.Length > 0) { using (aiColor4DMultiArray colors = assimp_mesh.Colors) { using (aiColor4DArray colors0 = colors.Get(0)) { Assimp.Convert.UnityToAssimp.Array(Assimp.Convert.UnityToAssimp.Color, mesh.colors, colors0); } } } context.progress.Update(ASSIMP_PROGRESS_FACTOR); }