Beispiel #1
0
        /// <summary>
        /// 运行时图片打包
        /// </summary>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="splitAtlasWhenPackingIfTooBig"></param>
        /// <param name="textureEditorMethods"></param>
        /// <param name="packingResult"></param>
        /// <returns></returns>
        IEnumerator __RunTexturePackerOnly(CombineTexturesIntoAtlasesCoroutineResult result,
                                           TexturePipelineData data,
                                           bool splitAtlasWhenPackingIfTooBig,
                                           EditorMethodsInterface textureEditorMethods,
                                           List <AtlasPackingResult> packingResult)
        {
            Debug.Log("__RunTexturePacker texture properties in shader:" + data.texPropertyNames.Count + " objsToMesh:" + data.allObjsToMesh.Count + " _fixOutOfBoundsUVs:" + data._fixOutOfBoundsUVs);
            List <GameObject> usedObjsToMesh = new List <GameObject>();

            yield return(TextureCombinerPipeline.__Step1_CollectDistinctMatTexturesAndUsedObjects(null, result, data, textureEditorMethods, usedObjsToMesh));

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

            data.allTexturesAreNullAndSameColor = new TextureCombinerPipeline.CreateAtlasForProperty[data.texPropertyNames.Count];
            yield return(TextureCombinerPipeline._Step2_CalculateIdealSizesForTexturesInAtlasAndPadding(null, result, data, textureEditorMethods));

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

            ITextureCombinerPacker texturePaker = TextureCombinerPipeline.CreatePacker(data.IsOnlyOneTextureInAtlasReuseTextures(), data._packingAlgorithm);

            //    run the texture packer only
            AtlasPackingResult[] aprs = TextureCombinerPipeline.RunTexturePackerOnly(data, splitAtlasWhenPackingIfTooBig, texturePaker);
            for (int i = 0; i < aprs.Length; i++)
            {
                packingResult.Add(aprs[i]);
            }
        }
Beispiel #2
0
        /// <summary>
        /// 合并贴图形成纹理图集
        /// </summary>
        public bool CombineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo,
                                               AtlasesAndRects resultAtlasesAndRects,
                                               Material resultMaterial,
                                               List <GameObject> objsToMesh,
                                               List <Material> allowedMaterialsFilter,
                                               EditorMethodsInterface textureEditorMethods = null,
                                               List <AtlasPackingResult> packingResults    = null,
                                               bool onlyPackRects = false,
                                               bool splitAtlasWhenPackingIfTooBig = false)
        {
            CombineTexturesIntoAtlasesCoroutineResult result = new CombineTexturesIntoAtlasesCoroutineResult();

            RunCorutineWithoutPause(
                _CombineTexturesIntoAtlases(
                    progressInfo,
                    result,
                    resultAtlasesAndRects,
                    resultMaterial,
                    objsToMesh,
                    allowedMaterialsFilter,
                    textureEditorMethods,
                    packingResults,
                    onlyPackRects,
                    splitAtlasWhenPackingIfTooBig
                    ),
                0);
            if (result.success == false)
            {
                Debug.LogError("Failed to generate atlases.");
            }
            return(result.success);
        }
Beispiel #3
0
        //float _maxTimePerFrameForCoroutine;
        public IEnumerator CombineTexturesIntoAtlasesCoroutine(ProgressUpdateDelegate progressInfo,
                                                               AtlasesAndRects resultAtlasesAndRects,
                                                               Material resultMaterial,
                                                               List <GameObject> objsToMesh,
                                                               List <Material> allowedMaterialsFilter,
                                                               EditorMethodsInterface textureEditorMethods = null,
                                                               CombineTexturesIntoAtlasesCoroutineResult coroutineResult = null,
                                                               float maxTimePerFrame = .01f,
                                                               List <AtlasPackingResult> packingResults = null,
                                                               bool onlyPackRects = false,
                                                               bool splitAtlasWhenPackingIfTooBig = false)
        {
            coroutineResult.success    = true;
            coroutineResult.isFinished = false;
            if (maxTimePerFrame <= 0f)
            {
                Debug.LogError("maxTimePerFrame must be a value greater than zero");
                coroutineResult.isFinished = true;
                yield break;
            }
            //_maxTimePerFrameForCoroutine = maxTimePerFrame;
            yield return(_CombineTexturesIntoAtlases(progressInfo,
                                                     coroutineResult,
                                                     resultAtlasesAndRects,
                                                     resultMaterial,
                                                     objsToMesh,
                                                     allowedMaterialsFilter,
                                                     textureEditorMethods,
                                                     packingResults,
                                                     onlyPackRects,
                                                     splitAtlasWhenPackingIfTooBig));

            coroutineResult.isFinished = true;
            yield break;
        }
Beispiel #4
0
 public virtual IEnumerator ConvertTexturesToReadableFormats(ProgressUpdateDelegate progressInfo,
                                                             CombineTexturesIntoAtlasesCoroutineResult result,
                                                             TexturePipelineData data,
                                                             TextureCombineHandler combiner,
                                                             EditorMethodsInterface textureEditorMethods)
 {
     Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures());
     //MakeProceduralTexturesReadable(progressInfo, result, data, combiner, textureEditorMethods, LOG_LEVEL);
     for (int i = 0; i < data.distinctMaterialTextures.Count; i++)
     {
         for (int j = 0; j < data.texPropertyNames.Count; j++)
         {
             MaterialPropTexture ts = data.distinctMaterialTextures[i].ts[j];
             if (!ts.isNull)
             {
                 if (textureEditorMethods != null)
                 {
                     Texture tx = ts.GetTexture2D();
                     if (progressInfo != null)
                     {
                         progressInfo(String.Format("Convert texture {0} to readable format ", tx), .5f);
                     }
                     textureEditorMethods.AddTextureFormat((Texture2D)tx, data.texPropertyNames[j].isNormalMap);
                 }
             }
         }
     }
     yield break;
 }
 public IEnumerator ConvertTexturesToReadableFormats(ProgressUpdateDelegate progressInfo,
                                                     CombineTexturesIntoAtlasesCoroutineResult result,
                                                     TexturePipelineData data,
                                                     TextureCombineHandler combiner,
                                                     EditorMethodsInterface textureEditorMethods)
 {
     Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures());
     yield break;
 }
Beispiel #6
0
        // texPropertyNames 是 resultMaterial中纹理属性的列表
        // allowedMaterialsFilter 是材料列表。 没有这些材料的物体将被忽略。这由多种材质过滤器使用
        // textureEditorMethods 仅封装编辑器功能,例如保存资产和跟踪纹理资产谁的格式已更改。 如果在运行时使用,则为null。
        IEnumerator __CombineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo,
                                                 CombineTexturesIntoAtlasesCoroutineResult result,
                                                 AtlasesAndRects resultAtlasesAndRects,
                                                 TexturePipelineData data,
                                                 bool splitAtlasWhenPackingIfTooBig,
                                                 EditorMethodsInterface textureEditorMethods)
        {
            if (progressInfo != null)
            {
                progressInfo("Collecting textures ", .01f);
            }

            // --- 1、记录各合并物体的源材质的 Prop Texture 信息写入 Data.distinctMaterialTextures
            //每个图集(主图,凹凸等)都将有的 MaterialTextures.Count 个图像。
            //每个 distinctMaterialTextures 对应一个游戏物体的某个材质,记录一组纹理,分别材质的在每个Prop图集一个。
            List <GameObject> usedObjsToMesh = new List <GameObject>();

            yield return(TextureCombinerPipeline.__Step1_CollectDistinctMatTexturesAndUsedObjects(progressInfo, result, data, textureEditorMethods, usedObjsToMesh));

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

            // --- 2、计算使每个材质属性中的多个材质的合理尺寸
            yield return(TextureCombinerPipeline._Step2_CalculateIdealSizesForTexturesInAtlasAndPadding(progressInfo, result, data, textureEditorMethods));

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

            // --- 3、创建特定打包方式的打包器
            ITextureCombinerPacker texturePaker = TextureCombinerPipeline.CreatePacker(data.IsOnlyOneTextureInAtlasReuseTextures(), data._packingAlgorithm);

            yield return(texturePaker.ConvertTexturesToReadableFormats(progressInfo, result, data, this, textureEditorMethods));

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

            // --- 4、计算各源材质在合并材质 Atlas 的排布
            AtlasPackingResult[] uvRects = texturePaker.CalculateAtlasRectangles(data, splitAtlasWhenPackingIfTooBig);

            // --- 5、创建 Atlas 并保存
            yield return(TextureCombinerPipeline.__Step3_BuildAndSaveAtlasesAndStoreResults(progressInfo,
                                                                                            result,
                                                                                            data,
                                                                                            this,
                                                                                            texturePaker,
                                                                                            uvRects[0],
                                                                                            textureEditorMethods,
                                                                                            resultAtlasesAndRects));
        }
Beispiel #7
0
        public static void MakeProceduralTexturesReadable(ProgressUpdateDelegate progressInfo,
                                                          CombineTexturesIntoAtlasesCoroutineResult result,
                                                          TexturePipelineData data,
                                                          TextureCombineHandler combiner,
                                                          EditorMethodsInterface textureEditorMethods)
        {
            Debug.LogError("TODO this should be done as close to textures being used as possible due to memory issues.");
            //make procedural materials readable

            /*
             * for (int i = 0; i < combiner._proceduralMaterials.Count; i++)
             * {
             *  if (!combiner._proceduralMaterials[i].proceduralMat.isReadable)
             *  {
             *      combiner._proceduralMaterials[i].originalIsReadableVal = combiner._proceduralMaterials[i].proceduralMat.isReadable;
             *      combiner._proceduralMaterials[i].proceduralMat.isReadable = true;
             *      //textureEditorMethods.AddProceduralMaterialFormat(_proceduralMaterials[i].proceduralMat);
             *      combiner._proceduralMaterials[i].proceduralMat.RebuildTexturesImmediately();
             *  }
             * }
             * //convert procedural textures to RAW format
             *
             * for (int i = 0; i < distinctMaterialTextures.Count; i++)
             * {
             *  for (int j = 0; j < texPropertyNames.Count; j++)
             *  {
             *      if (distinctMaterialTextures[i].ts[j].IsProceduralTexture())
             *      {
             *          if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Converting procedural texture to Textur2D:" + distinctMaterialTextures[i].ts[j].GetTexName() + " property:" + texPropertyNames[i]);
             *          Texture2D txx = distinctMaterialTextures[i].ts[j].ConvertProceduralToTexture2D(_temporaryTextures);
             *          distinctMaterialTextures[i].ts[j].t = txx;
             *      }
             *  }
             * }
             */
        }
Beispiel #8
0
        IEnumerator _CombineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo,
                                                CombineTexturesIntoAtlasesCoroutineResult result,
                                                AtlasesAndRects resultAtlasesAndRects,
                                                Material resultMaterial,
                                                List <GameObject> objsToMesh,
                                                List <Material> allowedMaterialsFilter,
                                                EditorMethodsInterface textureEditorMethods,
                                                List <AtlasPackingResult> atlasPackingResult,
                                                bool onlyPackRects,
                                                bool splitAtlasWhenPackingIfTooBig)
        {
            try
            {
                _temporaryTextures.Clear();
                MaterialPropTexture.readyToBuildAtlases = false;

                // ---- 0.合并材质前回调
                if (textureEditorMethods != null)
                {
                    textureEditorMethods.Clear();
                    textureEditorMethods.OnPreTextureBake();
                }

                // ---- 1.合并材质参数校验
                if (objsToMesh == null || objsToMesh.Count == 0)
                {
                    Debug.LogError("没有游戏物体参与合并");
                    result.success = false;
                    yield break;
                }

                if (_atlasPadding < 0)
                {
                    Debug.LogError("Atlas padding 必须大于等于零");
                    result.success = false;
                    yield break;
                }

                if (_maxTilingBakeSize < 2 || _maxTilingBakeSize > 4096)
                {
                    Debug.LogError("无效Tilling尺寸的值Invalid value for max tiling bake size.");
                    result.success = false;
                    yield break;
                }

                for (int i = 0; i < objsToMesh.Count; i++)
                {
                    Material[] ms = MeshBakerUtility.GetGOMaterials(objsToMesh[i]);
                    for (int j = 0; j < ms.Length; j++)
                    {
                        Material m = ms[j];
                        if (m == null)
                        {
                            Debug.LogError("游戏物体" + objsToMesh[i] + " 材质为空 ");
                            result.success = false;
                            yield break;
                        }
                    }
                }

                if (_fixOutOfBoundsUVs && (_packingAlgorithm == PackingAlgorithmEnum.MeshBakerTexturePacker_Horizontal ||
                                           _packingAlgorithm == PackingAlgorithmEnum.MeshBakerTexturePacker_Vertical))
                {
                    Debug.LogWarning("合并算法为 MeshBakerTexturePacker_Horizontal 或 MeshBakerTexturePacker_Vertical,建议不打开 Consider Mesh UVs 选项");
                }

                if (progressInfo != null)
                {
                    progressInfo("Collecting textures for " + objsToMesh.Count + " meshes.", .01f);
                }

                // ---- 2.创建材质合并管线数据
                TexturePipelineData data = CreatePipelineData(resultMaterial,
                                                              new List <ShaderTextureProperty>(),
                                                              objsToMesh,
                                                              allowedMaterialsFilter,
                                                              new List <MaterialPropTexturesSet>());

                // ---- 3.将材质的 shader 各参数信息写入管线数据中
                if (!TextureCombinerPipeline._CollectPropertyNames(data))
                {
                    result.success = false;
                    yield break;
                }

                // ---- 4.加载 Texture 混合器
                data.nonTexturePropertyBlender.LoadTextureBlendersIfNeeded(data.resultMaterial);

                // ---- 5.选择本地合并,或运行时合并
                if (onlyPackRects)
                {
                    yield return(__RunTexturePackerOnly(result, data, splitAtlasWhenPackingIfTooBig, textureEditorMethods, atlasPackingResult));
                }
                else
                {
                    yield return(__CombineTexturesIntoAtlases(progressInfo, result, resultAtlasesAndRects, data, splitAtlasWhenPackingIfTooBig, textureEditorMethods));
                }
            }
            finally
            {
                // ---- 6.删除缓存,合并材质完成回调
                _destroyAllTemporaryTextures();
                if (textureEditorMethods != null)
                {
                    textureEditorMethods.RestoreReadFlagsAndFormats(progressInfo);
                    textureEditorMethods.OnPostTextureBake();
                }
            }
        }
        /// <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;
        }
Beispiel #12
0
        /// <summary>
        /// 创建贴图 Atlas 协程
        /// </summary>
        /// <returns></returns>
        public IEnumerator CreateAtlasesCoroutine(ProgressUpdateDelegate progressInfo,
                                                  CreateAtlasesCoroutineResult coroutineResult,
                                                  bool saveAtlasesAsAssets             = false,
                                                  EditorMethodsInterface editorMethods = null,
                                                  float maxTimePerFrame = .01f)
        {
            OnCombinedTexturesCoroutineAtlasesAndRects = null;

            //--- 1、合并前检测
            if (maxTimePerFrame <= 0f)
            {
                Debug.LogError("maxTimePerFrame must be a value greater than zero");
                coroutineResult.isFinished = true;
                yield break;
            }

            //验证等级
            ValidationLevel vl = Application.isPlaying ? ValidationLevel.quick : ValidationLevel.robust;

            //验证
            if (!DoCombinedValidate(this, ObjsToCombineTypes.dontCare, null, vl))
            {
                coroutineResult.isFinished = true;
                yield break;
            }

            //合并为多材质验证
            if (_doMultiMaterial && !_ValidateResultMaterials())
            {
                coroutineResult.isFinished = true;
                yield break;
            }
            else if (!_doMultiMaterial)
            {
                //合并为单独材质
                if (_resultMaterial == null)
                {
                    Debug.LogError("Combined Material is null please create and assign a result material.");
                    coroutineResult.isFinished = true;
                    yield break;
                }
                Shader targShader = _resultMaterial.shader;
                for (int i = 0; i < objsToMesh.Count; i++)
                {
                    Material[] ms = MeshBakerUtility.GetGOMaterials(objsToMesh[i]);
                    for (int j = 0; j < ms.Length; j++)
                    {
                        Material m = ms[j];
                        if (m != null && m.shader != targShader)
                        {
                            Debug.LogWarning("游戏物体" + objsToMesh[i] + " 没有使用 shader " + targShader +
                                             " it may not have the required textures. " +
                                             "If not small solid color textures will be generated.");
                        }
                    }
                }
            }

            TextureCombineHandler combiner = CreateAndConfigureTextureCombiner();

            combiner.saveAtlasesAsAssets = saveAtlasesAsAssets;

            ////--- 2、初始化存储合并结果的数据结构
            int numResults = 1;

            if (_doMultiMaterial)
            {
                numResults = resultMaterials.Length;
            }

            OnCombinedTexturesCoroutineAtlasesAndRects = new AtlasesAndRects[numResults];
            for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++)
            {
                OnCombinedTexturesCoroutineAtlasesAndRects[i] = new AtlasesAndRects();
            }

            //--- 3、开始合并材质(单个,多个)
            for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++)
            {
                Material        resMatToPass;
                List <Material> sourceMats;
                if (_doMultiMaterial)
                {
                    sourceMats   = resultMaterials[i].sourceMaterials;
                    resMatToPass = resultMaterials[i].combinedMaterial;
                    combiner.fixOutOfBoundsUVs = resultMaterials[i].considerMeshUVs;
                }
                else
                {
                    resMatToPass = _resultMaterial;
                    sourceMats   = null;
                }

                //TextureHandler 材质合并协程结果
                CombineTexturesIntoAtlasesCoroutineResult coroutineResult2 = new CombineTexturesIntoAtlasesCoroutineResult();
                yield return(combiner.CombineTexturesIntoAtlasesCoroutine(progressInfo,
                                                                          OnCombinedTexturesCoroutineAtlasesAndRects[i],
                                                                          resMatToPass,
                                                                          objsToMesh,
                                                                          sourceMats,
                                                                          editorMethods,
                                                                          coroutineResult2,
                                                                          maxTimePerFrame));

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

            //--- 4、TextureBakeResults 保存合并结果
            unpackMat2RectMap(textureBakeResults);
            textureBakeResults.doMultiMaterial = _doMultiMaterial;
            if (_doMultiMaterial)
            {
                textureBakeResults.resultMaterials = resultMaterials;
            }
            else
            {
                MultiMaterial[] resMats = new MultiMaterial[1];
                resMats[0] = new MultiMaterial();
                resMats[0].combinedMaterial = _resultMaterial;
                resMats[0].considerMeshUVs  = _fixOutOfBoundsUVs;
                resMats[0].sourceMaterials  = new List <Material>();
                for (int i = 0; i < textureBakeResults.materialsAndUVRects.Length; i++)
                {
                    resMats[0].sourceMaterials.Add(textureBakeResults.materialsAndUVRects[i].material);
                }
                textureBakeResults.resultMaterials = resMats;
            }

            //--- 5、传递合并结果到 MeshCombiner
            MeshBakerCommon[] mb = GetComponentsInChildren <MeshBakerCommon>();
            for (int i = 0; i < mb.Length; i++)
            {
                mb[i].textureBakeResults = textureBakeResults;
            }
            coroutineResult.isFinished = true;

            //--- 6、合并材质结束回调
            if (coroutineResult.success && onBuiltAtlasesSuccess != null)
            {
                onBuiltAtlasesSuccess();
            }
            if (!coroutineResult.success && onBuiltAtlasesFail != null)
            {
                onBuiltAtlasesFail();
            }
        }