Beispiel #1
0
        //assumes all materials use the same obUVrects.
        //假设所有材料都使用相同的obUVrects。
        internal void CalcInitialFullSamplingRects(bool fixOutOfBoundsUVs)
        {
            DRect validFullSamplingRect = new DRect(0, 0, 1, 1);

            if (fixOutOfBoundsUVs)
            {
                validFullSamplingRect = obUVrect;
            }

            for (int propIdx = 0; propIdx < ts.Length; propIdx++)
            {
                if (!ts[propIdx].isNull)
                {
                    DRect matTiling = ts[propIdx].matTilingRect;
                    DRect ruv;
                    if (fixOutOfBoundsUVs)
                    {
                        ruv = obUVrect;
                    }
                    else
                    {
                        ruv = new DRect(0.0, 0.0, 1.0, 1.0);
                    }

                    ts[propIdx].SetEncapsulatingSamplingRect(this, UVRectUtility.CombineTransforms(ref ruv, ref matTiling));
                    validFullSamplingRect = ts[propIdx].GetEncapsulatingSamplingRect();
                }
            }

            //if some of the textures were null make them match the sampling of one of the other textures
            for (int propIdx = 0; propIdx < ts.Length; propIdx++)
            {
                if (ts[propIdx].isNull)
                {
                    ts[propIdx].SetEncapsulatingSamplingRect(this, validFullSamplingRect);
                }
            }
        }
 public MatAndTransformToMerged(DRect obUVrect, bool fixOutOfBoundsUVs, Material m)
 {
     _init(obUVrect, fixOutOfBoundsUVs, m);
 }
 public MatAndTransformToMerged(DRect obUVrect, bool fixOutOfBoundsUVs)
 {
     _init(obUVrect, fixOutOfBoundsUVs, null);
 }
        /// <summary>
        /// 为材料平铺和采样矩形和UV平铺分配初始值
        /// </summary>
        /// <param name="allTexturesUseSameMatTiling"></param>
        /// <param name="matTiling"></param>
        public void AssignInitialValuesForMaterialTilingAndSamplingRectMatAndUVTiling(bool allTexturesUseSameMatTiling, DRect matTiling)
        {
            if (allTexturesUseSameMatTiling)
            {
                materialTiling = matTiling;
            }
            else
            {
                materialTiling = new DRect(0f, 0f, 1f, 1f);
            }
            DRect tmpMatTiling = materialTiling;
            DRect obUVrect     = obUVRectIfTilingSame;

            samplingRectMatAndUVTiling = UVRectUtility.CombineTransforms(ref obUVrect, ref tmpMatTiling);
        }
        public override IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                                  TexturePipelineData 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 (!TextureCombinerPipeline._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();
                        if (progressInfo != null)
                        {
                            progressInfo(s, .01f);
                        }
                        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 (progressInfo != null)
                        {
                            progressInfo(s + " set ReadWrite flag", .01f);
                        }
                        if (textureEditorMethods != null)
                        {
                            textureEditorMethods.SetReadWriteFlag(t, true, true);
                        }
                        if (progressInfo != null)
                        {
                            progressInfo(s + "Copying to atlas: '" + matTex.GetTexName() + "'", .02f);
                        }
                        DRect samplingRect = texSet.ts[propIdx].GetEncapsulatingSamplingRect();
                        Debug.Assert(!texSet.ts[propIdx].isNull, string.Format("Adding texture {0} to atlas {1} for texSet {2} srcMat {3}",
                                                                               matTex.GetTexName(), property.name, texSetIdx, texSet.matsAndGOs.mats[0].GetMaterialName()));
                        yield return(CopyScaledAndTiledToAtlas(texSet.ts[propIdx],
                                                               texSet,
                                                               property,
                                                               samplingRect,
                                                               x,
                                                               y,
                                                               ww,
                                                               hh,
                                                               packedAtlasRects.padding[texSetIdx],
                                                               atlasPixels,
                                                               isNormalMap,
                                                               data,
                                                               combiner,
                                                               progressInfo));
                    }

                    yield return(data.numAtlases);

                    if (progressInfo != null)
                    {
                        progressInfo("Applying changes to atlas: '" + property.name + "'", .03f);
                    }
                    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 (progressInfo != null)
                {
                    progressInfo("Saving atlas: '" + property.name + "'", .04f);
                }
                if (data._saveAtlasesAsAssets && textureEditorMethods != null)
                {
                    textureEditorMethods.SaveAtlasToAssetDatabase(atlases[propIdx], data.texPropertyNames[propIdx], propIdx, data.resultMaterial);
                }
                else
                {
                    data.resultMaterial.SetTexture(data.texPropertyNames[propIdx].name, atlases[propIdx]);
                }

                data.resultMaterial.SetTextureOffset(data.texPropertyNames[propIdx].name, Vector2.zero);
                data.resultMaterial.SetTextureScale(data.texPropertyNames[propIdx].name, Vector2.one);
                combiner._destroyTemporaryTextures(data.texPropertyNames[propIdx].name);
            }

            yield break;
        }
        internal static IEnumerator CopyScaledAndTiledToAtlas(MaterialPropTexture source, MaterialPropTexturesSet sourceMaterial,
                                                              ShaderTextureProperty shaderPropertyName, DRect srcSamplingRect, int targX, int targY, int targW, int targH,
                                                              AtlasPadding padding,
                                                              Color[][] atlasPixels, bool isNormalMap,
                                                              TexturePipelineData data,
                                                              TextureCombineHandler combiner,
                                                              ProgressUpdateDelegate progressInfo = null)
        {
            //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++)
            {
                if (progressInfo != null && w > 0)
                {
                    progressInfo("CopyScaledAndTiledToAtlas " + (((float)i / (float)w) * 100f).ToString("F0"), .2f);
                }
                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];
                    yield return(null);
                }
                yield return(null);
            }
            yield break;
        }
Beispiel #7
0
        public void SuggestTreatment(List <GameObject> objsToMesh, Material[] resultMaterials, List <ShaderTextureProperty> _customShaderPropNames)
        {
            this._customShaderPropNames = _customShaderPropNames;
            StringBuilder sb = new StringBuilder();
            Dictionary <int, MeshAnalysisResult[]> meshAnalysisResultsCache = new Dictionary <int, MeshAnalysisResult[]>(); //cache results

            for (int i = 0; i < objsToMesh.Count; i++)
            {
                GameObject obj = objsToMesh[i];
                if (obj == null)
                {
                    continue;
                }
                Material[] ms = MeshBakerUtility.GetGOMaterials(objsToMesh[i]);
                if (ms.Length > 1)
                { // and each material is not mapped to its own layer
                    sb.AppendFormat("\nObject {0} uses {1} materials. Possible treatments:\n", objsToMesh[i].name, ms.Length);
                    sb.AppendFormat("  1) Collapse the submeshes together into one submesh in the combined mesh. Each of the original submesh materials will map to a different UV rectangle in the atlas(es) used by the combined material.\n");
                    sb.AppendFormat("  2) Use the multiple materials feature to map submeshes in the source mesh to submeshes in the combined mesh.\n");
                }
                Mesh m = MeshBakerUtility.GetMesh(obj);

                MeshAnalysisResult[] mar;
                if (!meshAnalysisResultsCache.TryGetValue(m.GetInstanceID(), out mar))
                {
                    mar = new MeshAnalysisResult[m.subMeshCount];
                    MeshBakerUtility.doSubmeshesShareVertsOrTris(m, ref mar[0]);
                    for (int j = 0; j < m.subMeshCount; j++)
                    {
                        MeshBakerUtility.hasOutOfBoundsUVs(m, ref mar[j], j);
                        //DRect outOfBoundsUVRect = new DRect(mar[j].uvRect);
                        mar[j].hasOverlappingSubmeshTris  = mar[0].hasOverlappingSubmeshTris;
                        mar[j].hasOverlappingSubmeshVerts = mar[0].hasOverlappingSubmeshVerts;
                    }
                    meshAnalysisResultsCache.Add(m.GetInstanceID(), mar);
                }

                for (int j = 0; j < ms.Length; j++)
                {
                    if (mar[j].hasOutOfBoundsUVs)
                    {
                        DRect r = new DRect(mar[j].uvRect);
                        sb.AppendFormat("\nObject {0} submesh={1} material={2} uses UVs outside the range 0,0 .. 1,1 to create tiling that tiles the box {3},{4} .. {5},{6}. This is a problem because the UVs outside the 0,0 .. 1,1 " +
                                        "rectangle will pick up neighboring textures in the atlas. Possible Treatments:\n", obj, j, ms[j], r.x.ToString("G4"), r.y.ToString("G4"), (r.x + r.width).ToString("G4"), (r.y + r.height).ToString("G4"));
                        sb.AppendFormat("    1) Ignore the problem. The tiling may not affect result significantly.\n");
                        sb.AppendFormat("    2) Use the 'fix out of bounds UVs' feature to bake the tiling and scale the UVs to fit in the 0,0 .. 1,1 rectangle.\n");
                        sb.AppendFormat("    3) Use the Multiple Materials feature to map the material on this submesh to its own submesh in the combined mesh. No other materials should map to this submesh. This will result in only one texture in the atlas(es) and the UVs should tile correctly.\n");
                        sb.AppendFormat("    4) Combine only meshes that use the same (or subset of) the set of materials on this mesh. The original material(s) can be applied to the result\n");
                    }
                }
                if (mar[0].hasOverlappingSubmeshVerts)
                {
                    sb.AppendFormat("\nObject {0} has submeshes that share vertices. This is a problem because each vertex can have only one UV coordinate and may be required to map to different positions in the various atlases that are generated. Possible treatments:\n", objsToMesh[i]);
                    sb.AppendFormat(" 1) Ignore the problem. The vertices may not affect the result.\n");
                    sb.AppendFormat(" 2) Use the Multiple Materials feature to map the submeshs that overlap to their own submeshs in the combined mesh. No other materials should map to this submesh. This will result in only one texture in the atlas(es) and the UVs should tile correctly.\n");
                    sb.AppendFormat(" 3) Combine only meshes that use the same (or subset of) the set of materials on this mesh. The original material(s) can be applied to the result\n");
                }
            }
            Dictionary <Material, List <GameObject> > m2gos = new Dictionary <Material, List <GameObject> >();

            for (int i = 0; i < objsToMesh.Count; i++)
            {
                if (objsToMesh[i] != null)
                {
                    Material[] ms = MeshBakerUtility.GetGOMaterials(objsToMesh[i]);
                    for (int j = 0; j < ms.Length; j++)
                    {
                        if (ms[j] != null)
                        {
                            List <GameObject> lgo;
                            if (!m2gos.TryGetValue(ms[j], out lgo))
                            {
                                lgo = new List <GameObject>();
                                m2gos.Add(ms[j], lgo);
                            }
                            if (!lgo.Contains(objsToMesh[i]))
                            {
                                lgo.Add(objsToMesh[i]);
                            }
                        }
                    }
                }
            }

            for (int i = 0; i < resultMaterials.Length; i++)
            {
                string resultMatShaderName = resultMaterials[i] != null ? "None" : resultMaterials[i].shader.name;
                TexturePipelineData data   = CreatePipelineData(resultMaterials[i], new List <ShaderTextureProperty>(), objsToMesh, new List <Material>(), new List <MaterialPropTexturesSet>());
                TextureCombinerPipeline._CollectPropertyNames(data);
                foreach (Material m in m2gos.Keys)
                {
                    for (int j = 0; j < data.texPropertyNames.Count; j++)
                    {
                        if (m.HasProperty(data.texPropertyNames[j].name))
                        {
                            Texture txx = TextureCombinerPipeline.GetTextureConsideringStandardShaderKeywords(resultMatShaderName, m, data.texPropertyNames[j].name);
                            if (txx != null)
                            {
                                Vector2 o = m.GetTextureOffset(data.texPropertyNames[j].name);
                                Vector3 s = m.GetTextureScale(data.texPropertyNames[j].name);
                                if (o.x < 0f || o.x + s.x > 1f ||
                                    o.y < 0f || o.y + s.y > 1f)
                                {
                                    sb.AppendFormat("\nMaterial {0} used by objects {1} uses texture {2} that is tiled (scale={3} offset={4}). If there is more than one texture in the atlas " +
                                                    " then Mesh Baker will bake the tiling into the atlas. If the baked tiling is large then quality can be lost. Possible treatments:\n", m, PrintList(m2gos[m]), txx, s, o);
                                    sb.AppendFormat("  1) Use the baked tiling.\n");
                                    sb.AppendFormat("  2) Use the Multiple Materials feature to map the material on this object/submesh to its own submesh in the combined mesh. No other materials should map to this submesh. The original material can be applied to this submesh.\n");
                                    sb.AppendFormat("  3) Combine only meshes that use the same (or subset of) the set of textures on this mesh. The original material can be applied to the result.\n");
                                }
                            }
                        }
                    }
                }
            }
            string outstr = "";

            if (sb.Length == 0)
            {
                outstr = "====== No problems detected. These meshes should combine well ====\n  If there are problems with the combined meshes please report the problem to digitalOpus.ca so we can improve Mesh Baker.";
            }
            else
            {
                outstr = "====== There are possible problems with these meshes that may prevent them from combining well. TREATMENT SUGGESTIONS (copy and paste to text editor if too big) =====\n" + sb.ToString();
            }
            Debug.Log(outstr);
        }
 public void SetEncapsulatingSamplingRect(MaterialPropTexturesSet ts, DRect r)
 {
     encapsulatingSamplingRect = r;
 }
Beispiel #9
0
 public void SetEncapsulatingSamplingRectForTesting(int propIdx, DRect newEncapsulatingSamplingRect)
 {
     ts[propIdx].SetEncapsulatingSamplingRect(this, newEncapsulatingSamplingRect);
 }
Beispiel #10
0
 public static DVector2 TransformPoint(ref DRect r, DVector2 p)
 {
     return(new DVector2((r.width * p.x + r.x), (r.height * p.y + r.y)));
 }
Beispiel #11
0
 public static Vector2 TransformPoint(ref DRect r, Vector2 p)
 {
     return(new Vector2((float)(r.width * p.x + r.x), (float)(r.height * p.y + r.y)));
 }
Beispiel #12
0
 /// <summary>
 ///  x 轴变换
 /// </summary>
 /// <param name="r"></param>
 /// <param name="x"></param>
 /// <returns></returns>
 public static float TransformX(DRect r, double x)
 {
     return((float)(r.width * x + r.x));
 }
        public void MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects(List <MaterialPropTexturesSet> distinctMaterialTextures)
        {
            int numMerged = 0;

            // IMPORTANT: Note that the verts stored in the mesh are NOT Normalized UV Coords. They are normalized * [UVTrans]. To get normalized UV
            // coords we must multiply them by [invUVTrans]. Need to do this to the verts in the mesh before we do any transforms with them.
            // Also check that all textures use same tiling. This is a prerequisite for merging.
            // Mark MB3_TexSet that are mergable (allTexturesUseSameMatTiling)
            //存储在网格中的顶点不是归一化UV坐标。 它们已归一化 * [UVTrans]。
            //获得归一化的 UV 坐标必须将其乘以[invUVTrans]。
            //在对它们进行任何转换之前,需要对网格中的顶点执行此操作。


            //检查所有纹理是否使用相同的拼贴。 这是合并的先决条件。
            //标记可合并的TexSet(allTexturesUseSameMatTiling)
            for (int i = 0; i < distinctMaterialTextures.Count; i++)
            {
                MaterialPropTexturesSet matPropsTextureSet = distinctMaterialTextures[i];
                int   idxOfFirstNotNull = -1;
                bool  allAreSame        = true;
                DRect firstRect         = new DRect();

                //判断不是相同的 texture 资源
                for (int propIdx = 0; propIdx < matPropsTextureSet.ts.Length; propIdx++)
                {
                    if (idxOfFirstNotNull != -1)
                    {
                        if (!matPropsTextureSet.ts[propIdx].isNull && firstRect != matPropsTextureSet.ts[propIdx].matTilingRect)
                        {
                            allAreSame = false;
                        }
                    }
                    //先找第一个非空纹理,设置为 idxOfFirstNotNull
                    else if (!matPropsTextureSet.ts[propIdx].isNull)
                    {
                        idxOfFirstNotNull = propIdx;
                        firstRect         = matPropsTextureSet.ts[propIdx].matTilingRect;
                    }
                }
                if (LOG_LEVEL_TRACE_MERGE_MAT_SUBRECTS == true)
                {
                    if (allAreSame)
                    {
                        Debug.LogFormat("TextureSet {0} allTexturesUseSameMatTiling = {1}", i, allAreSame);
                    }
                    else
                    {
                        Debug.Log(string.Format("Textures in material(s) do not all use the same material tiling. " +
                                                "This set of textures will not be considered for merge: {0} ", matPropsTextureSet.GetDescription()));
                    }
                }
                if (allAreSame)
                {
                    matPropsTextureSet.SetAllTexturesUseSameMatTilingTrue();
                }
            }

            //设置 材质Obj 名称
            for (int i = 0; i < distinctMaterialTextures.Count; i++)
            {
                MaterialPropTexturesSet matPropsTextureSet = distinctMaterialTextures[i];
                for (int matIdx = 0; matIdx < matPropsTextureSet.matsAndGOs.mats.Count; matIdx++)
                {
                    if (matPropsTextureSet.matsAndGOs.gos.Count > 0)
                    {
                        matPropsTextureSet.matsAndGOs.mats[matIdx].objName = matPropsTextureSet.matsAndGOs.gos[0].name;
                    }
                    else if (matPropsTextureSet.ts[0] != null)
                    {
                        matPropsTextureSet.matsAndGOs.mats[matIdx].objName = string.Format("[objWithTx:{0} atlasBlock:{1} matIdx{2}]", matPropsTextureSet.ts[0].GetTexName(), i, matIdx);
                    }
                    else
                    {
                        matPropsTextureSet.matsAndGOs.mats[matIdx].objName = string.Format("[objWithTx:{0} atlasBlock:{1} matIdx{2}]", "Unknown", i, matIdx);
                    }
                }

                matPropsTextureSet.CalcInitialFullSamplingRects(fixOutOfBoundsUVs);
                matPropsTextureSet.CalcMatAndUVSamplingRects();
            }

            // need to calculate the srcSampleRect for the complete tiling in the atlas
            // for each material need to know what the subrect would be in the atlas if material UVRect was 0,0,1,1 and Merged uvRect was full tiling
            //需要为图集中的完整切片计算src SampleRect
            //对于每种材料,如果材料UVRect为0,0,1,1并且合并的uvRect为完整平铺,则需要知道该图集在图集中的位置
            List <int> MarkedForDeletion = new List <int>();

            for (int i = 0; i < distinctMaterialTextures.Count; i++)
            {
                MaterialPropTexturesSet tx2 = distinctMaterialTextures[i];
                for (int j = i + 1; j < distinctMaterialTextures.Count; j++)
                {
                    MaterialPropTexturesSet tx1 = distinctMaterialTextures[j];
                    if (tx1.AllTexturesAreSameForMerge(tx2, _considerNonTextureProperties, resultMaterialTextureBlender))
                    {
                        double accumulatedAreaCombined    = 0f;
                        double accumulatedAreaNotCombined = 0f;
                        DRect  encapsulatingRectMerged    = new DRect();
                        int    idxOfFirstNotNull          = -1;
                        for (int propIdx = 0; propIdx < tx2.ts.Length; propIdx++)
                        {
                            if (!tx2.ts[propIdx].isNull)
                            {
                                if (idxOfFirstNotNull == -1)
                                {
                                    idxOfFirstNotNull = propIdx;
                                }
                            }
                        }

                        if (idxOfFirstNotNull != -1)
                        {
                            // only in here if all properties use the same tiling so don't need to worry about which propIdx we are dealing with
                            //Get the rect that encapsulates all material and UV tiling for materials and meshes in tx1
                            //如果所有属性都使用相同的tiling,因此无需担心我们正在处理哪个propIdx
                            //获取将所有材料和UV平铺封装为rect的rect在tx1中
                            DRect encapsulatingRect1 = tx1.matsAndGOs.mats[0].samplingRectMatAndUVTiling;
                            for (int matIdx = 1; matIdx < tx1.matsAndGOs.mats.Count; matIdx++)
                            {
                                DRect tmpSsamplingRectMatAndUVTilingTx1 = tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling;
                                encapsulatingRect1 = UVRectUtility.GetEncapsulatingRectShifted(ref encapsulatingRect1, ref tmpSsamplingRectMatAndUVTilingTx1);
                            }
                            //same for tx2
                            DRect encapsulatingRect2 = tx2.matsAndGOs.mats[0].samplingRectMatAndUVTiling;
                            for (int matIdx = 1; matIdx < tx2.matsAndGOs.mats.Count; matIdx++)
                            {
                                DRect tmpSsamplingRectMatAndUVTilingTx2 = tx2.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling;
                                encapsulatingRect2 = UVRectUtility.GetEncapsulatingRectShifted(ref encapsulatingRect2, ref tmpSsamplingRectMatAndUVTilingTx2);
                            }

                            encapsulatingRectMerged     = UVRectUtility.GetEncapsulatingRectShifted(ref encapsulatingRect1, ref encapsulatingRect2);
                            accumulatedAreaCombined    += encapsulatingRectMerged.width * encapsulatingRectMerged.height;
                            accumulatedAreaNotCombined += encapsulatingRect1.width * encapsulatingRect1.height + encapsulatingRect2.width * encapsulatingRect2.height;
                        }
                        else
                        {
                            encapsulatingRectMerged = new DRect(0f, 0f, 1f, 1f);
                        }

                        //the distinct material textures may overlap.
                        //if the area of these rectangles combined is less than the sum of these areas of these rectangles then merge these distinctMaterialTextures
                        if (accumulatedAreaCombined < accumulatedAreaNotCombined)
                        {
                            // merge tx2 into tx1
                            numMerged++;
                            StringBuilder sb = null;

                            sb = new StringBuilder();
                            sb.AppendFormat("About To Merge:\n   TextureSet1 {0}\n   TextureSet2 {1}\n", tx1.GetDescription(), tx2.GetDescription());

                            for (int matIdx = 0; matIdx < tx1.matsAndGOs.mats.Count; matIdx++)
                            {
                                sb.AppendFormat("tx1 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n",
                                                tx1.matsAndGOs.mats[matIdx].mat, tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx1.ts[0].GetEncapsulatingSamplingRect());
                            }
                            for (int matIdx = 0; matIdx < tx2.matsAndGOs.mats.Count; matIdx++)
                            {
                                sb.AppendFormat("tx2 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n",
                                                tx2.matsAndGOs.mats[matIdx].mat, tx2.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx2.ts[0].GetEncapsulatingSamplingRect());
                            }

                            //copy game objects over
                            for (int k = 0; k < tx2.matsAndGOs.gos.Count; k++)
                            {
                                if (!tx1.matsAndGOs.gos.Contains(tx2.matsAndGOs.gos[k]))
                                {
                                    tx1.matsAndGOs.gos.Add(tx2.matsAndGOs.gos[k]);
                                }
                            }

                            //copy materials over from tx2 to tx1
                            for (int matIdx = 0; matIdx < tx2.matsAndGOs.mats.Count; matIdx++)
                            {
                                tx1.matsAndGOs.mats.Add(tx2.matsAndGOs.mats[matIdx]);
                            }

                            tx1.SetEncapsulatingSamplingRectWhenMergingTexSets(encapsulatingRectMerged);
                            if (!MarkedForDeletion.Contains(i))
                            {
                                MarkedForDeletion.Add(i);
                            }

                            sb.AppendFormat("=== After Merge TextureSet {0}\n", tx1.GetDescription());
                            for (int matIdx = 0; matIdx < tx1.matsAndGOs.mats.Count; matIdx++)
                            {
                                sb.AppendFormat("tx1 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n",
                                                tx1.matsAndGOs.mats[matIdx].mat, tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx1.ts[0].GetEncapsulatingSamplingRect());
                            }
                            //Integrity check that sampling rects fit into enapsulating rects
                            if (MeshBakerRoot.DO_INTEGRITY_CHECKS)
                            {
                                if (MeshBakerRoot.DO_INTEGRITY_CHECKS)
                                {
                                    DoIntegrityCheckMergedEncapsulatingSamplingRects(distinctMaterialTextures);
                                }
                            }

                            Debug.Log(sb.ToString());

                            break;


                            Debug.Log(string.Format("Considered merging {0} and {1} but there was not enough overlap. It is more efficient to bake these to separate rectangles.", tx1.GetDescription(), tx2.GetDescription()));
                        }
                    }
                }
                //remove distinctMaterialTextures that were merged
                for (int j = MarkedForDeletion.Count - 1; j >= 0; j--)
                {
                    distinctMaterialTextures.RemoveAt(MarkedForDeletion[j]);
                }
                MarkedForDeletion.Clear();

                Debug.Log(string.Format("MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects complete merged {0} now have {1}", numMerged, distinctMaterialTextures.Count));

                if (MeshBakerRoot.DO_INTEGRITY_CHECKS)
                {
                    DoIntegrityCheckMergedEncapsulatingSamplingRects(distinctMaterialTextures);
                }
            }
        }