Ngui Shader Transparent Colored (Packed)和BMFont

来源:互联网 发布:域名注册时间查询 编辑:程序博客网 时间:2024/06/06 13:56

最近工作需要,为扩展Ngui的功能,需要自己实现一种效果,所以就打算先了解了解Ngui自带的shader,发现一般像Unlit - Dynamic Font,Unlit - Dynamic Font (AlphaClip),Unlit - Dynamic Font (SoftClip)这样都有三种配套的shader,但是Transparent Colored系列的却不止三个,还有Unlit - Transparent Colored (Packed),我就对比的看了一些它和Unlit - Transparent Colored的区别,区别也就在片段着色器的那几行代码,看过来看过去也没有看明白。。。。也没搜索到代码里哪里用到了这个packed的shader

好,那就上在网上搜搜吧,然后找到了一些关于制作ngui字体的教程http://www.unitymanual.com/blog-13559-220.html,提到了创建材质时使用带packed的shader,我就按照这个教程随便测试了一下,但发现其他的shader也可以,比如Unlit - Transparent Colored 。最后还发现使用Unlit - Transparent Colored (Packed)shader的时候,UILabel使用渐变色效果还会出现问题。



    同时在网上发现其他类似这样的教程,而且貌似也只有在字体相关方面的时候Unlit - Transparent Colored (Packed)才会被提到,于是,我就开始在NGUIText里去找找看了,好了,废话说完了,切入正题

先看看Unlit/Transparent Colored (Packed)内容

Shader "Unlit/Transparent Colored (Packed)"{Properties{_MainTex ("Base (RGB), Alpha (A)", 2D) = "black" {}//纹理}SubShader{LOD 200Tags{"Queue" = "Transparent""IgnoreProjector" = "True""RenderType" = "Transparent"}Pass{Cull OffLighting OffZWrite OffOffset -1, -1Fog { Mode Off }ColorMask RGBBlend SrcAlpha OneMinusSrcAlphaCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"sampler2D _MainTex;half4 _MainTex_ST;//定义顶点程序输入struct appdata_t{float4 vertex : POSITION;half4 color : COLOR;float2 texcoord : TEXCOORD0;};//定义片段程序输入struct v2f{float4 vertex : POSITION;half4 color : COLOR;float2 texcoord : TEXCOORD0;};v2f vert (appdata_t v){v2f o;o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);o.color = v.color;o.texcoord = v.texcoord;return o;}half4 frag (v2f IN) : COLOR{//关键在下面half4 mask = tex2D(_MainTex, IN.texcoord);half4 mixed = saturate(ceil(IN.color - 0.5));//这句是对顶点颜色各个分量四舍五入//单看下面这句不知所云,为什么是0.51,-0.49是什么意思??//和上面一句加在一起简化下来就是一个分段函数,设顶点颜色为x,  //col=2.04x; (当x>=0 且 x < 0.5)//col = 2.04x -0.5/0.49; (当x >= 0.5 且 x <= 1)half4 col = saturate((mixed * 0.51 - IN.color) / -0.49);//下面操作什么意思??不懂。。。不急,慢慢来mask *= mixed;col.a *= mask.r + mask.g + mask.b + mask.a;return col;}ENDCG}}Fallback Off}
在看完上面的shader的时候,我实在是不知道是干什么用的,好吧,看看NGUIText中有没相面的东西

突然发现了这几行代码

else{// Packed fonts come as alpha masks in each of the RGBA channels.// In order to use it we need to use a special shader.//// Limitations:// - Effects (drop shadow, outline) will not work.// - Should not be a part of the atlas (eastern fonts rarely are anyway).// - Lower color precisionColor col = uc;col *= 0.49f;switch (glyph.channel){case 1: col.b += 0.51f; break;case 2: col.g += 0.51f; break;case 4: col.r += 0.51f; break;case 8: col.a += 0.51f; break;}Color32 c = col;for (int j = 0, jmax = (bold ? 16 : 4); j < jmax; ++j)cols.Add(c);}

先将顶点颜色乘以0.49,然后根据字形的channel信息,选择给某个通道值加上0.51,为什么要这么做呢?channel又是什么呢?

几经折腾,终于找到了答案,原来,当我们使用Bitmap Font Generator工具为文字生成图片时,因为文字的信息只需要一个颜色通道就能存储下来,所以,可以在生成图片的时候在不同的通道写入不同的信息。具体参考http://www.angelcode.com/products/bmfont/doc/file_format.html#tags

导出的同时,还会导出一个txt文件,存储着图片和文字的一些信息,这里只列举一些

对应下图中的chnl value


说明每个通道可以存放不同的信息

导出文本中

char id=32   x=206   y=79    width=1     height=1     xoffset=0     yoffset=15    xadvance=4     page=0  chnl=15

最后一个参数解释如下



所以Ngui的做法很巧妙,如过使用了packed的功能,则需要把使用了哪个通道这个数据告诉shader,所有就有了下面

Color col = uc;col *= 0.49f;switch (glyph.channel){case 1: col.b += 0.51f; break;case 2: col.g += 0.51f; break;case 4: col.r += 0.51f; break;case 8: col.a += 0.51f; break;}Color32 c = col;for (int j = 0, jmax = (bold ? 16 : 4); j < jmax; ++j)cols.Add(c);
上面的意思是先将顶点颜色乘以0.49,然后,使用了哪个通道,就把哪个通道值加上0.51

所以,传到GPU中,使用了packed的纹理的字的顶点颜色肯定是三个分量小于0.5,字形使用了的通道值大于0.5,比如,渲染一个颜色值为(0.2,0.3,0.4,0.5)的文字,

而字体纹理只用到了R通道,则,Ngui会将顶点颜色设置为(0.2*0.49+0.51,0.3*0.49,0.4*0.49,0.5*0.49)= (0.608,0.147,0.196,0.245),这里就是将所有通道值缩小一半,字体使用的通道再加上0.51,这样保证了原来顶点颜色的信息,同时也标示出了哪个通道时字体纹理使用的,即大于0.5的那个通道。

在来看shader

half4 frag (v2f IN) : COLOR{half4 mask = tex2D(_MainTex, IN.texcoord);half4 mixed = saturate(ceil(IN.color - 0.5));half4 col = saturate((mixed * 0.51 - IN.color) / -0.49);mask *= mixed;col.a *= mask.r + mask.g + mask.b + mask.a;return col;}
首先mask取得片段对应纹理的颜色,但这个我们只使用其中一个通道

mixed会将顶点颜色四舍五入,所以就只会剩下一个通道值为1,其他的为0,上述的例子到这里就变成了(1,0,0,0)

然后我们的顶点颜色需要还原回来,所以half4 col = saturate((mixed * 0.51 - IN.color) / -0.49);,即col就是我们之前的顶点颜色,即(0.2,0.3,0.4,0.5)

然后mask*=mixed;,将纹理的其他值设置为0,只保留需要的通道值,即R分量值

最后,我们将字形信息通过顶点颜色的alpha分量表现出来,因为我们不知道用了哪个分量,但是mask中只有一个分量是非0的字形信息,其他的分量都置为了0,所以都加到了最终颜色的alpha分量

最终,我们用一个通道渲染出了我们设置的颜色的字体,但是却没有将通道的选择作为单独的变量传递给shader,所以我感觉Ngui的这种做法挺巧妙的


0 0