游戏的UI开发中常常会遇到染色问题。比如button失效变灰的效果,同一个道具通过策划表配的颜色值染上红绿蓝紫等颜色,效果例如以下

最笨最挫的方法当然是让美术多出几个资源图。这种一个缺点是浪费资源,在手游上资源的大小显得尤为重要。并且不好维护和复用。改动一个资源须要同一时候改动其它颜色的多个同类资源。一种比較好的解决方式是通过更换渲染的材质,用染色材质取代原来的材质。然后把原来材质的主纹理和透明纹理赋值给新的材质。这样就能够实现用程序动态切换颜色。并且仅仅须要一个基础资源。节省资源大小。easy维护。

以下给出这个解决方式的流程图。例如以下图所看到的

以下写一个样例,通过按r键,g键。b键。y键来动态切换染红色,染绿色。染蓝色,灰化效果。项目的GameObject图例如以下

染色普通颜色的材质相应的shader例如以下

[plain]

  1. Shader "Winter/ChangeColor" {
  2. Properties {
  3. _MainTex ("Base (RGB)", 2D) = "white" {}
  4. _Color ("Main Color", Color) = (1,1,1,1)
  5. }
  6. SubShader {
  7. Tags { "Queue" = "Transparent+10" }
  8. LOD 200
  9. Pass
  10. {
  11. ZWrite On
  12. ZTest Off
  13. Blend SrcAlpha OneMinusSrcAlpha
  14. Lighting Off
  15. //Cull Off
  16. CGPROGRAM
  17. #pragma vertex vert
  18. #pragma fragment frag
  19. #include "UnityCG.cginc"
  20. sampler2D _MainTex;
  21. fixed4 _Color;
  22. float _ColorCtrl;
  23. struct v2f
  24. {
  25. float4  pos : SV_POSITION;
  26. float2  uv : TEXCOORD0;
  27. };
  28. float4 _MainTex_ST;
  29. v2f vert (appdata_base v)
  30. {
  31. v2f o;
  32. o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
  33. o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
  34. return o;
  35. }
  36. fixed4 frag (v2f i) : COLOR
  37. {
  38. fixed4 texcol = tex2D (_MainTex, i.uv);
  39. result = texcol * _Color;
  40. result.a = texcol.a;
  41. return result;
  42. }
  43. ENDCG
  44. }
  45. }
  46. }

不同颜色要创建不同的材质,而且设置其颜色值,例如以下

 
 

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaXdpbnRlcmljZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" style="border:none; max-width:100%">

灰化效果比較特殊,颜色值不能弄成(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

[plain]

  1. Shader "Winter/Gray"
  2. {
  3. Properties
  4. {
  5. _MainTex ("Base (RGB)", 2D) = "white" { }
  6. }
  7. SubShader
  8. {
  9. Tags
  10. {
  11. "Queue" = "Transparent+10"
  12. }
  13. Pass
  14. {
  15. Lighting Off
  16. ZTest Off
  17. Cull Off
  18. Blend SrcAlpha OneMinusSrcAlpha
  19. CGPROGRAM
  20. #pragma vertex vert
  21. #pragma fragment frag
  22. #include "UnityCG.cginc"
  23. sampler2D _MainTex;
  24. sampler2D _AlphaTex;
  25. half4 _Color;
  26. struct v2f
  27. {
  28. float4  pos : SV_POSITION;
  29. float2  uv : TEXCOORD0;
  30. };
  31. half4 _MainTex_ST;
  32. half4 _AlphaTex_ST;
  33. v2f vert (appdata_base v)
  34. {
  35. v2f o;
  36. o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
  37. o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
  38. return o;
  39. }
  40. half4 frag (v2f i) : COLOR
  41. {
  42. half4 texcol = tex2D (_MainTex, i.uv);
  43. 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);
  44. return result;
  45. }
  46. ENDCG
  47. }
  48. }
  49. }

接着就是要改动Ngui的UISprite源代码。加入一个渲染的材质WinterMaterial, 在读取material值的时候。假设有自己定义的渲染材质,则须要读取自己定义渲染材质

[csharp]

  1. public override Material material
  2. {
  3. get
  4. {
  5. Material mat = base.material;
  6. if (mat == null)
  7. {
  8. mat = (mAtlas != null) ?

    mAtlas.spriteMaterial : null;

  9. mSprite = null;
  10. material = mat;
  11. if (mat != null) UpdateUVs(true);
  12. }
  13. if (WinterMaterial!=null)
  14. {
  15. return WinterMaterial;
  16. }
  17. else
  18. {
  19. return mat;
  20. }
  21. }
  22. }

然后。加入下面几个染色函数

[csharp]

  1. public void ShowAsRed()
  2. {
  3. ShowAsColor("file:///D:/u3dAB/WinterRedMat.assetbundle", WinterRedMat);
  4. }
  5. public void ShowAsGreen()
  6. {
  7. ShowAsColor("file:///D:/u3dAB/WinterGreenMat.assetbundle", WinterGreenMat);
  8. }
  9. public void ShowAsBlue()
  10. {
  11. ShowAsColor("file:///D:/u3dAB/WinterBlueMat.assetbundle", WinterBlueMat);
  12. }//须要加入染色值的,则须要加入材质和染色函数
  13. public void ShowAsGray()
  14. {
  15. StartCoroutine(<span style="font-family: Arial, Helvetica, sans-serif;">//自己定义的www函数</span>
[csharp]

  1. IzUtils.LoadAB("file:///D:/u3dAB/WinterGrayMat.assetbundle", (w) =>
  2. {//assetbundle是打包好的材质
  3. Material mat = w.assetBundle.mainAsset as Material;
  4. mat.mainTexture = material.mainTexture;
  5. WinterMaterial = mat;
  6. w.assetBundle.Unload(false);
  7. RefreshPanel(gameObject);
  8. })
  9. );
  10. }
  11. private void ShowAsColor(string matName, Material colorMaterial)
  12. {
  13. if (WinterMaterial == null || colorMaterial != WinterMaterial)
  14. {
  15. if (colorMaterial == null)
  16. {
  17. StartCoroutine(
  18. IzUtils.LoadAB(matName, (w) =>
  19. {
  20. Material mat = w.assetBundle.mainAsset as Material;
  21. mat.mainTexture = material.mainTexture;
  22. colorMaterial = mat;
  23. WinterMaterial = mat;
  24. w.assetBundle.Unload(false);
  25. RefreshPanel(gameObject);
  26. })
  27. );
  28. }
  29. else
  30. {
  31. WinterMaterial = colorMaterial;
  32. RefreshPanel(gameObject);
  33. }
  34. }
  35. }
  36. GameObject GetMostClosePanel(Transform rootTrans)
  37. {
  38. if (rootTrans.GetComponent<UIPanel>() != null)
  39. {
  40. return rootTrans.gameObject;
  41. }
  42. else if (rootTrans.parent == null)
  43. {
  44. return null;
  45. }
  46. else
  47. {
  48. return GetMostClosePanel(rootTrans.parent);
  49. }
  50. }
  51. GameObject panelObj = null;
  52. public bool selfRefresh = true;
  53. void RefreshPanel(GameObject go)
  54. {
  55. if (!selfRefresh)
  56. return;
  57. if (panelObj == null)
  58. {
  59. panelObj = GetMostClosePanel(go.transform);
  60. }
  61. if (panelObj != null)
  62. {
  63. panelObj.GetComponent<UIPanel>().enabled = false;
  64. panelObj.GetComponent<UIPanel>().enabled = true;
  65. go.SetActive(false);
  66. go.SetActive(true);
  67. }
  68. }

主程序调用方法

[csharp]

  1. using UnityEngine;
  2. using System.Collections;
  3. public class ChangeColorExample : MonoBehaviour {
  4. private UISprite m_kSprite;
  5. void Start ()
[csharp]

  1. {
  2. GameObject obj = GameObject.Find("Root/Camera/Anchor/Panel/Sprite");
  3. m_kSprite = obj.GetComponent<UISprite>();
  4. void Update()
  5. {
  6. if (Input.GetKeyUp(KeyCode.R))
  7. {
  8. m_kSprite.ShowAsRed();
  9. }
  10. else if (Input.GetKeyUp(KeyCode.G))
  11. {
  12. m_kSprite.ShowAsGreen();
  13. }
  14. else if (Input.GetKeyUp(KeyCode.B))
  15. {
  16. m_kSprite.ShowAsBlue();
  17. }
  18. else if (Input.GetKeyUp(KeyCode.Y))
  19. {
  20. m_kSprite.ShowAsGray();
  21. }
  22. }

核心的代码部分如上图所看到的,这样就能够通过按键rgby来切换染红绿蓝灰的效果。

效果如上面第一幅图所看到的。

总结,用程序来实现动态染色能够高度复用资源,节省空间大小。

可是资源的划分须要注意的一点是,假设在一个UIPanel里面有两个不同图集须要用同一个材质进行染色,那么会出现当中的一个出现纹理错乱的现象。眼下的解决方式是做多一个颜色值同样的材质。不同的图集用不同的染色材质,这样能够解决上面说的纹理错乱现象。

还有一个方法是设法把不同的图集弄到一块。这样也能够避免这个问题。

unity游戏开发之NGUI的UISprite染色的更多相关文章

  1. Unity游戏开发之“屏幕截图”

    原地址:http://sygame.lofter.com/post/117105_791680 在unity游戏开发中,可能会遇到在游戏中截屏的效果.这儿提供两种截屏方法.(方法二提供显示截图缩略图代 ...

  2. Unity游戏开发之C#快速入门

    C#是微软团队在开发.NET框架时开发的,它的构想接近于C.C++,也和JAVA十分相似,有许多强大的编程功能. 个人感受是C#吸收了众多编程语言的优点,从中可以看到C.C++.Java.Javasc ...

  3. unity游戏开发之entitas框架

    框架介绍 entitas是一个超快.超轻量的c# Entity-Component-System (ECS)框架,专门为Unity引擎设计.提供内部缓存和高速的组件访问,经过精心设计,可以在垃圾收集环 ...

  4. Unity游戏开发之“分层碰撞”

    有没有同学遇到过这样的情况:在游戏开发3D游戏中非经常见,比方让一个物体能穿过一个物体 而还有一个物体不能穿过这个物体,并且3个物体都不能穿过地面.在unity中这样的情况的处理是通过分层碰撞来解决的 ...

  5. [整理]Unity3D游戏开发之Lua

    原文1:[Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘(上) 各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我地博客地址是blog.csdn.net/qinyuanpei.如果 ...

  6. [Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘终结篇:UniLua热更新全然解读

    ---------------------------------------------------------------------------------------------------- ...

  7. [Unity3D]Unity3D游戏开发之从Unity3D到Eclipse

    ---------------------------------------------------------------------------------------------------- ...

  8. [Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘(下)

    ---------------------------------------------------------------------------------------------------- ...

  9. Cocos2d-x 3.x游戏开发之旅

    Cocos2d-x 3.x游戏开发之旅 钟迪龙 著   ISBN 978-7-121-24276-2 2014年10月出版 定价:79.00元 516页 16开 内容提要 <Cocos2d-x ...

随机推荐

  1. hdu5673-Robot

    题目: http://acm.hdu.edu.cn/showproblem.php?pid=5673 好久没打BC,当时这场过了3题,hack了一个,马马虎虎吧,因为前三个题确实不难. 这个是那场的第 ...

  2. layui日期输入框

    <div class="layui-form-item">                <label class="layui-form-label& ...

  3. Vue页面间传值,以及客户端数据存储

    初学Vue,遇到了页面传值的问题,大概网上学习了解了一下,在此跟大家分享一下学习心得,欢迎批评指正. 一.参数传值 如果是简单的页面传值,比如传一个id到详情页等等,推荐使用参数传值. 这里页面是通过 ...

  4. 1、Visual Studio Code安装及Hello Word

    一.环境初始化 1.下载 Visual Studio Code对应版本安装 2.下载.NET Core 2.0 SDK安装 3.安装Mono Debug   完成后界面如下:       二.创建控制 ...

  5. angular2之组件通讯

    定义父组件,在父组件中以路由插座形式引入子组件,定义相关输入输出属性 可以在同一模块内部定义多个组件,将一个组件引入另一个组件中去:也可以该模块整体导出,将该模块导入到其他模块,这样此模块中的组件就能 ...

  6. 【SQL】DUAL表

    DUAL表是Oracle系统中对所有用户可用的一个实际存在的1行1列的表,这个表不能用来存储信息,在实际应用中仅用来执行SELECT语句.可以使用DUAL表来查询系统的信息. --dual是1行1列的 ...

  7. Oracle存储过程给变量赋值的方法

    截止到目前我发现有三种方法可以在存储过程中给变量进行赋值: 1.直接法     := 如:v_flag := 0; 2.select into 如:假设变量名为v_flag,select count( ...

  8. 三维重建:SLAM相关的一些术语解释

    SLAM是一个工程问题,再次复习一下工程中可能用到的名词解释. 还是不要看了,高翔的科普读物已经出版了,读他的<slam十四讲>就可以了. 一.度量相关: 世界坐标系:描述图像的平面坐标系 ...

  9. Javascript语法,变量类型,条件,循环语句,函数,面向对象

    1.JavaScript代码革两种存在形式: <!-- 方式一 --> <script type='txt/javascript' src='/js/comment.js'>& ...

  10. Office 2013 提示找不到 Office.zh-cn\XXXXX

    1.先卸载Office 2013(已经卸载了的无视这一步)2.卸载Office 2013 后把C:\ProgramData\Microsoft\OFFICE文件删掉.3.删除下列注册信息1).依次点击 ...