Ejemplo n.º 1
0
        private static void InitProgress(Module.Import.Assimp.Context context, Module.ProgressCallback callback, aiScene scene)
        {
            uint nb_textures = 0;

            using (aiMaterialArray assimp_materials = scene.Materials)
            {
                uint nb_materials = assimp_materials.Size();

                for (uint i = 0; i < nb_materials; i++)
                {
                    using (aiMaterial material = assimp_materials.Get(i))
                    {
                        foreach (KeyValuePair <string, aiTextureType> pair in Assimp.Convert.textureTypes)
                        {
                            using (aiString texture_name = new aiString())
                            {
                                if (material.GetTexturePath(pair.Value, 0, texture_name))
                                {
                                    nb_textures++;
                                }
                            }
                        }
                    }
                }
            }

            uint nb_steps = Node.ASSIMP_PROGRESS_FACTOR * CountNodes(scene.mRootNode);

            nb_steps += Mesh.ASSIMP_PROGRESS_FACTOR * scene.Meshes.Size();
            nb_steps += Material.ASSIMP_PROGRESS_FACTOR * scene.Materials.Size();
            nb_steps += Texture.ASSIMP_PROGRESS_FACTOR * nb_textures;
            nb_steps  = (uint)(nb_steps / (1f - assimpNativeLoadingPrecentage));

            context.progress.Init(nb_steps, callback);
        }
Ejemplo n.º 2
0
        public static void FromAssimp(Module.Import.Assimp.Context context, aiScene scene)
        {
            if (scene.HasMaterials())
            {
                using (aiMaterialArray assimp_materials = scene.Materials)
                {
                    uint material_size = assimp_materials.Size();

                    // Reserve the right amount of memory
                    context.scene.materials = new Material[(int)material_size + 1];

                    // Create a material for lines
                    Material line_material = new Material();
                    line_material.name   = "Line";
                    line_material.shader = defaultAssimpLineShader;
                    line_material.floats = new Dictionary <string, float>();
                    line_material.colors = new Dictionary <string, Color>();
                    line_material.floats.Add(defaultAssimpLineShaderWidth, unityLineWidth);
                    line_material.colors.Add(Assimp.Convert.unityDiffuseColorName, Color.black);
                    context.scene.materials[(int)material_size] = line_material;

                    // Load all the materials
                    for (uint i = 0; i < material_size; i++)
                    {
                        aiMaterial material = assimp_materials.Get(i);

                        // LoadMaterial must dispose of the given material afterward
                        // We must use a proxy method for saving the result into the array because the index i is captured by the lambda otherwise and it's value is indefinite across multiple threads.
                        context.threads.ExecAndSaveToArray(context.scene.materials, (int)i, () => FromAssimp(context, scene, material));
                    }
                }
            }
        }
Ejemplo n.º 3
0
        private static void FromAssimpAlphaTexture(Module.Import.Assimp.Context context, Material material, aiMaterial material_data, aiScene scene, string unity_property, aiTextureType texture_type, Color default_color, Func <Color, float> op)
        {
            if (material_data.GetTextureCount(texture_type) > 0)
            {
                using (aiString texture_name = new aiString())
                {
                    if (material_data.GetTexturePath(texture_type, 0, texture_name))
                    {
                        Texture alpha    = new Texture(context, texture_name.ToString(), scene);
                        Texture base_tex = null;

                        Material.TextureParams param = material.GetTextureParams(unity_property);

                        if (param != null)
                        {
                            CLARTE.Backport.Tuple <Texture, uint> res = context.scene.GetAssimpTexture(param.index);

                            if (res != null)
                            {
                                base_tex = res.Item1;
                            }
                            else
                            {
                                Debug.LogErrorFormat("Invalid texture index. '{0}' was registered for material '{1}' as texture with index '{2}'. However no texture was found with this index.", unity_property, material.Name, param.index);
                            }
                        }
                        else
                        {
                            CLARTE.Backport.Tuple <Texture, uint> assimp_tex = context.scene.GetAssimpTexture(Guid.NewGuid().ToString(), () => new Texture("**E", alpha.width, alpha.height, default_color));

                            material.AddTextureParams(unity_property, new Material.TextureParams(assimp_tex.Item2));

                            base_tex = assimp_tex.Item1;
                        }

                        if (base_tex != null)
                        {
                            base_tex.AddToAlpha(alpha, op);

                            base_tex.filename = string.Format("**A{0}|{1}", base_tex.filename, texture_name.C_Str());
                        }
                    }
                }
            }
        }
Ejemplo n.º 4
0
        private void LoadFromAssimp(Module.Import.Assimp.Context context, string filename, aiScene scene)
        {
            if (!string.IsNullOrEmpty(filename))
            {
                byte[] tex;

                if (filename[0] == '*')
                {
                    // Embeded texture
                    string index_str = filename.Remove(0, 1);

                    uint index;
                    if (uint.TryParse(index_str, out index))
                    {
                        using (aiTextureArray array = scene.Textures)
                        {
                            if (index < array.Size())
                            {
                                using (aiTexture texture = array.Get(index))
                                {
                                    DecodeTexture(filename, texture.data);
                                }
                            }
                            else
                            {
                                Debug.LogError("Invalid embeded texture index \"" + index + "\" (out of bound).");
                            }
                        }
                    }
                    else
                    {
                        Debug.LogError("Invalid embeded texture name \"" + filename + "\" (not an index).");
                    }
                }
                else if (context.importer != null && (tex = context.importer.GetTexture(filename)) != null)
                {
                    DecodeTexture(filename, tex);
                }
                else
                {
                    LoadFromFile(context.path, filename);
                }
            }
        }
Ejemplo n.º 5
0
        private static void FromAssimpNormalsFromHeightmap(Module.Import.Assimp.Context context, Material material, aiMaterial material_data, aiScene scene)
        {
            if (material_data.GetTextureCount(Assimp.Convert.textureTypes[Assimp.Convert.unityBumpName]) <= 0)
            {
                using (aiString texture_name = new aiString())
                {
                    if (material_data.GetTexturePath(aiTextureType.aiTextureType_HEIGHT, 0, texture_name))
                    {
                        string filename = string.Format("**N{0}", texture_name.C_Str());

                        material.AddTextureParams(Assimp.Convert.unityBumpName, new Material.TextureParams(context.scene.GetAssimpTexture(filename, () =>
                        {
                            Texture texture = new Texture(context, texture_name.C_Str(), scene).HeightmapToNormals(0.5).Blur(0.5);

                            texture.filename = filename;

                            return(texture);
                        }).Item2));
                    }
                }
            }
        }
Ejemplo n.º 6
0
        public static void FromAssimp(Module.Import.Assimp.Context context, aiScene scene)
        {
            if (scene.HasMeshes())
            {
                using (aiMeshArray meshes = scene.Meshes)
                {
                    uint meshes_size = meshes.Size();

                    // Reserve the right amount of memory
                    context.scene.meshes = new Mesh[(int)meshes_size];

                    // Load all the meshes
                    for (uint i = 0; i < meshes_size; i++)
                    {
                        aiMesh mesh = meshes.Get(i);

                        // LoadGeometry must dispose of the given mesh afterward
                        // We must use a proxy method for saving the result into the array because the index i is captured by the lambda otherwise and it's value is indefinite across multiple threads.
                        context.threads.ExecAndSaveToArray(context.scene.meshes, (int)i, () => FromAssimp(context, mesh));
                    }
                }
            }
        }
Ejemplo n.º 7
0
        public static IEnumerator FromAssimp(Module.Import.Assimp.Context context, global::Assimp.Importer importer, Func <aiScene> loader, Module.ImporterReturnCallback return_callback, Module.ProgressCallback progress_callback)
        {
            if (progress_callback != null)
            {
                progress_callback(0.01f);
            }

            aiScene scene = null;

            // Async loading does not work in editor when not in play mode
            context.threads.AddTask(() => scene = loader());

            IEnumerator it = context.threads.WaitForTasksCompletion();

            while (it.MoveNext())
            {
                context.progress.Display();

                yield return(it.Current);
            }

            if (scene != null)
            {
                InitProgress(context, progress_callback, scene);

                context.progress.Update((uint)(assimpNativeLoadingPrecentage * context.progress.TotalSteps));

                context.scene = new Scene();

                context.scene.assimpTextures = new Dictionary <string, CLARTE.Backport.Tuple <Texture, uint> >();

                context.threads.AddTask(() => Mesh.FromAssimp(context, scene));
                context.threads.AddTask(() => Material.FromAssimp(context, scene));
                context.threads.AddTask(() => context.scene.root_node = Node.FromAssimp(context, scene, scene.mRootNode));

                it = context.threads.WaitForTasksCompletion();
                while (it.MoveNext())
                {
                    context.progress.Display();

                    yield return(it.Current);
                }

                // Assign materials to meshes now that all data is available
                context.threads.AddTask(() => Node.SetAssimpMeshesMaterials(context.scene, context.scene.root_node));
                // Assign textures to final array
                context.threads.AddTask(() =>
                {
                    context.scene.textures = new Texture[context.scene.assimpTextures.Count];

                    foreach (KeyValuePair <string, CLARTE.Backport.Tuple <Texture, uint> > pair in context.scene.assimpTextures)
                    {
                        context.scene.textures[pair.Value.Item2] = pair.Value.Item1;
                    }
                });

                // We can safelly dispose of the scene because all tasks must have been completed to reach this point, therefore we do not risque deallocating data used in another thread.
                // this method can take a few hundred milliseconds, therefore, we do it async and wait for it to complete before allowing new imports.
                context.threads.AddTask(scene.Dispose);
                context.threads.AddTask(importer.FreeScene);

                it = context.threads.WaitForTasksCompletion();
                while (it.MoveNext())
                {
                    context.progress.Display();

                    yield return(it.Current);
                }

                // Clean up
                context.scene.assimpTextures = null;

                if (return_callback != null)
                {
                    return_callback(context.scene);
                }

                context.Clean();
            }
            else
            {
                Debug.LogErrorFormat("Failed to open file: {0}{1}{2}.\nThe importer reported the following error: {3}", context.path, System.IO.Path.PathSeparator, context.filename, importer.GetErrorString());
            }
        }
Ejemplo n.º 8
0
        private static Material FromAssimp(Module.Import.Assimp.Context context, aiScene scene, aiMaterial material_data)
        {
            Material material = new Material();

            // Initialize dictionaries before hand because we do not know in advance wich ones we will need
            material.floats   = new Dictionary <string, float>();
            material.colors   = new Dictionary <string, Color>();
            material.textures = new Dictionary <string, TextureParams>();

            // Name
            using (aiString material_name = new aiString())
            {
                if (material_data.GetName(material_name))
                {
                    material.name = material_name.ToString();
                }
            }

            // shader
            material.shader = Constants.defaultAssimpShader;

            // Shininess
            float shininess;

            if (material_data.GetShininess(out shininess))
            {
                aiShadingMode shading;

                if (material_data.GetShadingModel(out shading))
                {
                    if (shading != aiShadingMode.aiShadingMode_Blinn && shading != aiShadingMode.aiShadingMode_Phong)
                    {
                        // Unsupported shading model
                        Debug.LogWarningFormat("The shading model for material {0} is not supported. The value for the shininess is likely to be incorrect.", material.name);
                    }
                }

                const int factor = 128;                 // unity shader factor
                shininess /= factor;
            }

            // Gloss
            float gloss;

            if (material_data.GetShininessStrength(out gloss))
            {
                shininess *= gloss;
            }

            // Reflectivity
            float reflectivity;

            if (material_data.GetReflectivity(out reflectivity))
            {
                material.floats.Add(Assimp.Convert.unityMetallicValueName, reflectivity);
            }

            material.floats.Add(Assimp.Convert.unityGlossinessValueName, Smoothness(shininess, reflectivity));

            // Colors
            foreach (KeyValuePair <string, Assimp.Convert.GetColor> pair in Assimp.Convert.GetColors(material_data))
            {
                using (aiColor4D color = new aiColor4D())
                {
                    if (pair.Value(color))
                    {
                        Color unity_color = Assimp.Convert.AssimpToUnity.Color(color);

                        bool set_color = true;

                        switch (pair.Key)
                        {
                        case Assimp.Convert.unityDiffuseColorName:
                            // Global opacity
                            float opacity;

                            if (material_data.GetOpacity(out opacity) && opacity < 1.0f)
                            {
                                unity_color.a = opacity;

                                material.floats.Add(Assimp.Convert.unityRenderModeName, (float)CLARTE.Shaders.Standard.Utility.BlendMode.TRANSPARENT);
                            }

                            break;

                        case Assimp.Convert.unitySpecularColorName:
                            // Specular color must be very close to black
                            unity_color = 0.1f * unity_color;

                            break;

                        case Assimp.Convert.unityEmissiveColorName:
                            if (!CLARTE.Shaders.Standard.Utility.ShouldEmissionBeEnabled(unity_color))
                            {
                                set_color = false;
                            }

                            break;
                        }

                        if (set_color)
                        {
                            material.colors.Add(pair.Key, unity_color);
                        }
                    }
                }
            }

            // Textures
            foreach (KeyValuePair <string, aiTextureType> pair in Assimp.Convert.textureTypes)
            {
                // Make a copy to avoid problem of loop variable captured by reference by lambda expression
                string        texture_key  = pair.Key;
                aiTextureType texture_type = pair.Value;

                context.threads.AddTask(() => Texture.FromAssimp(context, material, scene, material_data, texture_key, texture_type, reflectivity));
            }

            // We must dispose of the given parameter to free unused memory. However other tasks may still be using this material (i.e. textures), so we will let the garbage collector do it's job.
            //material_data.Dispose();

            context.progress.Update(ASSIMP_PROGRESS_FACTOR);

            return(material);
        }
Ejemplo n.º 9
0
        public static Node FromAssimp(Module.Import.Assimp.Context context, aiScene scene, aiNode assimp_node)
        {
            // Create new node object
            Node node = new Node();

            // Get node ID
            node.id = context.id++;

            // Get node name
            node.name = Assimp.Convert.Name(assimp_node.mName, "node");

            // Get node metadata
            using (aiMetadata meta = assimp_node.mMetaData)
            {
                UnityComponent metadata = UnityComponent.FromAssimpMetadata(meta);

                if (metadata != null)
                {
                    node.components = new UnityComponent[] { metadata };
                }
            }

            // Parse children recursively
            using (aiNodeArray children = assimp_node.Children)
            {
                uint children_size = children.Size();

                if (children_size > 0)
                {
                    node.children = new Node[children_size];

                    for (uint i = 0; i < children_size; i++)
                    {
                        aiNode child = children.Get(i);

                        // ParseNode must dispose of the given node afterward
                        // We must use a proxy method for saving the result into the array because the index i is captured by the lambda otherwise and it's value is indefinite across multiple threads.
                        context.threads.ExecAndSaveToArray(node.children, (int)i, () => FromAssimp(context, scene, child));
                    }
                }
            }

            // Parse meshes associated to this node
            using (aiUIntArray meshes = assimp_node.Meshes)
            {
                uint meshes_size = meshes.Size();

                if (meshes_size > 0)
                {
                    int global_meshes_size = (int)scene.Meshes.Size();

                    node.meshes = new GraphicMesh[meshes_size];

                    for (uint j = 0; j < meshes_size; j++)
                    {
                        node.meshes[j] = new GraphicMesh();

                        if (j < global_meshes_size)
                        {
                            uint mesh_index = meshes.Get(j);

                            node.meshes[j].meshIndex = (int)mesh_index;
                        }
                    }
                }
            }

            // Get the transform of this node
            using (aiVector3D position = new aiVector3D())
            {
                using (aiVector3D scaling = new aiVector3D())
                {
                    using (aiQuaternion rotation = new aiQuaternion())
                    {
                        assimp_node.mTransformation.Decompose(scaling, rotation, position);

                        node.position = Assimp.Convert.AssimpToUnity.Vector3(position);
                        node.rotation = Assimp.Convert.AssimpToUnity.Quaternion(rotation);
                        node.scale    = Assimp.Convert.AssimpToUnity.Vector3(scaling);
                    }
                }
            }

            // We must dispose of the given parameter to avoid memory leaks
            assimp_node.Dispose();

            context.progress.Update(ASSIMP_PROGRESS_FACTOR);

            return(node);
        }
Ejemplo n.º 10
0
        public static void FromAssimp(Module.Import.Assimp.Context context, Material material, aiScene scene, aiMaterial material_data, string texture_key, aiTextureType texture_type, float reflectivity)
        {
            if (texture_type != aiTextureType.aiTextureType_NONE && material_data.GetTextureCount(texture_type) > 0)
            {
                using (aiString texture_name = new aiString())
                {
                    if (material_data.GetTexturePath(texture_type, 0, texture_name))
                    {
                        string filename = texture_name.C_Str();

                        uint index = context.scene.GetAssimpTexture(filename, () => new Texture(context, filename, scene)).Item2;

                        material.AddTextureParams(texture_key, new Material.TextureParams(index));

                        context.progress.Update(ASSIMP_PROGRESS_FACTOR);
                    }
                }
            }

            Color default_color;

            // Add textures as alpha channel of existing textures, or compute normal map from heightmap if not defined.
            switch (texture_key)
            {
            case Assimp.Convert.unityMainTexName:
                default_color = Color.white;

                Color?diffuse = material.GetColor(Assimp.Convert.unityDiffuseColorName);

                if (diffuse.HasValue)
                {
                    default_color = diffuse.Value;
                }

                // Opacity as main texture alpha channel
                FromAssimpAlphaTexture(context, material, material_data, scene, Assimp.Convert.unityMainTexName, aiTextureType.aiTextureType_OPACITY, default_color, c => c.grayscale);
                break;

            case Assimp.Convert.unityMetallicGlossName:
                default_color = Color.black;

                float?metallic = material.GetFloat(Assimp.Convert.unityMetallicValueName);

                if (metallic.HasValue)
                {
                    default_color = new Color(metallic.Value, metallic.Value, metallic.Value, 1f);
                }

                // Shininess as alpha channel of metallic gloss map
                FromAssimpAlphaTexture(context, material, material_data, scene, Assimp.Convert.unityMetallicGlossName, aiTextureType.aiTextureType_SHININESS, default_color, c => Material.Smoothness(c.grayscale, reflectivity));
                break;

            case Assimp.Convert.unitySpecGlossName:
                default_color = Color.black;

                Color?specular = material.GetColor(Assimp.Convert.unitySpecularColorName);

                if (specular.HasValue)
                {
                    default_color = specular.Value;
                }

                // Shininess as alpha channel of specular gloss map
                FromAssimpAlphaTexture(context, material, material_data, scene, Assimp.Convert.unitySpecGlossName, aiTextureType.aiTextureType_SHININESS, default_color, c => Material.Smoothness(c.grayscale, reflectivity));
                break;

            case Assimp.Convert.unityBumpName:
                // Bump mapping from heightmap if not defined from normals
                FromAssimpNormalsFromHeightmap(context, material, material_data, scene);
                break;
            }
        }
Ejemplo n.º 11
0
 private Texture(Module.Import.Assimp.Context context, string filename, aiScene scene)
 {
     LoadFromAssimp(context, filename, scene);
 }
Ejemplo n.º 12
0
        private static Mesh FromAssimp(Module.Import.Assimp.Context context, aiMesh mesh_data)
        {
            // Create new mesh
            Mesh mesh = new Mesh();

            // Assimp does not support submeshes
            mesh.submeshes    = new SubMesh[1];
            mesh.submeshes[0] = new SubMesh();

            // Get material associated to this mesh
            mesh.assimpMaterial = (int)mesh_data.mMaterialIndex;

            // Get mesh name
            using (aiString mesh_name = mesh_data.mName)
            {
                mesh.name = Assimp.Convert.Name(mesh_name, "mesh");
            }

            // Get vertices
            if (mesh_data.HasPositions())
            {
                using (aiVector3DArray vertices = mesh_data.Vertices)
                {
                    mesh.vertices = Assimp.Convert.AssimpToUnity.Array <aiVector3D, Vector3>(Assimp.Convert.AssimpToUnity.Vector3, vertices);
                }
            }

            // Get normals
            if (mesh_data.HasNormals())
            {
                using (aiVector3DArray normals = mesh_data.Normals)
                {
                    mesh.normals = Assimp.Convert.AssimpToUnity.Array <aiVector3D, Vector3>(Assimp.Convert.AssimpToUnity.Vector3, normals);
                }
            }

            // Get tangents
            if (mesh_data.HasTangentsAndBitangents())
            {
                using (aiVector3DArray tangents = mesh_data.Tangents)
                {
                    mesh.tangents = Assimp.Convert.AssimpToUnity.Array <aiVector3D, Vector4>(Assimp.Convert.AssimpToUnity.Tangent, tangents);
                }
            }

            // Get faces
            if (mesh_data.HasFaces())
            {
                using (aiFaceArray faces = mesh_data.Faces)
                {
                    mesh.submeshes[0].triangles = Assimp.Convert.AssimpToUnity.Face(faces, out mesh.submeshes[0].topology);
                }
            }

            // Get UV coords
            if (mesh_data.GetNumUVChannels() > 0 && mesh_data.HasTextureCoords(0))
            {
                using (aiVector3DMultiArray texture_coords = mesh_data.TextureCoords)
                {
                    using (aiVector3DArray texture_coords0 = texture_coords.Get(0))
                    {
                        mesh.uv1 = Assimp.Convert.AssimpToUnity.Array <aiVector3D, Vector2>(Assimp.Convert.AssimpToUnity.UV, texture_coords0);
                    }

                    if (mesh_data.GetNumUVChannels() > 1 && mesh_data.HasTextureCoords(1))
                    {
                        using (aiVector3DArray texture_coords1 = texture_coords.Get(1))
                        {
                            mesh.uv2 = Assimp.Convert.AssimpToUnity.Array <aiVector3D, Vector2>(Assimp.Convert.AssimpToUnity.UV, texture_coords1);
                        }
                    }
                }
            }
            else
            {
                // No texture UVs. We need to generate some to avoid problems with most default unity shaders
                int size = mesh.vertices.Length;

                mesh.uv1 = new Vector2[size];
            }

            // Get vertex colors
            if (mesh_data.GetNumColorChannels() > 0 && mesh_data.HasVertexColors(0))
            {
                using (aiColor4DMultiArray colors = mesh_data.Colors)
                {
                    using (aiColor4DArray colors0 = colors.Get(0))
                    {
                        mesh.colors = Assimp.Convert.AssimpToUnity.Array <aiColor4D, Color>(Assimp.Convert.AssimpToUnity.Color, colors0);
                    }
                }
            }

            // TODO: anims + bones

            // We must dispose of the given parameter to free unused memory
            mesh_data.Dispose();

            context.progress.Update(ASSIMP_PROGRESS_FACTOR);

            return(mesh);
        }