// 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);
        }
Beispiel #2
0
        public override void CreateAtlases(
            TextureCombinePipelineData data,
            TextureCombineHandler combiner,
            AtlasPackingResult packedAtlasRects,
            Texture2D[] atlases,
            EditorMethodsInterface textureEditorMethods)
        {
            Rect[] uvRects = packedAtlasRects.rects;

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

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

            for (int propIdx = 0; propIdx < data.numAtlases; propIdx++)
            {
                Texture2D             atlas    = null;
                ShaderTextureProperty property = data.texPropertyNames[propIdx];
                if (!TextureCombinePipeline.ShouldWeCreateAtlasForThisProperty(propIdx, data.considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                {
                    atlas = null;
                    Debug.Log("=== Not creating atlas for " + property.name + " because textures are null and default value parameters are the same.");
                }
                else
                {
                    Debug.Log("=== Creating atlas for " + property.name);
                    GC.Collect();
                    CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data);

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

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

                    for (int texSetIdx = 0; texSetIdx < data.distinctMaterialTextures.Count; texSetIdx++)
                    {
                        MaterialPropTexturesSet texSet = data.distinctMaterialTextures[texSetIdx];
                        MaterialPropTexture     matTex = texSet.ts[propIdx];
                        string s = "Creating Atlas '" + property.name + "' texture " + matTex.GetTexName();

                        Debug.Log(string.Format("Adding texture {0} to atlas {1} for texSet {2} srcMat {3}", matTex.GetTexName(), property.name, texSetIdx, texSet.matsAndGOs.mats[0].GetMaterialName()));

                        Rect      r  = uvRects[texSetIdx];
                        Texture2D t  = texSet.ts[propIdx].GetTexture2D();
                        int       x  = Mathf.RoundToInt(r.x * atlasSizeX);
                        int       y  = Mathf.RoundToInt(r.y * atlasSizeY);
                        int       ww = Mathf.RoundToInt(r.width * atlasSizeX);
                        int       hh = Mathf.RoundToInt(r.height * atlasSizeY);
                        if (ww == 0 || hh == 0)
                        {
                            Debug.LogError("Image in atlas has no height or width " + r);
                        }

                        if (textureEditorMethods != null)
                        {
                            textureEditorMethods.SetReadWriteFlag(t, true, true);
                        }
                        DRect samplingRect = texSet.ts[propIdx].GetEncapsulatingSamplingRect();
                        CopyScaledAndTiledToAtlas(texSet.ts[propIdx],
                                                  texSet,
                                                  property,
                                                  samplingRect,
                                                  x,
                                                  y,
                                                  ww,
                                                  hh,
                                                  packedAtlasRects.padding[texSetIdx],
                                                  atlasPixels,
                                                  isNormalMap,
                                                  data,
                                                  combiner);
                    }

                    atlas = new Texture2D(atlasSizeX, atlasSizeY, TextureFormat.ARGB32, true);
                    for (int j = 0; j < atlasPixels.Length; j++)
                    {
                        atlas.SetPixels(0, j, atlasSizeX, 1, atlasPixels[j]);
                    }

                    atlas.Apply();
                    Debug.Log("Saving atlas " + property.name + " w=" + atlas.width + " h=" + atlas.height);
                }

                atlases[propIdx] = atlas;

                if (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);
            }
        }
        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();
            }
        }