ShaderForge学习笔记:RGB to HSV、HSV to RGB节点(色彩空间转换节点)
发表于2018-07-16
ShaderForge是一款为Unity所用的、基于节点操作的Shader插件。所以这个ShaderForge学习笔记系列希望可以帮到大家。这一篇就来介绍下色彩空间转换节点的使用。
ShaderForge色彩空间转换
一、官方说明
RGB to HSV
RGB to HSV节点根据节点输入的RGB颜色值输出HSV(色相、饱和度和明度)。色相和饱和度在0到1之间。对于曝光过度的颜色,明度可以超过1。
HSV to RGB
根据给定的HSV(色相、饱和度、明度)输入值。色相和饱和度在0到1之间。明度也一样,但是可以超过1来显示颜色。
二、简单介绍HSV色彩空间
艺术家有时偏好使用 HSV 颜色模型而不选择 RGB 或 CMYK 模型,因为它类似于人类感觉颜色的方式。RGB 和 CMYK 分别是加法原色和减法原色模型,以原色组合的方式定义颜色,而 HSV 以人类更熟悉的方式封装了关于颜色的信息:“这是什么颜色?深浅如何?明暗如何?”
HSV模型的三维表示从RGB立方体演化而来。设想从RGB沿立方体对角线的白色顶点向黑色顶点观察,就可以看到立方体的六边形外形。六边形边界表示色彩,水平轴表示纯度,明度沿垂直轴测量。
HSV对用户来说是一种直观的颜色模型。我们可以从一种纯色彩开始,即指定色彩角H,并让V=S=1,然后我们可以通过向其中加入黑色和白色来得到我们需要的颜色。增加黑色可以减小V而S不变,同样增加白色可以减小S而V不变。例如,要得到深蓝色,V=0.4 S=1 H=240度。要得到淡蓝色,V=1 S=0.4 H=240度。 一般说来,人眼最大能区分128种不同的色彩,130种色饱和度,23种明暗度。如果我们用16Bit表示HSV的话,可以用7位存放H,4位存放S,5位存放V,即745或者655就可以满足我们的需要了。
由于HSV是一种比较直观的颜色模型,所以在许多图像编辑工具中应用比较广泛,如Photoshop(在Photoshop中叫HSB)等等,但这也决定了它不适合使用在光照模型中,许多光线混合运算、光强运算等都无法直接使用HSV来实现。
色相(Hue)
色相(Hue)是饱和度和亮度都为100%的颜色。我的理解是,红色、绿色、蓝色三种原色,两两以不同比例混合后产生的颜色(可以只有一种颜色,最多只能两种颜色混合,不能三种颜色混合)。所有的色相可以用色相环来展示。
从物理学的角度上来讲,光线不为物体所吸收而反射出来的颜色,称之为色相。如果蓝色不为物体所吸收,那么呈现出来的就是蓝色。黑色是物体吸收了所有光线,无反射。白色相反。
饱和度(Saturation)
饱和度是指色彩的鲜艳程度,也称色彩的纯度。饱和度取决于该色中含色成分和消色成分(灰色)的比例(色彩的鲜明程度与它最大可能的鲜明程度的比值)。含色成分越大,饱和度越大;消色成分越大,饱和度越小。
明度(Value)
明度就是色彩的明暗程度,从物理学的角度上来讲,就是光线的折射度。
当颜色中白色成分较多时则明度高,黑色成分较多时则明度低。
三、颜色空间的转换
设 (r, g, b) 分别是一个颜色的红、绿和蓝坐标,它们的值是在 0 到 1 之间的实数。设 max 等价于 r, g 和 b 中的最大者。设 min 等于这些值中的最小者。
这里的 h ∈ [0, 360)是角度的色相角,而 s, v∈ [0,1] 是饱和度和亮度。
- RGB到HSV的转换
HSV到RGB的转换
四、应用实例-调节图片的色相、饱和度、明度
五、自定义UnityShader实现色彩空间的转换
rgb to hsv & hsv to rgb
1.完整代码
Shader "Hidden/HSV2RGB" { Properties { _MainTex("Rgb from Tex", 2D) = "" {} _HueOffset("Hue Offset", Range(0,1)) = 1 _SaturationOffset("Hue Offset", Range(-1,0)) = 1 _ValueOffset("Hue Offset", Range(-1,0)) = 1 } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } sampler2D _MainTex; float _HueOffset; float _SaturationOffset; float _ValueOffset; fixed4 frag (v2f i) : SV_Target { float4 tex = tex2D(_MainTex, i.uv); float3 rgb = tex.rgb; //rgb to hsv //在HLSL中, step(a,b)既是当b>=a时返回1,否则返回0,换句话说既是当a<=b时返回1,否则返回0。因此可以把被比较数灵活的插入a或b的位置,完成小于或大于的比较。 float4 k = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); float4 p = lerp(float4(rgb.bg, k.wz), float4(rgb.gb, k.xy), step(rgb.b, rgb.g)); // 比较r和max(b,g) float4 q = lerp(float4(p.xyw, rgb.r), float4(rgb.r, p.yzx), step(p.x, rgb.r)); float d = q.x - min(q.w, q.y); float e = 1.0e-10; float3 hsv = float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); // q.x 就是max(r,g,b)// 比较b和g //调整明度饱和度 hsv.x = hsv.x + _HueOffset; hsv.y = hsv.y + _SaturationOffset; hsv.z = hsv.z + _ValueOffset; //hsv to rgb rgb = saturate(3.0*abs(1.0-2.0*frac(hsv.x+float3(0.0,-1.0/3.0,1.0/3.0)))-1); //明度和饱和度为1时的颜色 rgb = (lerp(float3(1,1,1),rgb,hsv.y)*hsv.z); // hsv return fixed4(rgb, 1); } ENDCG } } }
2.效果展示
3.分析hsv to rgb关键算法
首先将hue值转为相应的rgb颜色值,hue转rgb的公式来由可参考:【shaderforge学习笔记】 Hue节点(色相节点),接着将hue转来的rgb值与(1,1,1)以饱和度(saturation)为依据进行插值,最后乘以明度。
float saturation = 0.8; // 饱和度 float value = 0.9; //明度 float hue = 1; //色相 float3 rgb = saturate(3.0*abs(1.0-2.0*frac(hue+float3(0.0,-1.0/3.0,1.0/3.0)))-1; //明度和饱和度为1时的颜色 float3 hsv = (lerp(float3(1,1,1),rgb),saturation)*value); // hsv
来自:https://blog.csdn.net/v_xchen_v/article/details/79366040