【Unity&Shader】NGUI实现图集变灰功能

来源:互联网 发布:mac图片处理 编辑:程序博客网 时间:2024/05/21 23:34

原文地址:http://bbs.9ria.com/thread-434334-1-1.html

需求分析

  • 直接调整Sprite或者Texture的Color值达不到美术所要的效果
  • 节省资源,为了实现去色效果,美术不必提供另外一张PS处理过后的图集,只需要程序修改shader动态处理即可怎么做
  • 修改NGUI使用的Shaders(新添加四个,为什么后文讲解)
  • 制作XX_Gary图集
  • 编写统一逻辑接口针对Sprite切换图集,针对UITexture切换Shader

修改NGUI使用的Shader

注意下NGUI使用的默认shader,该例子使用的是NGUI3.6.6,NGUI默认使用的一系列shader为下图 1 2 3 结尾,稍微提前一点的版本shader下图(SoftClip)(AlphaClip)复制出来四个按照原来的规则修改名字,注意一定要前缀一致,因为NGUI内部实现裁剪是需要通过修改后缀找到相应的shader进行替换实现的,然后在修改四个shader的内容,找到每个Shader内容的frag函数,在最后都加上同一段代码即可(前面各种计算得到col,再返回前将最终的col结果在进行一次处理)

更改四个shader

较旧版本NGUI

[C#] 纯文本查看 复制代码
?
1
2
3
4
5
6
7
8
<font color="#000000">half4 frag (v2f IN) : COLOR
{
        // ......
        //For gray shader change rgb value
        floatgrey = dot(col.rgb, float3(0.299, 0.587, 0.114));
        col.rgb = float3(grey, grey, grey);
        returncol;
}</font>
制作XX_Gray图集

游戏中针对需要置灰的元素图集需要重新制作一个额外的Gray图集,Normal图集和Gray图集使用同一个2DTexture,使用不同的材质

Gray图集
2015-7-15 19:05:44 上传
下载附件3.21 KB)
Gray图集

编写处理逻辑

统一的处理接口,基本原理是针对UISprite更换图集,针对UITexture更换Shader即可
具体的一种实现方式如下

<font color="#000000">using UnityEngine;using System.Collections;using System.Collections.Generic;public class GrayUIController : MonoBehaviour{    // UISprite : 更换图集(正常和置灰图集切换)    // UITexture:更换Shader为正常Shader和置灰使用的Shader    /      1.将同一个图集中的图片单独的变灰操作      2.将UITexture变灰去色     /    // 维护一个图集List    // 置灰图集    // 正常图集    public List grayAtlas;    public List normalAtlas;    public Hashtable shaderTable = new Hashtable();    public enum AtlasName    {        EM_AtlasName_None = -1,        EM_AtlasName_CommonAtlas,    }    private static GrayUIController instance = null;    public static GrayUIController GetInstance()    {        return instance;    }    void Awake()    {        instance = this;    }    ///    /// 将制定GameObject存在的UITexture和UISprite去色,变灰    ///    ///  目标物体    ///  是否变灰    ///  制定图集    public void ChangeObjectsToGray(GameObject targetObj, bool gray, AtlasName atlasName = AtlasName.EM_AtlasName_None)    {        UISprite[] sprites = targetObj.GetComponentsInChildren();        UITexture[] textures = targetObj.GetComponentsInChildren();        for (int i = 0; i < sprites.Length; i++)            ChangeUISpriteToGray(sprites, gray, atlasName);        for (int i = 0; i < textures.Length; i++)            ChangeUITextureToGary(textures, gray);    }    public bool ChangeUISpriteToGray(UISprite targetSprite, bool toGray, AtlasName atlasName = AtlasName.EM_AtlasName_None)    {        bool toGarySucess = false;        if (targetSprite != null)        {            List findAtlas = new List();            if (toGray)                findAtlas = grayAtlas;            else                findAtlas = normalAtlas;            UISpriteData findData = null;            string spriteName = targetSprite.spriteName;            // 如果指定图集,不用查找直接更换图集即可(高效方式)            if (atlasName != AtlasName.EM_AtlasName_None)            {                findData = findAtlas[(int)atlasName].GetSprite(spriteName);                if (findData != null)                {                    targetSprite.atlas = findAtlas[(int)atlasName];                    toGarySucess = true;                }            }            else            {                // 未指定图集,需要从现有的图集中查找对应的图集                for (int i = 0; i < findAtlas.Count; i++)                {                    findData = findAtlas.GetSprite(spriteName);                    if (findData != null)                    {                        targetSprite.atlas = findAtlas;                        toGarySucess = true;                        break;                    }                }            }        }        return toGarySucess;    }    ///    /// 将UITexture置灰操作    ///    ///    ///    public void ChangeUITextureToGary(UITexture texture, bool toGray)    {        Shader newShader = null;        if (toGray)        {            // 保存UITexture原Shader            if (!shaderTable.ContainsKey(texture))                shaderTable[texture] = texture.shader;            newShader = Shader.Find("Unlit/GrayShader");        }        else        {            // 恢复原Shader            if (shaderTable.ContainsKey(texture))                newShader = (Shader)shaderTable[texture];            else                newShader = Shader.Find("Unlit/Transparent Colored");        }        texture.shader = newShader;    }    private bool changeToGray = true;    public GameObject targets;    public void TestChangeGray()    {        ChangeObjectsToGray(targets, changeToGray, AtlasName.EM_AtlasName_CommonAtlas);        changeToGray = !changeToGray;    }}</font>



问题

为何要复制出来四个shader,如果只复制出来一个基本shader而没有复制另外三个处理裁剪的shader,当你在ScrollView等还有裁剪的Panel中存在变灰元素的时候就会提示"找不到xxshader"的错误,具体随着错误就知道在UIDrawCall中进行了裁剪过程的Shader替换(UIDrawCall中的CreateMaterial函数)


<font color="#000000">voidCreateMaterial ()
{
    // .....
    if(shaderName.StartsWith("Hidden/"))
            shaderName = shaderName.Substring(7);
    // Legacy functionality
    conststringsoft =" (SoftClip)";
    shaderName = shaderName.Replace(soft,"");
    if(mClipCount != 0)
    {
        shader = Shader.Find("Hidden/"+ shaderName +" "+ mClipCount);
        if(shader ==null) Shader.Find(shaderName +" "+ mClipCount);
        // Legacy functionality
        if(shader ==null&& mClipCount == 1)
        {
            mLegacyShader =true;
            shader = Shader.Find(shaderName + soft);
        }
    }
    elseshader = Shader.Find(shaderName);
    // ......
}</font>



如果创建了一个新的图集,会不会造成内存存在两张贴图,答案是不会,因为两个图集使用的同一张贴图,只不过材质球不一样而已,你可以在运行的时候打开Profiler查看图集引用的贴图,然后比对下内存使用情况即可


效果演示演示

2015-7-15 19:05:44 上传
下载附件(324.86 KB)
演示

Demo下载
游客,如果您要查看本帖隐藏内容请回复

(导入的DEMO,的NGUI文件夹可能有问题,请删除,重新导入正确的NGUI)

Unity3D学习笔记——NGUI之UIScrollView











0 0
原创粉丝点击