Exemple #1
0
    /// <summary>
    /// Creates for materials on renderer.
    /// </summary>
    /// <returns>Generates an MB2_TextureBakeResult that can be used if all objects to be combined use the same material.
    /// Returns a MB2_TextureBakeResults that will map all materials used by renderer r to
    /// the rectangle 0,0..1,1 in the atlas.</returns>
    /// <param name="r">The red component.</param>
    public static MB2_TextureBakeResults CreateForMaterialsOnRenderer(Renderer r)
    {
        MB2_TextureBakeResults tbr = (MB2_TextureBakeResults)ScriptableObject.CreateInstance(typeof(MB2_TextureBakeResults));
        //Material[] ms = r.sharedMaterials;
        //MB_MaterialAndUVRect[] mss = new MB_MaterialAndUVRect[r.sharedMaterials.Length];
        List <MB_MaterialAndUVRect> mss = new List <MB_MaterialAndUVRect>();

        Material[] ms;
        for (int i = 0; i < r.sharedMaterials.Length; i++)
        {
            if (r.sharedMaterials[i] != null)
            {
                MB_MaterialAndUVRect matAndUVRect = new MB_MaterialAndUVRect(r.sharedMaterials[i], new Rect(0f, 0f, 1f, 1f), new Rect(0f, 0f, 1f, 1f), new Rect(0f, 0f, 1f, 1f), new Rect(0f, 0f, 1f, 1f), r.name);
                if (!mss.Contains(matAndUVRect))
                {
                    mss.Add(matAndUVRect);
                }
            }
        }
        if (r.sharedMaterials.Length > 1)
        {
            tbr.prefabUVRects   = new Rect[mss.Count];
            tbr.materials       = ms = new Material[mss.Count];
            tbr.resultMaterials = new MB_MultiMaterial[mss.Count];
            for (int i = 0; i < mss.Count; i++)
            {
                ms[i] = mss[i].material;
                tbr.prefabUVRects[i]   = new Rect(0f, 0f, 1f, 1f);
                tbr.resultMaterials[i] = new MB_MultiMaterial();
                List <Material> sourceMats = new List <Material>();
                sourceMats.Add(ms[i]);
                tbr.resultMaterials[i].sourceMaterials  = sourceMats;
                tbr.resultMaterials[i].combinedMaterial = ms[i];
            }
            tbr.doMultiMaterial = true;
        }
        else
        {
            tbr.doMultiMaterial = false;
            tbr.prefabUVRects   = new Rect[] { new Rect(0f, 0f, 1f, 1f) };
            tbr.materials       = ms = new Material[] { mss[0].material };
            tbr.resultMaterial  = mss[0].material;
            tbr.resultMaterials = new MB_MultiMaterial[] { new MB_MultiMaterial() };
            List <Material> sourceMats = new List <Material>();
            sourceMats.Add(ms[0]);
            tbr.resultMaterials[0].sourceMaterials  = sourceMats;
            tbr.resultMaterials[0].combinedMaterial = mss[0].material;
        }
        tbr.materialsAndUVRects = mss.ToArray();
        tbr.fixOutOfBoundsUVs   = false;
        return(tbr);
    }
    public override bool Equals(object obj)
    {
        if (!(obj is MB_MaterialAndUVRect))
        {
            return(false);
        }
        MB_MaterialAndUVRect b = (MB_MaterialAndUVRect)obj;

        return(material == b.material &&
               allPropsUseSameTiling_samplingEncapsulatinRect == b.allPropsUseSameTiling_samplingEncapsulatinRect &&
               allPropsUseSameTiling_sourceMaterialTiling == b.allPropsUseSameTiling_sourceMaterialTiling &&
               allPropsUseSameTiling == b.allPropsUseSameTiling &&
               propsUseDifferntTiling_srcUVsamplingRect == b.propsUseDifferntTiling_srcUVsamplingRect);
    }
Exemple #3
0
        //Rect[] uvRectInAtlas;

        public Material2AtlasRectangleMapper(MB2_TextureBakeResults res)
        {
            tbr = res;
            matsAndSrcUVRect = res.materialsAndUVRects;
            //uvRectInAtlas = res.prefabUVRects;
            //allMatsAreUnique = true;

            //backward compatibility. this may be an old TextureBakeResult which has no materialsAndUVRects if so then build it now
            if (matsAndSrcUVRect == null || matsAndSrcUVRect.Length == 0)
            {
                matsAndSrcUVRect = new MB_MaterialAndUVRect[res.materials.Length];
                for (int i = 0; i < res.materials.Length; i++)
                {
                    matsAndSrcUVRect[i] = new MB_MaterialAndUVRect(res.materials[i], res.prefabUVRects[i], new Rect(0f, 0f, 1f, 1f));
                }
                res.materialsAndUVRects = matsAndSrcUVRect;
            }

            //count the number of times a material appears in the atlas. used for fast lookup
            numTimesMatAppearsInAtlas = new int[matsAndSrcUVRect.Length];
            for (int i = 0; i < matsAndSrcUVRect.Length; i++)
            {
                if (numTimesMatAppearsInAtlas[i] > 1)
                {
                    continue;
                }
                int count = 1;
                for (int j = i + 1; j < matsAndSrcUVRect.Length; j++)
                {
                    if (matsAndSrcUVRect[i].material == matsAndSrcUVRect[j].material)
                    {
                        count++;
                    }
                }
                numTimesMatAppearsInAtlas[i] = count;
                if (count > 1)
                {
                    //allMatsAreUnique = false;
                    for (int j = i + 1; j < matsAndSrcUVRect.Length; j++)
                    {
                        if (matsAndSrcUVRect[i].material == matsAndSrcUVRect[j].material)
                        {
                            numTimesMatAppearsInAtlas[j] = count;
                        }
                    }
                }
            }
        }
 public bool ContainsMaterial(Material m)
 {
     if (materialsAndUVRects.Length == 0)
     {
         materialsAndUVRects = new MB_MaterialAndUVRect[materials.Length];
         for (int i = 0; i < materialsAndUVRects.Length; i++)
         {
             materialsAndUVRects[i] = new MB_MaterialAndUVRect(materials[i], prefabUVRects[i], new Rect(0f, 0f, 1f, 1f), new Rect(0f, 0f, 1f, 1f), new Rect(0f, 0f, 1f, 1f), "");
         }
     }
     for (int i = 0; i < materialsAndUVRects.Length; i++)
     {
         if (materialsAndUVRects[i].material == m)
         {
             return(true);
         }
     }
     return(false);
 }
Exemple #5
0
    /// <summary>
    /// Creates for materials on renderer.
    /// </summary>
    /// <returns>Generates an MB2_TextureBakeResult that can be used if all objects to be combined use the same material.
    /// Returns a MB2_TextureBakeResults that will map all materials used by renderer r to
    /// the rectangle 0,0..1,1 in the atlas.</returns>
    /// <param name="r">The red component.</param>
    public static MB2_TextureBakeResults CreateForMaterialsOnRenderer(GameObject[] gos, List <Material> matsOnTargetRenderer)
    {
        HashSet <Material> fullMaterialList = new HashSet <Material>(matsOnTargetRenderer);

        for (int i = 0; i < gos.Length; i++)
        {
            if (gos[i] == null)
            {
                Debug.LogError(string.Format("Game object {0} in list of objects to add was null", i));
                return(null);
            }
            Material[] oMats = MB_Utility.GetGOMaterials(gos[i]);
            if (oMats.Length == 0)
            {
                Debug.LogError(string.Format("Game object {0} in list of objects to add no renderer", i));
                return(null);
            }
            for (int j = 0; j < oMats.Length; j++)
            {
                if (!fullMaterialList.Contains(oMats[j]))
                {
                    fullMaterialList.Add(oMats[j]);
                }
            }
        }
        Material[] rms = new Material[fullMaterialList.Count];
        fullMaterialList.CopyTo(rms);

        MB2_TextureBakeResults tbr = (MB2_TextureBakeResults)ScriptableObject.CreateInstance(typeof(MB2_TextureBakeResults));
        //Material[] ms = rms;
        //MB_MaterialAndUVRect[] mss = new MB_MaterialAndUVRect[rms.Length];
        List <MB_MaterialAndUVRect> mss = new List <MB_MaterialAndUVRect>();

        Material[] ms;
        for (int i = 0; i < rms.Length; i++)
        {
            if (rms[i] != null)
            {
                MB_MaterialAndUVRect matAndUVRect = new MB_MaterialAndUVRect(rms[i], new Rect(0f, 0f, 1f, 1f), new Rect(0f, 0f, 1f, 1f), new Rect(0f, 0f, 1f, 1f), new Rect(0f, 0f, 1f, 1f), "");
                if (!mss.Contains(matAndUVRect))
                {
                    mss.Add(matAndUVRect);
                }
            }
        }

        tbr.materials       = ms = new Material[mss.Count];
        tbr.resultMaterials = new MB_MultiMaterial[mss.Count];
        for (int i = 0; i < mss.Count; i++)
        {
            ms[i] = mss[i].material;
            tbr.resultMaterials[i] = new MB_MultiMaterial();
            List <Material> sourceMats = new List <Material>();
            sourceMats.Add(mss[i].material);
            tbr.resultMaterials[i].sourceMaterials  = sourceMats;
            tbr.resultMaterials[i].combinedMaterial = ms[i];
            tbr.resultMaterials[i].considerMeshUVs  = false;
        }
        if (rms.Length == 1)
        {
            tbr.doMultiMaterial = false;
        }
        else
        {
            tbr.doMultiMaterial = true;
        }

        tbr.materialsAndUVRects = mss.ToArray();
        //tbr.fixOutOfBoundsUVs = false;
        return(tbr);
    }
        /// <summary>
        /// A material can appear more than once in an atlas if using fixOutOfBoundsUVs.
        /// in this case you need to use the UV rect of the mesh to find the correct rectangle.
        /// If the all properties on the mat use the same tiling then
        /// encapsulatingRect can be larger and will include baked UV and material tiling
        /// If mat uses different tiling for different maps then encapsulatingRect is the uvs of
        /// source mesh used to bake atlas and sourceMaterialTilingOut is 0,0,1,1. This works because
        /// material tiling was baked into the atlas.
        /// </summary>
        public bool TryMapMaterialToUVRect(Material mat, Mesh m, int submeshIdx, int idxInResultMats, MB3_MeshCombinerSingle.MeshChannelsCache meshChannelCache, Dictionary <int, MB_Utility.MeshAnalysisResult[]> meshAnalysisCache,
                                           out MB_TextureTilingTreatment tilingTreatment,
                                           out Rect rectInAtlas,
                                           out Rect encapsulatingRectOut,
                                           out Rect sourceMaterialTilingOut,
                                           ref String errorMsg,
                                           MB2_LogLevel logLevel)
        {
            if (tbr.version < VERSION)
            {
                UpgradeToCurrentVersion(tbr);
            }
            tilingTreatment = MB_TextureTilingTreatment.unknown;
            if (tbr.materialsAndUVRects.Length == 0)
            {
                errorMsg                = "The 'Texture Bake Result' needs to be re-baked to be compatible with this version of Mesh Baker. Please re-bake using the MB3_TextureBaker.";
                rectInAtlas             = new Rect();
                encapsulatingRectOut    = new Rect();
                sourceMaterialTilingOut = new Rect();
                return(false);
            }
            if (mat == null)
            {
                rectInAtlas             = new Rect();
                encapsulatingRectOut    = new Rect();
                sourceMaterialTilingOut = new Rect();
                errorMsg = String.Format("Mesh {0} Had no material on submesh {1} cannot map to a material in the atlas", m.name, submeshIdx);
                return(false);
            }
            if (submeshIdx >= m.subMeshCount)
            {
                errorMsg                = "Submesh index is greater than the number of submeshes";
                rectInAtlas             = new Rect();
                encapsulatingRectOut    = new Rect();
                sourceMaterialTilingOut = new Rect();
                return(false);
            }

            //find the first index of this material
            int idx = -1;

            for (int i = 0; i < matsAndSrcUVRect.Length; i++)
            {
                if (mat == matsAndSrcUVRect[i].material)
                {
                    idx = i;
                    break;
                }
            }
            // if couldn't find material
            if (idx == -1)
            {
                rectInAtlas             = new Rect();
                encapsulatingRectOut    = new Rect();
                sourceMaterialTilingOut = new Rect();
                errorMsg = String.Format("Material {0} could not be found in the Texture Bake Result", mat.name);
                return(false);
            }

            if (!tbr.resultMaterials[idxInResultMats].considerMeshUVs)
            {
                if (numTimesMatAppearsInAtlas[idx] != 1)
                {
                    Debug.LogError("There is a problem with this TextureBakeResults. FixOutOfBoundsUVs is false and a material appears more than once.");
                }
                MB_MaterialAndUVRect mr = matsAndSrcUVRect[idx];
                rectInAtlas             = mr.atlasRect;
                tilingTreatment         = mr.tilingTreatment;
                encapsulatingRectOut    = mr.GetEncapsulatingRect();
                sourceMaterialTilingOut = mr.GetMaterialTilingRect();
                return(true);
            }
            else
            {
                //todo what if no UVs
                //Find UV rect in source mesh
                MB_Utility.MeshAnalysisResult[] mar;
                if (!meshAnalysisCache.TryGetValue(m.GetInstanceID(), out mar))
                {
                    mar = new MB_Utility.MeshAnalysisResult[m.subMeshCount];
                    for (int j = 0; j < m.subMeshCount; j++)
                    {
                        Vector2[] uvss = meshChannelCache.GetUv0Raw(m);
                        MB_Utility.hasOutOfBoundsUVs(uvss, m, ref mar[j], j);
                    }
                    meshAnalysisCache.Add(m.GetInstanceID(), mar);
                }

                //this could be a mesh that was not used in the texture baking that has huge UV tiling too big for the rect that was baked
                //find a record that has an atlas uvRect capable of containing this
                bool found                = false;
                Rect encapsulatingRect    = new Rect(0, 0, 0, 0);
                Rect sourceMaterialTiling = new Rect(0, 0, 0, 0);
                if (logLevel >= MB2_LogLevel.trace)
                {
                    Debug.Log(String.Format("Trying to find a rectangle in atlas capable of holding tiled sampling rect for mesh {0} using material {1} meshUVrect={2}", m, mat, mar[submeshIdx].uvRect.ToString("f5")));
                }
                for (int i = idx; i < matsAndSrcUVRect.Length; i++)
                {
                    MB_MaterialAndUVRect matAndUVrect = matsAndSrcUVRect[i];
                    if (matAndUVrect.material == mat)
                    {
                        if (matAndUVrect.allPropsUseSameTiling)
                        {
                            encapsulatingRect    = matAndUVrect.allPropsUseSameTiling_samplingEncapsulatinRect;
                            sourceMaterialTiling = matAndUVrect.allPropsUseSameTiling_sourceMaterialTiling;
                        }
                        else
                        {
                            encapsulatingRect    = matAndUVrect.propsUseDifferntTiling_srcUVsamplingRect;
                            sourceMaterialTiling = new Rect(0, 0, 1, 1);
                        }

                        if (IsMeshAndMaterialRectEnclosedByAtlasRect(
                                matAndUVrect.tilingTreatment,
                                mar[submeshIdx].uvRect,
                                sourceMaterialTiling,
                                encapsulatingRect,
                                logLevel))
                        {
                            if (logLevel >= MB2_LogLevel.trace)
                            {
                                Debug.Log("Found rect in atlas capable of containing tiled sampling rect for mesh " + m + " at idx=" + i);
                            }
                            idx   = i;
                            found = true;
                            break;
                        }
                    }
                }
                if (found)
                {
                    MB_MaterialAndUVRect mr = matsAndSrcUVRect[idx];
                    rectInAtlas             = mr.atlasRect;
                    tilingTreatment         = mr.tilingTreatment;
                    encapsulatingRectOut    = mr.GetEncapsulatingRect();
                    sourceMaterialTilingOut = mr.GetMaterialTilingRect();
                    return(true);
                }
                else
                {
                    rectInAtlas             = new Rect();
                    encapsulatingRectOut    = new Rect();
                    sourceMaterialTilingOut = new Rect();
                    errorMsg = String.Format("Could not find a tiled rectangle in the atlas capable of containing the uv and material tiling on mesh {0} for material {1}", m.name, mat);
                    return(false);
                }
            }
        }
Exemple #7
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();
        }