标签:style blog http io color os ar for sp
欢迎来到unity学习、unity培训、unity企业培训教育专区,这里有很多U3D资源、U3D培训视频、U3D教程、U3D常见问题、U3D项目源码,我们致力于打造业内unity3d培训、学习第一品牌。
游戏的UI开发中经常会遇到染色问题。例如按钮失效变灰的效果,同一个道具通过策划表配的颜色值染上红绿蓝紫等颜色,效果如下
最笨最挫的方法当然是让美术多出几个资源图,这样的一个缺点是浪费资源,在手游上资源的大小显得尤为重要。而且不好维护和复用,修改一个资源需要同时修改其他颜色的多个同类资源。一种比较好的解决方案是通过更换渲染的材质,用染色材质代替原来的材质,然后把原来材质的主纹理和透明纹理赋值给新的材质。这样就可以实现用程序动态切换颜色,而且只需要一个基础资源,节省资源大小,容易维护。
下面给出这个解决方案的流程图,如下图所示
下面写一个例子,通过按r键,g键,b键,y键来动态切换染红色,染绿色,染蓝色,灰化效果。项目的GameObject图如下
染色普通颜色的材质对应的shader如下
-
Shader "Winter/ChangeColor" {
-
Properties {
-
_MainTex ("Base (RGB)", 2D) = "white" {}
-
_Color ("Main Color", Color) = (1,1,1,1)
-
-
}
-
SubShader {
-
Tags { "Queue" = "Transparent+10" }
-
LOD 200
-
Pass
-
{
-
ZWrite On
-
ZTest Off
-
-
-
Blend SrcAlpha OneMinusSrcAlpha
-
Lighting Off
-
//Cull Off
-
CGPROGRAM
-
#pragma vertex vert
-
#pragma fragment frag
-
-
#include "UnityCG.cginc"
-
-
sampler2D _MainTex;
-
fixed4 _Color;
-
float _ColorCtrl;
-
-
struct v2f
-
{
-
float4 pos : SV_POSITION;
-
float2 uv : TEXCOORD0;
-
};
-
-
float4 _MainTex_ST;
-
-
v2f vert (appdata_base v)
-
{
-
v2f o;
-
o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
-
o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
-
return o;
-
}
-
-
fixed4 frag (v2f i) : COLOR
-
{
-
fixed4 texcol = tex2D (_MainTex, i.uv);
-
result = texcol * _Color;
-
result.a = texcol.a;
-
-
return result;
-
}
-
ENDCG
-
}
-
}
-
}
不同颜色要创建不同的材质,并且设置其颜色值,如下
灰化效果比较特殊,颜色值不能弄成(0,0,0,1)或者(1,1,1,1)。需要用到灰化函数
最终颜色的r = (原图r+原图g+原图b)*0.33
最终颜色的g = (原图r+原图g+原图b)*0.33
最终颜色的b = (原图r+原图g+原图b)*0.33
最终颜色的透明值 = 原图的透明值
根据上面,有下面的灰化shader
-
Shader "Winter/Gray"
-
{
-
Properties
-
{
-
_MainTex ("Base (RGB)", 2D) = "white" { }
-
}
-
SubShader
-
{
-
-
Tags
-
{
-
"Queue" = "Transparent+10"
-
}
-
Pass
-
{
-
Lighting Off
-
ZTest Off
-
Cull Off
-
Blend SrcAlpha OneMinusSrcAlpha
-
CGPROGRAM
-
#pragma vertex vert
-
#pragma fragment frag
-
-
#include "UnityCG.cginc"
-
-
sampler2D _MainTex;
-
sampler2D _AlphaTex;
-
half4 _Color;
-
-
struct v2f
-
{
-
float4 pos : SV_POSITION;
-
float2 uv : TEXCOORD0;
-
};
-
-
half4 _MainTex_ST;
-
half4 _AlphaTex_ST;
-
-
v2f vert (appdata_base v)
-
{
-
v2f o;
-
o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
-
o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
-
return o;
-
}
-
-
half4 frag (v2f i) : COLOR
-
{
-
half4 texcol = tex2D (_MainTex, i.uv);
-
half4 result = half4((texcol.r + texcol.g + texcol.b) * 0.33f,(texcol.r + texcol.g + texcol.b) * 0.33f,(texcol.r + texcol.g + texcol.b) * 0.33f,texcol.a);
-
return result;
-
}
-
ENDCG
-
}
-
}
-
}
接着就是要修改Ngui的UISprite源码,添加一个渲染的材质WinterMaterial, 在读取material值的时候,如果有自定义的渲染材质,则需要读取自定义渲染材质
-
public override Material material
-
{
-
get
-
{
-
Material mat = base.material;
-
-
if (mat == null)
-
{
-
mat = (mAtlas != null) ? mAtlas.spriteMaterial : null;
-
mSprite = null;
-
material = mat;
-
if (mat != null) UpdateUVs(true);
-
}
-
-
if (WinterMaterial!=null)
-
{
-
return WinterMaterial;
-
}
-
else
-
{
-
return mat;
-
}
-
}
-
}
然后,添加以下几个染色函数
-
public void ShowAsRed()
-
{
-
ShowAsColor("file:///D:/u3dAB/WinterRedMat.assetbundle", WinterRedMat);
-
}
-
-
public void ShowAsGreen()
-
{
-
ShowAsColor("file:///D:/u3dAB/WinterGreenMat.assetbundle", WinterGreenMat);
-
}
-
-
public void ShowAsBlue()
-
{
-
ShowAsColor("file:///D:/u3dAB/WinterBlueMat.assetbundle", WinterBlueMat);
-
}
-
public void ShowAsGray()
-
{
-
StartCoroutine(<span style="font-family: Arial, Helvetica, sans-serif;">
-
IzUtils.LoadAB("file:///D:/u3dAB/WinterGrayMat.assetbundle", (w) =>
-
{
-
Material mat = w.assetBundle.mainAsset as Material;
-
mat.mainTexture = material.mainTexture;
-
WinterMaterial = mat;
-
w.assetBundle.Unload(false);
-
RefreshPanel(gameObject);
-
})
-
);
-
}
-
private void ShowAsColor(string matName, Material colorMaterial)
-
{
-
if (WinterMaterial == null || colorMaterial != WinterMaterial)
-
{
-
if (colorMaterial == null)
-
{
-
StartCoroutine(
-
IzUtils.LoadAB(matName, (w) =>
-
{
-
Material mat = w.assetBundle.mainAsset as Material;
-
mat.mainTexture = material.mainTexture;
-
colorMaterial = mat;
-
WinterMaterial = mat;
-
w.assetBundle.Unload(false);
-
RefreshPanel(gameObject);
-
})
-
);
-
}
-
else
-
{
-
WinterMaterial = colorMaterial;
-
RefreshPanel(gameObject);
-
}
-
}
-
}
-
GameObject GetMostClosePanel(Transform rootTrans)
-
{
-
if (rootTrans.GetComponent<UIPanel>() != null)
-
{
-
return rootTrans.gameObject;
-
}
-
else if (rootTrans.parent == null)
-
{
-
return null;
-
}
-
else
-
{
-
return GetMostClosePanel(rootTrans.parent);
-
}
-
}
-
-
GameObject panelObj = null;
-
public bool selfRefresh = true;
-
-
void RefreshPanel(GameObject go)
-
{
-
if (!selfRefresh)
-
return;
-
-
if (panelObj == null)
-
{
-
panelObj = GetMostClosePanel(go.transform);
-
}
-
-
if (panelObj != null)
-
{
-
panelObj.GetComponent<UIPanel>().enabled = false;
-
panelObj.GetComponent<UIPanel>().enabled = true;
-
go.SetActive(false);
-
go.SetActive(true);
-
}
-
}
主程序调用方法
-
using UnityEngine;
-
using System.Collections;
-
-
public class ChangeColorExample : MonoBehaviour {
-
private UISprite m_kSprite;
-
void Start ()
-
{
-
GameObject obj = GameObject.Find("Root/Camera/Anchor/Panel/Sprite");
-
m_kSprite = obj.GetComponent<UISprite>();
-
-
-
void Update()
-
{
-
if (Input.GetKeyUp(KeyCode.R))
-
{
-
m_kSprite.ShowAsRed();
-
}
-
else if (Input.GetKeyUp(KeyCode.G))
-
{
-
m_kSprite.ShowAsGreen();
-
}
-
else if (Input.GetKeyUp(KeyCode.B))
-
{
-
m_kSprite.ShowAsBlue();
-
}
-
else if (Input.GetKeyUp(KeyCode.Y))
-
{
-
m_kSprite.ShowAsGray();
-
}
-
}
核心的代码部分如上图所示,这样就可以通过按键rgby来切换染红绿蓝灰的效果。效果如上面第一幅图所示。
总结,用程序来实现动态染色可以高度复用资源,节省空间大小。但是资源的划分需要注意的一点是,如果在一个UIPanel里面有两个不同图集需要用同一个材质进行染色,那么会出现其中的一个出现纹理错乱的现象。目前的解决方案是做多一个颜色值相同的材质,不同的图集用不同的染色材质,这样可以解决上面说的纹理错乱现象。另一个方法是设法把不同的图集弄到一块,这样也可以避免这个问题。
更多精彩请点击 http://www.gopedu.com/
unity游戏开发之NGUI的UISprite染色
标签:style blog http io color os ar for sp
原文地址:http://blog.csdn.net/book_longssl/article/details/40584907