[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):