[UGUI]TiledSliceEffect----Image的Tiled类型产生过多顶点的优化

如下图,当Image Type设置成Tile时会产生过多顶点。

 

 


 

解决方法是用一个shader,把sprite的uv范围和tile步长传进去,在shader里用求余的方法处理。

首先在canvas的Additional Shader Channels上勾选:

 

以下是图片分成九宫格后,Image Type为Sliced的一个解决方案:

新建一个TileSliceEffect脚本,继承BaseMeshEffect,下面要在ModifyMesh中添加代码。

当图片分成九宫格后,排列顺序如下:

      

 

四个角只缩放不tile,四个边只进行横向或纵向的tile,中间横向纵向都要tile。

 

每个九宫格又分成两个三角形一共六个点,顺序如下(与在atlas中的方向有关):

 

 

对于每个格中的六个点,取顶点范围:

var rectBorder = verts[6 * i + 4].position - verts[6 * i + 1].position;
rectBorder = new Vector3(Mathf.Abs(rectBorder.x), Mathf.Abs(rectBorder.y), Mathf.Abs(rectBorder.z));

而在sprite中,原始格子的范围是:

var overrideSprite = m_image.overrideSprite;
var border = overrideSprite.border;
var spriteSize = overrideSprite.rect.size;
float tileWidth = (spriteSize.x - border.x - border.z) / m_image.pixelsPerUnit;
float tileHeight = (spriteSize.y - border.y - border.w) / m_image.pixelsPerUnit;

从这里可以得到一个tile的缩放比例,比如x轴方向缩放比例为(此处当image大小小于一个tile时为缩放效果,大于一个tile时为平铺效果):

uv1.x = ((tileWidth == 0 || tileWidth >= rectBorder.x) ? 1f : tileWidth / rectBorder.x);

 

接下来还需要得到每个格子的uv范围:

var leftTopUV = verts[6 * i + 1].uv0;
var rightBottomUV = verts[6 * i + 4].uv0;

 

最后,要把这些信息传入shader。

 vert.uv2 = new Vector2 (leftTopUV.x, leftTopUV.y);
 vert.uv3 = new Vector2 (rightBottomUV.x, rightBottomUV.y);

 

shader是从builtin的DefaultUI基础上改的:

            struct appdata_t {
                float4 vertex:POSITION; 
                float4 color:COLOR; 
                float2 texcoord:TEXCOORD0; 
                float2 tile:TEXCOORD1; 
          float2 lt:TEXCOORD2;
          float2 rb:TEXCOORD3; };
struct v2f { float4 vertex:SV_POSITION; fixed4 color:COLOR; half4 texcoord:TEXCOORD0; half4 border:TEXCOORD1; float4 worldPosition:TEXCOORD2; };

 

在vs中,把参数分开里把两个参数分开:

OUT.texcoord.xy = IN.texcoord;
OUT.texcoord.zw = IN.tile;
OUT.border.xy = IN.lb;
OUT.border.zw = IN.rt;

fs中,对图片进行tile:

IN.texcoord.x = lerp(IN.texcoord.x, saturate(IN.border.x + fmod((IN.texcoord.x - IN.border.x) * IN.texcoord.z, IN.border.z - IN.border.x)), step(0, IN.texcoord.z)); 
IN.texcoord.y = lerp(IN.texcoord.y, saturate(IN.border.y + fmod((IN.texcoord.y - IN.border.y) * IN.texcoord.w, IN.border.w - IN.border.y)), step(0, IN.texcoord.w)); 

 

这样就完成了基于slice类型的tile实现,效果如下:

除了九宫格不会再增加任何顶点。

也可以实现如下效果(边缘缩放,中间tile):

 

posted @ 2017-02-02 18:23  DrAsh9N  阅读(2037)  评论(0编辑  收藏  举报