首页 > 代码库 > HSV颜色空间下标示数据类型

HSV颜色空间下标示数据类型

背景:类似于Unreal的Blueprint里,不同的数据类型,有不同的颜色来表示。
颜色方案有RGBA, HSL,HSV。直接用RGBA当然可以,只是经常容易导致颜色偏暗饱和度不够等问题,因此,直接选用HSV。(至于为什么没有选用HSL,呵呵,没比较,团队中其他人更喜欢HSV,这个问题在业界也是众说纷纭)。
令S=1.0f, V=1.0f,H则在0~359之间变化。
最终显示出来必须是RGBA,因此需要有HSV到RGBA的算法,这个网上很多,参见wiki: http://en.wikipedia.org/wiki/HSL_and_HSV
using System;
using UnityEngine;

        class ColorHelper
        {
        //reference: http://en.wikipedia.org/wiki/HSL_and_HSV
        public static Color ColorFromHSV(double _hue, double _saturation, double _value)
        {        
            int hi = Convert.ToInt32(Math.Floor(_hue / 60)) % 6;
            double f = _hue / 60 - Math.Floor(_hue / 60);

            _value = http://www.mamicode.com/_value * 255;>
需要提到的一点是,Unity里的RGBA里各颜色通道的取值被归一化为0~1.0的float了,不是0~255(当然,Debug时,还是将它们转化为0~255区间的值吧)。这里不小心被坑了下……
关于Hue如何取得,基本要求是同样的类型,颜色必须一样。 
方案0:GetInstanceId(),噢噢噢,这个只有UnityEngine.Object才有这接口,System.Object木有这个接口。 此方案不通。
方案1:GetHashCode(),确实能保证同样的类型,在每次的运行过程中,颜色保持一致。但是,GetHashCode()在再次运行程序时得到的HashCode可能会改变。这是有问题的。 
改进之,不知道_Type.GetHashCode()的算法如何,不过似乎字符串.GetHashCode(),同样的字符串,多次运行程序得到的HashCode是一样的。于是可以用_Type.FullName.GetHashCode()。
发现通过类型名称字符串得到的HashCode很相近,导致hue相近,RGBA颜色很接近。于是继续改进,将HashCode作一些处理,偏移,倍乘扩大。。。
在改进的路上尝试了一阵,发现,无论怎么改进hashCode,18种基本类型的颜色还是容易接近。。。 
嗯,也许有很高大上很好的算法能解决这个问题,但是……对于这种小规模的事情,就解决事情而言,都不如HardCode来得简便有效!
最终的解决方案:
HSV空间下,S=1.0f, V=1.0f,360种颜色如下:

自己看,挑看着舒服的颜色,将18种数据类型HardCode配色。
同时,为了方便扩展,也预留一个接口,自定义类型如果不想HardCode配色,也可以通过GetHashCode()来得到Hue从而得到相应颜色。
public Color GetTypeColor()
        {
            int hue = 0;
            if ( TypeHelper .registerTypeHueMap.TryGetValue(paramType, out hue) )
            {
                return ColorHelper .ColorFromHSV(hue, 1.0f, 1.0f);
            }
            else
            {
                int hashcode = paramType.FullName.GetHashCode();  
                return ColorHelper .ColorFromHSV(hashcode, 1.0f, 1.0f);
            }               
        }


附上测试颜色的代码:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using NewAge;
using System.Reflection;


public class DrawColor : MonoBehaviour {

    bool bShowAllHueColors = true;

    float top = 0.0f;
    public static Dictionary<Type, int> registerTypeHueMap = new Dictionary<Type, int>();

    float width = 100.0f;
   
    void Start()
    {
        Debug.Log("Draw Sth.");    
        registerTypeHueMap.Add(typeof(bool), 0);      
        registerTypeHueMap.Add(typeof(int), 120);
        registerTypeHueMap.Add(typeof(float), 30);
        registerTypeHueMap.Add(typeof(string), 240);  
        registerTypeHueMap.Add(typeof(Vector2), 50);
        registerTypeHueMap.Add(typeof(Vector3), 60);
        registerTypeHueMap.Add(typeof(Vector4), 85);
        registerTypeHueMap.Add(typeof(Transform), 180);
        registerTypeHueMap.Add(typeof(Quaternion), 210);            
        registerTypeHueMap.Add(typeof(TransformInfo), 255);
        registerTypeHueMap.Add(typeof(Shader), 280);
        registerTypeHueMap.Add(typeof(object), 160);
        registerTypeHueMap.Add(typeof(Matrix4x4), 10);
        registerTypeHueMap.Add(typeof(Material), 300);
        registerTypeHueMap.Add(typeof(GameObject), 190);
        registerTypeHueMap.Add(typeof(Component), 330);
        registerTypeHueMap.Add(typeof(AudioClip), 260);
        registerTypeHueMap.Add(typeof(AnimationClip), 230);           
    }

    void DrawTypeColor(Type _type)
    {
        Color colorToUse = ColorHelper.ColorFromHSV(registerTypeHueMap[_type], 1.0f, 1.0f);
        GUI.contentColor = colorToUse;
        Color debugColor = new Color(colorToUse.r * 255.0f, colorToUse.g * 255.0f, colorToUse.b * 255.0f, colorToUse.a * 255.0f);
        top += 30.0f;
        GUI.Label(new Rect(20.0f, top, 600.0f, 25.0f), _type.ToString() + " Hue:" + registerTypeHueMap[_type] + " " + debugColor.ToString());  //"show me the color"
    }

    void DrawAllTypeColors()
    {
        top = 0.0f;
        DrawTypeColor(typeof(int));
        DrawTypeColor(typeof(float));
        DrawTypeColor(typeof(bool));
        DrawTypeColor(typeof(string));
        DrawTypeColor(typeof(Vector2));
        DrawTypeColor(typeof(Vector3));
        DrawTypeColor(typeof(Vector4));
        DrawTypeColor(typeof(Transform));
        DrawTypeColor(typeof(Quaternion));
        DrawTypeColor(typeof(TransformInfo));
        DrawTypeColor(typeof(Shader));
        DrawTypeColor(typeof(object));
        DrawTypeColor(typeof(Matrix4x4));
        DrawTypeColor(typeof(Material));
        DrawTypeColor(typeof(GameObject));
        DrawTypeColor(typeof(Component));
        DrawTypeColor(typeof(AudioClip));
        DrawTypeColor(typeof(AnimationClip));
    }

    void DrawHueColor(int _hue, float left, float top)
    {
        Color colorToUse = ColorHelper.ColorFromHSV(_hue, 1.0f, 1.0f);
        GUI.contentColor = colorToUse;
        Color debugColor = new Color(colorToUse.r * 255.0f, colorToUse.g * 255.0f, colorToUse.b * 255.0f, colorToUse.a * 255.0f);       
       // GUI.Label(new Rect(left, top, 400.0f, 25.0f), "Color " + " Hue:" + _hue + " " + debugColor.ToString());  
        GUI.Label(new Rect(left, top, width, 25.0f), "Color " + " Hue:" + _hue);  
    }

    void DrawAllHueColors()
    {
        float top = 0.0f;
        float left = 20.0f;
        for (int i = 0; i < 360; ++i)
        {
            if (top + 25.0f > 730.0f)
            {
                top = 0.0f;
                left += width;
            }

            DrawHueColor(i, left, top);
            top += 25.0f;
        }
    }

    void OnGUI()
    {
        if (bShowAllHueColors)
        {
            DrawAllHueColors();
        }
        else
        {
            DrawAllTypeColors();
        }
       

    }
}




HSV颜色空间下标示数据类型