Unity Shader - HSV 和 RGB 的相互转换

本文深入探讨HSV和HSL颜色模型,解释其与RGB模型的区别,包括色相、饱和度和明度的概念。提供了HSV和RGB之间的转换算法,并通过Unity Shader实例展示了HSV在不同坐标系下的表现。

前言

对于颜色值, RGB 可能是我们接触最多的颜色模型,图像中的任何颜色都是由 红色(R) 、 绿色(G) 、 蓝色(B) 这三个通道合成的,这三种颜色可以组合成几乎所有的颜色。
然而,它并不直观,比如我随便说一个rgb值,你能猜到他是什么颜色吗?几乎不可能,所以,后面引入了 HSV 、 HSL 等颜色模型。 HSV 相对于 RGB 来说 是一种更加直观的颜色模型, HSV 更加符合我们人类视觉。

HSL和HSV 概念:

HSL 即色相、饱和度、亮度(英语:Hue, Saturation, Lightness)。
HSV 即色相、饱和度、明度(英语:Hue, Saturation, Value),又称HSB,其中B即英语:Brightness。
  • 色相(H)是色彩的基本属性,就是平常所说的颜色名称,如红色、黄色等。
  • 饱和度(S)是指色彩的纯度,越高色彩越纯,低则逐渐变灰,取0-100%的数值。
  • 明度(V),亮度(L),取0-100%

HSL和HSV色彩空间比较:

二者在数学上都是圆柱,但
HSV 在概念上可以被认为是颜色的倒圆锥体(黑点在下顶点,白色在上底面圆心);
HSL 在概念上表示了一个双圆锥体和圆球体(白色在上顶点,黑色在下顶点,最大横切面的圆心是半程灰色)。

HSV 和 RGB 之间的相互转换

以下函数由国外大神 Inigo Quilez 提供 https://www.shadertoy.com/view/MsS3Wc

HSB/HSV 转 RGB

    
// Official HSV to RGB conversion vec3 hsv2rgb ( in vec3 c ) { vec3 rgb = clamp ( abs ( mod ( c . x * 6.0 + vec3 ( 0.0 , 4.0 , 2.0 ) , 6.0 ) - 3.0 ) - 1.0 , 0.0 , 1.0 ) ; return c . z * mix ( vec3 ( 1.0 ) , rgb , c . y ) ; }
    
// Smooth HSV to RGB conversion // https://www.shadertoy.com/view/MsS3Wc vec3 hsv2rgb_smooth ( in vec3 c ) { vec3 rgb = clamp ( abs ( mod ( c . x * 6.0 + vec3 ( 0.0 , 4.0 , 2.0 ) , 6.0 ) - 3.0 ) - 1.0 , 0.0 , 1.0 ) ; rgb = rgb * rgb * ( 3.0 - 2.0 * rgb ) ; // cubic smoothing return c . z * mix ( vec3 ( 1.0 ) , rgb , c . y ) ; }
ShaderLab版:
    
float3 hsb2rgb ( float3 c ) { float3 rgb = clamp ( abs ( fmod ( c . x * 6.0 + float3 ( 0.0 , 4.0 , 2.0 ) , 6 ) - 3.0 ) - 1.0 , 0 , 1 ) ; rgb = rgb * rgb * ( 3.0 - 2.0 * rgb ) ; return c . z * lerp ( float3 ( 1 , 1 , 1 ) , rgb , c . y ) ; }

RGB 转 HSB/HSV

    
vec3 rgb2hsb ( in vec3 c ) { vec4 K = vec4 ( 0.0 , - 1.0 / 3.0 , 2.0 / 3.0 , - 1.0 ) ; vec4 p = mix ( vec4 ( c . bg , K . wz ) , vec4 ( c . gb , K . xy ) , step ( c . b , c . g ) ) ; vec4 q = mix ( vec4 ( p . xyw , c . r ) , vec4 ( c . r , p . yzx ) , step ( p . x , c . r ) ) ; float d = q . x - min ( q . w , q . y ) ; float e = 1.0e-10 ; return vec3 ( abs ( q . z + ( q . w - q . y ) / ( 6.0 * d + e ) ) , d / ( q . x + e ) , q . x ) ; }
ShaderLab版:
    
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 ) ; }

实践

下面我们在Unity Shader 中来看看

在笛卡尔坐标系下的SHV

由下图我们可以清晰的看到 X 轴 决定 色相,Y 轴 决定 饱和度
代码如下:
    
Shader "lcl/shader2D/HSV" { SubShader { Pass { CGPROGRAM // vert_img 是 UnityCG.cginc 内置的 # pragma vertex vert_img # pragma fragment frag #include "UnityCG.cginc" // 该函数由国外大神 Iñigo Quiles 提供 // https://www.shadertoy.com/view/MsS3Wc float3 hsb2rgb ( float3 c ) { float3 rgb = clamp ( abs ( fmod ( c . x * 6.0 + float3 ( 0.0 , 4.0 , 2.0 ) , 6 ) - 3.0 ) - 1.0 , 0 , 1 ) ; rgb = rgb * rgb * ( 3.0 - 2.0 * rgb ) ; return c . z * lerp ( float3 ( 1 , 1 , 1 ) , rgb , c . y ) ; } // ---------------------------【片元着色器】--------------------------- fixed4 frag ( v2f_img i ) : SV_Target { fixed4 col ; // hsb 转换为 rgb // uv.x 决定 色相, // uv.y 决定 亮度, col . rgb = hsb2rgb ( float3 ( i . uv . x , 1 , 1 - i . uv . y ) ) ; return col ; } ENDCG } } }

在极坐标系下的SHV

在极坐标系下,我们可以看到, 角度 决定 色相, 半径 决定 饱和度, 亮度固定
Shader代码如下:
    
Shader "lcl/shader2D/HSVInPolarCoordinate" { SubShader { Pass { CGPROGRAM // vert_img 是 UnityCG.cginc 内置的 # pragma vertex vert_img # pragma fragment frag #include "UnityCG.cginc" # define TWO_PI 6.28318530718 // 该函数由国外大神 Iñigo Quiles 提供 // https://www.shadertoy.com/view/MsS3Wc float3 hsb2rgb ( float3 c ) { float3 rgb = clamp ( abs ( fmod ( c . x * 6.0 + float3 ( 0.0 , 4.0 , 2.0 ) , 6 ) - 3.0 ) - 1.0 , 0 , 1 ) ; rgb = rgb * rgb * ( 3.0 - 2.0 * rgb ) ; return c . z * lerp ( float3 ( 1 , 1 , 1 ) , rgb , c . y ) ; } // ---------------------------【片元着色器】--------------------------- fixed4 frag ( v2f_img i ) : SV_Target { fixed4 col ; // 笛卡尔坐标系转换到极坐标系 float2 center = float2 ( 0.5 , 0.5 ) - i . uv ; float angle = atan2 ( center . y , center . x ) ; float radius = length ( center ) * 2.0 ; // 将角度 从(-PI, PI) 映射到 (0,1)范围 // 角度决定色相, 半径决定饱和度, 亮度固定 col . rgb = hsb2rgb ( float3 ( ( angle / TWO_PI ) + 0.5 , radius , 1.0 ) ) ; return col ; } ENDCG } } }

最后

欢迎来我 GitHub 点个Star,谢谢! 里面有我平时学习unity shader过程中实现的一些特效demo。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值