Пример #1
0
        public AtlasPackingResult[] CalculateAtlasRectangles(TexturePipelineData data, bool doMultiAtlas)
        {
            Debug.Assert(data.IsOnlyOneTextureInAtlasReuseTextures());
            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);

            MaterialPropTexture 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);
        }
Пример #2
0
        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 });
                }
            }
        }
Пример #3
0
 //normalize atlases so that that rects are 0 to 1
 public void normalizeRects(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;
     }
 }
Пример #4
0
        public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                         TexturePipelineData data,
                                         TextureCombineHandler combiner,
                                         AtlasPackingResult packedAtlasRects,
                                         Texture2D[] atlases,
                                         EditorMethodsInterface textureEditorMethods)
        {
            Debug.Assert(data.IsOnlyOneTextureInAtlasReuseTextures());
            Debug.Log("Only one image per atlas. Will re-use original texture");
            for (int i = 0; i < data.numAtlases; i++)
            {
                MaterialPropTexture 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, Vector2.one);
                data.resultMaterial.SetTextureOffset(data.texPropertyNames[i].name, Vector2.zero);
            }

            yield break;
        }
Пример #5
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);
            }
Пример #6
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;
            }
Пример #7
0
        public override IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                                  TexturePipelineData data,
                                                  TextureCombineHandler combiner,
                                                  AtlasPackingResult packedAtlasRects,
                                                  Texture2D[] atlases,
                                                  EditorMethodsInterface textureEditorMethods)
        {
            Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures());
            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 (!TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                {
                    atlas = null;
                }
                else
                {
                    Debug.LogWarning("Beginning loop " + propIdx + " num temporary textures " + combiner._getNumTemporaryTextures());
                    TextureCombinerPackerBase.CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data);
                    Texture2D[] texToPack = new Texture2D[data.distinctMaterialTextures.Count];
                    for (int texSetIdx = 0; texSetIdx < data.distinctMaterialTextures.Count; texSetIdx++)
                    {
                        MaterialPropTexturesSet 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);
                        //create a resized copy if necessary
                        if (tx.width != tWidth || tx.height != tHeight)
                        {
                            if (progressInfo != null)
                            {
                                progressInfo("Resizing texture '" + tx + "'", .01f);
                            }
                            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)
                    {
                        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);
                        }
                        Debug.Log("Estimated atlas minimum size:" + Math.Sqrt(estArea).ToString("F0"));
                        int maxAtlasSize = 4096;
                        uvRects = atlas.PackTextures(texToPack, data._atlasPadding, maxAtlasSize, false);
                        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;
        }
Пример #8
0
 public abstract IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                           TexturePipelineData data,
                                           TextureCombineHandler combiner,
                                           AtlasPackingResult packedAtlasRects,
                                           Texture2D[] atlases,
                                           EditorMethodsInterface textureEditorMethods);
Пример #9
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);
        }
Пример #10
0
 public static AtlasPackingResult TestStackRectanglesVertical(AtlasPackingResult a,
                                                              AtlasPackingResult b, int maxHeightDim, int maxWidthDim, bool stretchBToAtlasWidth)
 {
     return(MergeAtlasPackingResultStackBonA(a, b, maxWidthDim, maxHeightDim, stretchBToAtlasWidth, new VerticalPipeline()));
 }
Пример #11
0
        public override AtlasPackingResult[] CalculateAtlasRectangles(TexturePipelineData data, bool doMultiAtlas)
        {
            Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures());
            Debug.Assert(data._packingAlgorithm != 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++)
                    {
                        MaterialPropTexturesSet 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;
                        }
                    }
                    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++)
                    {
                        MaterialPropTexturesSet 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;
                        }
                    }
                    Debug.Log("Calculated max atlas height: " + maxHeight);
                    data._maxAtlasHeight = maxHeight;
                }
            }

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

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

            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.
            TexturePacker        tp;
            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 = 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);
                }


                packerRectsHorizontalVertical = tp.GetRects(imageSizesHorizontalVertical, paddingsHorizontalVertical, data._maxAtlasWidth, data._maxAtlasHeight, false);
                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 = 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 = CreateTexturePacker(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);
                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);
        }
Пример #12
0
        AtlasPackingResult _GetRectsSingleAtlas(List <Vector2> imgWidthHeights, List <AtlasPadding> paddings, int maxDimensionX, int maxDimensionY, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY, int recursionDepth)
        {
            AtlasPackingResult res = new AtlasPackingResult(paddings.ToArray());

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

            Debug.Log("Packing rects for: " + imgWidthHeights.Count);
            for (int i = 0; i < imgWidthHeights.Count; i++)
            {
                ImageAreaInAtlas im = new ImageAreaInAtlas(i, (int)imgWidthHeights[i].x, (int)imgWidthHeights[i].y, paddings[i], minImageSizeX, minImageSizeY);

                // if images are stacked horizontally then there is no padding at the top or bottom
                if (packingOrientation == TexturePackingOrientation.vertical)
                {
                    im.h -= paddings[i].topBottom * 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 -= paddings[i].leftRight * 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), maxDimensionX);
                }
                else
                {
                    outW = Mathf.Min(outW, maxDimensionX);
                }
            }
            else
            {
                if (atlasMustBePowerOfTwo)
                {
                    outH = Mathf.Min(CeilToNearestPowerOfTwo(outH), maxDimensionY);
                }
                else
                {
                    outH = Mathf.Min(outH, maxDimensionY);
                }
            }

            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))
            {
                res            = new AtlasPackingResult(paddings.ToArray());
                res.rects      = new Rect[images.Count];
                res.srcImgIdxs = new int[images.Count];
                res.atlasX     = outW;
                res.atlasY     = outH;
                for (int i = 0; i < images.Count; i++)
                {
                    ImageAreaInAtlas 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;
                    Debug.Log("Image: " + i + " imgID=" + im.imgId + " x=" + r.x * outW +
                              " y=" + r.y * outH + " w=" + r.width * outW +
                              " h=" + r.height * outH + " padding=" + paddings[i] + " outW=" + outW + " outH=" + outH);
                }
                res.CalcUsedWidthAndHeight();
                return(res);
            }
            Debug.Log("Packing failed returning null atlas result");
            return(null);
        }
        /// <summary>
        ///  Texture 合并管线第 3 步,创建 Atlas 并保存资源
        /// </summary>
        /// <returns></returns>
        internal static IEnumerator __Step3_BuildAndSaveAtlasesAndStoreResults(ProgressUpdateDelegate progressInfo,
                                                                               CombineTexturesIntoAtlasesCoroutineResult result,
                                                                               TexturePipelineData data,
                                                                               TextureCombineHandler combiner,
                                                                               ITextureCombinerPacker packer,
                                                                               AtlasPackingResult atlasPackingResult,
                                                                               EditorMethodsInterface textureEditorMethods,
                                                                               AtlasesAndRects resultAtlasesAndRects)
        {
            //run the garbage collector to free up as much memory as possible before bake to reduce MissingReferenceException problems
            GC.Collect();
            Texture2D[] atlases = new Texture2D[data.numAtlases];
            //StringBuilder report = GenerateReport(data);

            //创建图集
            yield return(packer.CreateAtlases(progressInfo, data, combiner, atlasPackingResult, atlases, textureEditorMethods));

            data.nonTexturePropertyBlender.AdjustNonTextureProperties(data.resultMaterial, data.texPropertyNames, data.distinctMaterialTextures, textureEditorMethods);

            if (data.distinctMaterialTextures.Count > 0)
            {
                data.distinctMaterialTextures[0].AdjustResultMaterialNonTextureProperties(data.resultMaterial, data.texPropertyNames);
            }

            //结果报告
            //if (progressInfo != null)
            //    progressInfo("Building Report", .7f);
            ////report on atlases created
            //StringBuilder atlasMessage = new StringBuilder();
            //atlasMessage.AppendLine("---- Atlases ------");
            //for (int i = 0; i < data.numAtlases; i++)
            //{
            //    if (atlases[i] != null)
            //    {
            //        atlasMessage.AppendLine("Created Atlas For: " + data.texPropertyNames[i].name + " h=" + atlases[i].height + " w=" + atlases[i].width);
            //    }
            //    else if (!_ShouldWeCreateAtlasForThisProperty(i, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
            //    {
            //        atlasMessage.AppendLine("Did not create atlas for " + data.texPropertyNames[i].name + " because all source textures were null.");
            //    }
            //}
            //report.Append(atlasMessage.ToString());

            List <MaterialAndUVRect> mat2rect_map = new List <MaterialAndUVRect>();

            for (int i = 0; i < data.distinctMaterialTextures.Count; i++)
            {
                MaterialPropTexturesSet        texSet = data.distinctMaterialTextures[i];
                List <MatAndTransformToMerged> mats   = texSet.matsAndGOs.mats;
                Rect allPropsUseSameTiling_encapsulatingSamplingRect;
                Rect propsUseDifferntTiling_obUVRect;
                texSet.GetRectsForTextureBakeResults(out allPropsUseSameTiling_encapsulatingSamplingRect, out propsUseDifferntTiling_obUVRect);
                for (int j = 0; j < mats.Count; j++)
                {
                    Rect allPropsUseSameTiling_sourceMaterialTiling = texSet.GetMaterialTilingRectForTextureBakerResults(j);
                    MaterialAndUVRect key = new MaterialAndUVRect(
                        mats[j].mat,
                        atlasPackingResult.rects[i],
                        texSet.allTexturesUseSameMatTiling,
                        allPropsUseSameTiling_sourceMaterialTiling,
                        allPropsUseSameTiling_encapsulatingSamplingRect,
                        propsUseDifferntTiling_obUVRect,
                        texSet.tilingTreatment,
                        mats[j].objName);
                    if (!mat2rect_map.Contains(key))
                    {
                        mat2rect_map.Add(key);
                    }
                }
            }

            resultAtlasesAndRects.atlases             = atlases;                                               // one per texture on result shader
            resultAtlasesAndRects.texPropertyNames    = ShaderTextureProperty.GetNames(data.texPropertyNames); // one per texture on source shader
            resultAtlasesAndRects.originMatToRect_map = mat2rect_map;

            if (progressInfo != null)
            {
                progressInfo("Restoring Texture Formats & Read Flags", .8f);
            }
            combiner._destroyAllTemporaryTextures();
            if (textureEditorMethods != null)
            {
                textureEditorMethods.RestoreReadFlagsAndFormats(progressInfo);
            }

            //if (report != null)
            //    Debug.Log(report.ToString());

            yield break;
        }
Пример #14
0
        //----------------- 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)
        {
            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;

            ImageAreaInAtlas[] imgsToAdd = new ImageAreaInAtlas[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);

                ImageAreaInAtlas im = imgsToAdd[i] = new ImageAreaInAtlas(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);
            }
            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 <AtalsAreaNode>  atlasNodes = new List <AtalsAreaNode>();
            Stack <AtalsAreaNode> stack      = new Stack <AtalsAreaNode>();
            AtalsAreaNode         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 <ImageAreaInAtlas> images = new List <ImageAreaInAtlas>();
                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].nodeAreaRect.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].nodeAreaRect.x;
                int outW = atlasNodes[i].nodeAreaRect.w;
                int outH = atlasNodes[i].nodeAreaRect.h;
                if (atlasMustBePowerOfTwo)
                {
                    outW = Mathf.Min(CeilToNearestPowerOfTwo(res.usedW), atlasNodes[i].nodeAreaRect.w);
                    outH = Mathf.Min(CeilToNearestPowerOfTwo(res.usedH), atlasNodes[i].nodeAreaRect.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);
                normalizeRects(res, paddings[i]);
                Debug.Log(String.Format("Done GetRects "));
            }

            return(rs.ToArray());
        }
Пример #15
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,
                                                List <AtlasPadding> paddings,
                                                int maxDimensionX,
                                                int maxDimensionY,
                                                int minImageSizeX,
                                                int minImageSizeY,
                                                int masterImageSizeX,
                                                int masterImageSizeY,
                                                int recursionDepth)
        {
            Debug.Log(string.Format("_GetRects 图片数量 ={0}, 最大尺寸X ={1}, 最小尺寸 X={2}, 最小尺寸 Y ={3}, masterImageSizeX={4}, masterImageSizeY={5}, 递归深度 = {6}",
                                    imgWidthHeights.Count, maxDimensionX, minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY, recursionDepth));
            if (recursionDepth > 10)
            {
                //最大递归深度设定为 10
                Debug.LogError("Maximum recursion depth reached. Couldn't find packing for these textures.");
                return(null);
            }
            float allImageTotalArea = 0;
            int   maxW = 0;
            int   maxH = 0;

            ImageAreaInAtlas[] imgsToAdd = new ImageAreaInAtlas[imgWidthHeights.Count];
            for (int i = 0; i < imgsToAdd.Length; i++)
            {
                int iw = (int)imgWidthHeights[i].x;
                int ih = (int)imgWidthHeights[i].y;

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

            if ((float)maxH / (float)maxW > 2)
            {
                Array.Sort(imgsToAdd, new ImageHeightComparer());
            }
            else if ((float)maxH / (float)maxW < .5)
            {
                Array.Sort(imgsToAdd, new ImageWidthComparer());
            }
            else
            {
                Array.Sort(imgsToAdd, new ImageAreaComparer());
            }

            //explore the space to find a resonably efficient packing
            //探索图片空间以找到合理有效的包装
            int sqrtArea = (int)Mathf.Sqrt(allImageTotalArea);
            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(allImageTotalArea / maxW), maxH);
                }
                if (maxH > sqrtArea)
                {
                    idealAtlasW = Mathf.Max(Mathf.CeilToInt(allImageTotalArea / 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();
                    Debug.Log("Probing h=" + steppedHeight + " w=" + steppedWidth);

                    if (ProbeSingleAtlas(imgsToAdd, steppedWidth, steppedHeight, allImageTotalArea, maxDimensionX, maxDimensionY, pr))
                    {
                        successW = true;
                        if (bestRoot == null)
                        {
                            bestRoot = pr;
                        }
                        else if (pr.GetScore(atlasMustBePowerOfTwo) > bestRoot.GetScore(atlasMustBePowerOfTwo))
                        {
                            bestRoot = pr;
                        }
                    }
                    else
                    {
                        numWIterations++;
                        steppedWidth = SetStepWidthHeight(steppedWidth, stepW, maxDimensionX);
                        Debug.Log("增加 Width h=" + steppedHeight + " w=" + steppedWidth);
                    }
                }
                steppedHeight = SetStepWidthHeight(steppedHeight, stepH, maxDimensionY);
                Debug.Log("增加 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;
            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 <ImageAreaInAtlas> images = new List <ImageAreaInAtlas>();

            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))
            {
                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++)
                {
                    ImageAreaInAtlas 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;
                    Debug.Log("Image: " + i + " imgID=" + im.imgId + " x=" + r.x * outW +
                              " y=" + r.y * outH + " w=" + r.width * outW +
                              " h=" + r.height * outH + " padding=" + paddings[i]);
                }
                res.CalcUsedWidthAndHeight();
                return(res);
            }
            else
            {
                Debug.Log("==================== REDOING PACKING ================");
                //root = null;
                return(_GetRectsSingleAtlas(imgWidthHeights, paddings, maxDimensionX, maxDimensionY, newMinSizeX, newMinSizeY, masterImageSizeX, masterImageSizeY, recursionDepth + 1));
            }


            //Debug.Log(String.Format("Done GetRects atlasW={0} atlasH={1}", bestRoot.w, bestRoot.h));

            //return res;
        }
        public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                         TexturePipelineData data,
                                         TextureCombineHandler combiner,
                                         AtlasPackingResult packedAtlasRects,
                                         Texture2D[] atlases,
                                         EditorMethodsInterface textureEditorMethods)
        {
            Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures());
            Rect[] uvRects = packedAtlasRects.rects;

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

            Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY);

            //create a game object
            GameObject renderAtlasesGO = null;

            try
            {
                renderAtlasesGO = new GameObject("MBrenderAtlasesGO");
                AtlasPackerRenderTexture atlasRenderTexture = renderAtlasesGO.AddComponent <AtlasPackerRenderTexture>();
                renderAtlasesGO.AddComponent <Camera>();
                if (data._considerNonTextureProperties)
                {
                    Debug.LogWarning("Blend Non-Texture Properties has limited functionality when used with Mesh Baker Texture Packer Fast.");
                }

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

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

                        if (progressInfo != null)
                        {
                            progressInfo("Creating Atlas '" + data.texPropertyNames[propIdx].name + "'", .01f);
                        }
                        // ===========
                        // configure it
                        Debug.Log("About to render " + data.texPropertyNames[propIdx].name + " isNormal=" + data.texPropertyNames[propIdx].isNormalMap);
                        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
                        // =============
                        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._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(data.texPropertyNames[propIdx].name); // need to save atlases before doing this
                }
            }
            catch (Exception ex)
            {
                //Debug.LogError(ex);
                Debug.LogException(ex);
            }
            finally
            {
                if (renderAtlasesGO != null)
                {
                    MeshBakerUtility.Destroy(renderAtlasesGO);
                }
            }
            yield break;
        }
        public override IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                                  TexturePipelineData data,
                                                  TextureCombineHandler combiner,
                                                  AtlasPackingResult packedAtlasRects,
                                                  Texture2D[] atlases,
                                                  EditorMethodsInterface textureEditorMethods)
        {
            Rect[] uvRects = packedAtlasRects.rects;

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

            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 (!TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                {
                    atlas = null;
                    Debug.Log("=== Not creating atlas for " + property.name + " because textures are null and default value parameters are the same.");
                }
                else
                {
                    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++)
                    {
                        MaterialPropTexturesSet texSet = data.distinctMaterialTextures[texSetIdx];
                        MaterialPropTexture     matTex = texSet.ts[propIdx];
                        string s = "Creating Atlas '" + property.name + "' texture " + matTex.GetTexName();
                        if (progressInfo != null)
                        {
                            progressInfo(s, .01f);
                        }
                        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));
                    }

                    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();
                    Debug.Log("Saving atlas " + property.name + " w=" + atlas.width + " h=" + atlas.height);
                }

                atlases[propIdx] = atlas;
                if (progressInfo != null)
                {
                    progressInfo("Saving atlas: '" + property.name + "'", .04f);
                }
                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(data.texPropertyNames[propIdx].name);
            }

            yield break;
        }
Пример #18
0
        AtlasPackingResult[] _GetRectsMultiAtlasHorizontal(List <Vector2> imgWidthHeights, List <AtlasPadding> paddings, int maxDimensionPassedX, int maxDimensionPassedY, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY)
        {
            List <AtlasPackingResult> rs = new List <AtlasPackingResult>();
            int extent = 0;
            int maxh   = 0;
            int maxw   = 0;

            Debug.Log("Packing rects for: " + imgWidthHeights.Count);

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

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

            while (allImages.Count > 0 || images.Count > 0)
            {
                ImageAreaInAtlas im = PopLargestThatFits(allImages, spaceRemaining, maxDimensionPassedY, images.Count == 0);
                if (im == null)
                {
                    Debug.Log("Atlas filled creating a new atlas ");
                    AtlasPackingResult apr = new AtlasPackingResult(paddings.ToArray());
                    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 = maxDimensionPassedY;
                }
                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 = maxDimensionPassedY - extent;
                }
            }

            for (int i = 0; i < rs.Count; i++)
            {
                int outH = rs[i].atlasY;
                int outW = Mathf.Min(rs[i].atlasX, maxDimensionPassedX);
                if (atlasMustBePowerOfTwo)
                {
                    outH = Mathf.Min(CeilToNearestPowerOfTwo(outH), maxDimensionPassedY);
                }
                else
                {
                    outH = Mathf.Min(outH, maxDimensionPassedY);
                }
                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, maxDimensionPassedX, maxDimensionPassedY, paddings[0], 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], paddings[i]);
                rs[i].CalcUsedWidthAndHeight();
            }
            //-----------------------------
            return(rs.ToArray());
        }