Unity中使用HSV颜色模型进行颜色的随机变化

发表于2019-01-23
评论1 4.9k浏览
经常能看到一些游戏中背景或是场景颜色的变换,每次进入游戏都能看到不一样的效果,像游戏Polyforge一样:

实现一个这样的效果,可以直接使用rgb颜色来随机,因为平时我们接触到的大部分都是rgb颜色,但是这样的话带来的效果就是有时候亮有时候暗,甚至有纯白纯黑。而我们想要的是鲜艳一些的,有没有办法只获取色系中的彩色部分呢?这时候HSV颜色模型就派上用场了!

关于颜色模型有很多种,这里就不做介绍了。

看一下HSV模型的样子:(图片来自百度百科

这个模型中颜色的参数分别是:色调(H),饱和度(S),明度(V)。

很明显,我们只要确定了S和V,随机H值就可以得到任意的颜色了。

在unity中的应用很简单,c#中的Color类已经给我们封装好了方法:
        Color.HSVToRGB();
        Color.RGBToHSV();

在shader中的转换网上有很多,找了一个比较简洁的,已经测试可以直接使用:
        CGINCLUDE
        float3 RGB2HSV(float3 c)  
        {  
            float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);  
            float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g));  
            float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r));  
            float d = q.x - min(q.w, q.y);  
            float e = 1.0e-10;  
            return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);  
        }  
        float3 HSV2RGB(float3 c)  
        {
            float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);  
            float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);  
            return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y);  
        }
        ENDCG

在C#中写了一个测试代码:
public class ColorSystemTest : MonoBehaviour {
    Material m ;
    float H;
    public float S;
    public float V;
	// Use this for initialization
	void Start () {
        m = transform.GetComponent<Renderer>().material;
        H = Random.Range(0f, 1f);
	}
	// Update is called once per frame
	void Update () {
        H += Time.deltaTime*0.1f ;
        H = H - (int)H;
        Color target = Color.HSVToRGB(H, S, V);
        m.SetVector("_Color", target);
	}
}

就是在update中不断的修改H值,让H从0-1不断循环,看下效果:

shader中的使用方法也顺便贴出来:
Shader "Custom/HSVColor" {
	Properties {
        _Rate("rotate rate", Range(0,1)) = 0
	}
	SubShader {
        Tags { "RenderType"="Opaque" }  
        LOD 200  
        CGINCLUDE
        float3 RGB2HSV(float3 c)  
        {  
            float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);  
            float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g));  
            float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r));  
            float d = q.x - min(q.w, q.y);  
            float e = 1.0e-10;  
            return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);  
        }  
        float3 HSV2RGB(float3 c)  
        {
            float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);  
            float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);  
            return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y);  
        }
        ENDCG
        Pass{    
		    CGPROGRAM    
            #include "UnityCG.cginc"    
            #pragma vertex vert_img    
            #pragma fragment frag    
            fixed _Rate;   
            float4 frag( v2f_img o ) : COLOR    
            {   
                float3 c = float3(0.0f,0.5f,0.5f);
                c.x = c.x + _Rate;
                c = HSV2RGB(c);
                return  float4(c,1.0f);  
            }   
            ENDCG  
        }  
	}
	FallBack "Diffuse"
}

此shader需要在c#中传入_Rate,即H的值。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引