Example #1
0
        public AtlasPackingResult[] CalculateAtlasRectangles(TexturePipelineData data, bool doMultiAtlas)
        {
            Debug.Assert(data.IsOnlyOneTextureInAtlasReuseTextures());
            Debug.Log("Only one image per atlas. Will re-use original texture");
            AtlasPackingResult[] packerRects = new AtlasPackingResult[1];
            AtlasPadding[]       paddings    = new AtlasPadding[] { new AtlasPadding(data._atlasPadding) };
            packerRects[0]            = new AtlasPackingResult(paddings);
            packerRects[0].rects      = new Rect[1];
            packerRects[0].srcImgIdxs = new int[] { 0 };
            packerRects[0].rects[0]   = new Rect(0f, 0f, 1f, 1f);

            MaterialPropTexture dmt = null;

            if (data.distinctMaterialTextures[0].ts.Length > 0)
            {
                dmt = data.distinctMaterialTextures[0].ts[0];
            }
            if (dmt == null || dmt.isNull)
            {
                packerRects[0].atlasX = 16;
                packerRects[0].atlasY = 16;
                packerRects[0].usedW  = 16;
                packerRects[0].usedH  = 16;
            }
            else
            {
                packerRects[0].atlasX = dmt.width;
                packerRects[0].atlasY = dmt.height;
                packerRects[0].usedW  = dmt.width;
                packerRects[0].usedH  = dmt.height;
            }
            return(packerRects);
        }
Example #2
0
 public virtual IEnumerator ConvertTexturesToReadableFormats(ProgressUpdateDelegate progressInfo,
                                                             CombineTexturesIntoAtlasesCoroutineResult result,
                                                             TexturePipelineData data,
                                                             TextureCombineHandler combiner,
                                                             EditorMethodsInterface textureEditorMethods)
 {
     Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures());
     //MakeProceduralTexturesReadable(progressInfo, result, data, combiner, textureEditorMethods, LOG_LEVEL);
     for (int i = 0; i < data.distinctMaterialTextures.Count; i++)
     {
         for (int j = 0; j < data.texPropertyNames.Count; j++)
         {
             MaterialPropTexture ts = data.distinctMaterialTextures[i].ts[j];
             if (!ts.isNull)
             {
                 if (textureEditorMethods != null)
                 {
                     Texture tx = ts.GetTexture2D();
                     if (progressInfo != null)
                     {
                         progressInfo(String.Format("Convert texture {0} to readable format ", tx), .5f);
                     }
                     textureEditorMethods.AddTextureFormat((Texture2D)tx, data.texPropertyNames[j].isNormalMap);
                 }
             }
         }
     }
     yield break;
 }
Example #3
0
        public void CreateColoredTexToReplaceNull(string propName, int propIdx, bool considerMeshUVs, TextureCombineHandler combiner, Color col)
        {
            MaterialPropTexture matTex = ts[propIdx];

            matTex.t = combiner._createTemporaryTexture(propName, 16, 16, TextureFormat.ARGB32, true);
            MeshBakerUtility.setSolidColor(matTex.GetTexture2D(), col);
        }
 public bool AreTexturesEqual(MaterialPropTexture b)
 {
     if (_t == b._t)
     {
         return(true);
     }
     return(false);
 }
Example #5
0
        // used by Unity texture packer to handle tiled textures.
        // may create a new texture that has the correct tiling to handle fix out of bounds UVs
        internal static Texture2D GetAdjustedForScaleAndOffset2(string propertyName,
                                                                MaterialPropTexture source,
                                                                Vector2 obUVoffset,
                                                                Vector2 obUVscale,
                                                                TexturePipelineData data,
                                                                TextureCombineHandler combiner)
        {
            Texture2D sourceTex = source.GetTexture2D();

            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(sourceTex); //no adjustment necessary
                    }
                }
                else
                {
                    return(sourceTex); //no adjustment necessary
                }
            }
            Vector2 dim = TextureCombinerPipeline.GetAdjustedForScaleAndOffset2Dimensions(source, obUVoffset, obUVscale, data);

            Debug.LogWarning("GetAdjustedForScaleAndOffset2: " + sourceTex + " " + obUVoffset + " " + obUVscale);
            float newWidth  = dim.x;
            float newHeight = dim.y;
            float scx       = (float)source.matTilingRect.width;
            float scy       = (float)source.matTilingRect.height;
            float ox        = (float)source.matTilingRect.x;
            float oy        = (float)source.matTilingRect.y;

            if (data._fixOutOfBoundsUVs)
            {
                scx *= obUVscale.x;
                scy *= obUVscale.y;
                ox   = (float)(source.matTilingRect.x * obUVscale.x + obUVoffset.x);
                oy   = (float)(source.matTilingRect.y * obUVscale.y + obUVoffset.y);
            }
            Texture2D newTex = combiner._createTemporaryTexture(propertyName, (int)newWidth, (int)newHeight, TextureFormat.ARGB32, true);

            for (int i = 0; i < newTex.width; i++)
            {
                for (int j = 0; j < newTex.height; j++)
                {
                    float u = i / newWidth * scx + ox;
                    float v = j / newHeight * scy + oy;
                    newTex.SetPixel(i, j, sourceTex.GetPixelBilinear(u, v));
                }
            }
            newTex.Apply();
            return(newTex);
        }
Example #6
0
 internal static void CreateTemporaryTexturesForAtlas(List <MaterialPropTexturesSet> distinctMaterialTextures, TextureCombineHandler combiner, int propIdx, TexturePipelineData 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);
         }
     }
 }
Example #7
0
        public Vector2 GetMaxRawTextureHeightWidth()
        {
            Vector2 max = new Vector2(0, 0);

            for (int propIdx = 0; propIdx < ts.Length; propIdx++)
            {
                MaterialPropTexture tx = ts[propIdx];
                if (!tx.isNull)
                {
                    max.x = Mathf.Max(max.x, tx.width);
                    max.y = Mathf.Max(max.y, tx.height);
                }
            }
            return(max);
        }
 /// <summary>
 /// 检测所有 textures 中只有一种纹理
 /// </summary>
 /// <param name="data"></param>
 /// <returns></returns>
 private static CreateAtlasForProperty[] CalculateAllTexturesAreNullAndSameColor(TexturePipelineData 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);
 }
Example #9
0
        public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                         TexturePipelineData data,
                                         TextureCombineHandler combiner,
                                         AtlasPackingResult packedAtlasRects,
                                         Texture2D[] atlases,
                                         EditorMethodsInterface textureEditorMethods)
        {
            Debug.Assert(data.IsOnlyOneTextureInAtlasReuseTextures());
            Debug.Log("Only one image per atlas. Will re-use original texture");
            for (int i = 0; i < data.numAtlases; i++)
            {
                MaterialPropTexture dmt = data.distinctMaterialTextures[0].ts[i];
                atlases[i] = dmt.GetTexture2D();
                data.resultMaterial.SetTexture(data.texPropertyNames[i].name, atlases[i]);
                data.resultMaterial.SetTextureScale(data.texPropertyNames[i].name, Vector2.one);
                data.resultMaterial.SetTextureOffset(data.texPropertyNames[i].name, Vector2.zero);
            }

            yield break;
        }
        internal static Vector2 GetAdjustedForScaleAndOffset2Dimensions(MaterialPropTexture source, Vector2 obUVoffset, Vector2 obUVscale, TexturePipelineData 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));
        }
        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;
        }
Example #13
0
        private void CopyScaledAndTiledToAtlas(MaterialPropTexturesSet texSet,
                                               MaterialPropTexture source,
                                               Vector2 obUVoffset,
                                               Vector2 obUVscale,
                                               Rect rec,
                                               ShaderTextureProperty texturePropertyName,
                                               TextureCombinerNonTextureProperties resultMatTexBlender,
                                               bool yIsFlipped)
        {
            Rect r = rec;

            myCamera.backgroundColor = resultMatTexBlender.GetColorForTemporaryTexture(texSet.matsAndGOs.mats[0].mat, texturePropertyName);
            //yIsFlipped = true;
            //if (yIsFlipped)
            //{
            //}
            r.y       = 1f - (r.y + r.height); // DrawTexture uses topLeft 0,0, Texture2D uses bottomLeft 0,0
            r.x      *= _destinationTexture.width;
            r.y      *= _destinationTexture.height;
            r.width  *= _destinationTexture.width;
            r.height *= _destinationTexture.height;

            Rect rPadded = r;

            rPadded.x      -= _padding;
            rPadded.y      -= _padding;
            rPadded.width  += _padding * 2;
            rPadded.height += _padding * 2;

            Rect targPr   = new Rect();
            Rect srcPrTex = texSet.ts[indexOfTexSetToRender].GetEncapsulatingSamplingRect().GetRect();

            if (!_fixOutOfBoundsUVs)
            {
                Debug.Assert(source.matTilingRect.GetRect() == texSet.ts[indexOfTexSetToRender].GetEncapsulatingSamplingRect().GetRect());
            }
            Texture2D tex = source.GetTexture2D();

            /*
             * if (_considerNonTextureProperties && resultMatTexBlender != null)
             * {
             *  if (LOG_LEVEL >= MB2_LogLevel.trace) Debug.Log(string.Format("Blending texture {0} mat {1} with non-texture properties using TextureBlender {2}", tex.name, texSet.mats[0].mat, resultMatTexBlender));
             *
             *  resultMatTexBlender.OnBeforeTintTexture(texSet.mats[0].mat, texturePropertyName.name);
             *  //combine the tintColor with the texture
             *  tex = combiner._createTextureCopy(tex);
             *  for (int i = 0; i < tex.height; i++)
             *  {
             *      Color[] cs = tex.GetPixels(0, i, tex.width, 1);
             *      for (int j = 0; j < cs.Length; j++)
             *      {
             *          cs[j] = resultMatTexBlender.OnBlendTexturePixel(texturePropertyName.name, cs[j]);
             *      }
             *      tex.SetPixels(0, i, tex.width, 1, cs);
             *  }
             *  tex.Apply();
             * }
             */


            //main texture
            TextureWrapMode oldTexWrapMode = tex.wrapMode;

            if (srcPrTex.width == 1f && srcPrTex.height == 1f && srcPrTex.x == 0f && srcPrTex.y == 0f)
            {
                //fixes bug where there is a dark line at the edge of the texture
                tex.wrapMode = TextureWrapMode.Clamp;
            }
            else
            {
                tex.wrapMode = TextureWrapMode.Repeat;
            }
            Debug.Log("DrawTexture tex=" + tex.name + " destRect=" + r + " srcRect=" + srcPrTex + " Mat=" + mat);
            //fill the padding first
            Rect srcPr = new Rect();

            //top margin
            srcPr.x       = srcPrTex.x;
            srcPr.y       = srcPrTex.y + 1 - 1f / tex.height;
            srcPr.width   = srcPrTex.width;
            srcPr.height  = 1f / tex.height;
            targPr.x      = r.x;
            targPr.y      = rPadded.y;
            targPr.width  = r.width;
            targPr.height = _padding;
            RenderTexture oldRT = RenderTexture.active;

            RenderTexture.active = _destinationTexture;
            Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat);

            //bot margin
            srcPr.x       = srcPrTex.x;
            srcPr.y       = srcPrTex.y;
            srcPr.width   = srcPrTex.width;
            srcPr.height  = 1f / tex.height;
            targPr.x      = r.x;
            targPr.y      = r.y + r.height;
            targPr.width  = r.width;
            targPr.height = _padding;
            Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat);


            //left margin
            srcPr.x       = srcPrTex.x;
            srcPr.y       = srcPrTex.y;
            srcPr.width   = 1f / tex.width;
            srcPr.height  = srcPrTex.height;
            targPr.x      = rPadded.x;
            targPr.y      = r.y;
            targPr.width  = _padding;
            targPr.height = r.height;
            Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat);

            //right margin
            srcPr.x       = srcPrTex.x + 1f - 1f / tex.width;
            srcPr.y       = srcPrTex.y;
            srcPr.width   = 1f / tex.width;
            srcPr.height  = srcPrTex.height;
            targPr.x      = r.x + r.width;
            targPr.y      = r.y;
            targPr.width  = _padding;
            targPr.height = r.height;
            Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat);


            //top left corner
            srcPr.x       = srcPrTex.x;
            srcPr.y       = srcPrTex.y + 1 - 1f / tex.height;
            srcPr.width   = 1f / tex.width;
            srcPr.height  = 1f / tex.height;
            targPr.x      = rPadded.x;
            targPr.y      = rPadded.y;
            targPr.width  = _padding;
            targPr.height = _padding;
            Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat);

            //top right corner
            srcPr.x       = srcPrTex.x + 1f - 1f / tex.width;
            srcPr.y       = srcPrTex.y + 1 - 1f / tex.height;
            srcPr.width   = 1f / tex.width;
            srcPr.height  = 1f / tex.height;
            targPr.x      = r.x + r.width;
            targPr.y      = rPadded.y;
            targPr.width  = _padding;
            targPr.height = _padding;
            Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat);

            //bot left corner
            srcPr.x       = srcPrTex.x;
            srcPr.y       = srcPrTex.y;
            srcPr.width   = 1f / tex.width;
            srcPr.height  = 1f / tex.height;
            targPr.x      = rPadded.x;
            targPr.y      = r.y + r.height;
            targPr.width  = _padding;
            targPr.height = _padding;
            Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat);

            //bot right corner
            srcPr.x       = srcPrTex.x + 1f - 1f / tex.width;
            srcPr.y       = srcPrTex.y;
            srcPr.width   = 1f / tex.width;
            srcPr.height  = 1f / tex.height;
            targPr.x      = r.x + r.width;
            targPr.y      = r.y + r.height;
            targPr.width  = _padding;
            targPr.height = _padding;
            Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat);

            //now the texture
            Graphics.DrawTexture(r, tex, srcPrTex, 0, 0, 0, 0, mat);
            RenderTexture.active = oldRT;
            tex.wrapMode         = oldTexWrapMode;
        }
Example #14
0
        public void OnRenderObject()
        {
            if (_doRenderAtlas)
            {
                //assett rs must be same length as textureSets;
                System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
                sw.Start();
                bool yIsFlipped = YisFlipped();
                for (int i = 0; i < rs.Length; i++)
                {
                    MaterialPropTexture texInfo = textureSets[i].ts[indexOfTexSetToRender];
                    Texture2D           tx      = texInfo.GetTexture2D();
                    if (tx != null)
                    {
                        Debug.Log("Added " + tx + " to atlas w=" + tx.width + " h=" + tx.height + " offset=" + texInfo.matTilingRect.min +
                                  " scale=" + texInfo.matTilingRect.size + " rect=" + rs[i] + " padding=" + _padding);
                    }
                    CopyScaledAndTiledToAtlas(textureSets[i], texInfo, textureSets[i].obUVoffset, textureSets[i].obUVscale, rs[i], _texPropertyName,
                                              _resultMaterialTextureBlender, yIsFlipped);
                }
                sw.Stop();
                sw.Start();
                Debug.Log("Total time for Graphics.DrawTexture calls " + (sw.ElapsedMilliseconds).ToString("f5"));
                Debug.Log("Copying RenderTexture to Texture2D. destW" + _destinationTexture.width + " destH" + _destinationTexture.height);

                //Convert the RenderTexture to a Texture2D
                Texture2D tempTexture;
                tempTexture = new Texture2D(_destinationTexture.width, _destinationTexture.height, TextureFormat.ARGB32, true);

                RenderTexture oldRT = RenderTexture.active;
                RenderTexture.active = _destinationTexture;
                int xblocks = Mathf.CeilToInt(((float)_destinationTexture.width) / 512);
                int yblocks = Mathf.CeilToInt(((float)_destinationTexture.height) / 512);
                if (xblocks == 0 || yblocks == 0)
                {
                    Debug.Log("Copying all in one shot");
                    tempTexture.ReadPixels(new Rect(0, 0, _destinationTexture.width, _destinationTexture.height), 0, 0, true);
                }
                else
                {
                    if (yIsFlipped == false)
                    {
                        for (int x = 0; x < xblocks; x++)
                        {
                            for (int y = 0; y < yblocks; y++)
                            {
                                int  xx = x * 512;
                                int  yy = y * 512;
                                Rect r  = new Rect(xx, yy, 512, 512);
                                tempTexture.ReadPixels(r, x * 512, y * 512, true);
                            }
                        }
                    }
                    else
                    {
                        Debug.Log("Not OpenGL copying blocks");
                        for (int x = 0; x < xblocks; x++)
                        {
                            for (int y = 0; y < yblocks; y++)
                            {
                                int  xx = x * 512;
                                int  yy = _destinationTexture.height - 512 - y * 512;
                                Rect r  = new Rect(xx, yy, 512, 512);
                                tempTexture.ReadPixels(r, x * 512, y * 512, true);
                            }
                        }
                    }
                }
                RenderTexture.active = oldRT;
                tempTexture.Apply();
                Debug.Log("TempTexture ");
                if (tempTexture.height <= 16 && tempTexture.width <= 16)
                {
                    _printTexture(tempTexture);
                }
                myCamera.targetTexture = null;
                RenderTexture.active   = null;

                targTex = tempTexture;
                Debug.Log("Total time to copy RenderTexture to Texture2D " + (sw.ElapsedMilliseconds).ToString("f5"));
            }
        }
        //第二步:计算每个材质的属性对应的 Textures 统一尺寸
        //每种材质(_mainTex,凹凸,Spec ect ...)中的纹理必须大小相同
        //计算要使用的最佳尺寸。 考虑平铺
        //如果图集中只有一种纹理会使用原始大小
        internal static IEnumerator _Step2_CalculateIdealSizesForTexturesInAtlasAndPadding(ProgressUpdateDelegate progressInfo,
                                                                                           CombineTexturesIntoAtlasesCoroutineResult result,
                                                                                           TexturePipelineData data,
                                                                                           EditorMethodsInterface textureEditorMethods)
        {
            MaterialPropTexture.readyToBuildAtlases = true;
            data.allTexturesAreNullAndSameColor     = CalculateAllTexturesAreNullAndSameColor(data);

            //calculate size of rectangles in atlas
            //计算 atlas 矩形尺寸
            int _padding = data._atlasPadding;

            if (data.distinctMaterialTextures.Count == 1 && data._fixOutOfBoundsUVs == false && data._considerNonTextureProperties == false)
            {
                Debug.Log("所有游戏物体使用相同的材质.将使用 Original textures .");
                _padding = 0;
                data.distinctMaterialTextures[0].SetThisIsOnlyTexSetInAtlasTrue();
                data.distinctMaterialTextures[0].SetTilingTreatmentAndAdjustEncapsulatingSamplingRect(TextureTilingTreatment.edgeToEdgeXY);
            }

            Debug.Assert(data.allTexturesAreNullAndSameColor.Length == data.texPropertyNames.Count,
                         "allTexturesAreNullAndSameColor array must be the same length of texPropertyNames.");

            for (int i = 0; i < data.distinctMaterialTextures.Count; i++)
            {
                Debug.Log("为 TexSet " + i + " of " + data.distinctMaterialTextures.Count + "计算合适的尺寸");
                MaterialPropTexturesSet txs = data.distinctMaterialTextures[i];
                txs.idealWidth  = 1;
                txs.idealHeight = 1;
                int tWidth  = 1;
                int tHeight = 1;
                Debug.Assert(txs.ts.Length == data.texPropertyNames.Count,
                             "length of arrays in each element of distinctMaterialTextures must be texPropertyNames.Count");

                //在 MaterialPropTexturesSet 中所有 MaterialPropTextures 应为相同尺寸
                for (int propIdx = 0; propIdx < data.texPropertyNames.Count; propIdx++)
                {
                    if (_ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                    {
                        MaterialPropTexture matTex = txs.ts[propIdx];
                        Debug.Log(string.Format("为 texSet {0} ,property {1} 计算合适尺寸", i, data.texPropertyNames[propIdx].name));
                        if (!matTex.matTilingRect.size.Equals(Vector2.one) && data.distinctMaterialTextures.Count > 1)
                        {
                            Debug.LogWarning("Texture " + matTex.GetTexName() + "is tiled by " +
                                             matTex.matTilingRect.size + " tiling will be baked into a texture with maxSize:" +
                                             data._maxTilingBakeSize);
                        }

                        if (!txs.obUVscale.Equals(Vector2.one) && data.distinctMaterialTextures.Count > 1 && data._fixOutOfBoundsUVs)
                        {
                            Debug.LogWarning("Texture " + matTex.GetTexName() +
                                             " has out of bounds UVs that effectively tile by " + txs.obUVscale +
                                             " tiling will be baked into a texture with maxSize:" + data._maxTilingBakeSize);
                        }

                        if (matTex.isNull)
                        {
                            txs.SetEncapsulatingRect(propIdx, data._fixOutOfBoundsUVs);
                            Debug.Log(string.Format("No source texture creating a 16x16 texture for {0} texSet {1} srcMat {2}",
                                                    data.texPropertyNames[propIdx].name, i, txs.matsAndGOs.mats[0].GetMaterialName()));
                        }

                        if (!matTex.isNull)
                        {
                            Vector2 dim = GetAdjustedForScaleAndOffset2Dimensions(matTex, txs.obUVoffset, txs.obUVscale, data);
                            if ((int)(dim.x * dim.y) > tWidth * tHeight)
                            {
                                Debug.Log(" 材质texture " + matTex.GetTexName() + " " + dim + " 需要比" + tWidth + " " + tHeight + "更大的尺寸");
                                tWidth  = (int)dim.x;
                                tHeight = (int)dim.y;
                            }
                        }
                    }
                }

                if (data._resizePowerOfTwoTextures)
                {
                    if (tWidth <= _padding * 5)
                    {
                        Debug.LogWarning(String.Format("Some of the textures have widths close to the size of the padding. " +
                                                       "It is not recommended to use _resizePowerOfTwoTextures with widths this small.", txs.ToString()));
                    }
                    if (tHeight <= _padding * 5)
                    {
                        Debug.LogWarning(String.Format("Some of the textures have heights close to the size of the padding. " +
                                                       "It is not recommended to use _resizePowerOfTwoTextures with heights this small.", txs.ToString()));
                    }
                    if (IsPowerOfTwo(tWidth))
                    {
                        tWidth -= _padding * 2;
                    }
                    if (IsPowerOfTwo(tHeight))
                    {
                        tHeight -= _padding * 2;
                    }
                    if (tWidth < 1)
                    {
                        tWidth = 1;
                    }
                    if (tHeight < 1)
                    {
                        tHeight = 1;
                    }
                }
                Debug.Log("Ideal size is " + tWidth + " " + tHeight);
                txs.idealWidth  = tWidth;
                txs.idealHeight = tHeight;
            }
            data._atlasPadding = _padding;
            yield break;
        }
        /// <summary>
        /// 第一步:
        ///     写入 TexturePipelineData 的 MaterialPropTexturesSet 列表,和 usedObjsToMesh 列表
        /// 每个TexSet在 Atlas 中都是一个矩形。
        /// 如果 allowedMaterialsFilter (过滤器)为空,那么将收集 allObjsToMesh 上的所有材质,usedObjsToMesh 将与allObjsToMesh相同
        /// 否则,将仅包括allowedMaterialsFilter中的材料,而usedObjsToMesh将是使用这些材料的objs。
        /// </summary>
        internal static IEnumerator __Step1_CollectDistinctMatTexturesAndUsedObjects(ProgressUpdateDelegate progressInfo,
                                                                                     CombineTexturesIntoAtlasesCoroutineResult result,
                                                                                     TexturePipelineData data,
                                                                                     EditorMethodsInterface textureEditorMethods,
                                                                                     List <GameObject> usedObjsToMesh)
        {
            // Collect distinct list of textures to combine from the materials on objsToCombine
            // 收集UsedObjects上不同的材质纹理
            bool outOfBoundsUVs = false;
            Dictionary <int, MeshAnalysisResult[]> meshAnalysisResultsCache = new Dictionary <int, MeshAnalysisResult[]>(); //cache results

            for (int i = 0; i < data.allObjsToMesh.Count; i++)
            {
                GameObject obj = data.allObjsToMesh[i];
                //报道进度
                if (progressInfo != null)
                {
                    progressInfo("Collecting textures for " + obj, ((float)i) / data.allObjsToMesh.Count / 2f);
                }

                if (obj == null)
                {
                    Debug.LogError("合并游戏物体列表中包含空物体");
                    result.success = false;
                    yield break;
                }

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

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

                //analyze mesh or grab cached result of previous analysis, stores one result for each submesh
                //处理网格数据
                MeshAnalysisResult[] meshAnalysisResults;//每个游戏物体的主网格子网格数据数组
                if (!meshAnalysisResultsCache.TryGetValue(sharedMesh.GetInstanceID(), out meshAnalysisResults))
                {
                    meshAnalysisResults = new MeshAnalysisResult[sharedMesh.subMeshCount];
                    for (int j = 0; j < sharedMesh.subMeshCount; j++)
                    {
                        MeshBakerUtility.hasOutOfBoundsUVs(sharedMesh, ref meshAnalysisResults[j], j);
                        if (data._normalizeTexelDensity)
                        {
                            meshAnalysisResults[j].submeshArea = GetSubmeshArea(sharedMesh, j);
                        }

                        if (data._fixOutOfBoundsUVs && !meshAnalysisResults[j].hasUVs)
                        {
                            meshAnalysisResults[j].uvRect = new Rect(0, 0, 1, 1);
                            Debug.LogWarning("Mesh for object " + obj + " has no UV channel but 'consider UVs' is enabled." +
                                             " Assuming UVs will be generated filling 0,0,1,1 rectangle.");
                        }
                    }
                    meshAnalysisResultsCache.Add(sharedMesh.GetInstanceID(), meshAnalysisResults);
                }

                if (data._fixOutOfBoundsUVs)
                {
                    Debug.Log("Mesh Analysis for object " + obj +
                              " numSubmesh=" + meshAnalysisResults.Length +
                              " HasOBUV=" + meshAnalysisResults[0].hasOutOfBoundsUVs +
                              " UVrectSubmesh0=" + meshAnalysisResults[0].uvRect);
                }


                //处理材质数据
                for (int matIdx = 0; matIdx < sharedMaterials.Length; matIdx++)
                {
                    ////for each submesh
                    //if (progressInfo != null)
                    //{
                    //    progressInfo(string.Format("Collecting textures for {0} submesh {1}", obj, matIdx),
                    //        ((float)i) / data.allObjsToMesh.Count / 2f);
                    //}
                    Material mat = sharedMaterials[matIdx];

                    // 材质过滤器
                    if (data.allowedMaterialsFilter != null && !data.allowedMaterialsFilter.Contains(mat))
                    {
                        continue;
                    }

                    outOfBoundsUVs = outOfBoundsUVs || meshAnalysisResults[matIdx].hasOutOfBoundsUVs;

                    if (mat.name.Contains("(Instance)"))
                    {
                        Debug.LogError("The sharedMaterial on object " + obj.name + " has been 'Instanced'." +
                                       " This was probably caused by a script accessing the meshRender.material property in the editor. " +
                                       " The material to UV Rectangle mapping will be incorrect. " +
                                       "To fix this recreate the object from its prefab or re-assign its material from the correct asset.");
                        result.success = false;
                        yield break;
                    }

                    if (data._fixOutOfBoundsUVs)
                    {
                        if (!MeshBakerUtility.AreAllSharedMaterialsDistinct(sharedMaterials))
                        {
                            Debug.LogWarning("游戏物体 " + obj.name + " 使用相同的材质在多个子网格. " +
                                             "可能生成奇怪的 resultAtlasesAndRects,尤其是与 _fixOutOfBoundsUVs 为 true 时");
                        }
                    }

                    //材质属性所用到的 Texutre
                    MaterialPropTexture[] mts = new MaterialPropTexture[data.texPropertyNames.Count];
                    for (int propIdx = 0; propIdx < data.texPropertyNames.Count; propIdx++)
                    {
                        Texture tx           = null;
                        Vector2 scale        = Vector2.one;
                        Vector2 offset       = Vector2.zero;
                        float   texelDensity = 0f;
                        if (mat.HasProperty(data.texPropertyNames[propIdx].name))
                        {
                            Texture txx = GetTextureConsideringStandardShaderKeywords(data.resultMaterial.shader.name, mat, data.texPropertyNames[propIdx].name);
                            if (txx != null)
                            {
                                if (txx is Texture2D)
                                {
                                    //TextureFormat 验证
                                    tx = txx;
                                    TextureFormat f           = ((Texture2D)tx).format;
                                    bool          isNormalMap = false;
                                    if (!Application.isPlaying && textureEditorMethods != null)
                                    {
                                        isNormalMap = textureEditorMethods.IsNormalMap((Texture2D)tx);
                                    }
                                    if ((f == TextureFormat.ARGB32 ||
                                         f == TextureFormat.RGBA32 ||
                                         f == TextureFormat.BGRA32 ||
                                         f == TextureFormat.RGB24 ||
                                         f == TextureFormat.Alpha8) && !isNormalMap) //DXT5 does not work
                                    {
                                        //可使用
                                    }
                                    else
                                    {
                                        //TRIED to copy texture using tex2.SetPixels(tex1.GetPixels()) but bug in 3.5 means DTX1 and 5 compressed textures come out skewe
                                        //尝试使用tex2.SetPixels(tex1.GetPixels())复制纹理,但是3.5中的bug意味着DTX1和5压缩纹理出现扭曲
                                        if (Application.isPlaying && data._packingAlgorithm != PackingAlgorithmEnum.MeshBakerTexturePacker_Fast)
                                        {
                                            Debug.LogWarning("合并列表中,游戏物体 " + obj.name + " 所使用的 Texture " +
                                                             tx.name + " 使用的格式 " + f +
                                                             "不是: ARGB32, RGBA32, BGRA32, RGB24, Alpha8 或 DXT. " +
                                                             "无法在运行时重新设置尺寸" +
                                                             "If format says 'compressed' try changing it to 'truecolor'");
                                            result.success = false;
                                            yield break;
                                        }
                                        else
                                        {
                                            tx = (Texture2D)mat.GetTexture(data.texPropertyNames[propIdx].name);
                                        }
                                    }
                                }
                                else
                                {
                                    Debug.LogError("合并列表中,游戏物体 " + obj.name + " 渲染网格使用的 Texture 不是 Texture2D. ");
                                    result.success = false;
                                    yield break;
                                }
                            }
                            //像素密度
                            if (tx != null && data._normalizeTexelDensity)
                            {
                                //不考虑平铺和UV采样超出范围
                                if (meshAnalysisResults[propIdx].submeshArea == 0)
                                {
                                    texelDensity = 0f;
                                }
                                else
                                {
                                    texelDensity = (tx.width * tx.height) / (meshAnalysisResults[propIdx].submeshArea);
                                }
                            }
                            //规格,偏移
                            GetMaterialScaleAndOffset(mat, data.texPropertyNames[propIdx].name, out offset, out scale);
                        }

                        mts[propIdx] = new MaterialPropTexture(tx, offset, scale, texelDensity);
                    }

                    // 收集材质参数值的平均值
                    data.nonTexturePropertyBlender.CollectAverageValuesOfNonTextureProperties(data.resultMaterial, mat);

                    Vector2 obUVscale  = new Vector2(meshAnalysisResults[matIdx].uvRect.width, meshAnalysisResults[matIdx].uvRect.height);
                    Vector2 obUVoffset = new Vector2(meshAnalysisResults[matIdx].uvRect.x, meshAnalysisResults[matIdx].uvRect.y);

                    //Add to distinct set of textures if not already there
                    TextureTilingTreatment tilingTreatment = TextureTilingTreatment.none;
                    if (data._fixOutOfBoundsUVs)
                    {
                        tilingTreatment = TextureTilingTreatment.considerUVs;
                    }

                    //合并信息 distinctMaterialTextures 数据设置

                    //材质各参数 Texture,及 UV 偏移数据映射
                    MaterialPropTexturesSet setOfTexs = new MaterialPropTexturesSet(mts, obUVoffset, obUVscale, tilingTreatment);  //one of these per submesh
                    //材质及各变化参数Rect 数据
                    MatAndTransformToMerged matt = new MatAndTransformToMerged(new DRect(obUVoffset, obUVscale), data._fixOutOfBoundsUVs, mat);

                    setOfTexs.matsAndGOs.mats.Add(matt);

                    MaterialPropTexturesSet setOfTexs2 = data.distinctMaterialTextures.Find(x => x.IsEqual(setOfTexs, data._fixOutOfBoundsUVs, data.nonTexturePropertyBlender));
                    if (setOfTexs2 != null)
                    {
                        setOfTexs = setOfTexs2;
                    }
                    else
                    {
                        data.distinctMaterialTextures.Add(setOfTexs);
                    }

                    if (!setOfTexs.matsAndGOs.mats.Contains(matt))
                    {
                        setOfTexs.matsAndGOs.mats.Add(matt);
                    }

                    if (!setOfTexs.matsAndGOs.gos.Contains(obj))
                    {
                        setOfTexs.matsAndGOs.gos.Add(obj);
                        //已使用 游戏物体
                        if (!usedObjsToMesh.Contains(obj))
                        {
                            usedObjsToMesh.Add(obj);
                        }
                    }
                }
            }

            Debug.Log(string.Format("第一阶段完成;" +
                                    "参与合并的游戏物体的不同材质,各自包含与shader属性对应的不同的纹理,收集到 {0} 组 textures,即 {0} 个不同的材质," +
                                    "fixOutOfBoundsUV:{1} " +
                                    "considerNonTextureProperties:{2}",
                                    data.distinctMaterialTextures.Count, data._fixOutOfBoundsUVs, data._considerNonTextureProperties));

            if (data.distinctMaterialTextures.Count == 0)
            {
                Debug.LogError("None of the source object materials matched any of the allowed materials for submesh with result material: " + data.resultMaterial);
                result.success = false;
                yield break;
            }

            TextureCombinerMerging merger = new TextureCombinerMerging(data._considerNonTextureProperties,
                                                                       data.nonTexturePropertyBlender, data._fixOutOfBoundsUVs);

            merger.MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects(data.distinctMaterialTextures);

            yield break;
        }