如下图,当Image Type设置成Tile时会产生过多顶点。
解决方法是用一个shader,把sprite的uv范围和tile步长传进去,在shader里用求余的方法处理。
以下是图片分成九宫格后,Image Type为Sliced的一个解决方案:
首先新建一个TileSliceEffect脚本,继承BaseMeshEffect,下面要在ModifyMesh中添加代码。
当图片分成九宫格后,排列顺序如下:
每个九宫格又分成两个三角形一共六个点,顺序如下(与在atlas中的方向有关):
对于每个格中的六个点,可定第一个点和第四个点为左上角和右下角的点,position范围为:
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 >= rectBorder.x ? 1f : tileWidth / rectBorder.x);
接下来还需要得到每个格子的uv范围:
var leftTopUV = verts[6 * i + 1].uv0; var rightBottomUV = verts[6 * i + 4].uv0;
最后,要把这些信息传入shader。
https://blog.innogames.com/unity-3d-tutorial-how-to-improve-text-field-outlines 这里有篇文章,介绍了UIVertex中有哪些参数可以使用。文章中使用tangent传入其他信息,但tangent和normal都是顶点方向信息,实测当image旋转后,会发生变化,所以接下来是比较恶心的代码:
vert.uv0 = vert.uv0 * 0.5f + new Vector2((int)(leftTopUV.x * 1000), (int)(leftTopUV.y * 1000)); vert.uv1 = uv1 * 0.5f + new Vector2((int)(rightBottomUV.x * 1000), (int)(rightBottomUV.y * 1000));
shader是从builtin的DefaultUI基础上改的:
struct appdata_t { float4 vertex:POSITION; float4 color:COLOR; float2 texcoord:TEXCOORD0; float2 tile:TEXCOORD1; }; struct v2f { float4 vertex:SV_POSITION; fixed4 color:COLOR; half4 texcoord:TEXCOORD0; half4 border:TEXCOORD1; float4 worldPosition:TEXCOORD2; };
vs中,将uv信息还原,并输出tile和border:
OUT.texcoord.xy = (IN.texcoord - floor(IN.texcoord)) * 2; OUT.texcoord.zw = lerp(0, 1.0 / ((IN.tile - floor(IN.tile)) * 2), step(0, IN.tile)); OUT.border.xy = floor(IN.texcoord) * 0.001; OUT.border.zw = floor(IN.tile) * 0.001;
fs中,对图片进行tile:
IN.texcoord.x = lerp(IN.texcoord.x, clamp(IN.border.x + fmod((IN.texcoord.x - IN.border.x) * IN.texcoord.z, IN.border.z - IN.border.x), 0, 1), step(0, IN.texcoord.z)); IN.texcoord.y = lerp(IN.texcoord.y, clamp(IN.border.y + fmod((IN.texcoord.y - IN.border.y) * IN.texcoord.w, IN.border.w - IN.border.y), 0, 1), step(0, IN.texcoord.w));
这样就完成了基于slice类型的tile实现,效果如下:
除了九宫格不会再增加任何顶点。
也可以实现如下效果(边缘缩放,中间tile):
[UGUI]TiledSliceEffect----Image的Tiled类型产生过多顶点的优化
原文:http://www.cnblogs.com/drashnane/p/6361437.html