Unity中使用HSV颜色模型进行颜色的随机变化
发表于2019-01-23
经常能看到一些游戏中背景或是场景颜色的变换,每次进入游戏都能看到不一样的效果,像游戏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的值。