UGUI学习笔记
【旧博客转移 - 2016年7月7日 23:13 】
最近用了下UGUI,毕竟是Unity官方内置的,估计以后也会慢慢取代NGU了,现在资料也还算丰富
图集打包方式
看了雨松MOMO的几篇文章UGUI研究院之全面理解图集与使用(三),看完后自己弄了一些图片实验了一下
sprite packer
这是UGUI自带的打包工具,同一个图集这里面会很智能的分成多个小图集,纹理格式不同(多张小图集是怎么合并渲染的?)
Sprite图片设置相同的packingTag就会打包到一个图集里,但是我发现Unity5.3.5版本的UGUI下,两张图设置不同的pack tag,居然只有1个setPass Call。而Unity4.6.7版本的UGUI下 ,两张图设置不同的pack tag就是2个drawCall。这点比较神奇~
但我还是觉得UGUI的自带图集不好用!(可能我还没搞懂,不会用~ 哈哈)
1.不是最小矩形,会多空白区域占内存(已经选了TightPackerPolicy 也不是最小矩形)
2.加载/释放不可控,貌似进入游戏就会全部加载进内存(用profiler看)
3.资源热跟新不好控制
建议用还是用TexturePacker自己写Atlas去控制
UGUI的结构
下载了UGUI源码粗略的看了一下,网上也有很多教程编译、调试源码的方法
UGUI的结构简单清晰,Image继承了MaskableGraphic->Graphic,
Graphic(控制渲染显示类,图片什么的最终都继承它)
Graphic类中的OnPopulateMesh方法会去生成顶点,三角形数据,用一些dirty变量控制重绘。
VertexHelper类:存放uv,vertex,color等数据。
其中核心的渲染部分CanvasRender代码Unity并没有开源,封装在了UnityEngine里面.. 所以看不到它是怎么合并贴图渲染的。
UGUI的默认Shader
UGUI图片的默认材质是在Graphic.defaultGraphicMaterial
这里面调用Canvas.GetDefaultCanvasMaterial()这个方法获取的。
自带的Shader可以在官网上下载的到
Shader "UI/Default" { Properties { [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} _Color ("Tint", Color) = (1,1,1,1) _StencilComp ("Stencil Comparison", Float) = 8 _Stencil ("Stencil ID", Float) = 0 _StencilOp ("Stencil Operation", Float) = 0 _StencilWriteMask ("Stencil Write Mask", Float) = 255 _StencilReadMask ("Stencil Read Mask", Float) = 255 _ColorMask ("Color Mask", Float) = 15 [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0 } SubShader { Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" "CanUseSpriteAtlas"="True" } Stencil { Ref [_Stencil] Comp [_StencilComp] Pass [_StencilOp] ReadMask [_StencilReadMask] WriteMask [_StencilWriteMask] } Cull Off Lighting Off ZWrite Off ZTest [unity_GUIZTestMode] Blend SrcAlpha OneMinusSrcAlpha ColorMask [_ColorMask] Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #include "UnityUI.cginc" #pragma multi_compile __ UNITY_UI_ALPHACLIP struct appdata_t { float4 vertex : POSITION; float4 color : COLOR; float2 texcoord : TEXCOORD0; }; struct v2f { float4 vertex : SV_POSITION; fixed4 color : COLOR; half2 texcoord : TEXCOORD0; float4 worldPosition : TEXCOORD1; }; fixed4 _Color; fixed4 _TextureSampleAdd; float4 _ClipRect; v2f vert(appdata_t IN) { v2f OUT; OUT.worldPosition = IN.vertex; OUT.vertex = mul(UNITY_MATRIX_MVP, OUT.worldPosition); OUT.texcoord = IN.texcoord; #ifdef UNITY_HALF_TEXEL_OFFSET OUT.vertex.xy += (_ScreenParams.zw-1.0)*float2(-1,1); #endif OUT.color = IN.color * _Color; return OUT; } sampler2D _MainTex; fixed4 frag(v2f IN) : SV_Target { half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color; color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect); #ifdef UNITY_UI_ALPHACLIP clip (color.a - 0.001); #endif return color; } ENDCG } } }
它跟NGUI一样也是用renderQueue控制渲染深度,但UGUI是使用Stencil模板测试来做遮罩的,所以如果重写UGUI的Shader想要支持Mask的话,就要加上Stencil的代码。
实现灰度图
非常简单,改写一下默认的Shader,在frag中加上灰度值转化的代码。
新建一个Material,挂上这个Shader,然后给要灰掉的图片使用这个材质就OK了,而且支持裁剪。
总结
UGUI使用很方便,分辨率自适应,锚点这些都很好控制。 而且它能吧Text跟Image都合并成一个pass(感觉整个Canvas下都会合并成1个pass) 不知道这样究竟能不能提高性能,表面上是减少了setPassCall,但我觉得上只要Image,或Text有改动,就会重新计算整个Canvas下所有组件合并网格。一些频繁变化的东西,还是弄成独立的Canvas好,比如血条,瓢字之类的。 现在只是大概了解了一下UGUI,还不太熟悉,如果我有理解的不对的地方欢迎留言交流哈~