예제 #1
0
        /// <summary>
        ///  Texture 合并管线第 3 步,创建 Atlas 并保存资源
        /// </summary>
        /// <returns></returns>
        internal static void Step3_BuildAndSaveAtlasesAndStoreResults(
            TextureCombinePipelineData data,
            TextureCombineHandler combiner,
            ITextureCombineAtlasPacker 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);

            //创建图集
            packer.CreateAtlases(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);
            }

            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;

            combiner._destroyAllTemporaryTextures();
        }
        // texPropertyNames 是 resultMaterial中纹理属性的列表
        // allowedMaterialsFilter 是材料列表。 没有这些材料的物体将被忽略。这由多种材质过滤器使用
        // textureEditorMethods 仅封装编辑器功能,例如保存资产和跟踪纹理资产谁的格式已更改。 如果在运行时使用,则为null。
        static void BeginCombineTexturesIntoAtlases(AtlasesAndRects resultAtlasesAndRects,
                                                    TextureCombinePipelineData data,
                                                    bool splitAtlasWhenPackingIfTooBig,
                                                    EditorMethodsInterface textureEditorMethods)
        {
            // --- 1、记录各合并物体的源材质的 Prop Texture 信息写入 Data.distinctMaterialTextures
            //每个图集(主图,凹凸等)都将有的 MaterialTextures.Count 个图像。
            //每个 distinctMaterialTextures 对应一个游戏物体的某个材质,记录一组纹理,分别材质的在每个Prop图集一个。
            List <GameObject> usedObjsToMesh = new List <GameObject>();

            TextureCombinePipeline.Step1_CollectDistinctMatTexturesAndUsedObjects(
                data, textureEditorMethods, usedObjsToMesh);

            // --- 2、计算使每个材质属性中的多个材质的合理尺寸
            TextureCombinePipeline.Step2_CalculateIdealSizesForTexturesInAtlasAndPadding(
                data, textureEditorMethods);


            // --- 3、创建特定打包方式的打包器
            ITextureCombineAtlasPacker texturePaker = CreateAtlasPacker(
                data.IsOnlyOneTextureInAtlasReuseTextures(),
                data.packingAlgorithm);

            texturePaker.ConvertTexturesToReadableFormats(data, textureEditorMethods);


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

            // --- 5、创建 Atlas 并保存
            TextureCombinePipeline.Step3_BuildAndSaveAtlasesAndStoreResults(
                data,
                null,
                texturePaker,
                uvRects[0],
                textureEditorMethods,
                resultAtlasesAndRects);
        }
        static void CombineTexturesIntoAtlases(AtlasesAndRects resultAtlasesAndRects,
                                               Material resultMaterial,
                                               List <GameObject> objsToMesh,
                                               List <Material> allowedMaterialsFilter,
                                               EditorMethodsInterface textureEditorMethods,
                                               bool splitAtlasWhenPackingIfTooBig = false)
        {
            try
            {
                MaterialPropTexture.readyToBuildAtlases = false;

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

                if (combineData.atlasPadding < 0)
                {
                    Debug.LogError("Atlas padding 必须大于等于零");
                    return;
                }

                if (combineData.maxTilingBakeSize < 2 || combineData.maxTilingBakeSize > 4096)
                {
                    Debug.LogError("无效Tilling尺寸的值Invalid value for max tiling bake size.");
                }

                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] + " 材质为空 ");
                        }
                    }
                }

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

                // ---- 2.将材质的 shader 各参数信息写入管线数据中
                if (!TextureCombinePipeline.CollectPropertyNames(combineData))
                {
                    return;
                }

                // ---- 3.加载 Texture 混合器
                combineData.nonTexturePropertyBlender.LoadTextureBlendersIfNeeded(combineData.ResultMaterial);

                // ---- 4.合并管道
                BeginCombineTexturesIntoAtlases(resultAtlasesAndRects, combineData, splitAtlasWhenPackingIfTooBig, textureEditorMethods);
            }
            finally
            {
                // ---- 6.删除缓存,合并材质完成回调
                //_destroyAllTemporaryTextures();
            }
        }
        /// <summary>
        /// 创建图集
        /// </summary>
        public static void CreateAtlases(List <GameObject> GameObjectsToCombine,
                                         bool saveAtlasesAsAssets = false)
        {
            try
            {
                combineData.ResultAtlasesAndRects = null;
                combineData.saveAtlasesAsAssets   = saveAtlasesAsAssets;
                //--- 1、合并前检测
                if (!ValidateCombineGameObject(GameObjectsToCombine))
                {
                    return;
                }

                //材质验证
                if (combineData.DoMultiMaterial)
                {
                    if (!_ValidateResultMaterials(GameObjectsToCombine, combineData.ResultMaterials))
                    {
                        return;
                    }
                }
                else
                {
                    if (!ValidateSingleResultMaterial(GameObjectsToCombine, combineData.ResultMaterial))
                    {
                        return;
                    }
                }


                ////--- 2、初始化存储合并结果的数据结构
                int numResults = 1;
                if (combineData.DoMultiMaterial)
                {
                    numResults = combineData.ResultMaterials.Length;
                }

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

                //--- 3、开始合并材质(单个,多个)
                for (int i = 0; i < combineData.ResultAtlasesAndRects.Length; i++)
                {
                    Material        resultMat;
                    List <Material> sourceMats;
                    if (combineData.DoMultiMaterial)
                    {
                        sourceMats = combineData.ResultMaterials[i].sourceMaterials;
                        resultMat  = combineData.ResultMaterials[i].combinedMaterial;
                        combineData.fixOutOfBoundsUVs = combineData.ResultMaterials[i].considerMeshUVs;
                    }
                    else
                    {
                        resultMat  = combineData.ResultMaterial;
                        sourceMats = null;  //为空则为全部合并
                    }

                    CombineTexturesIntoAtlases(combineData.ResultAtlasesAndRects[i],
                                               resultMat,
                                               GameObjectsToCombine,
                                               sourceMats,
                                               null);
                }

                //--- 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();
                //}
            }
            catch (Exception e)
            {
                Debug.LogError(e);
            }
            finally
            {
                if (saveAtlasesAsAssets)
                { //Atlases were saved to project so we don't need these ones
                    if (combineData.ResultAtlasesAndRects != null)
                    {
                        for (int j = 0; j < combineData.ResultAtlasesAndRects.Length; j++)
                        {
                            AtlasesAndRects mAndA = combineData.ResultAtlasesAndRects[j];
                            if (mAndA != null && mAndA.atlases != null)
                            {
                                for (int i = 0; i < mAndA.atlases.Length; i++)
                                {
                                    if (mAndA.atlases[i] != null)
                                    {
                                        //if (editorMethods != null)
                                        //{
                                        //    editorMethods.Destroy(mAndA.atlases[i]);
                                        //}
                                        //else
                                        //{
                                        MeshBakerUtility.Destroy(mAndA.atlases[i]);
                                        //}
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }