NGUI之UIButton"禁用"状态时置灰
2014-12-02 09:45
309 查看
NGUI中的Button几乎是最常用到的控件之一,并且可以组合各种组件(比如UIButtonColor,UIButtonOffset,UITweenxx),方便设置Button的各种状态下的属性,几乎可以满足我们的所有需求。
但是对于当Button的isEnabled属性设置为false时,根据设置的disableColor属性设置不可点击时的颜色时,虽然我们设置的灰色,但并不是我们想象中的样子!
设置的是灰色,实际运行结果却还是彩色的,只是暗了一点,并不能够很好地表现出其“禁用”的状态!
NGUI中大部分材质都使用的Unlit/Transparent Colored(PS:虽然在Unlit下,但并不是Unity3d内置的,而是NGUI扩展的)
找到其片段着色器,代码如下:
[plain] view
plaincopyprint?
fixed4 frag (v2f i) : COLOR
{
fixed4 col = tex2D(_MainTex, i.texcoord) * i.color;
return col;
}
这个片段着色器很简单,只在“最简单的着色器”上多加了一步,即将从定点着色器中传出的顶点颜色属性乘到了纹理采样得到的像素上。
看到这个代码,就很容易理解为什么是变暗,而不是变成灰色了
顶点的颜色数据是从UISprite之类的面板中传递进来的,其最大值是白色(255,255,255,255),而这里是正交化的,最大值白色对应(1.0,1.0,1.0,1.0),这也是默认值,当采样得到的像素值x1.0,相当于采样得到的纹理值;如果设置一个其他的颜色,正交化后肯定会小于1.0,当采样得到的像素值乘以这个值后,像素值会比之前小,而最小值是(0,0, 0,0)即黑色,也就是说如果设置一个不是白色的颜色,就会使像素值更接近于黑色,这就是变暗的原因!
这就更糟了!游戏中纹理是很占空间的,这样做相当于将UI资源翻了一倍!
还是从Shader方面入手吧!
想象一下,如果在着色器处理之前,传递一个bool值,当这个bool值为true时,正常绘制纹理;当这个bool值为false时,绘制灰色纹理。
(Unity3d的Shader中并不支持传递bool值,这里只是举个栗子)
这样看似很合理,也确实可以实现,但是会有一个问题,这个bool值肯定要在顶点着色器阶段传过去,而NGUI提供的“纹理打包”功能(即很多纹理合并成一个Atlas,即节省空间,还可以有一些其他信息,比如九宫格拉伸的参数。。。),当这个bool值为false时,这个Atlas中所有的绘制即全部变为灰色,这是不符合逻辑的,当然可以每张小图单独处理,即相当于损失掉NGUI的“纹理打包”功能
选取一个颜色值,作为约定为置灰的标记,当片段着色器检测到这个颜色值之后,执行渲染灰色的shader!
这个颜色值可以任意选择,我这里选取纯黑色作为“约定颜色”,片段着色器代码如下:
[plain] view
plaincopyprint?
fixed4 frag (v2f i) : COLOR
{
fixed4 col;
if (i.color.r < 0.001)
{
col = tex2D(_MainTex, i.texcoord);
float grey = dot(col.rgb, float3(0.299, 0.587, 0.114));
col.rgb = float3(grey, grey, grey);
}
else
{
col = tex2D(_MainTex, i.texcoord) * i.color;
}
return col;
}
其中(0.299,0.587,0.114)为灰度公式的参数
我复制了一份NGUI例子的纹理和材质,将此Shader设置到材质中,渲染效果如图
(最上面两个是原始状态下的效果,中间两个是NGUI提供的禁用状态效果,最下面两个分别是修改后Shader渲染同一个Atlas得到的结果)
这才是我想要的灰色!
以上文章转载自NGUI之UIButton"禁用"状态时置灰,感谢oneRain提供好文章
修改上面的代码通,过修改后效率明显大幅提升:
设置UISprite.color = Color.black;就能使用了。
原理是在v2f中申请一个寄存器TEXCOORD1放置数据gray,并在顶点程序vert中计算是否灰色,在片段程序frag中用i.gray == 0做if判断。
第一段代码效率低的原因是if (i.color.r < 0.001)这里访问了color的分量r,但在官方文档中明确说了这样做效率低,除非必要情况时才使用。
另外在PC中(fixed gray : TEXCOORD1;)可以改成(bool gray : TEXCOORD1;),但在移动设备(android和ios)中都会有问题,求解。
以上文章转载自修改Shader让NGUI支持灰色滤镜,感谢pw提供好文章
但是对于当Button的isEnabled属性设置为false时,根据设置的disableColor属性设置不可点击时的颜色时,虽然我们设置的灰色,但并不是我们想象中的样子!
设置的是灰色,实际运行结果却还是彩色的,只是暗了一点,并不能够很好地表现出其“禁用”的状态!
1.原理
Unity3d中所有的渲染都是基于Shader的,而Shader绑定在Material上,打开一个NGUI例子中自带的Material,得到其使用Shader的文件NGUI中大部分材质都使用的Unlit/Transparent Colored(PS:虽然在Unlit下,但并不是Unity3d内置的,而是NGUI扩展的)
找到其片段着色器,代码如下:
[plain] view
plaincopyprint?
fixed4 frag (v2f i) : COLOR
{
fixed4 col = tex2D(_MainTex, i.texcoord) * i.color;
return col;
}
这个片段着色器很简单,只在“最简单的着色器”上多加了一步,即将从定点着色器中传出的顶点颜色属性乘到了纹理采样得到的像素上。
看到这个代码,就很容易理解为什么是变暗,而不是变成灰色了
顶点的颜色数据是从UISprite之类的面板中传递进来的,其最大值是白色(255,255,255,255),而这里是正交化的,最大值白色对应(1.0,1.0,1.0,1.0),这也是默认值,当采样得到的像素值x1.0,相当于采样得到的纹理值;如果设置一个其他的颜色,正交化后肯定会小于1.0,当采样得到的像素值乘以这个值后,像素值会比之前小,而最小值是(0,0, 0,0)即黑色,也就是说如果设置一个不是白色的颜色,就会使像素值更接近于黑色,这就是变暗的原因!
2.置灰
NGUI只提供了这样一种变暗的功能,用来表现其“禁用”的状态,但是这并不是最好的结果,如果需要介于黑白之间的灰色纹理,难道非要美术对每一个可能会被置灰的纹理重新制作一张纹理吗?这就更糟了!游戏中纹理是很占空间的,这样做相当于将UI资源翻了一倍!
还是从Shader方面入手吧!
想象一下,如果在着色器处理之前,传递一个bool值,当这个bool值为true时,正常绘制纹理;当这个bool值为false时,绘制灰色纹理。
(Unity3d的Shader中并不支持传递bool值,这里只是举个栗子)
这样看似很合理,也确实可以实现,但是会有一个问题,这个bool值肯定要在顶点着色器阶段传过去,而NGUI提供的“纹理打包”功能(即很多纹理合并成一个Atlas,即节省空间,还可以有一些其他信息,比如九宫格拉伸的参数。。。),当这个bool值为false时,这个Atlas中所有的绘制即全部变为灰色,这是不符合逻辑的,当然可以每张小图单独处理,即相当于损失掉NGUI的“纹理打包”功能
3.解决方案
损失一个颜色值吧,作为“约定”!选取一个颜色值,作为约定为置灰的标记,当片段着色器检测到这个颜色值之后,执行渲染灰色的shader!
这个颜色值可以任意选择,我这里选取纯黑色作为“约定颜色”,片段着色器代码如下:
[plain] view
plaincopyprint?
fixed4 frag (v2f i) : COLOR
{
fixed4 col;
if (i.color.r < 0.001)
{
col = tex2D(_MainTex, i.texcoord);
float grey = dot(col.rgb, float3(0.299, 0.587, 0.114));
col.rgb = float3(grey, grey, grey);
}
else
{
col = tex2D(_MainTex, i.texcoord) * i.color;
}
return col;
}
其中(0.299,0.587,0.114)为灰度公式的参数
我复制了一份NGUI例子的纹理和材质,将此Shader设置到材质中,渲染效果如图
(最上面两个是原始状态下的效果,中间两个是NGUI提供的禁用状态效果,最下面两个分别是修改后Shader渲染同一个Atlas得到的结果)
这才是我想要的灰色!
以上文章转载自NGUI之UIButton"禁用"状态时置灰,感谢oneRain提供好文章
修改Shader让NGUI支持灰色滤镜
修改上面的代码通,过修改后效率明显大幅提升:struct v2f { float4 vertex : SV_POSITION; half2 texcoord : TEXCOORD0; fixed4 color : COLOR; fixed gray : TEXCOORD1; }; sampler2D _MainTex; float4 _MainTex_ST; v2f vert (appdata_t v) { v2f o; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); o.color = v.color; o.gray = dot(v.color, fixed4(1,1,1,0)); return o; } fixed4 frag (v2f i) : COLOR { fixed4 col; if (i.gray == 0) { col = tex2D(_MainTex, i.texcoord); col.rgb = dot(col.rgb, fixed3(.222,.707,.071)); } else { col = tex2D(_MainTex, i.texcoord) * i.color; } return col; }
设置UISprite.color = Color.black;就能使用了。
原理是在v2f中申请一个寄存器TEXCOORD1放置数据gray,并在顶点程序vert中计算是否灰色,在片段程序frag中用i.gray == 0做if判断。
第一段代码效率低的原因是if (i.color.r < 0.001)这里访问了color的分量r,但在官方文档中明确说了这样做效率低,除非必要情况时才使用。
另外在PC中(fixed gray : TEXCOORD1;)可以改成(bool gray : TEXCOORD1;),但在移动设备(android和ios)中都会有问题,求解。
以上文章转载自修改Shader让NGUI支持灰色滤镜,感谢pw提供好文章
相关文章推荐
- Unity3D开发(二):NGUI之UIButton"禁用"状态时置灰
- Unity3D开发(二):NGUI之UIButton"禁用"状态时置灰
- NGUI之UIButton"禁用"状态时置灰
- NGUI之UIButton"禁用"状态时置灰
- NGUI之UIButton"禁用"状态时置灰
- vmware安装CentOS " Intel VT-x 处于禁用状态"
- NGUI之UIButton"禁用"状态时置灰
- 客户端不能正常连接oracle,监听状态为"Not All Endpoints Registered"
- 对于win7"媒体流被管理员定义的组策略禁用"的解决办法
- "用户 'sa' 登录失败。原因: 该帐户被禁用。"的解决方案
- Citrix XenDesktop 分配的计算机一直显示"未注册"状态
- sqlpus报错"ORA-01033: ORACLE initialization or shutdown in progress",且数据库状态是"ORA-01507: database not m
- VC debug状态下"one or more files are out of date"的问题
- spring bean scope="prototype" 有状态bean 无状态bean
- linux 下 JFreeChart 乱码 (中文状态,十分怪异的小方块"口")
- ASP.NET "由於该物件目前的状态,导致作业无效"解决方法
- 消息 7314,级别 16,状态 1,第 1 行 链接服务器 "(null)" 的 OLE DB 访问接口 "MICROSOFT.JET.OLEDB.4.0" 不包含表 "Sheet1"。该表不存在,
- 关于XmlTextWriter的 "处于状态 Epilog 的标记 StartElement 将导致无效的 XML 文档"报错原因
- 异常:"System.Net.WebException: 请求因 HTTP 状态 401 失败:Unauthorized。"
- "此页的状态信息无效,可能已损坏"的解决方法