Esempio n. 1
0
        private Material CreateAtlasMaterialAndTexture(Atlasser generatedAtlas, string shaderToAtlas, TextureReuseManager textureReuseManager)
        {
            string fileName           = ((ObjectsGUI.CustomAtlasName == "") ? "Atlas " : (ObjectsGUI.CustomAtlasName + " ")) + shaderToAtlas.Replace('/', '_');
            string folderToSaveAssets = EditorApplication.currentScene;

            if (folderToSaveAssets == "") //scene is not saved yet.
            {
                folderToSaveAssets = Constants.NonSavedSceneFolderName + ".unity";
                Debug.LogWarning("WARNING: Scene has not been saved, saving baked objects to: " + Constants.NonSavedSceneFolderName + " folder");
            }

            folderToSaveAssets = folderToSaveAssets.Substring(0, folderToSaveAssets.Length - 6) + "-Atlas";//remove the ".unity" and add "-Atlas"
            if (!Directory.Exists(folderToSaveAssets))
            {
                Directory.CreateDirectory(folderToSaveAssets);
                AssetDatabase.ImportAsset(folderToSaveAssets);
            }

            string atlasTexturePath = folderToSaveAssets + Path.DirectorySeparatorChar + fileName;
            //create the material in the project and set the shader material to shaderToAtlas
            Material atlasMaterial = new Material(Shader.Find(shaderToAtlas));

            //save the material to the project view
            AssetDatabase.CreateAsset(atlasMaterial, atlasTexturePath + "Mat.mat");
            AssetDatabase.ImportAsset(atlasTexturePath + "Mat.mat");
            //load a reference from the project view to the material (this is done to be able to set the texture to the material in the project view)
            atlasMaterial = (Material)AssetDatabase.LoadAssetAtPath(atlasTexturePath + "Mat.mat", typeof(Material));

            List <string> shaderDefines = ShaderManager.Instance.GetShaderTexturesDefines(shaderToAtlas);

            for (int k = 0; k < shaderDefines.Count; k++)                                                //go trough each property of the shader.
            {
                List <Texture2D> texturesOfShader = GetTexturesToAtlasForShaderDefine(shaderDefines[k]); //Get thtextures for the property shderDefines[k] to atlas them
                List <Vector2>   scales           = GetScalesToAtlasForShaderDefine(shaderDefines[k]);
                List <Vector2>   offsets          = GetOffsetsToAtlasForShaderDefine(shaderDefines[k]);
                if (AdvancedMenuGUI.Instance.ReuseTextures)
                {
                    texturesOfShader = Utils.FilterTexsByIndex(texturesOfShader, textureReuseManager.GetTextureIndexes());
                    scales           = Utils.FilterVec2ByIndex(scales, textureReuseManager.GetTextureIndexes());
                    offsets          = Utils.FilterVec2ByIndex(offsets, textureReuseManager.GetTextureIndexes());
                }
                generatedAtlas.SaveAtlasToFile(atlasTexturePath + k.ToString() + ".png", texturesOfShader, scales, offsets);//save the atlas with the retrieved textures
                AssetDatabase.ImportAsset(atlasTexturePath + k.ToString() + ".png");
                Texture2D tex = (Texture2D)AssetDatabase.LoadAssetAtPath(atlasTexturePath + k.ToString() + ".png", typeof(Texture2D));

                atlasMaterial.SetTexture(shaderDefines[k], //set property shderDefines[k] for shader shaderToAtlas
                                         tex);
            }
            return(atlasMaterial);
        }
Esempio n. 2
0
        private static List <Vector2> offsets;  //used for tiling of the textures.


        //objToCombine should be correctly assembled,meaning has MeshRenderer,filter and shares the same type of shader across materials
        //combines the number of materials in the mesh renderer, not the submesh count.
        public static GameObject CombineMaterials(GameObject objToCombine, string shaderUsed)
        {
            List <string> shaderDefines = ShaderManager.Instance.GetShaderTexturesDefines(shaderUsed);

            Material[] materialsToCombine = objToCombine.GetComponent <MeshRenderer>().sharedMaterials;
            GetTexturesScalesAndOffsetsForShaderDefine(objToCombine, shaderDefines[0]);

            int      atlasSize = CalculateAproxAtlasSizeForMaterials(objToCombine, shaderUsed);
            Atlasser atlas     = new Atlasser(atlasSize, atlasSize);
            // generate atlas for the initial textures
            int resizeTimes = 1;

            for (int i = 0; i < texturesToAtlas.Count; i++)
            {
                Node resultNode = atlas.Insert(texturesToAtlas[i].width, texturesToAtlas[i].height);
                if (resultNode == null)
                {
                    int resizedAtlasSize = atlasSize + Mathf.RoundToInt((float)atlasSize * Constants.AtlasResizeFactor * resizeTimes);
                    atlas = new Atlasser(resizedAtlasSize, resizedAtlasSize);
                    i     = -1;//at the end of the loop 1 will be added and it will start in 0
                    resizeTimes++;
                }
            }

            //with the generated atlas, save the textures and load them and add them to the combinedMaterial
            string pathToAtlas      = CreateFolderForCombinedObject(objToCombine);
            string fileName         = "MaterialAtlas " + shaderUsed.Replace('/', '_');
            string atlasTexturePath = pathToAtlas + Path.DirectorySeparatorChar + fileName;

            //create material and fill with the combined to be textures in the material
            Material combinedMaterial = new Material(Shader.Find(shaderUsed));

            AssetDatabase.CreateAsset(combinedMaterial, atlasTexturePath + "Mat.mat");
            AssetDatabase.ImportAsset(atlasTexturePath + "Mat.mat");
            //AssetDatabase.Refresh();
            combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(atlasTexturePath + "Mat.mat", typeof(Material));

            for (int i = 0; i < shaderDefines.Count; i++)
            {
                GetTexturesScalesAndOffsetsForShaderDefine(objToCombine, shaderDefines[i]);
//				Debug.Log ("Creating atlas from multiple materials on gameobject");
                atlas.SaveAtlasToFile(atlasTexturePath + i.ToString() + ".png", texturesToAtlas, scales, offsets);
                AssetDatabase.ImportAsset(atlasTexturePath + i.ToString() + ".png");
                //AssetDatabase.Refresh();
                Texture2D savedAtlasTexture = (Texture2D)AssetDatabase.LoadAssetAtPath(atlasTexturePath + i.ToString() + ".png", typeof(Texture2D));
                combinedMaterial.SetTexture(shaderDefines[i], savedAtlasTexture);
            }
            //AssetDatabase.Refresh();

            Mesh masterMesh = objToCombine.GetComponent <MeshFilter>().sharedMesh;

            Mesh[] subMeshes = new Mesh[materialsToCombine.Length];
            for (int i = 0; i < subMeshes.Length; i++)
            {
                subMeshes[i] = ExtractMesh(masterMesh, i);
                Vector2[] remappedUVs = subMeshes[i].uv;
                for (int j = 0; j < remappedUVs.Length; j++)
                {
                    remappedUVs[j] = Utils.ReMapUV(remappedUVs[j], atlas.AtlasWidth, atlas.AtlasHeight, atlas.TexturePositions[i], objToCombine.name);
                }
                subMeshes[i].uv = remappedUVs;
            }
            GameObject combinedObj = GameObject.Instantiate(objToCombine,
                                                            objToCombine.transform.position,
                                                            objToCombine.transform.rotation) as GameObject;

            combinedObj.GetComponent <MeshRenderer>().sharedMaterials = new Material[] { combinedMaterial };
            combinedObj.GetComponent <MeshFilter>().sharedMesh        = Utils.CombineMeshes(subMeshes);

            combinedObj.transform.parent     = objToCombine.transform.parent;
            combinedObj.transform.localScale = objToCombine.transform.localScale;
            combinedObj.name = objToCombine.name;
            return(combinedObj);
        }
Esempio n. 3
0
        public void OptimizeShader(bool reuseTextures, bool generatePrefabs)
        {
            if (shaderName == "")//unknown shader doesnt need to be optimed
            {
                return;
            }
            int currentAtlasSize = CalculateAproxAtlasSize(reuseTextures); //(reuseTextures) ? aproxAtlasSizeReuseTextures : aproxAtlasSize;

            if ((objects.Count > 1 ||                                      //more than 1 obj or 1 obj with multiple mat
                 (objects.Count == 1 && objects[0] != null && objects[0].ObjHasMoreThanOneMaterial)) &&
                currentAtlasSize < Constants.MaxAtlasSize)                 //check the generated atlas size doesnt exceed max supported texture size

            {
                List <Rect> texturePositions = new List <Rect>(); //creo que puede morir porque el atlasser tiene adentro un rect.
                Node        resultNode       = null;              //nodes for the tree for atlasing


                Atlasser generatedAtlas = new Atlasser(currentAtlasSize, currentAtlasSize);
                int      resizeTimes    = 1;

                TextureReuseManager textureReuseManager = new TextureReuseManager();

                for (int j = objects.Count - 1; j >= 0; j--)  //start from the largest to the shortest textures
                {
                    if (objects[j].ObjHasMoreThanOneMaterial) //before atlassing multiple materials obj, combine it.
                    {
                        objects[j].ProcessAndCombineMaterials();
                    }

                    Vector2 textureToAtlasSize = objects[j].TextureSize;
                    if (reuseTextures)
                    {
                        //if texture is not registered already
                        if (!textureReuseManager.TextureRefExists(objects[j]))
                        {
                            //generate a node
                            resultNode = generatedAtlas.Insert(Mathf.RoundToInt((textureToAtlasSize.x != Constants.NULLV2.x) ? textureToAtlasSize.x : Constants.NullTextureSize),
                                                               Mathf.RoundToInt((textureToAtlasSize.y != Constants.NULLV2.y) ? textureToAtlasSize.y : Constants.NullTextureSize));
                            if (resultNode != null) //save node if fits in atlas
                            {
                                textureReuseManager.AddTextureRef(objects[j], resultNode.NodeRect, j);
                            }
                        }
                    }
                    else
                    {
                        resultNode = generatedAtlas.Insert(Mathf.RoundToInt((textureToAtlasSize.x != Constants.NULLV2.x) ? textureToAtlasSize.x : Constants.NullTextureSize),
                                                           Mathf.RoundToInt((textureToAtlasSize.y != Constants.NULLV2.y) ? textureToAtlasSize.y : Constants.NullTextureSize));
                    }
                    if (resultNode == null)
                    {
                        int resizedAtlasSize = currentAtlasSize + Mathf.RoundToInt((float)currentAtlasSize * Constants.AtlasResizeFactor * resizeTimes);
                        generatedAtlas = new Atlasser(resizedAtlasSize, resizedAtlasSize);
                        j = objects.Count;//Count and not .Count-1 bc at the end of the loop it will be substracted j-- and we want to start from Count-1

                        texturePositions.Clear();
                        textureReuseManager.ClearTextureRefs();
                        resizeTimes++;
                    }
                    else
                    {
                        if (reuseTextures)
                        {
                            texturePositions.Add(textureReuseManager.GetTextureRefPosition(objects[j]));
                        }
                        else
                        {
                            texturePositions.Add(resultNode.NodeRect);//save the texture rectangle
                        }
                    }
                }
                Material atlasMaterial = CreateAtlasMaterialAndTexture(generatedAtlas, shaderName, textureReuseManager);
                OptimizeDrawCalls(ref atlasMaterial,
                                  generatedAtlas.GetAtlasSize().x,
                                  generatedAtlas.GetAtlasSize().y,
                                  texturePositions,
                                  reuseTextures,
                                  textureReuseManager,
                                  generatePrefabs);
                //after the game object has been organized, remove the combined game objects.
                for (int i = 0; i < objects.Count; i++)
                {
                    if (objects[i].ObjWasCombined)
                    {
                        objects[i].ClearCombinedObject();
                    }
                }
            }
        }
Esempio n. 4
0
        private static List <Vector2> offsets;  //used for tiling of the textures.

        //objToCombine should be correctly assembled,meaning has MeshRenderer,filter and shares the same type of shader across materials
        //combines the number of materials in the mesh renderer, not the submesh count.
        public static GameObject CombineMaterials(GameObject objToCombine, string shaderUsed, bool usesSkinnedMeshRenderer)
        {
            List <string> shaderDefines = ShaderManager.Instance.GetShaderTexturesDefines(shaderUsed);

            Material[] materialsToCombine = usesSkinnedMeshRenderer ? objToCombine.GetComponent <SkinnedMeshRenderer>().sharedMaterials : objToCombine.GetComponent <MeshRenderer>().sharedMaterials;
            GetTexturesScalesAndOffsetsForShaderDefine(materialsToCombine, shaderDefines[0]);

            int objToCombineID = objToCombine.GetInstanceID();

            int      atlasSize = CalculateAproxAtlasSizeForMaterials(materialsToCombine, shaderUsed);
            Atlasser atlas     = new Atlasser(atlasSize, atlasSize, false /*dont force the atlas to be power of 2 as we are combining a material*/);
            string   atlasName = "Atlas";
            // generate atlas for the initial textures
            int resizeTimes = 1;

            for (int i = 0; i < texturesToAtlas.Count; i++)
            {
                Node   resultNode  = atlas.Insert(texturesToAtlas[i].width, texturesToAtlas[i].height);
                string texturePath = AssetDatabase.GetAssetPath(texturesToAtlas[i]).Replace(Path.DirectorySeparatorChar, '-');
                if (texturePath == "") //means we have a colored material, lets just peek at the color and get a hash
                {
                    texturePath = Utils.CalculateMD5Hash(texturesToAtlas[i].GetPixel(0, 0).ToString()).ToString();
                }
                atlasName += texturePath;
                if (resultNode == null)
                {
                    int resizedAtlasSize = atlasSize + Mathf.RoundToInt((float)atlasSize * Constants.AtlasResizeFactor * resizeTimes);
                    atlas     = new Atlasser(resizedAtlasSize, resizedAtlasSize, false /*dont force the atlas to be power of 2 as we are combining a material*/);
                    atlasName = "Atlas";
                    i         = -1;//at the end of the loop 1 will be added and it will start in 0
                    resizeTimes++;
                }
            }
            atlasName = "Tex" + Utils.CalculateMD5Hash(atlasName).ToString();//Remove the MD5 for debuging purposes to know where each tex comes from

            //with the generated atlas, save the textures and load them and add them to the combinedMaterial
            string pathToCombinedMaterials = CreateFolderForCombinedObjects();
            string atlasTexturePath        = pathToCombinedMaterials + Path.DirectorySeparatorChar;

            //create material and fill with the combined to be textures in the material
            string shaderMaterialName = shaderUsed;

            if (Utils.IsShaderStandard(shaderMaterialName))
            {
                shaderMaterialName = Utils.ExtractStandardShaderOriginalName(shaderMaterialName);
            }

            Material combinedMaterial = new Material(Shader.Find(shaderMaterialName));

            string materialPathAndName = atlasTexturePath + "Mat" + objToCombineID + ".mat";

            AssetDatabase.CreateAsset(combinedMaterial, materialPathAndName);
            AssetDatabase.ImportAsset(materialPathAndName);

            combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(materialPathAndName, typeof(Material));

            for (int i = 0; i < shaderDefines.Count; i++)
            {
                string scaleOffsetsID          = GetTexturesScalesAndOffsetsForShaderDefine(materialsToCombine, shaderDefines[i]);
                string atlasTexturePathAndName = atlasTexturePath + atlasName + i.ToString() + scaleOffsetsID + ".png";

                if (!File.Exists(atlasTexturePathAndName))
                {
                    atlas.SaveAtlasToFile(atlasTexturePathAndName, texturesToAtlas, scales, offsets);
                }

                AssetDatabase.ImportAsset(atlasTexturePathAndName);

                Texture2D savedAtlasTexture = (Texture2D)AssetDatabase.LoadAssetAtPath(atlasTexturePathAndName, typeof(Texture2D));
                combinedMaterial.SetTexture(shaderDefines[i], savedAtlasTexture);
            }

            Mesh masterMesh = usesSkinnedMeshRenderer ? objToCombine.GetComponent <SkinnedMeshRenderer>().sharedMesh : objToCombine.GetComponent <MeshFilter>().sharedMesh;

            Mesh[] subMeshes = new Mesh[materialsToCombine.Length];
            for (int i = 0; i < subMeshes.Length; i++)
            {
                //Debug.Log("Number of Meshes: " + subMeshes.Length + " i: " + i);
                subMeshes[i] = ExtractMesh(masterMesh, i);
                Vector2[] remappedUVs = subMeshes[i].uv;

                bool generatedTexture = (materialsToCombine[i].mainTexture == null);

                for (int j = 0; j < remappedUVs.Length; j++)
                {
                    remappedUVs[j] = Utils.ReMapUV(remappedUVs[j], atlas.AtlasWidth, atlas.AtlasHeight, atlas.TexturePositions[i], objToCombine.name, generatedTexture);
                }
                subMeshes[i].uv = remappedUVs;
            }
            GameObject combinedObj = GameObject.Instantiate(objToCombine,
                                                            objToCombine.transform.position,
                                                            objToCombine.transform.rotation) as GameObject;

            if (usesSkinnedMeshRenderer)
            {
                combinedObj.GetComponent <SkinnedMeshRenderer>().sharedMaterials        = new Material[] { combinedMaterial };
                combinedObj.GetComponent <SkinnedMeshRenderer>().sharedMesh             = Utils.CombineMeshes(subMeshes);
                combinedObj.GetComponent <SkinnedMeshRenderer>().sharedMesh.boneWeights = objToCombine.GetComponent <SkinnedMeshRenderer>().sharedMesh.boneWeights;
                combinedObj.GetComponent <SkinnedMeshRenderer>().sharedMesh.bindposes   = objToCombine.GetComponent <SkinnedMeshRenderer>().sharedMesh.bindposes;
            }
            else
            {
                combinedObj.GetComponent <MeshRenderer>().sharedMaterials = new Material[] { combinedMaterial };
                combinedObj.GetComponent <MeshFilter>().sharedMesh        = Utils.CombineMeshes(subMeshes);
            }
            combinedObj.transform.parent     = objToCombine.transform.parent;
            combinedObj.transform.localScale = objToCombine.transform.localScale;
            combinedObj.name = objToCombine.name;
            return(combinedObj);
        }
        void OnGUI()
        {
            if (NeedToReload())
            {
                ReloadDataStructures();
            }
            selectedMenuOption = GUI.SelectionGrid(new Rect(5, 8, window.position.width - 10, 20), selectedMenuOption, menuOptions, 3);
            switch (selectedMenuOption)
            {
            case 0:
                ObjectsGUI.Instance.DrawGUI(window);
                AdvancedMenuGUI.Instance.ClearConsole();
                menuOptions[0] = "Objects";
                break;

            case 1:
                ShadersGUI.Instance.DrawGUI(window);
                AdvancedMenuGUI.Instance.ClearConsole();
                menuOptions[0] = "Objects(" + ObjSorter.GetTotalSortedObjects() + ")";
                break;

            case 2:
                AdvancedMenuGUI.Instance.DrawGUI(window);
                menuOptions[0] = "Objects(" + ObjSorter.GetTotalSortedObjects() + ")";
                break;

            default:
                Debug.LogError("Unrecognized menu option: " + selectedMenuOption);
                break;
            }

            if (GUI.Button(new Rect(5, window.position.height - 35, window.position.width / 2 - 10, 33), "Clear Atlas"))
            {
                GameObject[] objsInHierarchy = Utils.GetAllObjectsInHierarchy();
                foreach (GameObject obj in objsInHierarchy)
                {
                    if (obj.name.Contains(Constants.OptimizedObjIdentifier))
                    {
                        DestroyImmediate(obj);
                    }
                    else
                    if (obj.GetComponent <MeshRenderer>() != null)
                    {
                        obj.GetComponent <MeshRenderer>().enabled = true;
                    }
                }
                // delete the folder where the atlas reside.
                string folderOfAtlas = EditorApplication.currentScene;
                if (folderOfAtlas == "")                  //scene is not saved yet.
                {
                    folderOfAtlas = Constants.NonSavedSceneFolderName + ".unity";
                    Debug.LogWarning("WARNING: Scene has not been saved, clearing baked objects from NOT_SAVED_SCENE folder");
                }
                folderOfAtlas = folderOfAtlas.Substring(0, folderOfAtlas.Length - 6) + "-Atlas";  //remove the ".unity"
                if (Directory.Exists(folderOfAtlas))
                {
                    FileUtil.DeleteFileOrDirectory(folderOfAtlas);
                    AssetDatabase.Refresh();
                }
            }

            GUI.enabled = CheckEmptyArray();     //if there are no textures deactivate the GUI
            if (GUI.Button(new Rect(window.position.width / 2, window.position.height - 35, window.position.width / 2 - 5, 33), "Bake Atlas"))
            {
                //Remove objects that are already optimized and start over.
                if (AdvancedMenuGUI.Instance.RemoveObjectsBeforeBaking)
                {
                    GameObject[] objsInHierarchy = Utils.GetAllObjectsInHierarchy();
                    foreach (GameObject obj in objsInHierarchy)
                    {
                        if (obj.name.Contains(Constants.OptimizedObjIdentifier))
                        {
                            GameObject.DestroyImmediate(obj);
                        }
                    }
                }

                List <Rect> texturePositions = new List <Rect>();  //creo que esto puede morir porque el atlasser tiene adentro un rect.
                string      progressBarInfo  = "";
                float       pace             = 1 / (float)ObjSorter.GetRecognizableShadersCount();
                float       progress         = pace;

                Node resultNode = null;    //nodes for the tree for atlasing
                for (int shaderIndex = 0; shaderIndex < ObjSorter.GetObjs().Count; shaderIndex++)
                {
                    EditorUtility.DisplayProgressBar("Optimization in progress... " +
                                                     (AdvancedMenuGUI.Instance.CreatePrefabsForObjects ? " Get coffee this will take some time..." : ""), progressBarInfo, progress);
                    progress += pace;

                    texturePositions.Clear();
                    TextureReuseManager textureReuseManager = new TextureReuseManager();

                    string shaderToAtlas = (ObjSorter.GetObjs()[shaderIndex][0] != null && ObjSorter.GetObjs()[shaderIndex][0].IsCorrectlyAssembled) ? ObjSorter.GetObjs()[shaderIndex][0].ShaderName : "";
                    progressBarInfo = "Processing shader " + shaderToAtlas + "...";
                    int atlasSize = ObjSorter.GetAproxAtlasSize(shaderIndex, AdvancedMenuGUI.Instance.ReuseTextures);

                    if (ShaderManager.Instance.ShaderExists(shaderToAtlas) &&
                        (ObjSorter.GetObjs()[shaderIndex].Count > 1 ||
                         (ObjSorter.GetObjs()[shaderIndex].Count == 1 && ObjSorter.GetObjs()[shaderIndex][0] != null && ObjSorter.GetObjs()[shaderIndex][0].ObjHasMoreThanOneMaterial)) && //more than 1 obj or 1obj wth multiple mat
                        atlasSize < Constants.MaxAtlasSize)                                                                                                                                //check the generated atlas size doesnt exceed max supported texture size
                    {
                        generatedAtlas = new Atlasser(atlasSize, atlasSize);
                        int resizeTimes = 1;

                        for (int j = ObjSorter.GetObjs()[shaderIndex].Count - 1; j >= 0; j--)   //start from the largest to the shortest textures
                        //before atlassing multiple materials obj, combine it.
                        {
                            if (ObjSorter.GetObjs()[shaderIndex][j].ObjHasMoreThanOneMaterial)
                            {
                                progressBarInfo = "Combining materials...";
                                ObjSorter.GetObjs()[shaderIndex][j].ProcessAndCombineMaterials();    //mirar esto, aca esta el problema  de multiple materiales y reimportacion
                            }

                            Vector2 textureToAtlasSize = ObjSorter.GetObjs()[shaderIndex][j].TextureSize;
                            if (AdvancedMenuGUI.Instance.ReuseTextures)
                            {
                                //if texture is not registered already
                                if (!textureReuseManager.TextureRefExists(ObjSorter.GetObjs()[shaderIndex][j]))
                                {
                                    //generate a node
                                    resultNode = generatedAtlas.Insert(Mathf.RoundToInt((textureToAtlasSize.x != Constants.NULLV2.x) ? textureToAtlasSize.x : Constants.NullTextureSize),
                                                                       Mathf.RoundToInt((textureToAtlasSize.y != Constants.NULLV2.y) ? textureToAtlasSize.y : Constants.NullTextureSize));
                                    if (resultNode != null)      //save node if fits in atlas
                                    {
                                        textureReuseManager.AddTextureRef(ObjSorter.GetObjs()[shaderIndex][j], resultNode.NodeRect, j);
                                    }
                                }
                            }
                            else
                            {
                                resultNode = generatedAtlas.Insert(Mathf.RoundToInt((textureToAtlasSize.x != Constants.NULLV2.x) ? textureToAtlasSize.x : Constants.NullTextureSize),
                                                                   Mathf.RoundToInt((textureToAtlasSize.y != Constants.NULLV2.y) ? textureToAtlasSize.y : Constants.NullTextureSize));
                            }

                            if (resultNode == null)
                            {
                                int resizedAtlasSize = atlasSize + Mathf.RoundToInt((float)atlasSize * Constants.AtlasResizeFactor * resizeTimes);
                                generatedAtlas = new Atlasser(resizedAtlasSize, resizedAtlasSize);
                                j = ObjSorter.GetObjs()[shaderIndex].Count;    //Count and not .Count-1 bc at the end of the loop it will be substracted j-- and we want to start from Count-1

                                texturePositions.Clear();
                                textureReuseManager.ClearTextureRefs();
                                resizeTimes++;
                            }
                            else
                            {
                                if (AdvancedMenuGUI.Instance.ReuseTextures)
                                {
                                    texturePositions.Add(textureReuseManager.GetTextureRefPosition(ObjSorter.GetObjs()[shaderIndex][j]));
                                }
                                else
                                {
                                    texturePositions.Add(resultNode.NodeRect);    //save the texture rectangle
                                }
                            }
                        }
                        progressBarInfo = "Saving textures to atlas...";
                        Material atlasMaterial = CreateAtlasMaterialAndTexture(shaderToAtlas, shaderIndex, textureReuseManager);
                        progressBarInfo = "Remapping coordinates...";

                        ObjSorter.OptimizeDrawCalls(ref atlasMaterial,
                                                    shaderIndex,
                                                    generatedAtlas.GetAtlasSize().x,
                                                    generatedAtlas.GetAtlasSize().y,
                                                    texturePositions,
                                                    AdvancedMenuGUI.Instance.ReuseTextures,
                                                    textureReuseManager,
                                                    AdvancedMenuGUI.Instance.CreatePrefabsForObjects);
                    }
                }

                //after the game object has been organized, remove the combined game objects.
                for (int shaderIndex = 0; shaderIndex < ObjSorter.GetObjs().Count; shaderIndex++)
                {
                    for (int j = ObjSorter.GetObjs()[shaderIndex].Count - 1; j >= 0; j--)
                    {
                        if (ObjSorter.GetObjs()[shaderIndex][j].ObjWasCombined)
                        {
                            ObjSorter.GetObjs()[shaderIndex][j].ClearCombinedObject();
                        }
                    }
                }
                EditorUtility.ClearProgressBar();
                AssetDatabase.Refresh();    //reimport the created atlases so they get displayed in the editor.
            }
        }
Esempio n. 6
0
        private Material CreateAtlasMaterialAndTexture(Atlasser generatedAtlas, string shaderToAtlas, TextureReuseManager textureReuseManager, int atlasNumber /*in case we have several atlases*/, int start, int end /*start & end used for multiple atlases*/)
        {
            string fileName           = ((ObjectsGUI.CustomAtlasName == "") ? "Atlas " : (ObjectsGUI.CustomAtlasName + " ")) + atlasNumber + shaderToAtlas.Replace('/', '_');
            string folderToSaveAssets = (PersistenceHandler.Instance.PathToSaveOptimizedObjs != "") ?
                                        PersistenceHandler.Instance.PathToSaveOptimizedObjs + Path.DirectorySeparatorChar + Utils.GetCurrentSceneName() :
                                        EditorSceneManager.GetActiveScene().path; //<- 5.4+ -- 5.3 -> EditorApplication.currentScene;

            if (EditorSceneManager.GetActiveScene().path == "")                   //scene is not saved yet.
            {
                folderToSaveAssets = Constants.NonSavedSceneFolderName + ".unity";
                Debug.LogWarning("WARNING: Scene has not been saved, saving baked objects to: " + Constants.NonSavedSceneFolderName + " folder");
            }

            folderToSaveAssets = folderToSaveAssets.Substring(0, folderToSaveAssets.Length - 6) + "-Atlas";//remove the ".unity" and add "-Atlas"
            if (!Directory.Exists(folderToSaveAssets))
            {
                Directory.CreateDirectory(folderToSaveAssets);
                AssetDatabase.ImportAsset(folderToSaveAssets);
            }
            string atlasTexturePath = folderToSaveAssets + Path.DirectorySeparatorChar + fileName;
            //create the material in the project and set the shader material to shaderToAtlas
            Material atlasMaterial = new Material(Shader.Find(standardShader ? Utils.ExtractStandardShaderOriginalName(shaderToAtlas) : shaderToAtlas));

            //save the material to the project view
            AssetDatabase.CreateAsset(atlasMaterial, atlasTexturePath + "Mat.mat");
            AssetDatabase.ImportAsset(atlasTexturePath + "Mat.mat");
            //load a reference from the project view to the material (this is done to be able to set the texture to the material in the project view)
            atlasMaterial = (Material)AssetDatabase.LoadAssetAtPath(atlasTexturePath + "Mat.mat", typeof(Material));

            List <string> shaderDefines;

            if (standardShader)
            {
                shaderDefines = ShaderManager.Instance.GetShaderTexturesDefines(shaderToAtlas, false, objectsToOptimize[0].ObjectMaterial);//we need the 1rst object in the list to know what textures are used.
            }
            else
            {
                shaderDefines = ShaderManager.Instance.GetShaderTexturesDefines(shaderToAtlas);
            }

            for (int k = 0; k < shaderDefines.Count; k++)   //go trough each property of the shader.
            {
                if (SettingsMenuGUI.Instance.ReuseTextures) //if we are reusing textures, get all the textures and then filter them by the TextureReuseManager
                {
                    start = 0;
                    end   = objectsToOptimize.Count;
                }
                List <Texture2D> texturesOfShader = GetTexturesToAtlasForShaderDefine(shaderDefines[k], start, end);//Get the textures for the property shaderDefines[k] to atlas them
                List <Vector2>   scales           = GetScalesToAtlasForShaderDefine(shaderDefines[k], start, end);
                List <Vector2>   offsets          = GetOffsetsToAtlasForShaderDefine(shaderDefines[k], start, end);
                if (SettingsMenuGUI.Instance.ReuseTextures)
                {
                    texturesOfShader = Utils.FilterTexsByIndex(texturesOfShader, textureReuseManager.GetTextureIndexes());
                    scales           = Utils.FilterVec2ByIndex(scales, textureReuseManager.GetTextureIndexes());
                    offsets          = Utils.FilterVec2ByIndex(offsets, textureReuseManager.GetTextureIndexes());
                }
                generatedAtlas.SaveAtlasToFile(atlasTexturePath + k.ToString() + ".png", texturesOfShader, scales, offsets);//save the atlas with the retrieved textures
                AssetDatabase.ImportAsset(atlasTexturePath + k.ToString() + ".png");
                Texture2D tex = (Texture2D)AssetDatabase.LoadAssetAtPath(atlasTexturePath + k.ToString() + ".png", typeof(Texture2D));

                atlasMaterial.SetTexture(shaderDefines[k], //set property shaderDefines[k] for shader shaderToAtlas
                                         tex);
            }
            return(atlasMaterial);
        }
Esempio n. 7
0
        public void OptimizeShader(bool reuseTextures, bool generatePrefabs, bool generatePowerOf2Atlases)
        {
            optimizedObjects.Clear(); //used for generating hierearchy

            if (shaderName == "")     //unknown shader doesnt need to be optimed
            {
                return;
            }
            int currentAtlasSize = Mathf.Min(CalculateAproxAtlasSize(reuseTextures, generatePowerOf2Atlases),
                                             Constants.MaxAtlasSize); /*Constants.MaxAtlasSize);*/

            if (objectsToOptimize.Count > 1 ||                        //more than 1 obj or 1 obj with multiple mat
                (objectsToOptimize.Count == 1 && objectsToOptimize[0] != null && objectsToOptimize[0].ObjHasMoreThanOneMaterial))
            {
                // // // when generating prefabs // // //
                folderToSavePrefabs = (PersistenceHandler.Instance.PathToSaveOptimizedObjs != "") ?
                                      PersistenceHandler.Instance.PathToSaveOptimizedObjs + Path.DirectorySeparatorChar + Utils.GetCurrentSceneName() :
                                      EditorSceneManager.GetActiveScene().path;//<--5.4 +
                //EditorApplication.currentScene;//<- 5.3 -
                if (generatePrefabs)
                {
                    //if(EditorApplication.currentScene == "") { //scene is not saved yet.
                    if (EditorSceneManager.GetActiveScene().path == "")//scene not saved yet.
                    {
                        folderToSavePrefabs = Constants.NonSavedSceneFolderName + ".unity";
                    }
                    folderToSavePrefabs  = folderToSavePrefabs.Substring(0, folderToSavePrefabs.Length - 6) + "-Atlas";//remove the ".unity"
                    folderToSavePrefabs += Path.DirectorySeparatorChar + "Prefabs";
                    if (!Directory.Exists(folderToSavePrefabs))
                    {
                        Directory.CreateDirectory(folderToSavePrefabs);
                        AssetDatabase.Refresh();
                    }
                }
                ///////////////////////////////////////////

                Node resultNode = null;//nodes for the tree for atlasing

                Atlasser generatedAtlas = new Atlasser(currentAtlasSize, currentAtlasSize, generatePowerOf2Atlases);
                int      resizeTimes    = 1;

                TextureReuseManager textureReuseManager = new TextureReuseManager();
                int lastAtlasStartingIndex = objectsToOptimize.Count - 1;
                int atlasNumber            = 1;                         //this is just for numbering the atlases
                int range = 0;                                          //how many items have we placed inside the current atlas.
                for (int j = objectsToOptimize.Count - 1; j >= 0; j--)  //start from the largest to the shortest textures
                {
                    if (objectsToOptimize[j].ObjHasMoreThanOneMaterial) //before atlassing multiple materials obj, combine it.
                    {
                        objectsToOptimize[j].ProcessAndCombineMaterials();
                    }

                    Vector2 textureToAtlasSize = objectsToOptimize[j].TextureSize;
                    if (objectsToOptimize[j].TextureArea > Constants.MaxAtlasSize * Constants.MaxAtlasSize)
                    {
                        Debug.LogError("Texture for game object: " + objectsToOptimize[j].GameObj.name + " is bigger than max atlas size: " + Constants.MaxAtlasSize + "x" + Constants.MaxAtlasSize + " ABORTING");
                        return;
                    }
                    if (reuseTextures)
                    {
                        if (!textureReuseManager.TextureRefExists(objectsToOptimize[j]))//if texture is not registered already
                        //generate a node
                        {
                            resultNode = generatedAtlas.Insert(Mathf.RoundToInt((textureToAtlasSize.x != Constants.NULLV2.x) ? textureToAtlasSize.x : Constants.NullTextureSize),
                                                               Mathf.RoundToInt((textureToAtlasSize.y != Constants.NULLV2.y) ? textureToAtlasSize.y : Constants.NullTextureSize));
                            if (resultNode != null) //save node if fits in atlas
                            {
                                textureReuseManager.AddTextureRef(objectsToOptimize[j], resultNode.NodeRect, j);
                            }
                        }
                    }
                    else
                    {
                        resultNode = generatedAtlas.Insert(Mathf.RoundToInt((textureToAtlasSize.x != Constants.NULLV2.x) ? textureToAtlasSize.x : Constants.NullTextureSize),
                                                           Mathf.RoundToInt((textureToAtlasSize.y != Constants.NULLV2.y) ? textureToAtlasSize.y : Constants.NullTextureSize));
                    }
                    if (resultNode == null)
                    {
                        int resizedAtlasSize = currentAtlasSize + Mathf.RoundToInt((float)currentAtlasSize * Constants.AtlasResizeFactor * resizeTimes);
                        if (resizedAtlasSize <= Constants.MaxAtlasSize)//If we still can place textures inside the atlas then increase the atlas.
                        {
                            if (generatePowerOf2Atlases)
                            {
                                resizedAtlasSize = Mathf.NextPowerOfTwo(resizedAtlasSize);
                            }
                            generatedAtlas = new Atlasser(resizedAtlasSize, resizedAtlasSize, generatePowerOf2Atlases);
                            j = lastAtlasStartingIndex + 1;//== Count and not .Count-1 bc at the end of the loop it will be substracted j-- and we want to start from Count-1

                            resizeTimes++;
                        }
                        else//lets save what we have gathered already into a material + objects and lets start over again.
                        {
                            lastAtlasStartingIndex = j;
                            Material atlasMaterial1 = CreateAtlasMaterialAndTexture(generatedAtlas, shaderName, textureReuseManager, atlasNumber, lastAtlasStartingIndex + 1, lastAtlasStartingIndex + 1 + range);
                            OptimizeDrawCalls(objectsToOptimize.GetRange(lastAtlasStartingIndex + 1, range),
                                              ref atlasMaterial1,
                                              generatedAtlas.GetAtlasSize().x, generatedAtlas.GetAtlasSize().y,
                                              generatedAtlas.TexturePositions,
                                              reuseTextures,
                                              textureReuseManager,//remember to clear this when creating one atlas.
                                              generatePrefabs);
                            CombineObjectsSelectedForCombine(generatePrefabs, atlasMaterial1, lastAtlasStartingIndex + 1, lastAtlasStartingIndex + 1 + range);
                            resizeTimes      = 1;
                            currentAtlasSize = Constants.MinAtlasSize;
                            generatedAtlas   = new Atlasser(currentAtlasSize, currentAtlasSize, generatePowerOf2Atlases);
                            atlasNumber++;
                            if (j == 0)
                            {
                                j++;   //if we happen to be creating an atlas in the last iteration of the loop. then we need to iterate once more to get the 1rst elementx
                            }
                        }
                        textureReuseManager.ClearTextureRefs();
                        range = 0;
                    }
                    else
                    {
                        range++;//increase range as the resultNode != null --> Insertion was successful
                    }
                }
                Material atlasMaterial = CreateAtlasMaterialAndTexture(generatedAtlas, shaderName, textureReuseManager, atlasNumber, 0, range);
                OptimizeDrawCalls(objectsToOptimize.GetRange(0, range),
                                  ref atlasMaterial,
                                  generatedAtlas.GetAtlasSize().x,
                                  generatedAtlas.GetAtlasSize().y,
                                  generatedAtlas.TexturePositions,
                                  reuseTextures,
                                  textureReuseManager,
                                  generatePrefabs);

                CombineObjectsSelectedForCombine(generatePrefabs, atlasMaterial, 0, range);

                //after the game object has been organized, remove the combined game objects.
                for (int i = 0; i < objectsToOptimize.Count; i++)
                {
                    if (objectsToOptimize[i].ObjWasCombined)
                    {
                        objectsToOptimize[i].ClearCombinedObject();
                    }
                }
            }
        }
Esempio n. 8
0
        private Material CreateAtlasMaterialAndTexture(Atlasser generatedAtlas, string shaderToAtlas, TextureReuseManager textureReuseManager, int atlasNumber /*in case we have several atlases*/, int start, int end /*start & end used for multiple atlases*/)
        {
            string fileName           = ((ObjectsGUI.CustomAtlasName == "") ? "Atlas " : (ObjectsGUI.CustomAtlasName + " ")) + atlasNumber + shaderToAtlas.Replace('/', '_');
            string folderToSaveAssets = (PersistenceHandler.Instance.PathToSaveOptimizedObjs != "") ?
                                        PersistenceHandler.Instance.PathToSaveOptimizedObjs + Path.DirectorySeparatorChar + Utils.GetCurrentSceneName() :
                                        #if UNITY_5_4_OR_NEWER
                                        UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene().path;
                                        #else
                                        EditorApplication.currentScene;
                                        #endif
        #if UNITY_5_4_OR_NEWER
            if (UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene().path == "")
            {
        #else
            if (EditorApplication.currentScene == "") //scene is not saved yet.
            {
        #endif
                folderToSaveAssets = Constants.NonSavedSceneFolderName + ".unity";
                Debug.LogWarning("WARNING: Scene has not been saved, saving baked objects to: " + Constants.NonSavedSceneFolderName + " folder");
            }

            folderToSaveAssets = folderToSaveAssets.Substring(0, folderToSaveAssets.Length - 6) + "-Atlas";//remove the ".unity" and add "-Atlas"
            if (!Directory.Exists(folderToSaveAssets))
            {
                Directory.CreateDirectory(folderToSaveAssets);
                AssetDatabase.ImportAsset(folderToSaveAssets);
            }
            string atlasTexturePath = folderToSaveAssets + Path.DirectorySeparatorChar + fileName;
            //create the material in the project and set the shader material to shaderToAtlas
            Material atlasMaterial = new Material(Shader.Find(standardShader ? Utils.ExtractStandardShaderOriginalName(shaderToAtlas) : shaderToAtlas));

            /*
             * if(standardShader) {
             *  atlasMaterial.EnableKeyword("_ALPHAPREMULTIPLY_ON");
             *  atlasMaterial.SetFloat("_Mode", 2);
             *  atlasMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
             *  atlasMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
             *  atlasMaterial.SetInt("_ZWrite", 0);
             *  atlasMaterial.DisableKeyword("_ALPHATEST_ON");
             *  atlasMaterial.EnableKeyword("_ALPHABLEND_ON");
             *  atlasMaterial.DisableKeyword("_ALPHAPREMULTIPLY_ON");
             *  atlasMaterial.renderQueue = 3000;
             *  //atlasMaterial.SetFloat("_Mode", 3f);d
             * }
             * //ACA CAMBIAR EL RENDERING MODE AL SHADER!!!
             *///SOLO FUCNIONA PARA RENDER MODE TRANSPARENTE, NO FUNCIONA PARA CUTOUT

            //save the material to the project view
            AssetDatabase.CreateAsset(atlasMaterial, atlasTexturePath + "Mat.mat");
            AssetDatabase.ImportAsset(atlasTexturePath + "Mat.mat");
            //load a reference from the project view to the material (this is done to be able to set the texture to the material in the project view)
            atlasMaterial = (Material)AssetDatabase.LoadAssetAtPath(atlasTexturePath + "Mat.mat", typeof(Material));

            List <string> shaderDefines;
            if (standardShader)
            {
                shaderDefines = ShaderManager.Instance.GetShaderTexturesDefines(shaderToAtlas, false, objectsToOptimize[0].ObjectMaterial);//we need the 1rst object in the list to know what textures are used.
            }
            else
            {
                shaderDefines = ShaderManager.Instance.GetShaderTexturesDefines(shaderToAtlas);
            }

            for (int k = 0; k < shaderDefines.Count; k++)   //go trough each property of the shader.
            {
                if (SettingsMenuGUI.Instance.ReuseTextures) //if we are reusing textures, get all the textures and then filter them by the TextureReuseManager
                {
                    start = 0;
                    end   = objectsToOptimize.Count;
                }
                List <Texture2D> texturesOfShader = GetTexturesToAtlasForShaderDefine(shaderDefines[k], start, end);//Get the textures for the property shaderDefines[k] to atlas them
                List <Vector2>   scales           = GetScalesToAtlasForShaderDefine(shaderDefines[k], start, end);
                List <Vector2>   offsets          = GetOffsetsToAtlasForShaderDefine(shaderDefines[k], start, end);
                if (SettingsMenuGUI.Instance.ReuseTextures)
                {
                    texturesOfShader = Utils.FilterTexsByIndex(texturesOfShader, textureReuseManager.GetTextureIndexes());
                    scales           = Utils.FilterVec2ByIndex(scales, textureReuseManager.GetTextureIndexes());
                    offsets          = Utils.FilterVec2ByIndex(offsets, textureReuseManager.GetTextureIndexes());
                }
                generatedAtlas.SaveAtlasToFile(atlasTexturePath + k.ToString() + ".png", texturesOfShader, scales, offsets);//save the atlas with the retrieved textures
                AssetDatabase.ImportAsset(atlasTexturePath + k.ToString() + ".png");
                Texture2D tex = (Texture2D)AssetDatabase.LoadAssetAtPath(atlasTexturePath + k.ToString() + ".png", typeof(Texture2D));

                atlasMaterial.SetTexture(shaderDefines[k], //set property shaderDefines[k] for shader shaderToAtlas
                                         tex);
            }
            return(atlasMaterial);
        }