首页 > 其他 > 详细

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

时间:2017-02-02 19:10:14      阅读:662      评论:0      收藏:0      [点我收藏+]

如下图,当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

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!