Exemplo n.º 1
0
 public virtual AtlasPackingResult[] CalculateAtlasRectangles(TexturePipelineData data, bool doMultiAtlas)
 {
     return(CalculateAtlasRectanglesStatic(data, doMultiAtlas));
 }
        /// <summary>
        /// 收集材质参数名称
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        internal static bool _CollectPropertyNames(TexturePipelineData data)
        {
            //try custom properties remove duplicates
            //尝试删除自定义属性的重复项
            for (int i = 0; i < data.texPropertyNames.Count; i++)
            {
                ShaderTextureProperty s = data._customShaderPropNames.Find(x => x.name.Equals(data.texPropertyNames[i].name));
                if (s != null)
                {
                    data._customShaderPropNames.Remove(s);
                }
            }

            Material m = data.resultMaterial;

            if (m == null)
            {
                Debug.LogError("合并材质为空。");
                return(false);
            }

            //Collect the property names for the textures
            for (int i = 0; i < shaderTexPropertyNames.Length; i++)
            {
                if (m.HasProperty(shaderTexPropertyNames[i].name))
                {
                    if (!data.texPropertyNames.Contains(shaderTexPropertyNames[i]))
                    {
                        data.texPropertyNames.Add(shaderTexPropertyNames[i]);
                    }
                    if (m.GetTextureOffset(shaderTexPropertyNames[i].name) != new Vector2(0f, 0f))
                    {
                        Debug.LogWarning("Result material has non-zero offset. This is may be incorrect.");
                    }
                    if (m.GetTextureScale(shaderTexPropertyNames[i].name) != new Vector2(1f, 1f))
                    {
                        Debug.LogWarning("Result material should have tiling of 1,1");
                    }
                }
            }

            for (int i = 0; i < data._customShaderPropNames.Count; i++)
            {
                if (m.HasProperty(data._customShaderPropNames[i].name))
                {
                    data.texPropertyNames.Add(data._customShaderPropNames[i]);
                    if (m.GetTextureOffset(data._customShaderPropNames[i].name) != new Vector2(0f, 0f))
                    {
                        Debug.LogWarning("Result material has non-zero offset. This is probably incorrect.");
                    }
                    if (m.GetTextureScale(data._customShaderPropNames[i].name) != new Vector2(1f, 1f))
                    {
                        Debug.LogWarning("Result material should probably have tiling of 1,1.");
                    }
                }
                else
                {
                    Debug.LogWarning("Result material shader does not use property " +
                                     data._customShaderPropNames[i].name + " in the list of custom shader property names");
                }
            }
            return(true);
        }
Exemplo n.º 3
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);
        }
 /// <summary>
 /// 检测所有 textures 中只有一种纹理
 /// </summary>
 /// <param name="data"></param>
 /// <returns></returns>
 private static CreateAtlasForProperty[] CalculateAllTexturesAreNullAndSameColor(TexturePipelineData data)
 {
     // check if all textures are null and use same color for each atlas
     // will not generate an atlas if so
     CreateAtlasForProperty[] shouldWeCreateAtlasForProp = new CreateAtlasForProperty[data.texPropertyNames.Count];
     for (int propIdx = 0; propIdx < data.texPropertyNames.Count; propIdx++)
     {
         MaterialPropTexture firstTexture = data.distinctMaterialTextures[0].ts[propIdx];
         Color firstColor = Color.black;
         if (data._considerNonTextureProperties)
         {
             firstColor = data.nonTexturePropertyBlender.GetColorAsItWouldAppearInAtlasIfNoTexture(
                 data.distinctMaterialTextures[0].matsAndGOs.mats[0].mat,
                 data.texPropertyNames[propIdx]);
         }
         int numTexturesExisting     = 0;
         int numTexturesMatchinFirst = 0;
         int numNonTexturePropertiesMatchingFirst = 0;
         for (int j = 0; j < data.distinctMaterialTextures.Count; j++)
         {
             if (!data.distinctMaterialTextures[j].ts[propIdx].isNull)
             {
                 numTexturesExisting++;
             }
             if (firstTexture.AreTexturesEqual(data.distinctMaterialTextures[j].ts[propIdx]))
             {
                 numTexturesMatchinFirst++;
             }
             if (data._considerNonTextureProperties)
             {
                 Color colJ = data.nonTexturePropertyBlender.GetColorAsItWouldAppearInAtlasIfNoTexture(data.distinctMaterialTextures[j].matsAndGOs.mats[0].mat, data.texPropertyNames[propIdx]);
                 if (colJ == firstColor)
                 {
                     numNonTexturePropertiesMatchingFirst++;
                 }
             }
         }
         shouldWeCreateAtlasForProp[propIdx].allTexturesAreNull        = numTexturesExisting == 0;
         shouldWeCreateAtlasForProp[propIdx].allTexturesAreSame        = numTexturesMatchinFirst == data.distinctMaterialTextures.Count;
         shouldWeCreateAtlasForProp[propIdx].allNonTexturePropsAreSame = numNonTexturePropertiesMatchingFirst == data.distinctMaterialTextures.Count;
         Debug.Log(String.Format("AllTexturesAreNullAndSameColor prop: {0} createAtlas:{1}  val:{2}",
                                 data.texPropertyNames[propIdx].name,
                                 _ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, shouldWeCreateAtlasForProp),
                                 shouldWeCreateAtlasForProp[propIdx]));
     }
     return(shouldWeCreateAtlasForProp);
 }
        internal static Vector2 GetAdjustedForScaleAndOffset2Dimensions(MaterialPropTexture source, Vector2 obUVoffset, Vector2 obUVscale, TexturePipelineData data)
        {
            if (source.matTilingRect.x == 0f && source.matTilingRect.y == 0f && source.matTilingRect.width == 1f && source.matTilingRect.height == 1f)
            {
                if (data._fixOutOfBoundsUVs)
                {
                    if (obUVoffset.x == 0f && obUVoffset.y == 0f && obUVscale.x == 1f && obUVscale.y == 1f)
                    {
                        return(new Vector2(source.width, source.height)); //no adjustment necessary
                    }
                }
                else
                {
                    return(new Vector2(source.width, source.height)); //no adjustment necessary
                }
            }

            Debug.Log("GetAdjustedForScaleAndOffset2Dimensions: " + source.GetTexName() + " " + obUVoffset + " " + obUVscale);
            Rect  encapsulatingSamplingRect = source.GetEncapsulatingSamplingRect().GetRect();
            float newWidth  = encapsulatingSamplingRect.width * source.width;
            float newHeight = encapsulatingSamplingRect.height * source.height;

            if (newWidth > data._maxTilingBakeSize)
            {
                newWidth = data._maxTilingBakeSize;
            }
            if (newHeight > data._maxTilingBakeSize)
            {
                newHeight = data._maxTilingBakeSize;
            }
            if (newWidth < 1f)
            {
                newWidth = 1f;
            }
            if (newHeight < 1f)
            {
                newHeight = 1f;
            }
            return(new Vector2(newWidth, newHeight));
        }
        /// <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;
        }
        //第二步:计算每个材质的属性对应的 Textures 统一尺寸
        //每种材质(_mainTex,凹凸,Spec ect ...)中的纹理必须大小相同
        //计算要使用的最佳尺寸。 考虑平铺
        //如果图集中只有一种纹理会使用原始大小
        internal static IEnumerator _Step2_CalculateIdealSizesForTexturesInAtlasAndPadding(ProgressUpdateDelegate progressInfo,
                                                                                           CombineTexturesIntoAtlasesCoroutineResult result,
                                                                                           TexturePipelineData data,
                                                                                           EditorMethodsInterface textureEditorMethods)
        {
            MaterialPropTexture.readyToBuildAtlases = true;
            data.allTexturesAreNullAndSameColor     = CalculateAllTexturesAreNullAndSameColor(data);

            //calculate size of rectangles in atlas
            //计算 atlas 矩形尺寸
            int _padding = data._atlasPadding;

            if (data.distinctMaterialTextures.Count == 1 && data._fixOutOfBoundsUVs == false && data._considerNonTextureProperties == false)
            {
                Debug.Log("所有游戏物体使用相同的材质.将使用 Original textures .");
                _padding = 0;
                data.distinctMaterialTextures[0].SetThisIsOnlyTexSetInAtlasTrue();
                data.distinctMaterialTextures[0].SetTilingTreatmentAndAdjustEncapsulatingSamplingRect(TextureTilingTreatment.edgeToEdgeXY);
            }

            Debug.Assert(data.allTexturesAreNullAndSameColor.Length == data.texPropertyNames.Count,
                         "allTexturesAreNullAndSameColor array must be the same length of texPropertyNames.");

            for (int i = 0; i < data.distinctMaterialTextures.Count; i++)
            {
                Debug.Log("为 TexSet " + i + " of " + data.distinctMaterialTextures.Count + "计算合适的尺寸");
                MaterialPropTexturesSet txs = data.distinctMaterialTextures[i];
                txs.idealWidth  = 1;
                txs.idealHeight = 1;
                int tWidth  = 1;
                int tHeight = 1;
                Debug.Assert(txs.ts.Length == data.texPropertyNames.Count,
                             "length of arrays in each element of distinctMaterialTextures must be texPropertyNames.Count");

                //在 MaterialPropTexturesSet 中所有 MaterialPropTextures 应为相同尺寸
                for (int propIdx = 0; propIdx < data.texPropertyNames.Count; propIdx++)
                {
                    if (_ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                    {
                        MaterialPropTexture matTex = txs.ts[propIdx];
                        Debug.Log(string.Format("为 texSet {0} ,property {1} 计算合适尺寸", i, data.texPropertyNames[propIdx].name));
                        if (!matTex.matTilingRect.size.Equals(Vector2.one) && data.distinctMaterialTextures.Count > 1)
                        {
                            Debug.LogWarning("Texture " + matTex.GetTexName() + "is tiled by " +
                                             matTex.matTilingRect.size + " tiling will be baked into a texture with maxSize:" +
                                             data._maxTilingBakeSize);
                        }

                        if (!txs.obUVscale.Equals(Vector2.one) && data.distinctMaterialTextures.Count > 1 && data._fixOutOfBoundsUVs)
                        {
                            Debug.LogWarning("Texture " + matTex.GetTexName() +
                                             " has out of bounds UVs that effectively tile by " + txs.obUVscale +
                                             " tiling will be baked into a texture with maxSize:" + data._maxTilingBakeSize);
                        }

                        if (matTex.isNull)
                        {
                            txs.SetEncapsulatingRect(propIdx, data._fixOutOfBoundsUVs);
                            Debug.Log(string.Format("No source texture creating a 16x16 texture for {0} texSet {1} srcMat {2}",
                                                    data.texPropertyNames[propIdx].name, i, txs.matsAndGOs.mats[0].GetMaterialName()));
                        }

                        if (!matTex.isNull)
                        {
                            Vector2 dim = GetAdjustedForScaleAndOffset2Dimensions(matTex, txs.obUVoffset, txs.obUVscale, data);
                            if ((int)(dim.x * dim.y) > tWidth * tHeight)
                            {
                                Debug.Log(" 材质texture " + matTex.GetTexName() + " " + dim + " 需要比" + tWidth + " " + tHeight + "更大的尺寸");
                                tWidth  = (int)dim.x;
                                tHeight = (int)dim.y;
                            }
                        }
                    }
                }

                if (data._resizePowerOfTwoTextures)
                {
                    if (tWidth <= _padding * 5)
                    {
                        Debug.LogWarning(String.Format("Some of the textures have widths close to the size of the padding. " +
                                                       "It is not recommended to use _resizePowerOfTwoTextures with widths this small.", txs.ToString()));
                    }
                    if (tHeight <= _padding * 5)
                    {
                        Debug.LogWarning(String.Format("Some of the textures have heights close to the size of the padding. " +
                                                       "It is not recommended to use _resizePowerOfTwoTextures with heights this small.", txs.ToString()));
                    }
                    if (IsPowerOfTwo(tWidth))
                    {
                        tWidth -= _padding * 2;
                    }
                    if (IsPowerOfTwo(tHeight))
                    {
                        tHeight -= _padding * 2;
                    }
                    if (tWidth < 1)
                    {
                        tWidth = 1;
                    }
                    if (tHeight < 1)
                    {
                        tHeight = 1;
                    }
                }
                Debug.Log("Ideal size is " + tWidth + " " + tHeight);
                txs.idealWidth  = tWidth;
                txs.idealHeight = tHeight;
            }
            data._atlasPadding = _padding;
            yield break;
        }
        /// <summary>
        /// 第一步:
        ///     写入 TexturePipelineData 的 MaterialPropTexturesSet 列表,和 usedObjsToMesh 列表
        /// 每个TexSet在 Atlas 中都是一个矩形。
        /// 如果 allowedMaterialsFilter (过滤器)为空,那么将收集 allObjsToMesh 上的所有材质,usedObjsToMesh 将与allObjsToMesh相同
        /// 否则,将仅包括allowedMaterialsFilter中的材料,而usedObjsToMesh将是使用这些材料的objs。
        /// </summary>
        internal static IEnumerator __Step1_CollectDistinctMatTexturesAndUsedObjects(ProgressUpdateDelegate progressInfo,
                                                                                     CombineTexturesIntoAtlasesCoroutineResult result,
                                                                                     TexturePipelineData data,
                                                                                     EditorMethodsInterface textureEditorMethods,
                                                                                     List <GameObject> usedObjsToMesh)
        {
            // Collect distinct list of textures to combine from the materials on objsToCombine
            // 收集UsedObjects上不同的材质纹理
            bool outOfBoundsUVs = false;
            Dictionary <int, MeshAnalysisResult[]> meshAnalysisResultsCache = new Dictionary <int, MeshAnalysisResult[]>(); //cache results

            for (int i = 0; i < data.allObjsToMesh.Count; i++)
            {
                GameObject obj = data.allObjsToMesh[i];
                //报道进度
                if (progressInfo != null)
                {
                    progressInfo("Collecting textures for " + obj, ((float)i) / data.allObjsToMesh.Count / 2f);
                }

                if (obj == null)
                {
                    Debug.LogError("合并游戏物体列表中包含空物体");
                    result.success = false;
                    yield break;
                }

                Mesh sharedMesh = MeshBakerUtility.GetMesh(obj);
                if (sharedMesh == null)
                {
                    Debug.LogError("游戏物体 " + obj.name + " 网格为空");
                    result.success = false;
                    yield break;
                }

                Material[] sharedMaterials = MeshBakerUtility.GetGOMaterials(obj);
                if (sharedMaterials.Length == 0)
                {
                    Debug.LogError("游戏物体 " + obj.name + " 材质为空.");
                    result.success = false;
                    yield break;
                }

                //analyze mesh or grab cached result of previous analysis, stores one result for each submesh
                //处理网格数据
                MeshAnalysisResult[] meshAnalysisResults;//每个游戏物体的主网格子网格数据数组
                if (!meshAnalysisResultsCache.TryGetValue(sharedMesh.GetInstanceID(), out meshAnalysisResults))
                {
                    meshAnalysisResults = new MeshAnalysisResult[sharedMesh.subMeshCount];
                    for (int j = 0; j < sharedMesh.subMeshCount; j++)
                    {
                        MeshBakerUtility.hasOutOfBoundsUVs(sharedMesh, ref meshAnalysisResults[j], j);
                        if (data._normalizeTexelDensity)
                        {
                            meshAnalysisResults[j].submeshArea = GetSubmeshArea(sharedMesh, j);
                        }

                        if (data._fixOutOfBoundsUVs && !meshAnalysisResults[j].hasUVs)
                        {
                            meshAnalysisResults[j].uvRect = new Rect(0, 0, 1, 1);
                            Debug.LogWarning("Mesh for object " + obj + " has no UV channel but 'consider UVs' is enabled." +
                                             " Assuming UVs will be generated filling 0,0,1,1 rectangle.");
                        }
                    }
                    meshAnalysisResultsCache.Add(sharedMesh.GetInstanceID(), meshAnalysisResults);
                }

                if (data._fixOutOfBoundsUVs)
                {
                    Debug.Log("Mesh Analysis for object " + obj +
                              " numSubmesh=" + meshAnalysisResults.Length +
                              " HasOBUV=" + meshAnalysisResults[0].hasOutOfBoundsUVs +
                              " UVrectSubmesh0=" + meshAnalysisResults[0].uvRect);
                }


                //处理材质数据
                for (int matIdx = 0; matIdx < sharedMaterials.Length; matIdx++)
                {
                    ////for each submesh
                    //if (progressInfo != null)
                    //{
                    //    progressInfo(string.Format("Collecting textures for {0} submesh {1}", obj, matIdx),
                    //        ((float)i) / data.allObjsToMesh.Count / 2f);
                    //}
                    Material mat = sharedMaterials[matIdx];

                    // 材质过滤器
                    if (data.allowedMaterialsFilter != null && !data.allowedMaterialsFilter.Contains(mat))
                    {
                        continue;
                    }

                    outOfBoundsUVs = outOfBoundsUVs || meshAnalysisResults[matIdx].hasOutOfBoundsUVs;

                    if (mat.name.Contains("(Instance)"))
                    {
                        Debug.LogError("The sharedMaterial on object " + obj.name + " has been 'Instanced'." +
                                       " This was probably caused by a script accessing the meshRender.material property in the editor. " +
                                       " The material to UV Rectangle mapping will be incorrect. " +
                                       "To fix this recreate the object from its prefab or re-assign its material from the correct asset.");
                        result.success = false;
                        yield break;
                    }

                    if (data._fixOutOfBoundsUVs)
                    {
                        if (!MeshBakerUtility.AreAllSharedMaterialsDistinct(sharedMaterials))
                        {
                            Debug.LogWarning("游戏物体 " + obj.name + " 使用相同的材质在多个子网格. " +
                                             "可能生成奇怪的 resultAtlasesAndRects,尤其是与 _fixOutOfBoundsUVs 为 true 时");
                        }
                    }

                    //材质属性所用到的 Texutre
                    MaterialPropTexture[] mts = new MaterialPropTexture[data.texPropertyNames.Count];
                    for (int propIdx = 0; propIdx < data.texPropertyNames.Count; propIdx++)
                    {
                        Texture tx           = null;
                        Vector2 scale        = Vector2.one;
                        Vector2 offset       = Vector2.zero;
                        float   texelDensity = 0f;
                        if (mat.HasProperty(data.texPropertyNames[propIdx].name))
                        {
                            Texture txx = GetTextureConsideringStandardShaderKeywords(data.resultMaterial.shader.name, mat, data.texPropertyNames[propIdx].name);
                            if (txx != null)
                            {
                                if (txx is Texture2D)
                                {
                                    //TextureFormat 验证
                                    tx = txx;
                                    TextureFormat f           = ((Texture2D)tx).format;
                                    bool          isNormalMap = false;
                                    if (!Application.isPlaying && textureEditorMethods != null)
                                    {
                                        isNormalMap = textureEditorMethods.IsNormalMap((Texture2D)tx);
                                    }
                                    if ((f == TextureFormat.ARGB32 ||
                                         f == TextureFormat.RGBA32 ||
                                         f == TextureFormat.BGRA32 ||
                                         f == TextureFormat.RGB24 ||
                                         f == TextureFormat.Alpha8) && !isNormalMap) //DXT5 does not work
                                    {
                                        //可使用
                                    }
                                    else
                                    {
                                        //TRIED to copy texture using tex2.SetPixels(tex1.GetPixels()) but bug in 3.5 means DTX1 and 5 compressed textures come out skewe
                                        //尝试使用tex2.SetPixels(tex1.GetPixels())复制纹理,但是3.5中的bug意味着DTX1和5压缩纹理出现扭曲
                                        if (Application.isPlaying && data._packingAlgorithm != PackingAlgorithmEnum.MeshBakerTexturePacker_Fast)
                                        {
                                            Debug.LogWarning("合并列表中,游戏物体 " + obj.name + " 所使用的 Texture " +
                                                             tx.name + " 使用的格式 " + f +
                                                             "不是: ARGB32, RGBA32, BGRA32, RGB24, Alpha8 或 DXT. " +
                                                             "无法在运行时重新设置尺寸" +
                                                             "If format says 'compressed' try changing it to 'truecolor'");
                                            result.success = false;
                                            yield break;
                                        }
                                        else
                                        {
                                            tx = (Texture2D)mat.GetTexture(data.texPropertyNames[propIdx].name);
                                        }
                                    }
                                }
                                else
                                {
                                    Debug.LogError("合并列表中,游戏物体 " + obj.name + " 渲染网格使用的 Texture 不是 Texture2D. ");
                                    result.success = false;
                                    yield break;
                                }
                            }
                            //像素密度
                            if (tx != null && data._normalizeTexelDensity)
                            {
                                //不考虑平铺和UV采样超出范围
                                if (meshAnalysisResults[propIdx].submeshArea == 0)
                                {
                                    texelDensity = 0f;
                                }
                                else
                                {
                                    texelDensity = (tx.width * tx.height) / (meshAnalysisResults[propIdx].submeshArea);
                                }
                            }
                            //规格,偏移
                            GetMaterialScaleAndOffset(mat, data.texPropertyNames[propIdx].name, out offset, out scale);
                        }

                        mts[propIdx] = new MaterialPropTexture(tx, offset, scale, texelDensity);
                    }

                    // 收集材质参数值的平均值
                    data.nonTexturePropertyBlender.CollectAverageValuesOfNonTextureProperties(data.resultMaterial, mat);

                    Vector2 obUVscale  = new Vector2(meshAnalysisResults[matIdx].uvRect.width, meshAnalysisResults[matIdx].uvRect.height);
                    Vector2 obUVoffset = new Vector2(meshAnalysisResults[matIdx].uvRect.x, meshAnalysisResults[matIdx].uvRect.y);

                    //Add to distinct set of textures if not already there
                    TextureTilingTreatment tilingTreatment = TextureTilingTreatment.none;
                    if (data._fixOutOfBoundsUVs)
                    {
                        tilingTreatment = TextureTilingTreatment.considerUVs;
                    }

                    //合并信息 distinctMaterialTextures 数据设置

                    //材质各参数 Texture,及 UV 偏移数据映射
                    MaterialPropTexturesSet setOfTexs = new MaterialPropTexturesSet(mts, obUVoffset, obUVscale, tilingTreatment);  //one of these per submesh
                    //材质及各变化参数Rect 数据
                    MatAndTransformToMerged matt = new MatAndTransformToMerged(new DRect(obUVoffset, obUVscale), data._fixOutOfBoundsUVs, mat);

                    setOfTexs.matsAndGOs.mats.Add(matt);

                    MaterialPropTexturesSet setOfTexs2 = data.distinctMaterialTextures.Find(x => x.IsEqual(setOfTexs, data._fixOutOfBoundsUVs, data.nonTexturePropertyBlender));
                    if (setOfTexs2 != null)
                    {
                        setOfTexs = setOfTexs2;
                    }
                    else
                    {
                        data.distinctMaterialTextures.Add(setOfTexs);
                    }

                    if (!setOfTexs.matsAndGOs.mats.Contains(matt))
                    {
                        setOfTexs.matsAndGOs.mats.Add(matt);
                    }

                    if (!setOfTexs.matsAndGOs.gos.Contains(obj))
                    {
                        setOfTexs.matsAndGOs.gos.Add(obj);
                        //已使用 游戏物体
                        if (!usedObjsToMesh.Contains(obj))
                        {
                            usedObjsToMesh.Add(obj);
                        }
                    }
                }
            }

            Debug.Log(string.Format("第一阶段完成;" +
                                    "参与合并的游戏物体的不同材质,各自包含与shader属性对应的不同的纹理,收集到 {0} 组 textures,即 {0} 个不同的材质," +
                                    "fixOutOfBoundsUV:{1} " +
                                    "considerNonTextureProperties:{2}",
                                    data.distinctMaterialTextures.Count, data._fixOutOfBoundsUVs, data._considerNonTextureProperties));

            if (data.distinctMaterialTextures.Count == 0)
            {
                Debug.LogError("None of the source object materials matched any of the allowed materials for submesh with result material: " + data.resultMaterial);
                result.success = false;
                yield break;
            }

            TextureCombinerMerging merger = new TextureCombinerMerging(data._considerNonTextureProperties,
                                                                       data.nonTexturePropertyBlender, data._fixOutOfBoundsUVs);

            merger.MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects(data.distinctMaterialTextures);

            yield break;
        }
        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 virtual AtlasPackingResult[] CalculateAtlasRectangles(TexturePipelineData data, bool doMultiAtlas)
 {
     Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures());
     return(TextureCombinerPackerBase.CalculateAtlasRectanglesStatic(data, doMultiAtlas));
 }