Unity Shader - HSV 和 RGB 的相互转换
前言
对于颜色值,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 之间的相互转换
以下函数由国外大神 Iñigo Quiles 提供
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/MsS3Wcfloat3 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/MsS3Wcfloat3 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 toCenter = float2(0.5,0.5)-i.uv;float angle = atan2(toCenter.y,toCenter.x);float radius = length(toCenter)*2.0;// 将角度 从(-PI, PI) 映射到 (0,1)范围// 角度决定色相, 半径决定饱和度, 亮度固定col.rgb = hsb2rgb(float3((angle/TWO_PI)+0.5,radius,1.0));return col;}ENDCG}}
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
