设为首页 加入收藏

TOP

Unity的UI究竟为什么可以合批(一)
2019-09-17 18:45:19 】 浏览:54
Tags:Unity 究竟 为什么 可以
1.UI/Default代码研究
首先,我想到的是,既然是对图集纹理进行采样,而且又不能统一更改材质的纹理UV值,我们通常写的shader都是直接根据模型UV值对主纹理进行采样,那会不会是shader中对MainTexture进行了什么神奇的处理,让图片采样只根据指定的UV值进行采样呢?
我去官网下载了shader代码,找到了UI/Default的具体实现:


fixed4 _Color;
fixed4 _TextureSampleAdd;
float4 _ClipRect;

v2f vert(appdata_t v)
{
v2f OUT;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
OUT.worldPosition = v.vertex;
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);

OUT.texcoord = v.texcoord;

OUT.color = v.color * _Color;
return OUT;
}

sampler2D _MainTex;

fixed4 frag(v2f IN) : SV_Target
{
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;

#ifdef UNITY_UI_CLIP_RECT
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#endif

#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif

return color;
}
看了上面的代码,我们可以基本确定,没有在shader中做什么特别神奇的MainTexture处理。但是我们还是可以发现一些不同的地方,这里上面的变量_Color,_TextureSampleAdd,_ClipRect并没有暴露在面板上,可以看出来这三个变量是通过某些脚本传递给shader的。
我们知道,伴随着Defalut材质的一般使用的是Image组件、Text组件。这两个组件会绘制顶点与三角形,然后使用指定的材质进行渲染。所以会不会是Image组件或Text组件中使用了什么算法,计算过图片UV值,并把上面三个变量填充好传给shader的呢?


2.Image组件代码研究
因为unity的ui代码已经开源了,所以我们很幸运的可以看到Image的源码是怎么实现的,因为Image组件代码很多,所以这里就只贴出比较主要的绘制顶点的函数:


/// <summary>
/// Update the UI renderer mesh.
/// </summary>
protected override void OnPopulateMesh(VertexHelper toFill)
{
if (activeSprite == null)
{
base.OnPopulateMesh(toFill);
return;
}

switch (type)
{
case Type.Simple:
if (!useSpriteMesh)
GenerateSimpleSprite(toFill, m_PreserveAspect);
else
GenerateSprite(toFill, m_PreserveAspect);
break;
case Type.Sliced:
GenerateSlicedSprite(toFill);
break;
case Type.Tiled:
GenerateTiledSprite(toFill);
break;
case Type.Filled:
GenerateFilledSprite(toFill, m_PreserveAspect);
break;
}
}

我们可以看到,这个函数是用来刷新UI渲染的,unity对图片的四种类型分别进行了处理,这里我们就只看一下最简单的Simple模式的代码:


/// <summary>
/// Generate vertices for a simple Image.
/// </summary>
void GenerateSimpleSprite(VertexHelper vh, bool lPreserveAspect)
{
Vector4 v = GetDrawingDimensions(lPreserveAspect);
var uv = (activeSprite != null) ? Sprites.DataUtility.GetOuterUV(activeSprite) : Vector4.zero;

var color32 = color;
vh.Clear();
vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(uv.x, uv.y));
vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(uv.x, uv.w));
vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(uv.z, uv.w));
vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(uv.z, uv.y));

vh.AddTriangle(0, 1, 2);
vh.AddTriangle(2, 3, 0);
}

/// Image's dimensions used for drawing. X = left, Y = bottom, Z = right, W = top.
private Vector4 GetDrawingDimensions(bool shouldPreserveAspect)
{
var padding = activeSprite == null ? Vector4.zero : Sprites.DataUtility.GetPadding(activeSprite);
var size = activeSprite == null ? Vector2.zero : new Vector2(activeSprite.rect.width, activeSprite.rect.height);

Rect r = GetPixelAdjustedRect();
// Debug.Log(string.Format("r:{2}, size:{0}, padding:{1}", size, padding, r));

int spriteW = Mathf.RoundToInt(size.x);
int spriteH = Mathf.RoundToInt(size.y);

var v = new Vector4(
padding.x / spriteW,
padding.y / spriteH,
(spriteW - padding.z) / spriteW,
(spriteH - padding.w) / spriteH);

if (shouldPreserveAspect &
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C# Dictionary 函数解析及使用方法 下一篇浅谈对多线程的理解(一)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目