예제 #1
0
 public override AtlasPackingResult[] GetRects(List <Vector2> imgWidthHeights, int maxDimension, int padding, bool doMultiAtlas)
 {
     if (doMultiAtlas)
     {
         if (packingOrientation == TexturePackingOrientation.vertical)
         {
             return(_GetRectsMultiAtlasVertical(imgWidthHeights, maxDimension, padding, 2 + padding * 2, 2 + padding * 2, 2 + padding * 2, 2 + padding * 2));
         }
         else
         {
             return(_GetRectsMultiAtlasHorizontal(imgWidthHeights, maxDimension, padding, 2 + padding * 2, 2 + padding * 2, 2 + padding * 2, 2 + padding * 2));
         }
     }
     else
     {
         AtlasPackingResult apr = _GetRectsSingleAtlas(imgWidthHeights, maxDimension, padding, 2 + padding * 2, 2 + padding * 2, 2 + padding * 2, 2 + padding * 2, 0);
         if (apr == null)
         {
             return(null);
         }
         else
         {
             return(new AtlasPackingResult[] { apr });
         }
     }
 }
        public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                         MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner,
                                         AtlasPackingResult packedAtlasRects,
                                         Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods,
                                         MB2_LogLevel LOG_LEVEL)
        {
            Debug.Assert(data.OnlyOneTextureInAtlasReuseTextures());
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("Only one image per atlas. Will re-use original texture");
            }
            for (int i = 0; i < data.numAtlases; i++)
            {
                MeshBakerMaterialTexture dmt = data.distinctMaterialTextures[0].ts[i];
                atlases[i] = dmt.GetTexture2D();
                if (data.resultType == MB2_TextureBakeResults.ResultType.atlas)
                {
                    data.resultMaterial.SetTexture(data.texPropertyNames[i].name, atlases[i]);
                    data.resultMaterial.SetTextureScale(data.texPropertyNames[i].name, Vector2.one);
                    data.resultMaterial.SetTextureOffset(data.texPropertyNames[i].name, Vector2.zero);
                }
            }

            yield break;
        }
        public override AtlasPackingResult[] GetRects(List <Vector2> imgWidthHeights, List <AtlasPadding> paddings, int maxDimensionX, int maxDimensionY, bool doMultiAtlas)
        {
            Debug.Assert(imgWidthHeights.Count == paddings.Count, imgWidthHeights.Count + " " + paddings.Count);
            int maxPaddingX = 0;
            int maxPaddingY = 0;

            for (int i = 0; i < paddings.Count; i++)
            {
                maxPaddingX = Mathf.Max(maxPaddingX, paddings[i].leftRight);
                maxPaddingY = Mathf.Max(maxPaddingY, paddings[i].topBottom);
            }
            if (doMultiAtlas)
            {
                return(_GetRectsMultiAtlas(imgWidthHeights, paddings, maxDimensionX, maxDimensionY, 2 + maxPaddingX * 2, 2 + maxPaddingY * 2, 2 + maxPaddingX * 2, 2 + maxPaddingY * 2));
            }
            else
            {
                AtlasPackingResult apr = _GetRectsSingleAtlas(imgWidthHeights, paddings, maxDimensionX, maxDimensionY, 2 + maxPaddingX * 2, 2 + maxPaddingY * 2, 2 + maxPaddingX * 2, 2 + maxPaddingY * 2, 0);
                if (apr == null)
                {
                    return(null);
                }
                else
                {
                    return(new AtlasPackingResult[] { apr });
                }
            }
        }
        public AtlasPackingResult[] CalculateAtlasRectangles(MB3_TextureCombinerPipeline.TexturePipelineData data, bool doMultiAtlas, MB2_LogLevel LOG_LEVEL)
        {
            Debug.Assert(data.OnlyOneTextureInAtlasReuseTextures());
            if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Only one image per atlas. Will re-use original texture");
            AtlasPackingResult[] packerRects = new AtlasPackingResult[1];
            AtlasPadding[] paddings = new AtlasPadding[] { new AtlasPadding(data._atlasPadding) };
            packerRects[0] = new AtlasPackingResult(paddings);
            packerRects[0].rects = new Rect[1];
            packerRects[0].srcImgIdxs = new int[] { 0 };
            packerRects[0].rects[0] = new Rect(0f, 0f, 1f, 1f);

            MeshBakerMaterialTexture dmt = null;
            if (data.distinctMaterialTextures[0].ts.Length > 0)
            {
                dmt = data.distinctMaterialTextures[0].ts[0];

            }
            if (dmt == null || dmt.isNull)
            {
                packerRects[0].atlasX = 16;
                packerRects[0].atlasY = 16;
                packerRects[0].usedW = 16;
                packerRects[0].usedH = 16;
            }
            else
            {
                packerRects[0].atlasX = dmt.width;
                packerRects[0].atlasY = dmt.height;
                packerRects[0].usedW = dmt.width;
                packerRects[0].usedH = dmt.height;
            }
            return packerRects;
        }
 //normalize atlases so that that rects are 0 to 1
 public void ConvertToRectsWithoutPaddingAndNormalize01(AtlasPackingResult rr, AtlasPadding padding)
 {
     for (int i = 0; i < rr.rects.Length; i++)
     {
         rr.rects[i].x      = (rr.rects[i].x + padding.leftRight) / rr.atlasX;
         rr.rects[i].y      = (rr.rects[i].y + padding.topBottom) / rr.atlasY;
         rr.rects[i].width  = (rr.rects[i].width - padding.leftRight * 2) / rr.atlasX;
         rr.rects[i].height = (rr.rects[i].height - padding.topBottom * 2) / rr.atlasY;
     }
 }
예제 #6
0
 //normalize atlases so that that rects are 0 to 1
 void normalizeRects(AtlasPackingResult rr, int padding)
 {
     for (int i = 0; i < rr.rects.Length; i++)
     {
         rr.rects[i].x      = (rr.rects[i].x + padding) / rr.atlasX;
         rr.rects[i].y      = (rr.rects[i].y + padding) / rr.atlasY;
         rr.rects[i].width  = (rr.rects[i].width - padding * 2) / rr.atlasX;
         rr.rects[i].height = (rr.rects[i].height - padding * 2) / rr.atlasY;
     }
 }
예제 #7
0
        public AtlasPackingResult CalculateAtlasRectangles(MB3_TextureCombinerPipeline.TexturePipelineData data, MB2_LogLevel LOG_LEVEL)
        {
            if (data._packingAlgorithm == MB2_PackingAlgorithmEnum.UnitysPackTextures)
            {
                //with Unity texture packer we don't find the rectangles, Unity does. When packer is run
                return(new AtlasPackingResult(new AtlasPadding[0]));
            }
            AtlasPackingResult uvRects;

            if (data.distinctMaterialTextures.Count == 1 && data._fixOutOfBoundsUVs == false)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.Log("Only one image per atlas. Will re-use original texture");
                }
                AtlasPadding[] paddings = new AtlasPadding[] { new AtlasPadding(data._atlasPadding) };
                uvRects          = new AtlasPackingResult(paddings);
                uvRects.rects    = new Rect[1];
                uvRects.rects[0] = new Rect(0f, 0f, 1f, 1f);
                uvRects.atlasX   = data.distinctMaterialTextures[0].idealWidth;
                uvRects.atlasY   = data.distinctMaterialTextures[0].idealHeight;
            }
            else
            {
                List <Vector2> imageSizes = new List <Vector2>();
                for (int i = 0; i < data.distinctMaterialTextures.Count; i++)
                {
                    imageSizes.Add(new Vector2(data.distinctMaterialTextures[i].idealWidth, data.distinctMaterialTextures[i].idealHeight));
                }
                MB2_TexturePacker tp = MB3_TextureCombinerPipeline.CreateTexturePacker(data._packingAlgorithm);
                tp.atlasMustBePowerOfTwo = data._meshBakerTexturePackerForcePowerOfTwo;
                int atlasMaxDimension        = data._maxAtlasSize;
                List <AtlasPadding> paddings = new List <AtlasPadding>();
                for (int i = 0; i < imageSizes.Count; i++)
                {
                    AtlasPadding padding = new AtlasPadding();
                    padding.topBottom = data._atlasPadding;
                    padding.leftRight = data._atlasPadding;
                    if (data._packingAlgorithm == MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Horizontal)
                    {
                        padding.leftRight = 0;
                    }
                    if (data._packingAlgorithm == MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Vertical)
                    {
                        padding.topBottom = 0;
                    }
                    paddings.Add(padding);
                }
                AtlasPackingResult[] packerRects = tp.GetRects(imageSizes, paddings, atlasMaxDimension, atlasMaxDimension, false);
                uvRects = packerRects[0];
            }
            return(uvRects);
        }
예제 #8
0
 public AtlasPackingResult[] GetRects(List <Vector2> imgWidthHeights, int maxDimension, int padding, bool doMultiAtlas)
 {
     if (doMultiAtlas)
     {
         return(_GetRectsMultiAtlas(imgWidthHeights, maxDimension, padding, 2 + padding * 2, 2 + padding * 2, 2 + padding * 2, 2 + padding * 2));
     }
     else
     {
         AtlasPackingResult apr = _GetRectsSingleAtlas(imgWidthHeights, maxDimension, padding, 2 + padding * 2, 2 + padding * 2, 2 + padding * 2, 2 + padding * 2, 0);
         if (apr == null)
         {
             return(null);
         }
         else
         {
             return(new AtlasPackingResult[] { apr });
         }
     }
 }
예제 #9
0
            public void MergeAtlasPackingResultStackBonAInternal(AtlasPackingResult a, AtlasPackingResult b, out Rect AatlasToFinal, out Rect BatlasToFinal, bool stretchBToAtlasWidth, int maxWidthDim, int maxHeightDim, out int atlasX, out int atlasY)
            {
                // first calc width scale and offset
                float finalW = a.usedW + b.usedW;
                float scaleXa, scaleXb;

                if (finalW > maxWidthDim)
                {
                    scaleXa = maxWidthDim / finalW;                                              //0,1
                    float offsetBx = ((float)Mathf.FloorToInt(a.usedW * scaleXa)) / maxWidthDim; //0,1
                    scaleXa       = offsetBx;
                    scaleXb       = (1f - offsetBx);
                    AatlasToFinal = new Rect(0, 0, scaleXa, 1);
                    BatlasToFinal = new Rect(offsetBx, 0, scaleXb, 1);
                }
                else
                {
                    float offsetBx = a.usedW / finalW;
                    AatlasToFinal = new Rect(0, 0, offsetBx, 1);
                    BatlasToFinal = new Rect(offsetBx, 0, b.usedW / finalW, 1);
                }

                //next calc width scale and offset
                if (a.atlasX > b.atlasX)
                {
                    if (!stretchBToAtlasWidth)
                    {
                        // b rects will be placed in a larger atlas which will make them smaller
                        BatlasToFinal.width = ((float)b.atlasX) / a.atlasX;
                    }
                }
                else if (b.atlasX > a.atlasX)
                {
                    // a rects will be placed in a larger atlas which will make them smaller
                    AatlasToFinal.width = ((float)a.atlasX) / b.atlasX;
                }

                atlasX = a.usedW + b.usedW;
                atlasY = Mathf.Max(a.usedH, b.usedH);
            }
예제 #10
0
            public void MergeAtlasPackingResultStackBonAInternal(AtlasPackingResult a, AtlasPackingResult b, out Rect AatlasToFinal, out Rect BatlasToFinal, bool stretchBToAtlasWidth, int maxWidthDim, int maxHeightDim, out int atlasX, out int atlasY)
            {
                float finalH = a.usedH + b.usedH;
                float scaleYa, scaleYb;

                if (finalH > maxHeightDim)
                {
                    scaleYa = maxHeightDim / finalH;                                              //0,1
                    float offsetBy = ((float)Mathf.FloorToInt(a.usedH * scaleYa)) / maxHeightDim; //0,1
                    scaleYa       = offsetBy;
                    scaleYb       = (1f - offsetBy);
                    AatlasToFinal = new Rect(0, 0, 1, scaleYa);
                    BatlasToFinal = new Rect(0, offsetBy, 1, scaleYb);
                }
                else
                {
                    float offsetBy = a.usedH / finalH;
                    AatlasToFinal = new Rect(0, 0, 1, offsetBy);
                    BatlasToFinal = new Rect(0, offsetBy, 1, b.usedH / finalH);
                }

                //next calc width scale and offset
                if (a.atlasX > b.atlasX)
                {
                    if (!stretchBToAtlasWidth)
                    {
                        // b rects will be placed in a larger atlas which will make them smaller
                        BatlasToFinal.width = ((float)b.atlasX) / a.atlasX;
                    }
                }
                else if (b.atlasX > a.atlasX)
                {
                    // a rects will be placed in a larger atlas which will make them smaller
                    AatlasToFinal.width = ((float)a.atlasX) / b.atlasX;
                }

                atlasX = Mathf.Max(a.usedW, b.usedW);
                atlasY = a.usedH + b.usedH;
            }
예제 #11
0
        public override IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                                  MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner,
                                                  AtlasPackingResult packedAtlasRects,
                                                  Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods,
                                                  MB2_LogLevel LOG_LEVEL)
        {
            Debug.Assert(!data.OnlyOneTextureInAtlasReuseTextures());
            Rect[] uvRects = packedAtlasRects.rects;

            long estArea    = 0;
            int  atlasSizeX = 1;
            int  atlasSizeY = 1;

            uvRects = null;
            for (int propIdx = 0; propIdx < data.numAtlases; propIdx++)
            {
                //-----------------------
                ShaderTextureProperty prop  = data.texPropertyNames[propIdx];
                Texture2D             atlas = null;
                if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                {
                    atlas = null;
                }
                else
                {
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.LogWarning("Beginning loop " + propIdx + " num temporary textures " + combiner._getNumTemporaryTextures());
                    }
                    MB3_TextureCombinerPackerRoot.CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data);
                    Texture2D[] texToPack = new Texture2D[data.distinctMaterialTextures.Count];
                    for (int texSetIdx = 0; texSetIdx < data.distinctMaterialTextures.Count; texSetIdx++)
                    {
                        MB_TexSet txs     = data.distinctMaterialTextures[texSetIdx];
                        int       tWidth  = txs.idealWidth;
                        int       tHeight = txs.idealHeight;
                        Texture2D tx      = txs.ts[propIdx].GetTexture2D();
                        if (progressInfo != null)
                        {
                            progressInfo("Adjusting for scale and offset " + tx, .01f);
                        }

                        if (textureEditorMethods != null)
                        {
                            textureEditorMethods.SetReadWriteFlag(tx, true, true);
                        }

                        tx = GetAdjustedForScaleAndOffset2(prop.name, txs.ts[propIdx], txs.obUVoffset, txs.obUVscale, data, combiner, LOG_LEVEL);
                        //create a resized copy if necessary
                        if (tx.width != tWidth || tx.height != tHeight)
                        {
                            if (progressInfo != null)
                            {
                                progressInfo("Resizing texture '" + tx + "'", .01f);
                            }
                            if (LOG_LEVEL >= MB2_LogLevel.debug)
                            {
                                Debug.LogWarning("Copying and resizing texture " + prop.name + " from " + tx.width + "x" + tx.height + " to " + tWidth + "x" + tHeight);
                            }
                            tx = combiner._resizeTexture(prop.name, (Texture2D)tx, tWidth, tHeight);
                        }

                        estArea += tx.width * tx.height;
                        if (data._considerNonTextureProperties)
                        {
                            //combine the tintColor with the texture
                            tx = combiner._createTextureCopy(prop.name, tx);
                            data.nonTexturePropertyBlender.TintTextureWithTextureCombiner(tx, data.distinctMaterialTextures[texSetIdx], prop);
                        }

                        texToPack[texSetIdx] = tx;
                    }

                    if (textureEditorMethods != null)
                    {
                        textureEditorMethods.CheckBuildSettings(estArea);
                    }

                    if (Math.Sqrt(estArea) > 3500f)
                    {
                        if (LOG_LEVEL >= MB2_LogLevel.warn)
                        {
                            Debug.LogWarning("The maximum possible atlas size is 4096. Textures may be shrunk");
                        }
                    }

                    atlas = new Texture2D(1, 1, TextureFormat.ARGB32, true);
                    if (progressInfo != null)
                    {
                        progressInfo("Packing texture atlas " + prop.name, .25f);
                    }
                    if (propIdx == 0)
                    {
                        if (progressInfo != null)
                        {
                            progressInfo("Estimated min size of atlases: " + Math.Sqrt(estArea).ToString("F0"), .1f);
                        }
                        if (LOG_LEVEL >= MB2_LogLevel.info)
                        {
                            Debug.Log("Estimated atlas minimum size:" + Math.Sqrt(estArea).ToString("F0"));
                        }
                        int maxAtlasSize = 4096;
                        uvRects = atlas.PackTextures(texToPack, data._atlasPadding, maxAtlasSize, false);
                        if (LOG_LEVEL >= MB2_LogLevel.info)
                        {
                            Debug.Log("After pack textures atlas size " + atlas.width + " " + atlas.height);
                        }
                        atlasSizeX = atlas.width;
                        atlasSizeY = atlas.height;
                        atlas.Apply();
                    }
                    else
                    {
                        if (progressInfo != null)
                        {
                            progressInfo("Copying Textures Into: " + prop.name, .1f);
                        }
                        atlas = _copyTexturesIntoAtlas(texToPack, data._atlasPadding, uvRects, atlasSizeX, atlasSizeY, combiner);
                    }
                }

                atlases[propIdx] = atlas;
                //----------------------

                if (data._saveAtlasesAsAssets && textureEditorMethods != null)
                {
                    textureEditorMethods.SaveAtlasToAssetDatabase(atlases[propIdx], prop, propIdx, data.resultMaterial);
                }
                data.resultMaterial.SetTextureOffset(prop.name, Vector2.zero);
                data.resultMaterial.SetTextureScale(prop.name, Vector2.one);
                combiner._destroyTemporaryTextures(prop.name);
                GC.Collect();
            }
            packedAtlasRects.rects = uvRects;
            yield break;
        }
        public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                         MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner,
                                         AtlasPackingResult packedAtlasRects,
                                         Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods,
                                         MB2_LogLevel LOG_LEVEL)
        {
            Rect[] uvRects = packedAtlasRects.rects;
            if (data.distinctMaterialTextures.Count == 1 && data._fixOutOfBoundsUVs == false)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.Log("Only one image per atlas. Will re-use original texture");
                }
                uvRects    = new Rect[1];
                uvRects[0] = new Rect(0f, 0f, 1f, 1f);
                for (int i = 0; i < data.numAtlases; i++)
                {
                    MeshBakerMaterialTexture dmt = data.distinctMaterialTextures[0].ts[i];
                    atlases[i] = dmt.GetTexture2D();
                    data.resultMaterial.SetTexture(data.texPropertyNames[i].name, atlases[i]);
                    data.resultMaterial.SetTextureScale(data.texPropertyNames[i].name, dmt.matTilingRect.size);
                    data.resultMaterial.SetTextureOffset(data.texPropertyNames[i].name, dmt.matTilingRect.min);
                }
            }
            else
            {
                long estArea    = 0;
                int  atlasSizeX = 1;
                int  atlasSizeY = 1;
                uvRects = null;
                for (int i = 0; i < data.numAtlases; i++)
                { //i is an atlas "MainTex", "BumpMap" etc...
                  //-----------------------
                    Texture2D atlas = null;
                    if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(i, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                    {
                        atlas = null;
                    }
                    else
                    {
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.LogWarning("Beginning loop " + i + " num temporary textures " + combiner._temporaryTextures.Count);
                        }
                        for (int j = 0; j < data.distinctMaterialTextures.Count; j++)
                        { //j is a distinct set of textures one for each of "MainTex", "BumpMap" etc...
                            MB_TexSet txs = data.distinctMaterialTextures[j];

                            int tWidth  = txs.idealWidth;
                            int tHeight = txs.idealHeight;

                            Texture2D tx = txs.ts[i].GetTexture2D();
                            if (tx == null)
                            {
                                tx = txs.ts[i].t = combiner._createTemporaryTexture(tWidth, tHeight, TextureFormat.ARGB32, true);
                                if (data._considerNonTextureProperties && data.nonTexturePropertyBlender != null)
                                {
                                    Color col = data.nonTexturePropertyBlender.GetColorIfNoTexture(txs.matsAndGOs.mats[0].mat, data.texPropertyNames[i]);
                                    if (LOG_LEVEL >= MB2_LogLevel.trace)
                                    {
                                        Debug.Log("Setting texture to solid color " + col);
                                    }
                                    MB_Utility.setSolidColor(tx, col);
                                }
                                else
                                {
                                    Color col = MB3_TextureCombinerNonTextureProperties.GetColorIfNoTexture(data.texPropertyNames[i]);
                                    MB_Utility.setSolidColor(tx, col);
                                }
                            }

                            if (progressInfo != null)
                            {
                                progressInfo("Adjusting for scale and offset " + tx, .01f);
                            }
                            if (textureEditorMethods != null)
                            {
                                textureEditorMethods.SetReadWriteFlag(tx, true, true);
                            }
                            tx = GetAdjustedForScaleAndOffset2(txs.ts[i], txs.obUVoffset, txs.obUVscale, data, combiner, LOG_LEVEL);

                            //create a resized copy if necessary
                            if (tx.width != tWidth || tx.height != tHeight)
                            {
                                if (progressInfo != null)
                                {
                                    progressInfo("Resizing texture '" + tx + "'", .01f);
                                }
                                if (LOG_LEVEL >= MB2_LogLevel.debug)
                                {
                                    Debug.LogWarning("Copying and resizing texture " + data.texPropertyNames[i].name + " from " + tx.width + "x" + tx.height + " to " + tWidth + "x" + tHeight);
                                }
                                tx = combiner._resizeTexture((Texture2D)tx, tWidth, tHeight);
                            }

                            txs.ts[i].t = tx;
                        }

                        Texture2D[] texToPack = new Texture2D[data.distinctMaterialTextures.Count];
                        for (int j = 0; j < data.distinctMaterialTextures.Count; j++)
                        {
                            Texture2D tx = data.distinctMaterialTextures[j].ts[i].GetTexture2D();
                            estArea += tx.width * tx.height;
                            if (data._considerNonTextureProperties)
                            {
                                //combine the tintColor with the texture
                                tx = combiner._createTextureCopy(tx);
                                data.nonTexturePropertyBlender.TintTextureWithTextureCombiner(tx, data.distinctMaterialTextures[j], data.texPropertyNames[i]);
                            }
                            texToPack[j] = tx;
                        }

                        if (textureEditorMethods != null)
                        {
                            textureEditorMethods.CheckBuildSettings(estArea);
                        }

                        if (Math.Sqrt(estArea) > 3500f)
                        {
                            if (LOG_LEVEL >= MB2_LogLevel.warn)
                            {
                                Debug.LogWarning("The maximum possible atlas size is 4096. Textures may be shrunk");
                            }
                        }
                        atlas = new Texture2D(1, 1, TextureFormat.ARGB32, true);
                        if (progressInfo != null)
                        {
                            progressInfo("Packing texture atlas " + data.texPropertyNames[i].name, .25f);
                        }
                        if (i == 0)
                        {
                            if (progressInfo != null)
                            {
                                progressInfo("Estimated min size of atlases: " + Math.Sqrt(estArea).ToString("F0"), .1f);
                            }
                            if (LOG_LEVEL >= MB2_LogLevel.info)
                            {
                                Debug.Log("Estimated atlas minimum size:" + Math.Sqrt(estArea).ToString("F0"));
                            }

                            if (data.distinctMaterialTextures.Count == 1 && data._fixOutOfBoundsUVs == false)
                            { //don't want to force power of 2 so tiling will still work
                                uvRects = new Rect[1] {
                                    new Rect(0f, 0f, 1f, 1f)
                                };
                                atlas = _copyTexturesIntoAtlas(texToPack, data._atlasPadding, uvRects, texToPack[0].width, texToPack[0].height, combiner);
                            }
                            else
                            {
                                int maxAtlasSize = 4096;
                                uvRects = atlas.PackTextures(texToPack, data._atlasPadding, maxAtlasSize, false);
                            }

                            if (LOG_LEVEL >= MB2_LogLevel.info)
                            {
                                Debug.Log("After pack textures atlas size " + atlas.width + " " + atlas.height);
                            }
                            atlasSizeX = atlas.width;
                            atlasSizeY = atlas.height;
                            atlas.Apply();
                        }
                        else
                        {
                            if (progressInfo != null)
                            {
                                progressInfo("Copying Textures Into: " + data.texPropertyNames[i].name, .1f);
                            }
                            atlas = _copyTexturesIntoAtlas(texToPack, data._atlasPadding, uvRects, atlasSizeX, atlasSizeY, combiner);
                        }
                    }
                    atlases[i] = atlas;
                    //----------------------

                    if (data._saveAtlasesAsAssets && textureEditorMethods != null)
                    {
                        textureEditorMethods.SaveAtlasToAssetDatabase(atlases[i], data.texPropertyNames[i], i, data.resultMaterial);
                    }
                    data.resultMaterial.SetTextureOffset(data.texPropertyNames[i].name, Vector2.zero);
                    data.resultMaterial.SetTextureScale(data.texPropertyNames[i].name, Vector2.one);

                    combiner._destroyTemporaryTextures(); // need to save atlases before doing this
                    GC.Collect();
                }
            }
            packedAtlasRects.rects = uvRects;
            yield break;
        }
        public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                         MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner,
                                         AtlasPackingResult packedAtlasRects,
                                         Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods,
                                         MB2_LogLevel LOG_LEVEL)
        {
            Rect[] uvRects = packedAtlasRects.rects;
            if (uvRects.Length == 1)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.Log("Only one image per atlas. Will re-use original texture");
                }
                for (int i = 0; i < data.numAtlases; i++)
                {
                    MeshBakerMaterialTexture dmt = data.distinctMaterialTextures[0].ts[i];
                    atlases[i] = dmt.GetTexture2D();
                    data.resultMaterial.SetTexture(data.texPropertyNames[i].name, atlases[i]);
                    data.resultMaterial.SetTextureScale(data.texPropertyNames[i].name, dmt.matTilingRect.size);
                    data.resultMaterial.SetTextureOffset(data.texPropertyNames[i].name, dmt.matTilingRect.min);
                }
            }
            else
            {
                int atlasSizeX = packedAtlasRects.atlasX;
                int atlasSizeY = packedAtlasRects.atlasY;
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY);
                }
                for (int propIdx = 0; propIdx < data.numAtlases; propIdx++)
                {
                    Texture2D atlas = null;
                    if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                    {
                        atlas = null;
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("=== Not creating atlas for " + data.texPropertyNames[propIdx].name + " because textures are null and default value parameters are the same.");
                        }
                    }
                    else
                    {
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("=== Creating atlas for " + data.texPropertyNames[propIdx].name);
                        }
                        GC.Collect();

                        //use a jagged array because it is much more efficient in memory
                        Color[][] atlasPixels = new Color[atlasSizeY][];
                        for (int j = 0; j < atlasPixels.Length; j++)
                        {
                            atlasPixels[j] = new Color[atlasSizeX];
                        }
                        bool isNormalMap = false;
                        if (data.texPropertyNames[propIdx].isNormalMap)
                        {
                            isNormalMap = true;
                        }

                        for (int texSetIdx = 0; texSetIdx < data.distinctMaterialTextures.Count; texSetIdx++)
                        {
                            string s = "Creating Atlas '" + data.texPropertyNames[propIdx].name + "' texture " + data.distinctMaterialTextures[texSetIdx];
                            if (progressInfo != null)
                            {
                                progressInfo(s, .01f);
                            }
                            MB_TexSet texSet = data.distinctMaterialTextures[texSetIdx];
                            if (LOG_LEVEL >= MB2_LogLevel.trace)
                            {
                                Debug.Log(string.Format("Adding texture {0} to atlas {1}", texSet.ts[propIdx].GetTexture2D() == null ? "null" : texSet.ts[propIdx].GetTexName(), data.texPropertyNames[propIdx]));
                            }
                            Rect      r  = uvRects[texSetIdx];
                            Texture2D t  = texSet.ts[propIdx].GetTexture2D();
                            int       x  = Mathf.RoundToInt(r.x * atlasSizeX);
                            int       y  = Mathf.RoundToInt(r.y * atlasSizeY);
                            int       ww = Mathf.RoundToInt(r.width * atlasSizeX);
                            int       hh = Mathf.RoundToInt(r.height * atlasSizeY);
                            if (ww == 0 || hh == 0)
                            {
                                Debug.LogError("Image in atlas has no height or width " + r);
                            }
                            if (progressInfo != null)
                            {
                                progressInfo(s + " set ReadWrite flag", .01f);
                            }
                            if (textureEditorMethods != null)
                            {
                                textureEditorMethods.SetReadWriteFlag(t, true, true);
                            }
                            if (progressInfo != null)
                            {
                                progressInfo(s + "Copying to atlas: '" + texSet.ts[propIdx].GetTexName() + "'", .02f);
                            }
                            DRect samplingRect = texSet.ts[propIdx].encapsulatingSamplingRect;
                            yield return(CopyScaledAndTiledToAtlas(texSet.ts[propIdx], texSet, data.texPropertyNames[propIdx], samplingRect, x, y, ww, hh, packedAtlasRects.padding[texSetIdx], atlasPixels, isNormalMap, data, combiner, progressInfo, LOG_LEVEL));
                            //							Debug.Log("after copyScaledAndTiledAtlas");
                        }
                        yield return(data.numAtlases);

                        if (progressInfo != null)
                        {
                            progressInfo("Applying changes to atlas: '" + data.texPropertyNames[propIdx].name + "'", .03f);
                        }
                        atlas = new Texture2D(atlasSizeX, atlasSizeY, TextureFormat.ARGB32, true);
                        for (int j = 0; j < atlasPixels.Length; j++)
                        {
                            atlas.SetPixels(0, j, atlasSizeX, 1, atlasPixels[j]);
                        }
                        atlas.Apply();
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("Saving atlas " + data.texPropertyNames[propIdx].name + " w=" + atlas.width + " h=" + atlas.height);
                        }
                    }
                    atlases[propIdx] = atlas;
                    if (progressInfo != null)
                    {
                        progressInfo("Saving atlas: '" + data.texPropertyNames[propIdx].name + "'", .04f);
                    }
                    System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
                    sw.Start();

                    if (data._saveAtlasesAsAssets && textureEditorMethods != null)
                    {
                        textureEditorMethods.SaveAtlasToAssetDatabase(atlases[propIdx], data.texPropertyNames[propIdx], propIdx, data.resultMaterial);
                    }
                    else
                    {
                        data.resultMaterial.SetTexture(data.texPropertyNames[propIdx].name, atlases[propIdx]);
                    }
                    data.resultMaterial.SetTextureOffset(data.texPropertyNames[propIdx].name, Vector2.zero);
                    data.resultMaterial.SetTextureScale(data.texPropertyNames[propIdx].name, Vector2.one);
                    combiner._destroyTemporaryTextures(); // need to save atlases before doing this
                }
            }
            //data.rectsInAtlas = uvRects;
            //			Debug.Log("finished!");
            yield break;
        }
예제 #14
0
        public static AtlasPackingResult MergeAtlasPackingResultStackBonA(AtlasPackingResult a,
                                                                          AtlasPackingResult b, int maxHeightDim, int maxWidthDim, bool stretchBToAtlasWidth)
        {
            Debug.Assert(a.usedW == a.atlasX);
            Debug.Assert(a.usedH == a.atlasY);
            Debug.Assert(b.usedW == b.atlasX);
            Debug.Assert(b.usedH == b.atlasY);
            Debug.Assert(a.usedW <= maxWidthDim, a.usedW + " " + maxWidthDim);
            Debug.Assert(a.usedH <= maxHeightDim, a.usedH + " " + maxHeightDim);
            Debug.Assert(b.usedH <= maxHeightDim);
            Debug.Assert(b.usedW <= maxWidthDim);

            Rect AatlasToFinal;
            Rect BatlasToFinal;

            // first calc height scale and offset
            float finalH = a.usedH + b.usedH;
            float scaleYa, scaleYb;

            if (finalH > maxHeightDim)
            {
                scaleYa = maxHeightDim / finalH;                                              //0,1
                float offsetBy = ((float)Mathf.FloorToInt(a.usedH * scaleYa)) / maxHeightDim; //0,1
                scaleYa       = offsetBy;
                scaleYb       = (1f - offsetBy);
                AatlasToFinal = new Rect(0, 0, 1, scaleYa);
                BatlasToFinal = new Rect(0, offsetBy, 1, scaleYb);
            }
            else
            {
                float offsetBy = a.usedH / finalH;
                AatlasToFinal = new Rect(0, 0, 1, offsetBy);
                BatlasToFinal = new Rect(0, offsetBy, 1, b.usedH / finalH);
            }

            //next calc width scale and offset
            if (a.atlasX > b.atlasX)
            {
                if (!stretchBToAtlasWidth)
                {
                    // b rects will be placed in a larger atlas which will make them smaller
                    BatlasToFinal.width = ((float)b.atlasX) / a.atlasX;
                }
            }
            else if (b.atlasX > a.atlasX)
            {
                // a rects will be placed in a larger atlas which will make them smaller
                AatlasToFinal.width = ((float)a.atlasX) / b.atlasX;
            }

            Rect[]         newRects   = new Rect[a.rects.Length + b.rects.Length];
            AtlasPadding[] paddings   = new AtlasPadding[a.rects.Length + b.rects.Length];
            int[]          srcImgIdxs = new int[a.rects.Length + b.rects.Length];
            Array.Copy(a.padding, paddings, a.padding.Length);
            Array.Copy(b.padding, 0, paddings, a.padding.Length, b.padding.Length);
            Array.Copy(a.srcImgIdxs, srcImgIdxs, a.srcImgIdxs.Length);
            Array.Copy(b.srcImgIdxs, 0, srcImgIdxs, a.srcImgIdxs.Length, b.srcImgIdxs.Length);
            Array.Copy(a.rects, newRects, a.rects.Length);
            int   atlasX = Mathf.Max(a.usedW, b.usedW);
            int   atlasY = a.usedH + b.usedH;
            float maxx   = 0f;
            float maxy   = 0f;

            for (int i = 0; i < a.rects.Length; i++)
            {
                Rect r = a.rects[i];
                r.x           = AatlasToFinal.x + r.x * AatlasToFinal.width;
                r.y           = AatlasToFinal.y + r.y * AatlasToFinal.height;
                r.width      *= AatlasToFinal.width;
                r.height     *= AatlasToFinal.height;
                maxx          = Mathf.Max(maxx, r.xMax);
                maxy          = Mathf.Max(maxy, r.yMax);
                newRects[i]   = r;
                srcImgIdxs[i] = a.srcImgIdxs[i];
            }

            for (int i = 0; i < b.rects.Length; i++)
            {
                Rect r = b.rects[i];
                r.x       = BatlasToFinal.x + r.x * BatlasToFinal.width;
                r.y       = BatlasToFinal.y + r.y * BatlasToFinal.height;
                r.width  *= BatlasToFinal.width;
                r.height *= BatlasToFinal.height;
                maxx      = Mathf.Max(maxx, r.xMax);
                maxy      = Mathf.Max(maxy, r.yMax);
                newRects[a.rects.Length + i]   = r;
                srcImgIdxs[a.rects.Length + i] = b.srcImgIdxs[i];
            }

            AtlasPackingResult res = new AtlasPackingResult(paddings);

            res.atlasX     = atlasX;
            res.atlasY     = atlasY;
            res.padding    = paddings;
            res.rects      = newRects;
            res.srcImgIdxs = srcImgIdxs;
            res.CalcUsedWidthAndHeight();

            return(res);
        }
예제 #15
0
        public override AtlasPackingResult[] CalculateAtlasRectangles(MB3_TextureCombinerPipeline.TexturePipelineData data, bool doMultiAtlas, MB2_LogLevel LOG_LEVEL)
        {
            Debug.Assert(!data.OnlyOneTextureInAtlasReuseTextures());

            //TODO parameter
            int maxAtlasWidth = 512;

            Debug.Assert(data._packingAlgorithm != MB2_PackingAlgorithmEnum.UnitysPackTextures, "Unity texture packer cannot be used");

            //split the list of distinctMaterialTextures into two bins
            List <MB_TexSet> horizontalVerticalDistinctMaterialTextures = new List <MB_TexSet>();
            List <MB_TexSet> regularTextures = new List <MB_TexSet>();

            for (int i = 0; i < data.distinctMaterialTextures.Count; i++)
            {
                MB_TexSet texSet = data.distinctMaterialTextures[i];
                if (texSet.idealWidth >= maxAtlasWidth &&
                    texSet.ts[0].GetEncapsulatingSamplingRect().width > 1f)
                {
                    horizontalVerticalDistinctMaterialTextures.Add(texSet);
                }
                else
                {
                    regularTextures.Add(texSet);
                }
            }
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log(String.Format("Splitting list of distinctMaterialTextures numHorizontalVertical={0} numRegular={1}", horizontalVerticalDistinctMaterialTextures.Count, regularTextures.Count));
            }

            //pack one with the horizontal texture packer
            MB2_TexturePacker        tp;
            MB2_PackingAlgorithmEnum packingAlgorithm;
            int atlasMaxDimension = data._maxAtlasSize;

            AtlasPackingResult[] packerRectsHorizontalVertical;
            if (horizontalVerticalDistinctMaterialTextures.Count > 0)
            {
                packingAlgorithm = MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Horizontal;
                List <Vector2> imageSizesHorizontalVertical = new List <Vector2>();
                for (int i = 0; i < horizontalVerticalDistinctMaterialTextures.Count; i++)
                {
                    horizontalVerticalDistinctMaterialTextures[i].SetTilingTreatmentAndAdjustEncapsulatingSamplingRect(MB_TextureTilingTreatment.edgeToEdgeX);
                    imageSizesHorizontalVertical.Add(new Vector2(horizontalVerticalDistinctMaterialTextures[i].idealWidth, horizontalVerticalDistinctMaterialTextures[i].idealHeight));
                }
                tp = MB3_TextureCombinerPipeline.CreateTexturePacker(packingAlgorithm);
                tp.atlasMustBePowerOfTwo = false;
                List <AtlasPadding> paddingsHorizontalVertical = new List <AtlasPadding>();
                for (int i = 0; i < imageSizesHorizontalVertical.Count; i++)
                {
                    AtlasPadding padding = new AtlasPadding();
                    padding.topBottom = data._atlasPadding;
                    padding.leftRight = data._atlasPadding;
                    if (packingAlgorithm == MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Horizontal)
                    {
                        padding.leftRight = 0;
                    }
                    if (packingAlgorithm == MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Vertical)
                    {
                        padding.topBottom = 0;
                    }
                    paddingsHorizontalVertical.Add(padding);
                }
                tp.LOG_LEVEL = MB2_LogLevel.trace;
                packerRectsHorizontalVertical = tp.GetRects(imageSizesHorizontalVertical, paddingsHorizontalVertical, maxAtlasWidth, atlasMaxDimension, false);
            }
            else
            {
                packerRectsHorizontalVertical = new AtlasPackingResult[0];
            }
            AtlasPackingResult[] packerRectsRegular;
            if (regularTextures.Count > 0)
            {
                //pack other with regular texture packer
                packingAlgorithm = MB2_PackingAlgorithmEnum.MeshBakerTexturePacker;
                List <Vector2> imageSizesRegular = new List <Vector2>();
                for (int i = 0; i < regularTextures.Count; i++)
                {
                    imageSizesRegular.Add(new Vector2(regularTextures[i].idealWidth, regularTextures[i].idealHeight));
                }
                tp = MB3_TextureCombinerPipeline.CreateTexturePacker(MB2_PackingAlgorithmEnum.MeshBakerTexturePacker);
                tp.atlasMustBePowerOfTwo = false;
                List <AtlasPadding> paddingsRegular = new List <AtlasPadding>();
                for (int i = 0; i < imageSizesRegular.Count; i++)
                {
                    AtlasPadding padding = new AtlasPadding();
                    padding.topBottom = data._atlasPadding;
                    padding.leftRight = data._atlasPadding;
                    paddingsRegular.Add(padding);
                }
                tp.LOG_LEVEL       = MB2_LogLevel.trace;
                packerRectsRegular = tp.GetRects(imageSizesRegular, paddingsRegular, maxAtlasWidth, atlasMaxDimension, false);
            }
            else
            {
                packerRectsRegular = new AtlasPackingResult[0];
            }

            AtlasPackingResult result = null;

            if (packerRectsHorizontalVertical.Length == 0 && packerRectsRegular.Length == 0)
            {
                Debug.Assert(false, "Should never have reached this.");
                return(null);
            }
            else if (packerRectsHorizontalVertical.Length > 0 && packerRectsRegular.Length > 0)
            {
                result = MergeAtlasPackingResultStackBonA(packerRectsHorizontalVertical[0], packerRectsRegular[0], atlasMaxDimension, maxAtlasWidth, true);
            }
            else if (packerRectsHorizontalVertical.Length > 0)
            {
                Debug.LogError("TODO handle this");
                result = packerRectsHorizontalVertical[0];
            }
            else if (packerRectsRegular.Length > 0)
            {
                Debug.LogError("TODO handle this.");
                result = packerRectsRegular[0];
            }

            Debug.Assert(data.distinctMaterialTextures.Count == result.rects.Length);
            //We re-ordered the distinctMaterial textures so replace the list with the new reordered one
            horizontalVerticalDistinctMaterialTextures.AddRange(regularTextures);
            data.distinctMaterialTextures = horizontalVerticalDistinctMaterialTextures;
            AtlasPackingResult[] results;
            if (result != null)
            {
                results = new AtlasPackingResult[] { result }
            }
            ;
            else
            {
                results = new AtlasPackingResult[0];
            }
            return(results);
        }
        public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                         MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner,
                                         AtlasPackingResult packedAtlasRects,
                                         Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods,
                                         MB2_LogLevel LOG_LEVEL)
        {
            Rect[] uvRects = packedAtlasRects.rects;
            if (uvRects.Length == 1)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.Log("Only one image per atlas. Will re-use original texture");
                }
                for (int i = 0; i < data.numAtlases; i++)
                {
                    MeshBakerMaterialTexture dmt = data.distinctMaterialTextures[0].ts[i];
                    atlases[i] = dmt.GetTexture2D();
                    data.resultMaterial.SetTexture(data.texPropertyNames[i].name, atlases[i]);
                    data.resultMaterial.SetTextureScale(data.texPropertyNames[i].name, dmt.matTilingRect.size);
                    data.resultMaterial.SetTextureOffset(data.texPropertyNames[i].name, dmt.matTilingRect.min);
                }
            }
            else
            {
                int atlasSizeX = packedAtlasRects.atlasX;
                int atlasSizeY = packedAtlasRects.atlasY;
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY);
                }

                //create a game object
                GameObject renderAtlasesGO = null;
                try
                {
                    renderAtlasesGO = new GameObject("MBrenderAtlasesGO");
                    MB3_AtlasPackerRenderTexture atlasRenderTexture = renderAtlasesGO.AddComponent <MB3_AtlasPackerRenderTexture>();
                    renderAtlasesGO.AddComponent <Camera>();
                    if (data._considerNonTextureProperties)
                    {
                        if (LOG_LEVEL >= MB2_LogLevel.warn)
                        {
                            Debug.LogWarning("Blend Non-Texture Properties has limited functionality when used with Mesh Baker Texture Packer Fast.");
                        }
                    }
                    for (int i = 0; i < data.numAtlases; i++)
                    {
                        Texture2D atlas = null;
                        if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(i, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                        {
                            atlas = null;
                            if (LOG_LEVEL >= MB2_LogLevel.debug)
                            {
                                Debug.Log("Not creating atlas for " + data.texPropertyNames[i].name + " because textures are null and default value parameters are the same.");
                            }
                        }
                        else
                        {
                            GC.Collect();
                            if (progressInfo != null)
                            {
                                progressInfo("Creating Atlas '" + data.texPropertyNames[i].name + "'", .01f);
                            }
                            // ===========
                            // configure it
                            if (LOG_LEVEL >= MB2_LogLevel.debug)
                            {
                                Debug.Log("About to render " + data.texPropertyNames[i].name + " isNormal=" + data.texPropertyNames[i].isNormalMap);
                            }
                            atlasRenderTexture.LOG_LEVEL                    = LOG_LEVEL;
                            atlasRenderTexture.width                        = atlasSizeX;
                            atlasRenderTexture.height                       = atlasSizeY;
                            atlasRenderTexture.padding                      = data._atlasPadding;
                            atlasRenderTexture.rects                        = uvRects;
                            atlasRenderTexture.textureSets                  = data.distinctMaterialTextures;
                            atlasRenderTexture.indexOfTexSetToRender        = i;
                            atlasRenderTexture.texPropertyName              = data.texPropertyNames[i];
                            atlasRenderTexture.isNormalMap                  = data.texPropertyNames[i].isNormalMap;
                            atlasRenderTexture.fixOutOfBoundsUVs            = data._fixOutOfBoundsUVs;
                            atlasRenderTexture.considerNonTextureProperties = data._considerNonTextureProperties;
                            atlasRenderTexture.resultMaterialTextureBlender = data.nonTexturePropertyBlender;
                            // call render on it
                            atlas = atlasRenderTexture.OnRenderAtlas(combiner);

                            // destroy it
                            // =============
                            if (LOG_LEVEL >= MB2_LogLevel.debug)
                            {
                                Debug.Log("Saving atlas " + data.texPropertyNames[i].name + " w=" + atlas.width + " h=" + atlas.height + " id=" + atlas.GetInstanceID());
                            }
                        }
                        atlases[i] = atlas;
                        if (progressInfo != null)
                        {
                            progressInfo("Saving atlas: '" + data.texPropertyNames[i].name + "'", .04f);
                        }
                        if (data._saveAtlasesAsAssets && textureEditorMethods != null)
                        {
                            textureEditorMethods.SaveAtlasToAssetDatabase(atlases[i], data.texPropertyNames[i], i, data.resultMaterial);
                        }
                        else
                        {
                            data.resultMaterial.SetTexture(data.texPropertyNames[i].name, atlases[i]);
                        }
                        data.resultMaterial.SetTextureOffset(data.texPropertyNames[i].name, Vector2.zero);
                        data.resultMaterial.SetTextureScale(data.texPropertyNames[i].name, Vector2.one);
                        combiner._destroyTemporaryTextures(); // need to save atlases before doing this
                    }
                }
                catch (Exception ex)
                {
                    //Debug.LogError(ex);
                    Debug.LogException(ex);
                }
                finally
                {
                    if (renderAtlasesGO != null)
                    {
                        MB_Utility.Destroy(renderAtlasesGO);
                    }
                }
            }
            yield break;
        }
 public abstract IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                           MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner,
                                           AtlasPackingResult packedAtlasRects,
                                           Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods,
                                           MB2_LogLevel LOG_LEVEL);
예제 #18
0
        private static AtlasPackingResult MergeAtlasPackingResultStackBonA(AtlasPackingResult a,
                                                                           AtlasPackingResult b, int maxWidthDim, int maxHeightDim, bool stretchBToAtlasWidth, IPipeline pipeline)
        {
            Debug.Assert(a.usedW == a.atlasX);
            Debug.Assert(a.usedH == a.atlasY);
            Debug.Assert(b.usedW == b.atlasX);
            Debug.Assert(b.usedH == b.atlasY);
            Debug.Assert(a.usedW <= maxWidthDim, a.usedW + " " + maxWidthDim);
            Debug.Assert(a.usedH <= maxHeightDim, a.usedH + " " + maxHeightDim);
            Debug.Assert(b.usedH <= maxHeightDim);
            Debug.Assert(b.usedW <= maxWidthDim, b.usedW + " " + maxWidthDim);

            Rect AatlasToFinal;
            Rect BatlasToFinal;

            // first calc height scale and offset
            int atlasX;
            int atlasY;

            pipeline.MergeAtlasPackingResultStackBonAInternal(a, b, out AatlasToFinal, out BatlasToFinal, stretchBToAtlasWidth, maxWidthDim, maxHeightDim, out atlasX, out atlasY);

            Rect[]         newRects   = new Rect[a.rects.Length + b.rects.Length];
            AtlasPadding[] paddings   = new AtlasPadding[a.rects.Length + b.rects.Length];
            int[]          srcImgIdxs = new int[a.rects.Length + b.rects.Length];
            Array.Copy(a.padding, paddings, a.padding.Length);
            Array.Copy(b.padding, 0, paddings, a.padding.Length, b.padding.Length);
            Array.Copy(a.srcImgIdxs, srcImgIdxs, a.srcImgIdxs.Length);
            Array.Copy(b.srcImgIdxs, 0, srcImgIdxs, a.srcImgIdxs.Length, b.srcImgIdxs.Length);
            Array.Copy(a.rects, newRects, a.rects.Length);
            for (int i = 0; i < a.rects.Length; i++)
            {
                Rect r = a.rects[i];
                r.x       = AatlasToFinal.x + r.x * AatlasToFinal.width;
                r.y       = AatlasToFinal.y + r.y * AatlasToFinal.height;
                r.width  *= AatlasToFinal.width;
                r.height *= AatlasToFinal.height;
                Debug.Assert(r.max.x <= 1f);
                Debug.Assert(r.max.y <= 1f);
                Debug.Assert(r.min.x >= 0f);
                Debug.Assert(r.min.y >= 0f);
                newRects[i]   = r;
                srcImgIdxs[i] = a.srcImgIdxs[i];
            }

            for (int i = 0; i < b.rects.Length; i++)
            {
                Rect r = b.rects[i];
                r.x       = BatlasToFinal.x + r.x * BatlasToFinal.width;
                r.y       = BatlasToFinal.y + r.y * BatlasToFinal.height;
                r.width  *= BatlasToFinal.width;
                r.height *= BatlasToFinal.height;
                Debug.Assert(r.max.x <= 1f);
                Debug.Assert(r.max.y <= 1f);
                Debug.Assert(r.min.x >= 0f);
                Debug.Assert(r.min.y >= 0f);
                newRects[a.rects.Length + i]   = r;
                srcImgIdxs[a.rects.Length + i] = b.srcImgIdxs[i];
            }

            AtlasPackingResult res = new AtlasPackingResult(paddings);

            res.atlasX     = atlasX;
            res.atlasY     = atlasY;
            res.padding    = paddings;
            res.rects      = newRects;
            res.srcImgIdxs = srcImgIdxs;
            res.CalcUsedWidthAndHeight();
            return(res);
        }
예제 #19
0
        public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                         MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner,
                                         AtlasPackingResult packedAtlasRects,
                                         Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods,
                                         MB2_LogLevel LOG_LEVEL)
        {
            Debug.Assert(!data.OnlyOneTextureInAtlasReuseTextures());
            Rect[] uvRects = packedAtlasRects.rects;

            int atlasSizeX = packedAtlasRects.atlasX;
            int atlasSizeY = packedAtlasRects.atlasY;

            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY);
            }

            int layer = data._layerTexturePackerFastV2;

            Debug.Assert(layer >= 0 && layer <= 32);

            //create a game object
            mesh             = new Mesh();
            renderAtlasesGO  = null;
            cameraGameObject = null;
            try
            {
                System.Diagnostics.Stopwatch db_time_MB3_TextureCombinerPackerMeshBakerFastV2_CreateAtlases = new System.Diagnostics.Stopwatch();
                db_time_MB3_TextureCombinerPackerMeshBakerFastV2_CreateAtlases.Start();
                renderAtlasesGO  = new GameObject("MBrenderAtlasesGO");
                cameraGameObject = new GameObject("MBCameraGameObject");
                MB3_AtlasPackerRenderTextureUsingMesh atlasRenderer = new MB3_AtlasPackerRenderTextureUsingMesh();
                OneTimeSetup(atlasRenderer, renderAtlasesGO, cameraGameObject, atlasSizeX, atlasSizeY, data._atlasPadding, layer, LOG_LEVEL);

                if (data._considerNonTextureProperties && LOG_LEVEL >= MB2_LogLevel.warn)
                {
                    Debug.LogWarning("Blend Non-Texture Properties has limited functionality when used with Mesh Baker Texture Packer Fast.");
                }

                List <Material> mats = new List <Material>();
                for (int propIdx = 0; propIdx < data.numAtlases; propIdx++)
                {
                    Texture2D atlas = null;
                    if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                    {
                        atlas = null;
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("Not creating atlas for " + data.texPropertyNames[propIdx].name + " because textures are null and default value parameters are the same.");
                        }
                    }
                    else
                    {
                        if (progressInfo != null)
                        {
                            progressInfo("Creating Atlas '" + data.texPropertyNames[propIdx].name + "'", .01f);
                        }

                        // configure it
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("About to render " + data.texPropertyNames[propIdx].name + " isNormal=" + data.texPropertyNames[propIdx].isNormalMap);
                        }

                        // Create the mesh
                        mats.Clear();

                        MB3_AtlasPackerRenderTextureUsingMesh.MeshAtlas.BuildAtlas(packedAtlasRects, data.distinctMaterialTextures, propIdx, packedAtlasRects.atlasX, packedAtlasRects.atlasY, mesh, mats, data.texPropertyNames[propIdx], data, combiner, textureEditorMethods, LOG_LEVEL);
                        {
                            MeshFilter mf = renderAtlasesGO.GetComponent <MeshFilter>();
                            mf.sharedMesh = mesh;
                            MeshRenderer mrr = renderAtlasesGO.GetComponent <MeshRenderer>();
                            Material[]   mrs = mats.ToArray();
                            mrr.sharedMaterials = mrs;
                        }

                        // Render
                        atlas = atlasRenderer.DoRenderAtlas(cameraGameObject, packedAtlasRects.atlasX, packedAtlasRects.atlasY, data.texPropertyNames[propIdx].isNormalMap, data.texPropertyNames[propIdx]);

                        {
                            for (int i = 0; i < mats.Count; i++)
                            {
                                MB_Utility.Destroy(mats[i]);
                            }
                            mats.Clear();
                        }

                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("Saving atlas " + data.texPropertyNames[propIdx].name + " w=" + atlas.width + " h=" + atlas.height + " id=" + atlas.GetInstanceID());
                        }
                    }
                    atlases[propIdx] = atlas;
                    if (progressInfo != null)
                    {
                        progressInfo("Saving atlas: '" + data.texPropertyNames[propIdx].name + "'", .04f);
                    }
                    if (data.resultType == MB2_TextureBakeResults.ResultType.atlas)
                    {
                        MB3_TextureCombinerPackerRoot.SaveAtlasAndConfigureResultMaterial(data, textureEditorMethods, atlases[propIdx], data.texPropertyNames[propIdx], propIdx);
                    }

                    combiner._destroyTemporaryTextures(data.texPropertyNames[propIdx].name); // need to save atlases before doing this
                }

                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.LogFormat("Timing MB3_TextureCombinerPackerMeshBakerFastV2.CreateAtlases={0}",
                                    db_time_MB3_TextureCombinerPackerMeshBakerFastV2_CreateAtlases.ElapsedMilliseconds * .001f);
                }
            }
            catch (Exception ex)
            {
                Debug.LogError(ex.Message + "\n" + ex.StackTrace.ToString());
            }
            finally
            {
                if (renderAtlasesGO != null)
                {
                    MB_Utility.Destroy(renderAtlasesGO);
                }
                if (cameraGameObject != null)
                {
                    MB_Utility.Destroy(cameraGameObject);
                }
                if (mesh != null)
                {
                    MB_Utility.Destroy(mesh);
                }
            }
            yield break;
        }
        //----------------- Algorithm for fitting everything into multiple Atlases
        //
        // for images being added calc area, maxW, maxH. A perfectly packed atlas will match area exactly. atlas must be at least maxH and maxW in size.
        // Sort images from big to small using either height, width or area comparer
        //
        // If an image is bigger than maxDim, then shrink it to max size on the largest dimension
        // distribute images using the new algorithm, should never have to expand the atlas instead create new atlases as needed
        // should not need to scale atlases
        //
        AtlasPackingResult[] _GetRectsMultiAtlas(List <Vector2> imgWidthHeights, List <AtlasPadding> paddings, int maxDimensionPassedX, int maxDimensionPassedY, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY)
        {
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log(String.Format("_GetRects numImages={0}, maxDimensionX={1}, maxDimensionY={2} minImageSizeX={3}, minImageSizeY={4}, masterImageSizeX={5}, masterImageSizeY={6}",
                                        imgWidthHeights.Count, maxDimensionPassedX, maxDimensionPassedY, minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY));
            }
            float area = 0;
            int   maxW = 0;
            int   maxH = 0;

            Image[] imgsToAdd     = new Image[imgWidthHeights.Count];
            int     maxDimensionX = maxDimensionPassedX;
            int     maxDimensionY = maxDimensionPassedY;

            if (atlasMustBePowerOfTwo)
            {
                maxDimensionX = RoundToNearestPositivePowerOfTwo(maxDimensionX);
                maxDimensionY = RoundToNearestPositivePowerOfTwo(maxDimensionY);
            }
            for (int i = 0; i < imgsToAdd.Length; i++)
            {
                int iw = (int)imgWidthHeights[i].x;
                int ih = (int)imgWidthHeights[i].y;

                //shrink the image so that it fits in maxDimenion if it is larger than maxDimension if atlas exceeds maxDim x maxDim then new alas will be created
                iw = Mathf.Min(iw, maxDimensionX - paddings[i].leftRight * 2);
                ih = Mathf.Min(ih, maxDimensionY - paddings[i].topBottom * 2);

                Image im = imgsToAdd[i] = new Image(i, iw, ih, paddings[i], minImageSizeX, minImageSizeY);
                area += im.w * im.h;
                maxW  = Mathf.Max(maxW, im.w);
                maxH  = Mathf.Max(maxH, im.h);
            }

            //explore the space to find a resonably efficient packing
            //int sqrtArea = (int)Mathf.Sqrt(area);
            int idealAtlasW;
            int idealAtlasH;

            if (atlasMustBePowerOfTwo)
            {
                idealAtlasH = RoundToNearestPositivePowerOfTwo(maxDimensionY);
                idealAtlasW = RoundToNearestPositivePowerOfTwo(maxDimensionX);
            }
            else
            {
                idealAtlasH = maxDimensionY;
                idealAtlasW = maxDimensionX;
            }

            if (idealAtlasW == 0)
            {
                idealAtlasW = 4;
            }
            if (idealAtlasH == 0)
            {
                idealAtlasH = 4;
            }

            ProbeResult pr = new ProbeResult();

            Array.Sort(imgsToAdd, new ImageHeightComparer());
            if (ProbeMultiAtlas(imgsToAdd, idealAtlasW, idealAtlasH, area, maxDimensionX, maxDimensionY, pr))
            {
                bestRoot = pr;
            }
            Array.Sort(imgsToAdd, new ImageWidthComparer());
            if (ProbeMultiAtlas(imgsToAdd, idealAtlasW, idealAtlasH, area, maxDimensionX, maxDimensionY, pr))
            {
                if (pr.totalAtlasArea < bestRoot.totalAtlasArea)
                {
                    bestRoot = pr;
                }
            }
            Array.Sort(imgsToAdd, new ImageAreaComparer());
            if (ProbeMultiAtlas(imgsToAdd, idealAtlasW, idealAtlasH, area, maxDimensionX, maxDimensionY, pr))
            {
                if (pr.totalAtlasArea < bestRoot.totalAtlasArea)
                {
                    bestRoot = pr;
                }
            }

            if (bestRoot == null)
            {
                return(null);
            }
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("Best fit found: w=" + bestRoot.w + " h=" + bestRoot.h + " efficiency=" + bestRoot.efficiency + " squareness=" + bestRoot.squareness + " fits in max dimension=" + bestRoot.largerOrEqualToMaxDim);
            }

            //the atlas can be larger than the max dimension scale it if this is the case
            //int newMinSizeX = minImageSizeX;
            //int newMinSizeY = minImageSizeY;
            List <AtlasPackingResult> rs = new List <AtlasPackingResult>();

            // find all Nodes that are an individual atlas
            List <Node>  atlasNodes = new List <Node>();
            Stack <Node> stack      = new Stack <Node>();
            Node         node       = bestRoot.root;

            while (node != null)
            {
                stack.Push(node);
                node = node.child[0];
            }

            // traverse the tree collecting atlasNodes
            while (stack.Count > 0)
            {
                node = stack.Pop();
                if (node.isFullAtlas == NodeType.maxDim)
                {
                    atlasNodes.Add(node);
                }
                if (node.child[1] != null)
                {
                    node = node.child[1];
                    while (node != null)
                    {
                        stack.Push(node);
                        node = node.child[0];
                    }
                }
            }

            //pack atlases so they all fit
            for (int i = 0; i < atlasNodes.Count; i++)
            {
                List <Image> images = new List <Image>();
                flattenTree(atlasNodes[i], images);
                Rect[] rss       = new Rect[images.Count];
                int[]  srcImgIdx = new int[images.Count];
                for (int j = 0; j < images.Count; j++)
                {
                    rss[j]       = (new Rect(images[j].x - atlasNodes[i].r.x, images[j].y, images[j].w, images[j].h));
                    srcImgIdx[j] = images[j].imgId;
                }
                AtlasPackingResult res = new AtlasPackingResult(paddings.ToArray());
                GetExtent(atlasNodes[i], ref res.usedW, ref res.usedH);
                res.usedW -= atlasNodes[i].r.x;
                int outW = atlasNodes[i].r.w;
                int outH = atlasNodes[i].r.h;
                if (atlasMustBePowerOfTwo)
                {
                    outW = Mathf.Min(CeilToNearestPowerOfTwo(res.usedW), atlasNodes[i].r.w);
                    outH = Mathf.Min(CeilToNearestPowerOfTwo(res.usedH), atlasNodes[i].r.h);
                    if (outH < outW / 2)
                    {
                        outH = outW / 2;                  //smaller dim can't be less than half larger
                    }
                    if (outW < outH / 2)
                    {
                        outW = outH / 2;
                    }
                }
                else
                {
                    outW = res.usedW;
                    outH = res.usedH;
                }

                res.atlasY = outH;
                res.atlasX = outW;

                res.rects      = rss;
                res.srcImgIdxs = srcImgIdx;
                res.CalcUsedWidthAndHeight();
                rs.Add(res);
                ConvertToRectsWithoutPaddingAndNormalize01(res, paddings[i]);
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug(String.Format("Done GetRects "));
                }
            }

            return(rs.ToArray());
        }
예제 #21
0
            internal static void BuildAtlas(
                AtlasPackingResult packedAtlasRects,
                List <MB_TexSet> distinctMaterialTextures,
                int propIdx,
                int atlasSizeX, int atlasSizeY,
                Mesh m,
                List <Material> generatedMats,
                ShaderTextureProperty property,
                MB3_TextureCombinerPipeline.TexturePipelineData data,
                MB3_TextureCombiner combiner,
                MB2_EditorMethodsInterface textureEditorMethods,
                MB2_LogLevel LOG_LEVEL)
            {
                // Collect vertices and quads for mesh that we will use for the atlas.
                Debug.Assert(generatedMats.Count == 0, "Previous mats should have been destroyed");
                generatedMats.Clear();
                List <Vector3> vs  = new List <Vector3>();
                List <Vector2> uvs = new List <Vector2>();

                // One submesh and material per texture that we are packing
                List <int>[] ts = new List <int> [distinctMaterialTextures.Count];
                for (int i = 0; i < ts.Length; i++)
                {
                    ts[i] = new List <int>();
                }

                MeshBakerMaterialTexture.readyToBuildAtlases = true;
                GC.Collect();
                MB3_TextureCombinerPackerRoot.CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data);

                Rect[] uvRects = packedAtlasRects.rects;
                for (int texSetIdx = 0; texSetIdx < distinctMaterialTextures.Count; texSetIdx++)
                {
                    MB_TexSet texSet = distinctMaterialTextures[texSetIdx];
                    MeshBakerMaterialTexture matTex = texSet.ts[propIdx];

                    if (LOG_LEVEL >= MB2_LogLevel.trace)
                    {
                        Debug.Log(string.Format("Adding texture {0} to atlas {1} for texSet {2} srcMat {3}", matTex.GetTexName(), property.name, texSetIdx, texSet.matsAndGOs.mats[0].GetMaterialName()));
                    }
                    Rect      r  = uvRects[texSetIdx];
                    Texture2D t  = matTex.GetTexture2D();
                    int       x  = Mathf.RoundToInt(r.x * atlasSizeX);
                    int       y  = Mathf.RoundToInt(r.y * atlasSizeY);
                    int       ww = Mathf.RoundToInt(r.width * atlasSizeX);
                    int       hh = Mathf.RoundToInt(r.height * atlasSizeY);
                    r = new Rect(x, y, ww, hh);
                    if (ww == 0 || hh == 0)
                    {
                        Debug.LogError("Image in atlas has no height or width " + r);
                    }
                    DRect samplingRect = texSet.ts[propIdx].GetEncapsulatingSamplingRect();
                    Debug.Assert(!texSet.ts[propIdx].isNull, string.Format("Adding texture {0} to atlas {1} for texSet {2} srcMat {3}", matTex.GetTexName(), property.name, texSetIdx, texSet.matsAndGOs.mats[0].GetMaterialName()));

                    AtlasPadding padding = packedAtlasRects.padding[texSetIdx];
                    AddNineSlicedRect(r, padding.leftRight, padding.topBottom, samplingRect.GetRect(), vs, uvs, ts[texSetIdx], t.width, t.height, t.name);

                    Material mt = new Material(Shader.Find("MeshBaker/Unlit/UnlitWithAlpha"));

                    bool isSavingAsANormalMapAssetThatWillBeImported = property.isNormalMap && data._saveAtlasesAsAssets;
                    MBVersion.PipelineType pipelineType = MBVersion.DetectPipeline();
                    if (pipelineType == MBVersion.PipelineType.URP)
                    {
                        ConfigureMaterial_DefaultPipeline(mt, t, isSavingAsANormalMapAssetThatWillBeImported, LOG_LEVEL);
                        //ConfigureMaterial_URP(mt, t, isSavingAsANormalMapAssetThatWillBeImported, LOG_LEVEL);
                    }
                    else if (pipelineType == MBVersion.PipelineType.HDRP)
                    {
                        ConfigureMaterial_DefaultPipeline(mt, t, isSavingAsANormalMapAssetThatWillBeImported, LOG_LEVEL);
                    }
                    else
                    {
                        ConfigureMaterial_DefaultPipeline(mt, t, isSavingAsANormalMapAssetThatWillBeImported, LOG_LEVEL);
                    }

                    generatedMats.Add(mt);
                }

                // Apply to the mesh
                m.Clear();
                m.vertices     = vs.ToArray();
                m.uv           = uvs.ToArray();
                m.subMeshCount = ts.Length;
                for (int i = 0; i < m.subMeshCount; i++)
                {
                    m.SetIndices(ts[i].ToArray(), MeshTopology.Triangles, i);
                }
                MeshBakerMaterialTexture.readyToBuildAtlases = false;
            }
예제 #22
0
        AtlasPackingResult[] _GetRectsMultiAtlasHorizontal(List <Vector2> imgWidthHeights, int maxDimensionPassed, int padding, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY)
        {
            List <AtlasPackingResult> rs = new List <AtlasPackingResult>();
            int extent = 0;
            int maxh   = 0;
            int maxw   = 0;

            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("Packing rects for: " + imgWidthHeights.Count);
            }

            List <Image> allImages = new List <Image>();

            for (int i = 0; i < imgWidthHeights.Count; i++)
            {
                Image im = new Image(i, (int)imgWidthHeights[i].x, (int)imgWidthHeights[i].y, padding, minImageSizeX, minImageSizeY);
                im.w -= padding * 2;
                allImages.Add(im);
            }
            allImages.Sort(new ImageHeightComparer());
            List <Image> images         = new List <Image>();
            List <Rect>  rects          = new List <Rect>();
            int          spaceRemaining = maxDimensionPassed;

            while (allImages.Count > 0 || images.Count > 0)
            {
                Image im = PopLargestThatFits(allImages, spaceRemaining, maxDimensionPassed, images.Count == 0);
                if (im == null)
                {
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("Atlas filled creating a new atlas ");
                    }
                    AtlasPackingResult apr = new AtlasPackingResult();
                    apr.atlasX = maxw;
                    apr.atlasY = maxh;
                    Rect[] rss       = new Rect[images.Count];
                    int[]  srcImgIdx = new int[images.Count];
                    for (int j = 0; j < images.Count; j++)
                    {
                        Rect r = new Rect(images[j].x, images[j].y,
                                          stretchImagesToEdges ? maxw : images[j].w,
                                          images[j].h);
                        rss[j]       = r;
                        srcImgIdx[j] = images[j].imgId;
                    }
                    apr.rects      = rss;
                    apr.srcImgIdxs = srcImgIdx;

                    images.Clear();
                    rects.Clear();
                    extent = 0;
                    maxh   = 0;
                    rs.Add(apr);
                    spaceRemaining = maxDimensionPassed;
                }
                else
                {
                    im.x = 0;
                    im.y = extent;
                    images.Add(im);
                    rects.Add(new Rect(0, extent, im.w, im.h));
                    extent        += im.h;
                    maxw           = Mathf.Max(maxw, im.w);
                    maxh           = extent;
                    spaceRemaining = maxDimensionPassed - extent;
                }
            }

            for (int i = 0; i < rs.Count; i++)
            {
                int outH = rs[i].atlasY;
                int outW = Mathf.Min(rs[i].atlasX, maxDimensionPassed);
                if (atlasMustBePowerOfTwo)
                {
                    outH = Mathf.Min(CeilToNearestPowerOfTwo(outH), maxDimensionPassed);
                }
                else
                {
                    outH = Mathf.Min(outH, maxDimensionPassed);
                }
                rs[i].atlasY = outH;
                //-------------------------------
                //scale atlas to fit maxDimension
                float padX, padY;
                int   newMinSizeX, newMinSizeY;
                ScaleAtlasToFitMaxDim(new Vector2(rs[i].atlasX, rs[i].atlasY), images, maxDimensionPassed, padding, minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY,
                                      ref outW, ref outH, out padX, out padY, out newMinSizeX, out newMinSizeY);
            }



            //normalize atlases so that that rects are 0 to 1
            for (int i = 0; i < rs.Count; i++)
            {
                normalizeRects(rs[i], padding, 0);
            }
            //-----------------------------
            return(rs.ToArray());
        }
예제 #23
0
        public override IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                                  MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner,
                                                  AtlasPackingResult packedAtlasRects,
                                                  Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods,
                                                  MB2_LogLevel LOG_LEVEL)
        {
            Rect[] uvRects = packedAtlasRects.rects;

            int atlasSizeX = packedAtlasRects.atlasX;
            int atlasSizeY = packedAtlasRects.atlasY;

            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY);
            }

            for (int propIdx = 0; propIdx < data.numAtlases; propIdx++)
            {
                Texture2D             atlas    = null;
                ShaderTextureProperty property = data.texPropertyNames[propIdx];
                if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                {
                    atlas = null;
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("=== Not creating atlas for " + property.name + " because textures are null and default value parameters are the same.");
                    }
                }
                else
                {
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("=== Creating atlas for " + property.name);
                    }

                    GC.Collect();

                    CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data);

                    //use a jagged array because it is much more efficient in memory
                    Color[][] atlasPixels = new Color[atlasSizeY][];
                    for (int j = 0; j < atlasPixels.Length; j++)
                    {
                        atlasPixels[j] = new Color[atlasSizeX];
                    }

                    bool isNormalMap = false;
                    if (property.isNormalMap)
                    {
                        isNormalMap = true;
                    }

                    for (int texSetIdx = 0; texSetIdx < data.distinctMaterialTextures.Count; texSetIdx++)
                    {
                        MB_TexSet texSet = data.distinctMaterialTextures[texSetIdx];
                        MeshBakerMaterialTexture matTex = texSet.ts[propIdx];
                        string s = "Creating Atlas '" + property.name + "' texture " + matTex.GetTexName();
                        if (progressInfo != null)
                        {
                            progressInfo(s, .01f);
                        }
                        if (LOG_LEVEL >= MB2_LogLevel.trace)
                        {
                            Debug.Log(string.Format("Adding texture {0} to atlas {1} for texSet {2} srcMat {3}", matTex.GetTexName(), property.name, texSetIdx, texSet.matsAndGOs.mats[0].GetMaterialName()));
                        }
                        Rect      r  = uvRects[texSetIdx];
                        Texture2D t  = texSet.ts[propIdx].GetTexture2D();
                        int       x  = Mathf.RoundToInt(r.x * atlasSizeX);
                        int       y  = Mathf.RoundToInt(r.y * atlasSizeY);
                        int       ww = Mathf.RoundToInt(r.width * atlasSizeX);
                        int       hh = Mathf.RoundToInt(r.height * atlasSizeY);
                        if (ww == 0 || hh == 0)
                        {
                            Debug.LogError("Image in atlas has no height or width " + r);
                        }
                        if (progressInfo != null)
                        {
                            progressInfo(s + " set ReadWrite flag", .01f);
                        }
                        if (textureEditorMethods != null)
                        {
                            textureEditorMethods.SetReadWriteFlag(t, true, true);
                        }
                        if (progressInfo != null)
                        {
                            progressInfo(s + "Copying to atlas: '" + matTex.GetTexName() + "'", .02f);
                        }
                        DRect samplingRect = texSet.ts[propIdx].GetEncapsulatingSamplingRect();
                        Debug.Assert(!texSet.ts[propIdx].isNull, string.Format("Adding texture {0} to atlas {1} for texSet {2} srcMat {3}", matTex.GetTexName(), property.name, texSetIdx, texSet.matsAndGOs.mats[0].GetMaterialName()));
                        yield return(CopyScaledAndTiledToAtlas(texSet.ts[propIdx], texSet, property, samplingRect, x, y, ww, hh, packedAtlasRects.padding[texSetIdx], atlasPixels, isNormalMap, data, combiner, progressInfo, LOG_LEVEL));
                    }

                    yield return(data.numAtlases);

                    if (progressInfo != null)
                    {
                        progressInfo("Applying changes to atlas: '" + property.name + "'", .03f);
                    }
                    atlas = new Texture2D(atlasSizeX, atlasSizeY, TextureFormat.ARGB32, true);
                    for (int j = 0; j < atlasPixels.Length; j++)
                    {
                        atlas.SetPixels(0, j, atlasSizeX, 1, atlasPixels[j]);
                    }

                    atlas.Apply();
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("Saving atlas " + property.name + " w=" + atlas.width + " h=" + atlas.height);
                    }
                }

                atlases[propIdx] = atlas;
                if (progressInfo != null)
                {
                    progressInfo("Saving atlas: '" + property.name + "'", .04f);
                }
                System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
                sw.Start();
                if (data.resultType == MB2_TextureBakeResults.ResultType.atlas)
                {
                    SaveAtlasAndConfigureResultMaterial(data, textureEditorMethods, atlases[propIdx], data.texPropertyNames[propIdx], propIdx);
                }

                combiner._destroyTemporaryTextures(data.texPropertyNames[propIdx].name);
            }

            yield break;
        }
예제 #24
0
        /*
         * Packed rects may exceed atlas size and require scaling
         * When scaling want pixel perfect fit in atlas. Corners of rects should exactly align with pixel grid
         * Padding should be subtracted from pixel perfect rect to create pixel perfect square
         */
        AtlasPackingResult ScaleAtlasToFitMaxDim(ProbeResult root, List <Vector2> imgWidthHeights, List <Image> images, int maxDimension, int padding, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY, int outW, int outH, int recursionDepth)
        {
            int  newMinSizeX = minImageSizeX;
            int  newMinSizeY = minImageSizeY;
            bool redoPacking = false;
            //AtlasPackingResult[] rs = null;

            // the atlas may be packed larger than the maxDimension. If so then the atlas needs to be scaled down to fit
            float padX = (float)padding / (float)outW; //padding needs to be pixel perfect in size

            if (root.w > maxDimension)
            {
                padX = (float)padding / (float)maxDimension;
                float scaleFactor = (float)maxDimension / (float)root.w;
                if (LOG_LEVEL >= MB2_LogLevel.warn)
                {
                    Debug.LogWarning("Packing exceeded atlas width shrinking to " + scaleFactor);
                }
                for (int i = 0; i < images.Count; i++)
                {
                    Image im = images[i];
                    if (im.w * scaleFactor < masterImageSizeX)
                    { //check if small images will be rounded too small. If so need to redo packing forcing a larger min size
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("Small images are being scaled to zero. Will need to redo packing with larger minTexSizeX.");
                        }
                        redoPacking = true;
                        newMinSizeX = Mathf.CeilToInt(minImageSizeX / scaleFactor);
                    }
                    int right = (int)((im.x + im.w) * scaleFactor);
                    im.x = (int)(scaleFactor * im.x);
                    im.w = right - im.x;
                }
                outW = maxDimension;
            }

            float padY = (float)padding / (float)outH;

            if (root.h > maxDimension)
            {
                //float minSizeY = ((float)minImageSizeY + 1) / maxDimension;
                padY = (float)padding / (float)maxDimension;
                float scaleFactor = (float)maxDimension / (float)root.h;
                if (LOG_LEVEL >= MB2_LogLevel.warn)
                {
                    Debug.LogWarning("Packing exceeded atlas height shrinking to " + scaleFactor);
                }
                for (int i = 0; i < images.Count; i++)
                {
                    Image im = images[i];
                    if (im.h * scaleFactor < masterImageSizeY)
                    { //check if small images will be rounded too small. If so need to redo packing forcing a larger min size
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("Small images are being scaled to zero. Will need to redo packing with larger minTexSizeY.");
                        }
                        redoPacking = true;
                        newMinSizeY = Mathf.CeilToInt(minImageSizeY / scaleFactor);
                    }
                    int bottom = (int)((im.y + im.h) * scaleFactor);
                    im.y = (int)(scaleFactor * im.y);
                    im.h = bottom - im.y;
                }
                outH = maxDimension;
            }

            AtlasPackingResult res;

            if (!redoPacking)
            {
                res            = new AtlasPackingResult();
                res.rects      = new Rect[images.Count];
                res.srcImgIdxs = new int[images.Count];
                res.atlasX     = outW;
                res.atlasY     = outH;
                res.usedW      = -1;
                res.usedH      = -1;
                for (int i = 0; i < images.Count; i++)
                {
                    Image im = images[i];
                    Rect  r  = res.rects[i] = new Rect((float)im.x / (float)outW + padX,
                                                       (float)im.y / (float)outH + padY,
                                                       (float)im.w / (float)outW - padX * 2f,
                                                       (float)im.h / (float)outH - padY * 2f);
                    res.srcImgIdxs[i] = im.imgId;
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        MB2_Log.LogDebug("Image: " + i + " imgID=" + im.imgId + " x=" + r.x * outW +
                                         " y=" + r.y * outH + " w=" + r.width * outW +
                                         " h=" + r.height * outH + " padding=" + padding);
                    }
                }
                return(res);
            }
            else
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.Log("==================== REDOING PACKING ================");
                }
                root = null;
                return(_GetRectsSingleAtlas(imgWidthHeights, maxDimension, padding, newMinSizeX, newMinSizeY, masterImageSizeX, masterImageSizeY, recursionDepth + 1));
            }
        }
예제 #25
0
        //------------------ Algorithm for fitting everything into one atlas and scaling down
        //
        // for images being added calc area, maxW, maxH. A perfectly packed atlas will match area exactly. atlas must be at least maxH and maxW in size.
        // Sort images from big to small using either height, width or area comparer
        // Explore space to find a resonably efficient packing. Grow the atlas gradually until a fit is found
        // Scale atlas to fit
        //
        AtlasPackingResult _GetRectsSingleAtlas(List <Vector2> imgWidthHeights, int maxDimension, int padding, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY, int recursionDepth)
        {
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log(String.Format("_GetRects numImages={0}, maxDimension={1}, padding={2}, minImageSizeX={3}, minImageSizeY={4}, masterImageSizeX={5}, masterImageSizeY={6}, recursionDepth={7}",
                                        imgWidthHeights.Count, maxDimension, padding, minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY, recursionDepth));
            }
            if (recursionDepth > 10)
            {
                if (LOG_LEVEL >= MB2_LogLevel.error)
                {
                    Debug.LogError("Maximum recursion depth reached. Couldn't find packing for these textures.");
                }
                return(null);
            }
            float area = 0;
            int   maxW = 0;
            int   maxH = 0;

            Image[] imgsToAdd = new Image[imgWidthHeights.Count];
            for (int i = 0; i < imgsToAdd.Length; i++)
            {
                int   iw = (int)imgWidthHeights[i].x;
                int   ih = (int)imgWidthHeights[i].y;
                Image im = imgsToAdd[i] = new Image(i, iw, ih, padding, minImageSizeX, minImageSizeY);
                area += im.w * im.h;
                maxW  = Mathf.Max(maxW, im.w);
                maxH  = Mathf.Max(maxH, im.h);
            }

            if ((float)maxH / (float)maxW > 2)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using height Comparer");
                }
                Array.Sort(imgsToAdd, new ImageHeightComparer());
            }
            else if ((float)maxH / (float)maxW < .5)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using width Comparer");
                }
                Array.Sort(imgsToAdd, new ImageWidthComparer());
            }
            else
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using area Comparer");
                }
                Array.Sort(imgsToAdd, new ImageAreaComparer());
            }

            //explore the space to find a resonably efficient packing
            int sqrtArea = (int)Mathf.Sqrt(area);
            int idealAtlasW;
            int idealAtlasH;

            if (doPowerOfTwoTextures)
            {
                idealAtlasW = idealAtlasH = RoundToNearestPositivePowerOfTwo(sqrtArea);
                if (maxW > idealAtlasW)
                {
                    idealAtlasW = CeilToNearestPowerOfTwo(idealAtlasW);
                }
                if (maxH > idealAtlasH)
                {
                    idealAtlasH = CeilToNearestPowerOfTwo(idealAtlasH);
                }
            }
            else
            {
                idealAtlasW = sqrtArea;
                idealAtlasH = sqrtArea;
                if (maxW > sqrtArea)
                {
                    idealAtlasW = maxW;
                    idealAtlasH = Mathf.Max(Mathf.CeilToInt(area / maxW), maxH);
                }
                if (maxH > sqrtArea)
                {
                    idealAtlasW = Mathf.Max(Mathf.CeilToInt(area / maxH), maxW);
                    idealAtlasH = maxH;
                }
            }

            if (idealAtlasW == 0)
            {
                idealAtlasW = 4;
            }
            if (idealAtlasH == 0)
            {
                idealAtlasH = 4;
            }
            int stepW = (int)(idealAtlasW * .15f);
            int stepH = (int)(idealAtlasH * .15f);

            if (stepW == 0)
            {
                stepW = 1;
            }
            if (stepH == 0)
            {
                stepH = 1;
            }
            int numWIterations = 2;
            int steppedWidth   = idealAtlasW;
            int steppedHeight  = idealAtlasH;

            while (numWIterations >= 1 && steppedHeight < sqrtArea * 1000)
            {
                bool successW = false;
                numWIterations = 0;
                steppedWidth   = idealAtlasW;
                while (!successW && steppedWidth < sqrtArea * 1000)
                {
                    ProbeResult pr = new ProbeResult();
                    if (LOG_LEVEL >= MB2_LogLevel.trace)
                    {
                        Debug.Log("Probing h=" + steppedHeight + " w=" + steppedWidth);
                    }
                    if (ProbeSingleAtlas(imgsToAdd, steppedWidth, steppedHeight, area, maxDimension, pr))
                    {
                        successW = true;
                        if (bestRoot == null)
                        {
                            bestRoot = pr;
                        }
                        else if (pr.GetScore(doPowerOfTwoTextures) > bestRoot.GetScore(doPowerOfTwoTextures))
                        {
                            bestRoot = pr;
                        }
                    }
                    else
                    {
                        numWIterations++;
                        steppedWidth = StepWidthHeight(steppedWidth, stepW, maxDimension);
                        if (LOG_LEVEL >= MB2_LogLevel.trace)
                        {
                            MB2_Log.LogDebug("increasing Width h=" + steppedHeight + " w=" + steppedWidth);
                        }
                    }
                }
                steppedHeight = StepWidthHeight(steppedHeight, stepH, maxDimension);
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("increasing Height h=" + steppedHeight + " w=" + steppedWidth);
                }
            }
            if (bestRoot == null)
            {
                return(null);
            }

            int outW = 0;
            int outH = 0;

            if (doPowerOfTwoTextures)
            {
                outW = Mathf.Min(CeilToNearestPowerOfTwo(bestRoot.w), maxDimension);
                outH = Mathf.Min(CeilToNearestPowerOfTwo(bestRoot.h), maxDimension);
                if (outH < outW / 2)
                {
                    outH = outW / 2;                                  //smaller dim can't be less than half larger
                }
                if (outW < outH / 2)
                {
                    outW = outH / 2;
                }
            }
            else
            {
                outW = Mathf.Min(bestRoot.w, maxDimension);
                outH = Mathf.Min(bestRoot.h, maxDimension);
            }

            bestRoot.outW = outW;
            bestRoot.outH = outH;
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("Best fit found: atlasW=" + outW + " atlasH" + outH + " w=" + bestRoot.w + " h=" + bestRoot.h + " efficiency=" + bestRoot.efficiency + " squareness=" + bestRoot.squareness + " fits in max dimension=" + bestRoot.largerOrEqualToMaxDim);
            }

            //Debug.Assert(images.Count != imgsToAdd.Length, "Result images not the same lentgh as source"));

            //the atlas can be larger than the max dimension scale it if this is the case
            //int newMinSizeX = minImageSizeX;
            //int	newMinSizeY = minImageSizeY;


            List <Image> images = new List <Image>();

            flattenTree(bestRoot.root, images);
            images.Sort(new ImgIDComparer());
            // the atlas may be packed larger than the maxDimension. If so then the atlas needs to be scaled down to fit
            AtlasPackingResult res = ScaleAtlasToFitMaxDim(bestRoot, imgWidthHeights, images, maxDimension, padding, minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY, outW, outH, recursionDepth);

            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                MB2_Log.LogDebug(String.Format("Done GetRects atlasW={0} atlasH={1}", bestRoot.w, bestRoot.h));
            }

            return(res);
        }
        public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                         MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner,
                                         AtlasPackingResult packedAtlasRects,
                                         Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods,
                                         MB2_LogLevel LOG_LEVEL)
        {
            Debug.Assert(!data.OnlyOneTextureInAtlasReuseTextures());
            Rect[] uvRects = packedAtlasRects.rects;

            int atlasSizeX = packedAtlasRects.atlasX;
            int atlasSizeY = packedAtlasRects.atlasY;

            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY);
            }

            //create a game object
            GameObject renderAtlasesGO = null;

            try
            {
                renderAtlasesGO = new GameObject("MBrenderAtlasesGO");
                MB3_AtlasPackerRenderTexture atlasRenderTexture = renderAtlasesGO.AddComponent <MB3_AtlasPackerRenderTexture>();
                renderAtlasesGO.AddComponent <Camera>();
                if (data._considerNonTextureProperties && LOG_LEVEL >= MB2_LogLevel.warn)
                {
                    Debug.LogError("Blend Non-Texture Properties has limited functionality when used with Mesh Baker Texture Packer Fast. If no texture is pesent, then a small texture matching the non-texture property will be created and used in the atlas. But non-texture properties will not be blended into texture.");
                }

                for (int propIdx = 0; propIdx < data.numAtlases; propIdx++)
                {
                    Texture2D atlas = null;
                    if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                    {
                        atlas = null;
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("Not creating atlas for " + data.texPropertyNames[propIdx].name + " because textures are null and default value parameters are the same.");
                        }
                    }
                    else
                    {
                        GC.Collect();

                        MB3_TextureCombinerPackerRoot.CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data);

                        if (progressInfo != null)
                        {
                            progressInfo("Creating Atlas '" + data.texPropertyNames[propIdx].name + "'", .01f);
                        }
                        // ===========
                        // configure it
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("About to render " + data.texPropertyNames[propIdx].name + " isNormal=" + data.texPropertyNames[propIdx].isNormalMap);
                        }
                        atlasRenderTexture.LOG_LEVEL                    = LOG_LEVEL;
                        atlasRenderTexture.width                        = atlasSizeX;
                        atlasRenderTexture.height                       = atlasSizeY;
                        atlasRenderTexture.padding                      = data._atlasPadding;
                        atlasRenderTexture.rects                        = uvRects;
                        atlasRenderTexture.textureSets                  = data.distinctMaterialTextures;
                        atlasRenderTexture.indexOfTexSetToRender        = propIdx;
                        atlasRenderTexture.texPropertyName              = data.texPropertyNames[propIdx];
                        atlasRenderTexture.isNormalMap                  = data.texPropertyNames[propIdx].isNormalMap;
                        atlasRenderTexture.fixOutOfBoundsUVs            = data._fixOutOfBoundsUVs;
                        atlasRenderTexture.considerNonTextureProperties = data._considerNonTextureProperties;
                        atlasRenderTexture.resultMaterialTextureBlender = data.nonTexturePropertyBlender;
                        // call render on it
                        atlas = atlasRenderTexture.OnRenderAtlas(combiner);

                        // destroy it
                        // =============
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("Saving atlas " + data.texPropertyNames[propIdx].name + " w=" + atlas.width + " h=" + atlas.height + " id=" + atlas.GetInstanceID());
                        }
                    }
                    atlases[propIdx] = atlas;
                    if (progressInfo != null)
                    {
                        progressInfo("Saving atlas: '" + data.texPropertyNames[propIdx].name + "'", .04f);
                    }
                    if (data.resultType == MB2_TextureBakeResults.ResultType.atlas)
                    {
                        MB3_TextureCombinerPackerRoot.SaveAtlasAndConfigureResultMaterial(data, textureEditorMethods, atlases[propIdx], data.texPropertyNames[propIdx], propIdx);
                    }

                    combiner._destroyTemporaryTextures(data.texPropertyNames[propIdx].name); // need to save atlases before doing this
                }
            }
            catch (Exception ex)
            {
                //Debug.LogError(ex);
                Debug.LogError(ex.Message + "\n" + ex.StackTrace.ToString());
            }
            finally
            {
                if (renderAtlasesGO != null)
                {
                    MB_Utility.Destroy(renderAtlasesGO);
                }
            }
            yield break;
        }
예제 #27
0
 public static AtlasPackingResult TestStackRectanglesVertical(AtlasPackingResult a,
                                                              AtlasPackingResult b, int maxHeightDim, int maxWidthDim, bool stretchBToAtlasWidth)
 {
     return(MergeAtlasPackingResultStackBonA(a, b, maxWidthDim, maxHeightDim, stretchBToAtlasWidth, new VerticalPipeline()));
 }
예제 #28
0
        AtlasPackingResult _GetRectsSingleAtlas(List <Vector2> imgWidthHeights, int maxDimension, int padding, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY, int recursionDepth)
        {
            AtlasPackingResult res = new AtlasPackingResult();

            List <Rect>  rects  = new List <Rect>();
            int          extent = 0;
            int          maxh   = 0;
            int          maxw   = 0;
            List <Image> images = new List <Image>();

            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("Packing rects for: " + imgWidthHeights.Count);
            }
            for (int i = 0; i < imgWidthHeights.Count; i++)
            {
                Image im = new Image(i, (int)imgWidthHeights[i].x, (int)imgWidthHeights[i].y, padding, minImageSizeX, minImageSizeY);

                // if images are stacked horizontally then there is no padding at the top or bottom
                if (packingOrientation == TexturePackingOrientation.vertical)
                {
                    im.h -= padding * 2;
                    im.x  = extent;
                    im.y  = 0;
                    rects.Add(new Rect(im.w, im.h, extent, 0));
                    extent += im.w;
                    maxh    = Mathf.Max(maxh, im.h);
                }
                else
                {
                    im.w -= padding * 2;
                    im.y  = extent;
                    im.x  = 0;
                    rects.Add(new Rect(im.w, im.h, 0, extent));
                    extent += im.h;
                    maxw    = Mathf.Max(maxw, im.w);
                }
                images.Add(im);
            }
            //scale atlas to fit maxDimension
            Vector2 rootWH;

            if (packingOrientation == TexturePackingOrientation.vertical)
            {
                rootWH = new Vector2(extent, maxh);
            }
            else
            {
                rootWH = new Vector2(maxw, extent);
            }
            int outW = (int)rootWH.x;
            int outH = (int)rootWH.y;

            if (packingOrientation == TexturePackingOrientation.vertical)
            {
                if (atlasMustBePowerOfTwo)
                {
                    outW = Mathf.Min(CeilToNearestPowerOfTwo(outW), maxDimension);
                }
                else
                {
                    outW = Mathf.Min(outW, maxDimension);
                }
            }
            else
            {
                if (atlasMustBePowerOfTwo)
                {
                    outH = Mathf.Min(CeilToNearestPowerOfTwo(outH), maxDimension);
                }
                else
                {
                    outH = Mathf.Min(outH, maxDimension);
                }
            }

            float padX, padY;
            int   newMinSizeX, newMinSizeY;

            if (!ScaleAtlasToFitMaxDim(rootWH, images, maxDimension, padding, minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY,
                                       ref outW, ref outH, out padX, out padY, out newMinSizeX, out newMinSizeY))
            {
                res            = new AtlasPackingResult();
                res.rects      = new Rect[images.Count];
                res.srcImgIdxs = new int[images.Count];
                res.atlasX     = outW;
                res.atlasY     = outH;
                res.usedW      = -1;
                res.usedH      = -1;
                for (int i = 0; i < images.Count; i++)
                {
                    Image im = images[i];
                    Rect  r;
                    if (packingOrientation == TexturePackingOrientation.vertical)
                    {
                        r = res.rects[i] = new Rect((float)im.x / (float)outW + padX,
                                                    (float)im.y / (float)outH,
                                                    (float)im.w / (float)outW - padX * 2f,
                                                    stretchImagesToEdges ? 1f : (float)im.h / (float)outH);          // all images are stretched to fill the height
                    }
                    else
                    {
                        r = res.rects[i] = new Rect((float)im.x / (float)outW,
                                                    (float)im.y / (float)outH + padY,
                                                    (stretchImagesToEdges ? 1f : ((float)im.w / (float)outW)),
                                                    (float)im.h / (float)outH - padY * 2f);          // all images are stretched to fill the height
                    }
                    res.srcImgIdxs[i] = im.imgId;
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        MB2_Log.LogDebug("Image: " + i + " imgID=" + im.imgId + " x=" + r.x * outW +
                                         " y=" + r.y * outH + " w=" + r.width * outW +
                                         " h=" + r.height * outH + " padding=" + padding + " outW=" + outW + " outH=" + outH);
                    }
                }
                return(res);
            }
            Debug.Log("Packing failed returning null atlas result");
            return(null);
        }
        //------------------ Algorithm for fitting everything into one atlas and scaling down
        //
        // for images being added calc area, maxW, maxH. A perfectly packed atlas will match area exactly. atlas must be at least maxH and maxW in size.
        // Sort images from big to small using either height, width or area comparer
        // Explore space to find a resonably efficient packing. Grow the atlas gradually until a fit is found
        // Scale atlas to fit
        //
        AtlasPackingResult _GetRectsSingleAtlas(List <Vector2> imgWidthHeights, List <AtlasPadding> paddings, int maxDimensionX, int maxDimensionY, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY, int recursionDepth)
        {
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log(String.Format("_GetRects numImages={0}, maxDimension={1}, minImageSizeX={2}, minImageSizeY={3}, masterImageSizeX={4}, masterImageSizeY={5}, recursionDepth={6}",
                                        imgWidthHeights.Count, maxDimensionX, minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY, recursionDepth));
            }
            if (recursionDepth > MAX_RECURSION_DEPTH)
            {
                if (LOG_LEVEL >= MB2_LogLevel.error)
                {
                    Debug.LogError("Maximum recursion depth reached. The baked atlas is likely not very good. " +
                                   " This happens when the packed atlases exceeds the maximum" +
                                   " atlas size in one or both dimensions so that the atlas needs to be downscaled AND there are some very thin or very small images (only-a-few-pixels)." +
                                   " these very thin images can 'vanish' completely when the atlas is downscaled.\n\n" +
                                   " Try one or more of the following: using multiple atlases, increase the maximum atlas size, don't use 'force-power-of-two', remove the source materials that are are using very small/thin textures.");
                }
                //return null;
            }
            float area = 0;
            int   maxW = 0;
            int   maxH = 0;

            Image[] imgsToAdd = new Image[imgWidthHeights.Count];
            for (int i = 0; i < imgsToAdd.Length; i++)
            {
                int   iw = (int)imgWidthHeights[i].x;
                int   ih = (int)imgWidthHeights[i].y;
                Image im = imgsToAdd[i] = new Image(i, iw, ih, paddings[i], minImageSizeX, minImageSizeY);
                area += im.w * im.h;
                maxW  = Mathf.Max(maxW, im.w);
                maxH  = Mathf.Max(maxH, im.h);
            }

            if ((float)maxH / (float)maxW > 2)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using height Comparer");
                }
                Array.Sort(imgsToAdd, new ImageHeightComparer());
            }
            else if ((float)maxH / (float)maxW < .5)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using width Comparer");
                }
                Array.Sort(imgsToAdd, new ImageWidthComparer());
            }
            else
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using area Comparer");
                }
                Array.Sort(imgsToAdd, new ImageAreaComparer());
            }

            //explore the space to find a resonably efficient packing
            int sqrtArea = (int)Mathf.Sqrt(area);
            int idealAtlasW;
            int idealAtlasH;

            if (atlasMustBePowerOfTwo)
            {
                idealAtlasW = idealAtlasH = RoundToNearestPositivePowerOfTwo(sqrtArea);
                if (maxW > idealAtlasW)
                {
                    idealAtlasW = CeilToNearestPowerOfTwo(idealAtlasW);
                }
                if (maxH > idealAtlasH)
                {
                    idealAtlasH = CeilToNearestPowerOfTwo(idealAtlasH);
                }
            }
            else
            {
                idealAtlasW = sqrtArea;
                idealAtlasH = sqrtArea;
                if (maxW > sqrtArea)
                {
                    idealAtlasW = maxW;
                    idealAtlasH = Mathf.Max(Mathf.CeilToInt(area / maxW), maxH);
                }
                if (maxH > sqrtArea)
                {
                    idealAtlasW = Mathf.Max(Mathf.CeilToInt(area / maxH), maxW);
                    idealAtlasH = maxH;
                }
            }

            if (idealAtlasW == 0)
            {
                idealAtlasW = 4;
            }
            if (idealAtlasH == 0)
            {
                idealAtlasH = 4;
            }
            int stepW = (int)(idealAtlasW * .15f);
            int stepH = (int)(idealAtlasH * .15f);

            if (stepW == 0)
            {
                stepW = 1;
            }
            if (stepH == 0)
            {
                stepH = 1;
            }
            int numWIterations = 2;
            int steppedWidth   = idealAtlasW;
            int steppedHeight  = idealAtlasH;

            while (numWIterations >= 1 && steppedHeight < sqrtArea * 1000)
            {
                bool successW = false;
                numWIterations = 0;
                steppedWidth   = idealAtlasW;
                while (!successW && steppedWidth < sqrtArea * 1000)
                {
                    ProbeResult pr = new ProbeResult();
                    if (LOG_LEVEL >= MB2_LogLevel.trace)
                    {
                        Debug.Log("Probing h=" + steppedHeight + " w=" + steppedWidth);
                    }
                    if (ProbeSingleAtlas(imgsToAdd, steppedWidth, steppedHeight, area, maxDimensionX, maxDimensionY, pr))
                    {
                        successW = true;
                        if (bestRoot == null)
                        {
                            bestRoot = pr;
                        }
                        else if (pr.GetScore(atlasMustBePowerOfTwo) > bestRoot.GetScore(atlasMustBePowerOfTwo))
                        {
                            bestRoot = pr;
                        }
                    }
                    else
                    {
                        numWIterations++;
                        steppedWidth = StepWidthHeight(steppedWidth, stepW, maxDimensionX);
                        if (LOG_LEVEL >= MB2_LogLevel.trace)
                        {
                            MB2_Log.LogDebug("increasing Width h=" + steppedHeight + " w=" + steppedWidth);
                        }
                    }
                }
                steppedHeight = StepWidthHeight(steppedHeight, stepH, maxDimensionY);
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("increasing Height h=" + steppedHeight + " w=" + steppedWidth);
                }
            }
            if (bestRoot == null)
            {
                return(null);
            }

            int outW = 0;
            int outH = 0;

            if (atlasMustBePowerOfTwo)
            {
                outW = Mathf.Min(CeilToNearestPowerOfTwo(bestRoot.w), maxDimensionX);
                outH = Mathf.Min(CeilToNearestPowerOfTwo(bestRoot.h), maxDimensionY);
                if (outH < outW / 2)
                {
                    outH = outW / 2;                                  //smaller dim can't be less than half larger
                }
                if (outW < outH / 2)
                {
                    outW = outH / 2;
                }
            }
            else
            {
                outW = Mathf.Min(bestRoot.w, maxDimensionX);
                outH = Mathf.Min(bestRoot.h, maxDimensionY);
            }

            bestRoot.outW = outW;
            bestRoot.outH = outH;
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("Best fit found: atlasW=" + outW + " atlasH" + outH + " w=" + bestRoot.w + " h=" + bestRoot.h + " efficiency=" + bestRoot.efficiency + " squareness=" + bestRoot.squareness + " fits in max dimension=" + bestRoot.largerOrEqualToMaxDim);
            }

            //Debug.Assert(images.Count != imgsToAdd.Length, "Result images not the same lentgh as source"));

            //the atlas can be larger than the max dimension scale it if this is the case
            //int newMinSizeX = minImageSizeX;
            //int	newMinSizeY = minImageSizeY;


            List <Image> images = new List <Image>();

            flattenTree(bestRoot.root, images);
            images.Sort(new ImgIDComparer());
            // the atlas may be packed larger than the maxDimension. If so then the atlas needs to be scaled down to fit
            Vector2 rootWH = new Vector2(bestRoot.w, bestRoot.h);
            float   padX, padY;
            int     newMinSizeX, newMinSizeY;

            if (!ScaleAtlasToFitMaxDim(rootWH, images, maxDimensionX, maxDimensionY, paddings[0], minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY,
                                       ref outW, ref outH, out padX, out padY, out newMinSizeX, out newMinSizeY) ||
                recursionDepth > MAX_RECURSION_DEPTH)
            {
                AtlasPackingResult res = new AtlasPackingResult(paddings.ToArray());
                res.rects      = new Rect[images.Count];
                res.srcImgIdxs = new int[images.Count];
                res.atlasX     = outW;
                res.atlasY     = outH;
                res.usedW      = -1;
                res.usedH      = -1;
                for (int i = 0; i < images.Count; i++)
                {
                    Image im = images[i];
                    Rect  r  = res.rects[i] = new Rect((float)im.x / (float)outW + padX,
                                                       (float)im.y / (float)outH + padY,
                                                       (float)im.w / (float)outW - padX * 2f,
                                                       (float)im.h / (float)outH - padY * 2f);
                    res.srcImgIdxs[i] = im.imgId;
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        MB2_Log.LogDebug("Image: " + i + " imgID=" + im.imgId + " x=" + r.x * outW +
                                         " y=" + r.y * outH + " w=" + r.width * outW +
                                         " h=" + r.height * outH + " padding=" + (paddings[i].leftRight * 2) + "x" + (paddings[i].topBottom * 2));
                    }
                }
                res.CalcUsedWidthAndHeight();
                return(res);
            }
            else
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.Log("==================== REDOING PACKING ================");
                }
                //root = null;
                return(_GetRectsSingleAtlas(imgWidthHeights, paddings, maxDimensionX, maxDimensionY, newMinSizeX, newMinSizeY, masterImageSizeX, masterImageSizeY, recursionDepth + 1));
            }


            //if (LOG_LEVEL >= MB2_LogLevel.debug) MB2_Log.LogDebug(String.Format("Done GetRects atlasW={0} atlasH={1}", bestRoot.w, bestRoot.h));

            //return res;
        }
예제 #30
0
        public override AtlasPackingResult[] CalculateAtlasRectangles(MB3_TextureCombinerPipeline.TexturePipelineData data, bool doMultiAtlas, MB2_LogLevel LOG_LEVEL)
        {
            Debug.Assert(!data.OnlyOneTextureInAtlasReuseTextures());
            Debug.Assert(data._packingAlgorithm != MB2_PackingAlgorithmEnum.UnitysPackTextures, "Unity texture packer cannot be used");

            IPipeline pipeline;

            if (_atlasDirection == AtlasDirection.horizontal)
            {
                pipeline = new HorizontalPipeline();
            }
            else
            {
                pipeline = new VerticalPipeline();
            }

            //int maxAtlasWidth = data._maxAtlasWidth;
            //int maxAtlasHeight = data._maxAtlasHeight;
            if (_atlasDirection == AtlasDirection.horizontal)
            {
                if (!data._useMaxAtlasWidthOverride)
                {
                    // need to get the width of the atlas without mesh uvs considered
                    int maxWidth = 2;
                    for (int i = 0; i < data.distinctMaterialTextures.Count; i++)
                    {
                        MB_TexSet ts = data.distinctMaterialTextures[i];
                        int       w;
                        if (data._fixOutOfBoundsUVs)
                        {
                            Vector2 rawHeightWidth = ts.GetMaxRawTextureHeightWidth();
                            w = (int)rawHeightWidth.x;
                        }
                        else
                        {
                            w = ts.idealWidth;
                        }
                        if (ts.idealWidth > maxWidth)
                        {
                            maxWidth = w;
                        }
                    }
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("Calculated max atlas width: " + maxWidth);
                    }
                    data._maxAtlasWidth = maxWidth;
                }
            }
            else
            {
                if (!data._useMaxAtlasHeightOverride)
                {
                    int maxHeight = 2;
                    for (int i = 0; i < data.distinctMaterialTextures.Count; i++)
                    {
                        MB_TexSet ts = data.distinctMaterialTextures[i];
                        int       h;
                        if (data._fixOutOfBoundsUVs)
                        {
                            Vector2 rawHeightWidth = ts.GetMaxRawTextureHeightWidth();
                            h = (int)rawHeightWidth.y;
                        }
                        else
                        {
                            h = ts.idealHeight;
                        }
                        if (ts.idealHeight > maxHeight)
                        {
                            maxHeight = h;
                        }
                    }
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("Calculated max atlas height: " + maxHeight);
                    }
                    data._maxAtlasHeight = maxHeight;
                }
            }

            //split the list of distinctMaterialTextures into two bins
            List <MB_TexSet> horizontalVerticalDistinctMaterialTextures = new List <MB_TexSet>();
            List <MB_TexSet> regularTextures = new List <MB_TexSet>();

            for (int i = 0; i < data.distinctMaterialTextures.Count; i++)
            {
                pipeline.SortTexSetIntoBins(data.distinctMaterialTextures[i], horizontalVerticalDistinctMaterialTextures, regularTextures, data._maxAtlasWidth, data._maxAtlasHeight);
            }

            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log(String.Format("Splitting list of distinctMaterialTextures numHorizontalVertical={0} numRegular={1} maxAtlasWidth={2} maxAtlasHeight={3}", horizontalVerticalDistinctMaterialTextures.Count, regularTextures.Count, data._maxAtlasWidth, data._maxAtlasHeight));
            }

            //pack one bin with the horizontal vertical texture packer.
            MB2_TexturePacker        tp;
            MB2_PackingAlgorithmEnum packingAlgorithm;

            AtlasPackingResult[] packerRectsHorizontalVertical;
            if (horizontalVerticalDistinctMaterialTextures.Count > 0)
            {
                packingAlgorithm = pipeline.GetPackingAlg();
                List <Vector2> imageSizesHorizontalVertical = new List <Vector2>();
                for (int i = 0; i < horizontalVerticalDistinctMaterialTextures.Count; i++)
                {
                    horizontalVerticalDistinctMaterialTextures[i].SetTilingTreatmentAndAdjustEncapsulatingSamplingRect(pipeline.GetEdge2EdgeTreatment());
                    imageSizesHorizontalVertical.Add(new Vector2(horizontalVerticalDistinctMaterialTextures[i].idealWidth, horizontalVerticalDistinctMaterialTextures[i].idealHeight));
                }

                tp = MB3_TextureCombinerPipeline.CreateTexturePacker(packingAlgorithm);
                tp.atlasMustBePowerOfTwo = false;
                List <AtlasPadding> paddingsHorizontalVertical = new List <AtlasPadding>();
                for (int i = 0; i < imageSizesHorizontalVertical.Count; i++)
                {
                    AtlasPadding padding = new AtlasPadding();
                    pipeline.InitializeAtlasPadding(ref padding, data._atlasPadding);
                    paddingsHorizontalVertical.Add(padding);
                }

                tp.LOG_LEVEL = MB2_LogLevel.trace;
                packerRectsHorizontalVertical = tp.GetRects(imageSizesHorizontalVertical, paddingsHorizontalVertical, data._maxAtlasWidth, data._maxAtlasHeight, false);
                if (LOG_LEVEL >= MB2_LogLevel.trace)
                {
                    Debug.Log(String.Format("Packed {0} textures with edgeToEdge tiling into an atlas of size {1} by {2} usedW {3} usedH {4}", horizontalVerticalDistinctMaterialTextures.Count, packerRectsHorizontalVertical[0].atlasX, packerRectsHorizontalVertical[0].atlasY, packerRectsHorizontalVertical[0].usedW, packerRectsHorizontalVertical[0].usedH));
                }
            }
            else
            {
                packerRectsHorizontalVertical = new AtlasPackingResult[0];
            }

            //pack other bin with regular texture packer
            AtlasPackingResult[] packerRectsRegular;
            if (regularTextures.Count > 0)
            {
                packingAlgorithm = MB2_PackingAlgorithmEnum.MeshBakerTexturePacker;
                List <Vector2> imageSizesRegular = new List <Vector2>();
                for (int i = 0; i < regularTextures.Count; i++)
                {
                    imageSizesRegular.Add(new Vector2(regularTextures[i].idealWidth, regularTextures[i].idealHeight));
                }

                tp = MB3_TextureCombinerPipeline.CreateTexturePacker(MB2_PackingAlgorithmEnum.MeshBakerTexturePacker);
                tp.atlasMustBePowerOfTwo = false;
                List <AtlasPadding> paddingsRegular = new List <AtlasPadding>();
                for (int i = 0; i < imageSizesRegular.Count; i++)
                {
                    AtlasPadding padding = new AtlasPadding();
                    padding.topBottom = data._atlasPadding;
                    padding.leftRight = data._atlasPadding;
                    paddingsRegular.Add(padding);
                }

                int atlasRegularMaxWidth, atlasRegularMaxHeight;
                int usedHorizontalVertWidth = 0, usedHorizontalVertHeight = 0;
                if (packerRectsHorizontalVertical.Length > 0)
                {
                    usedHorizontalVertHeight = packerRectsHorizontalVertical[0].atlasY;
                    usedHorizontalVertWidth  = packerRectsHorizontalVertical[0].atlasX;
                }
                pipeline.GetExtraRoomForRegularAtlas(usedHorizontalVertWidth, usedHorizontalVertHeight, data._maxAtlasWidth, data._maxAtlasHeight, out atlasRegularMaxWidth, out atlasRegularMaxHeight);
                packerRectsRegular = tp.GetRects(imageSizesRegular, paddingsRegular, atlasRegularMaxWidth, atlasRegularMaxHeight, false);
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.Log(String.Format("Packed {0} textures without edgeToEdge tiling into an atlas of size {1} by {2} usedW {3} usedH {4}", regularTextures.Count, packerRectsRegular[0].atlasX, packerRectsRegular[0].atlasY, packerRectsRegular[0].usedW, packerRectsRegular[0].usedH));
                }
            }
            else
            {
                packerRectsRegular = new AtlasPackingResult[0];
            }


            AtlasPackingResult result = null;

            if (packerRectsHorizontalVertical.Length == 0 && packerRectsRegular.Length == 0)
            {
                Debug.Assert(false, "Should never have reached this.");
                return(null);
            }
            else if (packerRectsHorizontalVertical.Length > 0 && packerRectsRegular.Length > 0)
            {
                result = MergeAtlasPackingResultStackBonA(packerRectsHorizontalVertical[0], packerRectsRegular[0], data._maxAtlasWidth, data._maxAtlasHeight, true, pipeline);
            }
            else if (packerRectsHorizontalVertical.Length > 0)
            {
                result = packerRectsHorizontalVertical[0];
            }
            else if (packerRectsRegular.Length > 0)
            {
                result = packerRectsRegular[0];
            }

            Debug.Assert(data.distinctMaterialTextures.Count == result.rects.Length);

            //We re-ordered the distinctMaterial textures so replace the list with the new reordered one
            horizontalVerticalDistinctMaterialTextures.AddRange(regularTextures);
            data.distinctMaterialTextures = horizontalVerticalDistinctMaterialTextures;
            AtlasPackingResult[] results;
            if (result != null)
            {
                results = new AtlasPackingResult[] { result }
            }
            ;
            else
            {
                results = new AtlasPackingResult[0];
            }
            return(results);
        }