public bool DoAnyResultMatsUseConsiderMeshUVs()
    {
        if (resultType == ResultType.atlas)
        {
            if (resultMaterials == null)
            {
                return(false);
            }
            for (int i = 0; i < resultMaterials.Length; i++)
            {
                if (resultMaterials[i].considerMeshUVs)
                {
                    return(true);
                }
            }

            return(false);
        }
        else
        {
            if (resultMaterialsTexArray == null)
            {
                return(false);
            }
            for (int i = 0; i < resultMaterialsTexArray.Length; i++)
            {
                MB_MultiMaterialTexArray resMat = resultMaterialsTexArray[i];
                for (int j = 0; j < resMat.slices.Count; j++)
                {
                    if (resMat.slices[j].considerMeshUVs)
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
    }
Exemplo n.º 2
0
    internal IEnumerator _CreateAtlasesCoroutineTextureArray(MB3_TextureCombiner combiner, ProgressUpdateDelegate progressInfo, MB3_TextureCombiner.CreateAtlasesCoroutineResult coroutineResult, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null, float maxTimePerFrame = .01f)
    {
        MB_TextureArrayResultMaterial[] bakedMatsAndSlices = null;

        // Validate the formats
        if (textureArrayOutputFormats == null || textureArrayOutputFormats.Length == 0)
        {
            Debug.LogError("No Texture Array Output Formats. There must be at least one entry.");
            coroutineResult.isFinished = true;
            yield break;
        }

        for (int i = 0; i < textureArrayOutputFormats.Length; i++)
        {
            if (!textureArrayOutputFormats[i].ValidateTextureImporterFormatsExistsForTextureFormats(editorMethods, i))
            {
                Debug.LogError("Could not map the selected texture format to a Texture Importer Format. Safest options are ARGB32, or RGB24.");
                coroutineResult.isFinished = true;
                yield break;
            }
        }

        for (int resMatIdx = 0; resMatIdx < resultMaterialsTexArray.Length; resMatIdx++)
        {
            MB_MultiMaterialTexArray textureArraySliceConfig = resultMaterialsTexArray[resMatIdx];
            if (textureArraySliceConfig.combinedMaterial == null)
            {
                Debug.LogError("Material is null for Texture Array Slice Configuration: " + resMatIdx + ".");
                coroutineResult.isFinished = true;
                yield break;
            }


            List <MB_TexArraySlice> slices = textureArraySliceConfig.slices;
            for (int sliceIdx = 0; sliceIdx < slices.Count; sliceIdx++)
            {
                for (int srcMatIdx = 0; srcMatIdx < slices[sliceIdx].sourceMaterials.Count; srcMatIdx++)
                {
                    MB_TexArraySliceRendererMatPair sourceMat = slices[sliceIdx].sourceMaterials[srcMatIdx];
                    if (sourceMat.sourceMaterial == null)
                    {
                        Debug.LogError("Source material is null for Texture Array Slice Configuration: " + resMatIdx + " slice: " + sliceIdx);
                        coroutineResult.isFinished = true;
                        yield break;
                    }

                    if (slices[sliceIdx].considerMeshUVs)
                    {
                        if (sourceMat.renderer == null)
                        {
                            Debug.LogError("Renderer is null for Texture Array Slice Configuration: " + resMatIdx + " slice: " + sliceIdx + ". If considerUVs is enabled then a renderer must be supplied for each source material. The same source material can be used multiple times.");
                            coroutineResult.isFinished = true;
                            yield break;
                        }
                    }
                    else
                    {
                        // TODO check for duplicate source mats.
                    }
                }
            }
        }

        // initialize structure to store results. For texture arrays the structure is two layers deep.
        // First layer is resultMaterial / submesh (each result material can use a different shader)
        // Second layer is a set of TextureArrays for the TextureProperties on that result material.
        int numResultMats = resultMaterialsTexArray.Length;

        bakedMatsAndSlices = new MB_TextureArrayResultMaterial[numResultMats];
        for (int resMatIdx = 0; resMatIdx < bakedMatsAndSlices.Length; resMatIdx++)
        {
            bakedMatsAndSlices[resMatIdx] = new MB_TextureArrayResultMaterial();
            int numSlices = resultMaterialsTexArray[resMatIdx].slices.Count;
            MB_AtlasesAndRects[] slices = bakedMatsAndSlices[resMatIdx].slices = new MB_AtlasesAndRects[numSlices];
            for (int j = 0; j < numSlices; j++)
            {
                slices[j] = new MB_AtlasesAndRects();
            }
        }

        // Some of the slices will be atlases (more than one atlas per slice).
        // Do the material combining for these. First loop over the result materials (1 per submeshes).
        for (int resMatIdx = 0; resMatIdx < bakedMatsAndSlices.Length; resMatIdx++)
        {
            yield return(MB_TextureArrays._CreateAtlasesCoroutineSingleResultMaterial(resMatIdx, bakedMatsAndSlices[resMatIdx], resultMaterialsTexArray[resMatIdx],
                                                                                      objsToMesh,
                                                                                      combiner,
                                                                                      textureArrayOutputFormats,
                                                                                      resultMaterialsTexArray,
                                                                                      customShaderProperties,
                                                                                      progressInfo, coroutineResult, saveAtlasesAsAssets, editorMethods, maxTimePerFrame));

            if (!coroutineResult.success)
            {
                yield break;
            }
        }

        if (coroutineResult.success)
        {
            // Save the results into the TextureBakeResults.
            unpackMat2RectMap(bakedMatsAndSlices);
            if (editorMethods != null)
            {
                editorMethods.GetMaterialPrimaryKeysIfAddressables(textureBakeResults);
            }
            textureBakeResults.resultType              = MB2_TextureBakeResults.ResultType.textureArray;
            textureBakeResults.resultMaterials         = new MB_MultiMaterial[0];
            textureBakeResults.resultMaterialsTexArray = resultMaterialsTexArray;
            if (LOG_LEVEL >= MB2_LogLevel.info)
            {
                Debug.Log("Created Texture2DArrays");
            }
        }
        else
        {
            if (LOG_LEVEL >= MB2_LogLevel.info)
            {
                Debug.Log("Failed to create Texture2DArrays");
            }
        }
    }
Exemplo n.º 3
0
        public static void ConfigureTextureArraysFromObjsToCombine(MB3_TextureBaker mom, SerializedProperty resultMaterialsTexArrays, SerializedObject textureBaker)
        {
            if (mom.GetObjectsToCombine().Count == 0)
            {
                Debug.LogError("You need to add some objects to combine before building the texture array result materials.");
                return;
            }
            if (resultMaterialsTexArrays.arraySize > 0)
            {
                Debug.LogError("You already have some texture array result materials configured. You must remove these before doing this operation.");
                return;
            }
            if (mom.textureBakeResults == null)
            {
                Debug.LogError("Texture Bake Result asset must be set before using this operation.");
                return;
            }

            //validate that the objects to be combined are valid
            for (int i = 0; i < mom.GetObjectsToCombine().Count; i++)
            {
                GameObject go = mom.GetObjectsToCombine()[i];
                if (go == null)
                {
                    Debug.LogError("Null object in list of objects to combine at position " + i);
                    return;
                }

                if (MB_Utility.GetMesh(go) == null)
                {
                    Debug.LogError("Could not get mesh for object in list of objects to combine at position " + i);
                    return;
                }

                Renderer r = go.GetComponent <Renderer>();
                if (r == null || (!(r is MeshRenderer) && !(r is SkinnedMeshRenderer)))
                {
                    Debug.LogError("GameObject at position " + i + " in list of objects to combine did not have a renderer");
                    return;
                }
                if (r.sharedMaterial == null)
                {
                    Debug.LogError("GameObject at position " + i + " in list of objects to combine has a null material");
                    return;
                }
            }

            //Will sort into "result material"
            //  slices
            Dictionary <MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo, List <Slice> > shader2ResultMat_map = new Dictionary <MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo, List <Slice> >();

            // first pass split by shader and analyse meshes.
            List <GameObject> objsToCombine = mom.GetObjectsToCombine();

            for (int meshIdx = 0; meshIdx < objsToCombine.Count; meshIdx++)
            {
                GameObject srcGo = objsToCombine[meshIdx];
                Mesh       mesh  = MB_Utility.GetMesh(srcGo);
                Renderer   r     = MB_Utility.GetRenderer(srcGo);

                if (mom.LOG_LEVEL >= MB2_LogLevel.trace)
                {
                    Debug.Log("1st Pass 'Split By Shader' Processing Mesh: " + mesh + " Num submeshes: " + r.sharedMaterials.Length);
                }
                for (int submeshIdx = 0; submeshIdx < r.sharedMaterials.Length; submeshIdx++)
                {
                    if (r.sharedMaterials[submeshIdx] == null)
                    {
                        continue;
                    }

                    MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo newKey = new MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo(r.sharedMaterials[submeshIdx].shader, r.sharedMaterials[submeshIdx]);
                    // Initially we fill the list of srcMaterials with garbage MB_MaterialAndUVRects. Will get proper ones when we atlas pack.
                    MB_MaterialAndUVRect submeshMaterial = new MB_MaterialAndUVRect(
                        r.sharedMaterials[submeshIdx],
                        new Rect(0, 0, 0, 0),              // garbage value
                        false,                             //garbage value
                        new Rect(0, 0, 0, 0),              // garbage value
                        new Rect(0, 0, 0, 0),              // garbage value
                        new Rect(0, 0, 1, 1),              // garbage value
                        MB_TextureTilingTreatment.unknown, // garbage value
                        r.name);
                    submeshMaterial.objectsThatUse = new List <GameObject>();
                    submeshMaterial.objectsThatUse.Add(r.gameObject);
                    if (!shader2ResultMat_map.ContainsKey(newKey))
                    {
                        // this is a new shader create a new result material
                        Slice srcMaterials = new Slice
                        {
                            atlasRects    = new List <MB_MaterialAndUVRect>(),
                            numAtlasRects = 1,
                        };
                        srcMaterials.atlasRects.Add(submeshMaterial);
                        List <Slice> binsOfMatsThatUseShader = new List <Slice>();
                        binsOfMatsThatUseShader.Add(srcMaterials);
                        if (mom.LOG_LEVEL >= MB2_LogLevel.trace)
                        {
                            Debug.Log("  Adding Source Material: " + submeshMaterial.material);
                        }
                        shader2ResultMat_map.Add(newKey, binsOfMatsThatUseShader);
                    }
                    else
                    {
                        // there is a result material that uses this shader. Add this source material
                        Slice srcMaterials = shader2ResultMat_map[newKey][0]; // There should only be one list of source materials
                        if (srcMaterials.atlasRects.Find(x => x.material == submeshMaterial.material) == null)
                        {
                            if (mom.LOG_LEVEL >= MB2_LogLevel.trace)
                            {
                                Debug.Log("  Adding Source Material: " + submeshMaterial.material);
                            }
                            srcMaterials.atlasRects.Add(submeshMaterial);
                        }
                    }
                }
            }

            int resMatCount = 0;

            foreach (MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo resultMat in shader2ResultMat_map.Keys)
            {
                // at this point there there should be only one slice with all the source materials
                resMatCount++;

                // For each result material, all source materials are in the first slice.
                // We will now split these using a texture packer. Each "atlas" generated by the packer will be a slice.
                {
                    // All source materials should be in the first slice at this point.
                    List <Slice>      slices                = shader2ResultMat_map[resultMat];
                    List <Slice>      newSlices             = new List <Slice>();
                    Slice             firstSlice            = slices[0];
                    List <Material>   allMatsThatUserShader = new List <Material>();
                    List <GameObject> objsThatUseFirstSlice = new List <GameObject>();
                    for (int i = 0; i < firstSlice.atlasRects.Count; i++)
                    {
                        allMatsThatUserShader.Add(firstSlice.atlasRects[i].material);
                        if (!objsThatUseFirstSlice.Contains(firstSlice.atlasRects[i].objectsThatUse[0]))
                        {
                            objsThatUseFirstSlice.Add(firstSlice.atlasRects[i].objectsThatUse[0]);
                        }
                    }

                    MB3_TextureCombiner combiner = mom.CreateAndConfigureTextureCombiner();
                    combiner.packingAlgorithm    = MB2_PackingAlgorithmEnum.MeshBakerTexturePacker;
                    combiner.saveAtlasesAsAssets = false;
                    combiner.fixOutOfBoundsUVs   = true;
                    combiner.doMergeDistinctMaterialTexturesThatWouldExceedAtlasSize = true;
                    List <AtlasPackingResult> packingResults = new List <AtlasPackingResult>();
                    Material tempMat = new Material(resultMat.shader);

                    if (mom.LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("======== 2nd pass. Use atlas packer to split the first slice into multiple if it exceeds atlas size. ");
                    }
                    combiner.CombineTexturesIntoAtlases(null, null, tempMat, mom.GetObjectsToCombine(), allMatsThatUserShader, null, packingResults,
                                                        onlyPackRects: true, splitAtlasWhenPackingIfTooBig: true);
                    if (mom.LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("======== Completed packing with texture packer. numPackingResults: " + packingResults.Count);
                    }
                    newSlices.Clear();

                    // The texture packing just split the atlas into multiple atlases. Each atlas will become a "slice".
                    for (int newSliceIdx = 0; newSliceIdx < packingResults.Count; newSliceIdx++)
                    {
                        List <MB_MaterialAndUVRect> sourceMats     = new List <MB_MaterialAndUVRect>();
                        List <MB_MaterialAndUVRect> packedMatRects = (List <MB_MaterialAndUVRect>)packingResults[newSliceIdx].data;
                        HashSet <Rect> distinctAtlasRects          = new HashSet <Rect>();
                        for (int packedMatRectIdx = 0; packedMatRectIdx < packedMatRects.Count; packedMatRectIdx++)
                        {
                            MB_MaterialAndUVRect muvr = packedMatRects[packedMatRectIdx];
                            distinctAtlasRects.Add(muvr.atlasRect);
                            {
                                Rect    encapsulatingRect = muvr.GetEncapsulatingRect();
                                Vector2 sizeInAtlas_px    = new Vector2(
                                    packingResults[newSliceIdx].atlasX * encapsulatingRect.width,
                                    packingResults[newSliceIdx].atlasY * encapsulatingRect.height);
                            }
                            sourceMats.Add(muvr);
                        }

                        Slice slice = new Slice()
                        {
                            atlasRects    = sourceMats,
                            packingResult = packingResults[newSliceIdx],
                            numAtlasRects = distinctAtlasRects.Count,
                        };

                        newSlices.Add(slice);
                    }

                    // Replace first slice with split version.
                    if (mom.LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("First slice exceeded atlas size splitting it into " + newSlices.Count + " slices");
                    }
                    slices.RemoveAt(0);
                    for (int i = 0; i < newSlices.Count; i++)
                    {
                        slices.Insert(i, newSlices[i]);
                    }
                }
            }

            // build the texture array result materials
            if (shader2ResultMat_map.Count == 0)
            {
                Debug.LogError("Found no materials in list of objects to combine");
            }
            mom.resultMaterialsTexArray = new MB_MultiMaterialTexArray[shader2ResultMat_map.Count];
            int k = 0;

            foreach (MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo resMatKey in shader2ResultMat_map.Keys)
            {
                List <Slice>             srcSlices = shader2ResultMat_map[resMatKey];
                MB_MultiMaterialTexArray mm        = mom.resultMaterialsTexArray[k] = new MB_MultiMaterialTexArray();
                for (int sliceIdx = 0; sliceIdx < srcSlices.Count; sliceIdx++)
                {
                    Slice            slice    = srcSlices[sliceIdx];
                    MB_TexArraySlice resSlice = new MB_TexArraySlice();
                    List <Material>  usedMats = new List <Material>();

                    for (int srcMatIdx = 0; srcMatIdx < slice.atlasRects.Count; srcMatIdx++)
                    {
                        MB_MaterialAndUVRect matAndUVRect = slice.atlasRects[srcMatIdx];
                        List <GameObject>    objsThatUse  = matAndUVRect.objectsThatUse;
                        for (int objsThatUseIdx = 0; objsThatUseIdx < objsThatUse.Count; objsThatUseIdx++)
                        {
                            GameObject obj = objsThatUse[objsThatUseIdx];
                            if (!resSlice.ContainsMaterialAndMesh(slice.atlasRects[srcMatIdx].material, MB_Utility.GetMesh(obj)))
                            {
                                resSlice.sourceMaterials.Add(
                                    new MB_TexArraySliceRendererMatPair()
                                {
                                    renderer       = obj,
                                    sourceMaterial = slice.atlasRects[srcMatIdx].material
                                }
                                    );
                            }
                        }
                    }

                    {
                        // Should we use considerUVs
                        bool doConsiderUVs = false;
                        //     If there is more than one atlas rectangle in a slice then use considerUVs
                        if (slice.numAtlasRects > 1)
                        {
                            doConsiderUVs = true;
                        }
                        else
                        {
                            //     There is only one source material, could be:
                            //          - lots of tiling (don't want consider UVs)
                            //          - We are extracting a small part of a large atlas (want considerUVs)
                            if (slice.packingResult.atlasX >= mom.maxAtlasSize ||
                                slice.packingResult.atlasY >= mom.maxAtlasSize)
                            {
                                doConsiderUVs = false; // lots of tiling
                            }
                            else
                            {
                                doConsiderUVs = true; // extracting a small part of an atlas
                            }
                        }

                        resSlice.considerMeshUVs = doConsiderUVs;
                    }

                    mm.slices.Add(resSlice);
                }

                // Enforce integrity. If a material appears in more than one slice then all those slices must be considerUVs=true
                {
                    // collect all distinct materials
                    HashSet <Material>         distinctMats   = new HashSet <Material>();
                    Dictionary <Material, int> mat2sliceCount = new Dictionary <Material, int>();
                    for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++)
                    {
                        for (int sliceMatIdx = 0; sliceMatIdx < mm.slices[sliceIdx].sourceMaterials.Count; sliceMatIdx++)
                        {
                            Material mat = mm.slices[sliceIdx].sourceMaterials[sliceMatIdx].sourceMaterial;
                            distinctMats.Add(mat);
                            mat2sliceCount[mat] = 0;
                        }
                    }

                    // Count the number of slices that use each material.
                    foreach (Material mat in distinctMats)
                    {
                        for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++)
                        {
                            if (mm.slices[sliceIdx].ContainsMaterial(mat))
                            {
                                mat2sliceCount[mat] = mat2sliceCount[mat] + 1;
                            }
                        }
                    }

                    // Check that considerUVs is true for any materials that appear more than once
                    foreach (Material mat in distinctMats)
                    {
                        if (mat2sliceCount[mat] > 1)
                        {
                            for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++)
                            {
                                if (mm.slices[sliceIdx].ContainsMaterial(mat))
                                {
                                    if (mom.LOG_LEVEL >= MB2_LogLevel.debug &&
                                        mm.slices[sliceIdx].considerMeshUVs)
                                    {
                                        Debug.Log("There was a material " + mat + " that was used by more than one slice and considerUVs was false. sliceIdx:" + sliceIdx);
                                    }
                                    mm.slices[sliceIdx].considerMeshUVs = true;
                                }
                            }
                        }
                    }
                }

                // Cleanup. remove "Renderer"s from source materials that do not use considerUVs and delete extra
                {
                    // put any slices with consider UVs first
                    List <MB_TexArraySlice> newSlices = new List <MB_TexArraySlice>();
                    for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++)
                    {
                        if (mm.slices[sliceIdx].considerMeshUVs == true)
                        {
                            newSlices.Add(mm.slices[sliceIdx]);
                        }
                    }

                    // for any slices without considerUVs, remove "renderer" and truncate
                    for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++)
                    {
                        MB_TexArraySlice slice = mm.slices[sliceIdx];
                        if (slice.considerMeshUVs == false)
                        {
                            newSlices.Add(slice);
                            HashSet <Material> distinctMats = slice.GetDistinctMaterials();
                            slice.sourceMaterials.Clear();
                            foreach (Material mat in distinctMats)
                            {
                                slice.sourceMaterials.Add(new MB_TexArraySliceRendererMatPair()
                                {
                                    sourceMaterial = mat
                                });
                            }
                        }
                    }

                    mm.slices = newSlices;
                }

                string   pth           = AssetDatabase.GetAssetPath(mom.textureBakeResults);
                string   baseName      = Path.GetFileNameWithoutExtension(pth);
                string   folderPath    = pth.Substring(0, pth.Length - baseName.Length - 6);
                string   matName       = folderPath + baseName + "-mat" + k + ".mat";
                Material existingAsset = AssetDatabase.LoadAssetAtPath <Material>(matName);
                if (!existingAsset)
                {
                    Material newMat = new Material(Shader.Find("Standard"));
                    // Don't try to configure the material we need the user to pick a shader that has TextureArrays
                    AssetDatabase.CreateAsset(newMat, matName);
                }

                mm.combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(matName, typeof(Material));
                k++;
            }


            MBVersionEditor.UpdateIfDirtyOrScript(textureBaker);
            textureBaker.Update();
        }
Exemplo n.º 4
0
        public static IEnumerator _CreateAtlasesCoroutineSingleResultMaterial(int resMatIdx,
                                                                              MB_TextureArrayResultMaterial bakedMatsAndSlicesResMat,
                                                                              MB_MultiMaterialTexArray resMatConfig,
                                                                              List <GameObject> objsToMesh,
                                                                              MB3_TextureCombiner combiner,
                                                                              MB_TextureArrayFormatSet[] textureArrayOutputFormats,
                                                                              MB_MultiMaterialTexArray[] resultMaterialsTexArray,
                                                                              List <ShaderTextureProperty> customShaderProperties,
                                                                              ProgressUpdateDelegate progressInfo,
                                                                              MB3_TextureCombiner.CreateAtlasesCoroutineResult coroutineResult,
                                                                              bool saveAtlasesAsAssets = false,
                                                                              MB2_EditorMethodsInterface editorMethods = null,
                                                                              float maxTimePerFrame = .01f)
        {
            MB2_LogLevel LOG_LEVEL = combiner.LOG_LEVEL;

            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("Baking atlases for result material " + resMatIdx + " num slices:" + resMatConfig.slices.Count);
            }
            // Each result material can be one set of slices per textureProperty. Each slice can be an atlas.
            // Create atlases for each slice.
            List <MB3_TextureCombiner.TemporaryTexture> generatedTemporaryAtlases = new List <MB3_TextureCombiner.TemporaryTexture>();

            {
                combiner.saveAtlasesAsAssets = false; // Don't want generated atlas slices to be assets
                List <MB_TexArraySlice> slicesConfig = resMatConfig.slices;
                for (int sliceIdx = 0; sliceIdx < slicesConfig.Count; sliceIdx++)
                {
                    Material resMatToPass = null;
                    List <MB_TexArraySliceRendererMatPair> srcMatAndObjPairs = slicesConfig[sliceIdx].sourceMaterials;

                    if (LOG_LEVEL >= MB2_LogLevel.trace)
                    {
                        Debug.Log(" Baking atlases for result material:" + resMatIdx + " slice:" + sliceIdx);
                    }
                    resMatToPass = resMatConfig.combinedMaterial;
                    combiner.fixOutOfBoundsUVs = slicesConfig[sliceIdx].considerMeshUVs;
                    MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult coroutineResult2 = new MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult();
                    MB_AtlasesAndRects sliceAtlasesAndRectOutput = bakedMatsAndSlicesResMat.slices[sliceIdx];
                    List <Material>    usedMats = new List <Material>();
                    slicesConfig[sliceIdx].GetAllUsedMaterials(usedMats);

                    yield return(combiner.CombineTexturesIntoAtlasesCoroutine(progressInfo, sliceAtlasesAndRectOutput, resMatToPass, slicesConfig[sliceIdx].GetAllUsedRenderers(objsToMesh), usedMats, editorMethods, coroutineResult2, maxTimePerFrame,
                                                                              onlyPackRects: false, splitAtlasWhenPackingIfTooBig: false));

                    coroutineResult.success = coroutineResult2.success;
                    if (!coroutineResult.success)
                    {
                        coroutineResult.isFinished = true;
                        yield break;
                    }

                    // Track which slices are new generated texture instances. Atlases could be original texture assets (one tex per atlas) or temporary texture instances in memory that will need to be destroyed.
                    {
                        for (int texPropIdx = 0; texPropIdx < sliceAtlasesAndRectOutput.atlases.Length; texPropIdx++)
                        {
                            Texture2D atlas = sliceAtlasesAndRectOutput.atlases[texPropIdx];
                            if (atlas != null)
                            {
                                bool atlasWasASourceTexture = false;
                                for (int srcMatIdx = 0; srcMatIdx < srcMatAndObjPairs.Count; srcMatIdx++)
                                {
                                    Material srcMat = srcMatAndObjPairs[srcMatIdx].sourceMaterial;
                                    if (srcMat.HasProperty(sliceAtlasesAndRectOutput.texPropertyNames[texPropIdx]) &&
                                        srcMat.GetTexture(sliceAtlasesAndRectOutput.texPropertyNames[texPropIdx]) == atlas)
                                    {
                                        atlasWasASourceTexture = true;
                                        break;
                                    }
                                }

                                if (!atlasWasASourceTexture)
                                {
                                    generatedTemporaryAtlases.Add(new MB3_TextureCombiner.TemporaryTexture(sliceAtlasesAndRectOutput.texPropertyNames[texPropIdx], atlas));
                                }
                            }
                        }
                    } // end visit slices

                    Debug.Assert(combiner._getNumTemporaryTextures() == 0, "Combiner should have no temporary textures.");
                }

                combiner.saveAtlasesAsAssets = saveAtlasesAsAssets; // Restore original setting.
            }

            // Generated atlas textures are temporary for texture arrays. They exist only in memory. Need to be cleaned up after we create slices.
            for (int i = 0; i < generatedTemporaryAtlases.Count; i++)
            {
                combiner.AddTemporaryTexture(generatedTemporaryAtlases[i]);
            }

            List <ShaderTextureProperty> texPropertyNames = new List <ShaderTextureProperty>();

            MB3_TextureCombinerPipeline._CollectPropertyNames(texPropertyNames, customShaderProperties, resMatConfig.combinedMaterial, LOG_LEVEL);

            // The slices are built from different source-material-lists. Each slice can have different sets of texture properties missing (nulls).
            // Build a master list of texture properties.
            bool[] hasTexForProperty = MB_TextureArrays.DetermineWhichPropertiesHaveTextures(bakedMatsAndSlicesResMat.slices);

            List <Texture2D> temporaryTextureAssets = new List <Texture2D>();

            try
            {
                MB_MultiMaterialTexArray resMaterial = resMatConfig;
                Dictionary <string, MB_TexArrayForProperty> resTexArraysByProperty = new Dictionary <string, MB_TexArrayForProperty>();
                {
                    // Initialize so I don't need to check if properties exist later.
                    for (int propIdx = 0; propIdx < texPropertyNames.Count; propIdx++)
                    {
                        if (hasTexForProperty[propIdx])
                        {
                            resTexArraysByProperty[texPropertyNames[propIdx].name] =
                                new MB_TexArrayForProperty(texPropertyNames[propIdx].name, new MB_TextureArrayReference[textureArrayOutputFormats.Length]);
                        }
                    }
                }


                MB3_TextureCombinerNonTextureProperties textureBlender = null;
                textureBlender = new MB3_TextureCombinerNonTextureProperties(LOG_LEVEL, combiner.considerNonTextureProperties);
                textureBlender.LoadTextureBlendersIfNeeded(resMatConfig.combinedMaterial);
                textureBlender.AdjustNonTextureProperties(resMatConfig.combinedMaterial, texPropertyNames, editorMethods);

                // Vist each TextureFormatSet
                for (int texFormatSetIdx = 0; texFormatSetIdx < textureArrayOutputFormats.Length; texFormatSetIdx++)
                {
                    MB_TextureArrayFormatSet textureArrayFormatSet = textureArrayOutputFormats[texFormatSetIdx];
                    editorMethods.Clear();

                    MB_TextureArrays.TexturePropertyData texPropertyData = new MB_TextureArrays.TexturePropertyData();
                    MB_TextureArrays.FindBestSizeAndMipCountAndFormatForTextureArrays(texPropertyNames, combiner.maxAtlasSize, textureArrayFormatSet, bakedMatsAndSlicesResMat.slices, texPropertyData);

                    // Create textures we might need to create if they don't exist.
                    {
                        for (int propIdx = 0; propIdx < hasTexForProperty.Length; propIdx++)
                        {
                            if (hasTexForProperty[propIdx])
                            {
                                TextureFormat format       = texPropertyData.formats[propIdx];
                                int           numSlices    = bakedMatsAndSlicesResMat.slices.Length;
                                int           targetWidth  = (int)texPropertyData.sizes[propIdx].x;
                                int           targetHeight = (int)texPropertyData.sizes[propIdx].y;
                                for (int sliceIdx = 0; sliceIdx < numSlices; sliceIdx++)
                                {
                                    if (bakedMatsAndSlicesResMat.slices[sliceIdx].atlases[propIdx] == null)
                                    {
                                        // Can only setSolidColor on truecolor textures. First create a texture in trucolor format
                                        Texture2D sliceTex = new Texture2D(targetWidth, targetHeight, TextureFormat.ARGB32, texPropertyData.doMips[propIdx]);
                                        Color     col      = textureBlender.GetColorForTemporaryTexture(resMatConfig.slices[sliceIdx].sourceMaterials[0].sourceMaterial, texPropertyNames[propIdx]);
                                        MB_Utility.setSolidColor(sliceTex, col);
                                        // Now create a copy of this texture in target format.
                                        bakedMatsAndSlicesResMat.slices[sliceIdx].atlases[propIdx] = editorMethods.CreateTemporaryAssetCopy(texPropertyNames[propIdx], sliceTex, targetWidth, targetHeight, format, LOG_LEVEL);
                                        temporaryTextureAssets.Add(bakedMatsAndSlicesResMat.slices[sliceIdx].atlases[propIdx]);
                                        MB_Utility.Destroy(sliceTex);
                                    }
                                }
                            }
                        }
                    }


                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("Converting source textures to readable formats.");
                    }
                    if (MB_TextureArrays.ConvertTexturesToReadableFormat(texPropertyData, bakedMatsAndSlicesResMat.slices, hasTexForProperty, texPropertyNames, combiner, LOG_LEVEL, temporaryTextureAssets, editorMethods))
                    {
                        // We now have a set of slices (one per textureProperty). Build these into Texture2DArray's.
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("Creating texture arrays");
                        }
                        if (LOG_LEVEL >= MB2_LogLevel.info)
                        {
                            Debug.Log("THERE MAY BE ERRORS IN THE CONSOLE ABOUT 'Rebuilding mipmaps ... not supported'. THESE ARE PROBABLY FALSE POSITIVES AND CAN BE IGNORED.");
                        }
                        Texture2DArray[] textureArrays = MB_TextureArrays.CreateTextureArraysForResultMaterial(texPropertyData, texPropertyNames, bakedMatsAndSlicesResMat.slices, hasTexForProperty, combiner, LOG_LEVEL);


                        // Now have texture arrays for a result material, for all props. Save it.
                        for (int propIdx = 0; propIdx < textureArrays.Length; propIdx++)
                        {
                            if (hasTexForProperty[propIdx])
                            {
                                MB_TextureArrayReference texRef = new MB_TextureArrayReference(textureArrayFormatSet.name, textureArrays[propIdx]);
                                resTexArraysByProperty[texPropertyNames[propIdx].name].formats[texFormatSetIdx] = texRef;
                                if (saveAtlasesAsAssets)
                                {
                                    editorMethods.SaveTextureArrayToAssetDatabase(textureArrays[propIdx],
                                                                                  textureArrayFormatSet.GetFormatForProperty(texPropertyNames[propIdx].name),
                                                                                  bakedMatsAndSlicesResMat.slices[0].texPropertyNames[propIdx],
                                                                                  propIdx, resMaterial.combinedMaterial);
                                }
                            }
                        }
                    }
                } // end vist format set

                resMaterial.textureProperties = new List <MB_TexArrayForProperty>();
                foreach (MB_TexArrayForProperty val in resTexArraysByProperty.Values)
                {
                    resMaterial.textureProperties.Add(val);
                }
            }
            catch (Exception e)
            {
                Debug.LogError(e.Message + "\n" + e.StackTrace.ToString());
                coroutineResult.isFinished = true;
                coroutineResult.success    = false;
            }
            finally
            {
                editorMethods.RestoreReadFlagsAndFormats(progressInfo);
                combiner._destroyAllTemporaryTextures();
                for (int i = 0; i < temporaryTextureAssets.Count; i++)
                {
                    editorMethods.DestroyAsset(temporaryTextureAssets[i]);
                }
                temporaryTextureAssets.Clear();
            }
        }
Exemplo n.º 5
0
        public static string ReportTextureSizesAndFormats(MB3_TextureBaker mom)
        {
            if (mom.resultType != MB2_TextureBakeResults.ResultType.textureArray)
            {
                Debug.LogError("Result Type must be Texture Array.");
                return("");
            }

            for (int resMatIdx = 0; resMatIdx < mom.resultMaterialsTexArray.Length; resMatIdx++)
            {
                MB_MultiMaterialTexArray resMatTexArray = mom.resultMaterialsTexArray[resMatIdx];
                if (resMatTexArray.combinedMaterial == null)
                {
                    Debug.LogError("Result Material " + resMatIdx + " is null");
                    return("");
                }
            }

            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            // Visit each result material
            for (int resMatIdx = 0; resMatIdx < mom.resultMaterialsTexArray.Length; resMatIdx++)
            {
                MB_MultiMaterialTexArray resMatTexArray = mom.resultMaterialsTexArray[resMatIdx];

                // Do an atlas pack in order to collect all the textures needed by the result material
                // And group these by material texture property.

                MB3_TextureCombiner combiner = mom.CreateAndConfigureTextureCombiner();
                combiner.saveAtlasesAsAssets = false;
                combiner.fixOutOfBoundsUVs   = false;
                List <AtlasPackingResult> packingResults = new List <AtlasPackingResult>();
                Material tempMat = new Material(resMatTexArray.combinedMaterial.shader);

                List <Material> allSourceMaterials = new List <Material>();
                for (int sliceIdx = 0; sliceIdx < resMatTexArray.slices.Count; sliceIdx++)
                {
                    List <Material> srcMats = new List <Material>();
                    resMatTexArray.slices[sliceIdx].GetAllUsedMaterials(srcMats);
                    for (int srcMatIdx = 0; srcMatIdx < srcMats.Count; srcMatIdx++)
                    {
                        if (srcMats[srcMatIdx] != null && !allSourceMaterials.Contains(srcMats[srcMatIdx]))
                        {
                            allSourceMaterials.Add(srcMats[srcMatIdx]);
                        }
                    }
                }

                MB_AtlasesAndRects atlasesAndRects = new MB_AtlasesAndRects();
                combiner.CombineTexturesIntoAtlases(null, atlasesAndRects, tempMat, mom.GetObjectsToCombine(), allSourceMaterials, null, packingResults,
                                                    onlyPackRects: true, splitAtlasWhenPackingIfTooBig: false);

                // Now vist the packing results and collect all the textures
                Debug.Assert(packingResults.Count == 1);
                for (int texPropIdx = 0; texPropIdx < atlasesAndRects.texPropertyNames.Length; texPropIdx++)
                {
                    string propertyName = atlasesAndRects.texPropertyNames[texPropIdx];
                    sb.AppendLine(String.Format("Prop: {0}", propertyName));

                    List <MB_MaterialAndUVRect> matsData    = (List <MB_MaterialAndUVRect>)packingResults[0].data;
                    HashSet <Material>          visitedMats = new HashSet <Material>();
                    for (int matAndGoIdx = 0; matAndGoIdx < matsData.Count; matAndGoIdx++)
                    {
                        Material mat = matsData[matAndGoIdx].material;
                        if (visitedMats.Contains(mat))
                        {
                            continue;
                        }
                        visitedMats.Add(mat);
                        if (mat.HasProperty(propertyName))
                        {
                            Texture tex = mat.GetTexture(propertyName);
                            if (tex != null)
                            {
                                string texFormatString = "UnknownFormat";
                                string texWrapMode     = "UnknownClampMode";
                                if (tex is Texture2D)
                                {
                                    texFormatString = ((Texture2D)tex).format.ToString();
                                    texWrapMode     = ((Texture2D)tex).wrapMode.ToString();
                                }

                                sb.AppendLine(String.Format("    {0} x {1}  format:{2}  wrapMode:{3}   {4}", tex.width.ToString().PadLeft(6, ' '), tex.height.ToString().PadRight(6, ' '), texFormatString.PadRight(20, ' '), texWrapMode.PadRight(12, ' '), tex.name));
                            }
                        }
                    }
                }
            }

            return(sb.ToString());
        }