/// <summary>
        /// 计算合并贴图 Atlas Rect
        /// </summary>
        /// <param name="data"></param>
        /// <param name="doMultiAtlas"></param>
        /// <returns></returns>
        public static AtlasPackingResult[] CalculateAtlasRectanglesStatic(TextureCombinePipelineData data, bool doMultiAtlas)
        {
            List <Vector2> imageSizes = new List <Vector2>();

            for (int i = 0; i < data.distinctMaterialTextures.Count; i++)
            {
                imageSizes.Add(new Vector2(data.distinctMaterialTextures[i].idealWidth, data.distinctMaterialTextures[i].idealHeight));
            }

            TexturePacker tp = CreateTexturePacker(data.packingAlgorithm);

            tp.atlasMustBePowerOfTwo = data.meshBakerTexturePackerForcePowerOfTwo;

            List <AtlasPadding> paddings = new List <AtlasPadding>();

            for (int i = 0; i < imageSizes.Count; i++)
            {
                AtlasPadding padding = new AtlasPadding();
                padding.topBottom = data.atlasPadding;
                padding.leftRight = data.atlasPadding;
                if (data.packingAlgorithm == PackingAlgorithmEnum.MeshBakerTexturePacker_Horizontal)
                {
                    padding.leftRight = 0;
                }
                if (data.packingAlgorithm == PackingAlgorithmEnum.MeshBakerTexturePacker_Vertical)
                {
                    padding.topBottom = 0;
                }
                paddings.Add(padding);
            }

            return(tp.GetRects(imageSizes, paddings, data.maxAtlasWidth, data.maxAtlasHeight, doMultiAtlas));
        }
 public static void CombineMaterial(List <GameObject> gameObjectToCombine, GameObjectCombineSetting setting, TextureCombinePipelineData data)
 {
     combineData    = data;
     combineSetting = setting;
     CreateCombinedMaterialInfoAsset(gameObjectToCombine);
     CreateAtlases(gameObjectToCombine);
 }
Beispiel #3
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();
        }
 internal static void CreateTemporaryTexturesForAtlas(List <MaterialPropTexturesSet> distinctMaterialTextures,
                                                      TextureCombineHandler combiner,
                                                      int propIdx,
                                                      TextureCombinePipelineData data)
 {
     for (int texSetIdx = 0; texSetIdx < data.distinctMaterialTextures.Count; texSetIdx++)
     {
         MaterialPropTexturesSet txs    = data.distinctMaterialTextures[texSetIdx];
         MaterialPropTexture     matTex = txs.ts[propIdx];
         if (matTex.isNull)
         {
             //create a small 16 x 16 texture to use in the atlas
             Color col = data.nonTexturePropertyBlender.GetColorForTemporaryTexture(txs.matsAndGOs.mats[0].mat, data.texPropertyNames[propIdx]);
             txs.CreateColoredTexToReplaceNull(data.texPropertyNames[propIdx].name, propIdx, data.fixOutOfBoundsUVs, combiner, col);
         }
     }
 }
 public virtual void ConvertTexturesToReadableFormats(
     TextureCombinePipelineData data,
     EditorMethodsInterface textureEditorMethods)
 {
     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();
                     textureEditorMethods.AddTextureFormat(
                         (Texture2D)tx, data.texPropertyNames[j].isNormalMap);
                 }
             }
         }
     }
 }
        // 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);
        }
 public virtual AtlasPackingResult[] CalculateAtlasRectangles(TextureCombinePipelineData data, bool doMultiAtlas)
 {
     return(CalculateAtlasRectanglesStatic(data, doMultiAtlas));
 }
 public abstract void CreateAtlases(TextureCombinePipelineData data,
                                    TextureCombineHandler combiner,
                                    AtlasPackingResult packedAtlasRects,
                                    Texture2D[] atlases,
                                    EditorMethodsInterface textureEditorMethods);
        private static TextureCombinePipelineData CreateCombineData(GameObjectCombineSetting setting)
        {
            var newCombineData = new TextureCombinePipelineData();

            return(newCombineData);
        }
Beispiel #10
0
        //第二步:计算每个材质的属性对应的 Textures 统一尺寸
        //每种材质(_mainTex,凹凸,Spec ect ...)中的纹理必须大小相同
        //计算要使用的最佳尺寸。 考虑平铺
        //如果图集中只有一种纹理会使用原始大小
        internal static void Step2_CalculateIdealSizesForTexturesInAtlasAndPadding(
            TextureCombinePipelineData data,
            EditorMethodsInterface textureEditorMethods)
        {
            MaterialPropTexture.readyToBuildAtlases = true;
            data.allTexturesAreNullAndSameColor     = CalculateAllTexturesAreNullAndSameColor(data);

            //计算 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;
        }
 public TextureCombiner()
 {
     combineData = new TextureCombinePipelineData();
 }
Beispiel #12
0
        internal static Vector2 GetAdjustedForScaleAndOffset2Dimensions(MaterialPropTexture source, Vector2 obUVoffset, Vector2 obUVscale, TextureCombinePipelineData 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));
        }
Beispiel #13
0
        //public static bool TextureCombineEntrance(TextureCombinePipelineData combineData,
        //    AtlasesAndRects resultAtlasesAndRectsData,
        //    Material resultMaterial)
        //{
        //    bool isCombineSuccess = false;
        //    MaterialPropTexture.readyToBuildAtlases = false;
        //    return isCombineSuccess;
        //}

        /// <summary>
        /// 收集材质参数名称
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        internal static bool CollectPropertyNames(TextureCombinePipelineData 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);
        }
Beispiel #14
0
 /// <summary>
 /// 检测所有 textures 中只有一种纹理
 /// </summary>
 /// <param name="data"></param>
 /// <returns></returns>
 private static CreateAtlasForProperty[] CalculateAllTexturesAreNullAndSameColor(TextureCombinePipelineData 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);
 }
Beispiel #15
0
        internal static void CopyScaledAndTiledToAtlas(MaterialPropTexture source,
                                                       MaterialPropTexturesSet sourceMaterial,
                                                       ShaderTextureProperty shaderPropertyName,
                                                       DRect srcSamplingRect,
                                                       int targX, int targY, int targW, int targH,
                                                       AtlasPadding padding,
                                                       Color[][] atlasPixels, bool isNormalMap,
                                                       TextureCombinePipelineData data,
                                                       TextureCombineHandler combiner)
        {
            //HasFinished = false;
            Texture2D t = source.GetTexture2D();

            Debug.Log(string.Format("CopyScaledAndTiledToAtlas: {0} inAtlasX={1} inAtlasY={2} inAtlasW={3} inAtlasH={4} paddX={5} paddY={6} srcSamplingRect={7}",
                                    t, targX, targY, targW, targH, padding.leftRight, padding.topBottom, srcSamplingRect));

            float newWidth  = targW;
            float newHeight = targH;
            float scx       = (float)srcSamplingRect.width;
            float scy       = (float)srcSamplingRect.height;
            float ox        = (float)srcSamplingRect.x;
            float oy        = (float)srcSamplingRect.y;
            int   w         = (int)newWidth;
            int   h         = (int)newHeight;

            if (data.considerNonTextureProperties)
            {
                t = combiner._createTextureCopy(shaderPropertyName.name, t);
                t = data.nonTexturePropertyBlender.TintTextureWithTextureCombiner(t, sourceMaterial, shaderPropertyName);
            }
            for (int i = 0; i < w; i++)
            {
                for (int j = 0; j < h; j++)
                {
                    float u = i / newWidth * scx + ox;
                    float v = j / newHeight * scy + oy;
                    atlasPixels[targY + j][targX + i] = t.GetPixelBilinear(u, v);
                }
            }

            //bleed the border colors into the padding
            for (int i = 0; i < w; i++)
            {
                for (int j = 1; j <= padding.topBottom; j++)
                {
                    //top margin
                    atlasPixels[(targY - j)][targX + i] = atlasPixels[(targY)][targX + i];
                    //bottom margin
                    atlasPixels[(targY + h - 1 + j)][targX + i] = atlasPixels[(targY + h - 1)][targX + i];
                }
            }
            for (int j = 0; j < h; j++)
            {
                for (int i = 1; i <= padding.leftRight; i++)
                {
                    //left margin
                    atlasPixels[(targY + j)][targX - i] = atlasPixels[(targY + j)][targX];
                    //right margin
                    atlasPixels[(targY + j)][targX + w + i - 1] = atlasPixels[(targY + j)][targX + w - 1];
                }
            }
            //corners
            for (int i = 1; i <= padding.leftRight; i++)
            {
                for (int j = 1; j <= padding.topBottom; j++)
                {
                    atlasPixels[(targY - j)][targX - i]                 = atlasPixels[targY][targX];
                    atlasPixels[(targY + h - 1 + j)][targX - i]         = atlasPixels[(targY + h - 1)][targX];
                    atlasPixels[(targY + h - 1 + j)][targX + w + i - 1] = atlasPixels[(targY + h - 1)][targX + w - 1];
                    atlasPixels[(targY - j)][targX + w + i - 1]         = atlasPixels[targY][targX + w - 1];
                }
            }
        }
Beispiel #16
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);
            }
        }
Beispiel #17
0
        /// <summary>
        /// 第一步:
        /// 写入 TexturePipelineData 的 MaterialPropTexturesSet 列表,和 usedObjsToMesh 列表
        /// 每个TexSet在 Atlas 中都是一个矩形。
        /// 如果 allowedMaterialsFilter (过滤器)为空,则将收集 allObjsToMesh 上的所有材质,usedObjsToMesh 将与allObjsToMesh相同
        /// 否则,将仅包括 allowedMaterialsFilter 中的材质,usedObjsToMesh将是使用这些材料的objs。
        /// </summary>
        internal static void Step1_CollectDistinctMatTexturesAndUsedObjects(TextureCombinePipelineData data,
                                                                            EditorMethodsInterface textureEditorMethods,
                                                                            List <GameObject> usedObjsToMesh)
        {
            // 收集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 (obj == null)
                {
                    Debug.LogError("合并游戏物体列表中包含空物体");
                    return;
                }

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

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

                //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);
                }

                //处理材质数据
                for (int matIdx = 0; matIdx < sharedMaterials.Length; matIdx++)
                {
                    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.");
                        return;
                    }

                    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'");
                                            return;
                                        }
                                        else
                                        {
                                            tx = (Texture2D)mat.GetTexture(data.texPropertyNames[propIdx].name);
                                        }
                                    }
                                }
                                else
                                {
                                    Debug.LogError("合并列表中,游戏物体 " + obj.name + " 渲染网格使用的 Texture 不是 Texture2D. ");
                                    return;
                                }
                            }
                            //像素密度
                            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);
                return;
            }

            TextureCombinerMerging merger = new TextureCombinerMerging(data.considerNonTextureProperties,
                                                                       data.nonTexturePropertyBlender, data.fixOutOfBoundsUVs);

            merger.MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects(data.distinctMaterialTextures);
        }