色彩空间与带区间的色相调整

在游戏的战斗中,两军对垒,需要让玩家区分敌我,颜色是一个很重要的标识。

Blue Cavalry Red Cavalry

上图是一个蓝方骑士和一个红方骑士,可以看出他们除了标识颜色不一样外,其余完全一样。假使在游戏内的士兵用序列帧动画来实现,如果两个阵营用两套序列帧来实现的话。首先美术工序变得复杂,其次会导致游戏内存消耗增大,最后还会使包体积变大。

真实的情况是图片只有蓝方骑士,红色骑士只不过在运行时通过色相转换(Hue Shift)得到的。

在了解如何进行色相转换之前,我们有必要了解什么是色彩空间。

色彩空间

色彩空间是描述使用一组值表示颜色方法的抽象数学模型,比如绝大多数人都知道的三原色模型就是一种色彩空间。

RGB

RGB色彩空间指的是用红(Red)绿(Green)蓝(Blue)这三种原色描述任意颜色的色彩空间。

RGB Model

为什么采用红绿蓝作为三原色?是因为人的眼睛的锥形感光细胞对红绿蓝的光线比较敏感。

通常在计算机内部用8个bit来分别描述红绿蓝的强度,即数字从0到255,0表示此颜色强度最低(完全没有),而255则表示此颜色的强度最强。

RGB采用简单的加法来描述所有颜色,比如黄色为(255, 255, 0),黑色为(0, 0, 0),白色为(255, 255, 255)。

HSV

HSV是RGB的一种变形,分别用色相(Hue)饱和度(Saturation)明度(Value)三个数值来描述颜色。

HSV相较于RGB用人类更为熟悉的方式封装了关于颜色的信息:

这是什么颜色?深浅如何?明暗如何?

  • 色相指的是色彩的基本属性,回答了所问的第一个问题:这是什么颜色?通常色相表达为一个环,称为色环,对应角度为0到360度。
  • 饱和度指的是色彩的纯度,越高则表示色彩越纯,越低则逐渐变灰,回答了所问的第二个问题:深浅如何?数值为百分比,即0到1。
  • 明度指的是颜色的亮暗程度,越高则越显得发白,越低则越显得发黑,回答了所问的第三个问题:明暗如何?数值为百分比,即0到1。

HSV可以用一个圆锥来表示,有助于建立直观的理解。

HSV Model

HSV和RGB间的转换有一套比较复杂的公式,这不在本文的讨论范围内。

其它

除了RGB和HSV外,还有很多其他的色彩空间,比较知名的有与HSV相似的HSL,印刷常用的CMYK和电视常用的YUV

色相调整

在了解完色彩空间后,现在回到最开始的问题,如何在运行时将蓝方士兵渲染成红方士兵呢?

答案很简单,对蓝方士兵进行指定范围内(蓝色)的色相调整,即对色相落入一定范围内的像素的色相进行调整。

shader

关于色相调整的shader网络上有很多开源实现,譬如hsva-unity是可以直接在Unity内使用的shader

它的核心代码很简单:

float4 frag(Fragment IN) : COLOR
{
    //获取该像素原图的RGBA颜色值
    float4 color = tex2D (_MainTex, IN.uv_MainTex);
    //将RGB转化为HSV格式
    float3 hsv = rgb2hsv(color.rgb);
    //影响因子乘数,只对色相处在[_HSVRangeMin, _HSVRangeMax]返回1,其余则返回0
    float affectMult = step(_HSVRangeMin, hsv.r) * step(hsv.r, _HSVRangeMax);
    //将原HSV进行修改色相,饱和度和明度的修改,仅在影响因子为1时修改生效,再将修改后的HSV转化为RGB格式
    float3 rgb = hsv2rgb(hsv + _HSVAAdjust.xyz * affectMult);
    //返回最终该像素的RGBA,其中透明度通道也加上施加调整的影响
    return float4(rgb, color.a + _HSVAAdjust.a);
}

其中_HSVRangeMin定义了可以被调整的色相下限,_HSVRangeMax则定义了上限。

step(edge, x)函数在x小于edge时返回0,否则返回1。

float affectMult = step(_HSVRangeMin, hsv.r) * step(hsv.r, _HSVRangeMax);

这段代码表示HSV的第一个分量(即色相)在区间[_HSVRangeMin, _HSVRangeMax]内时返回1,否则返回0,即指定了可以进行调整的色相范围。

Hue Bar

根据色相条,可以知道蓝色的色相范围大概在180到260间,如果按0-1表示,则在0.5到0.7间。

所以我们把_HSVRangeMin设置为0.5,把_HSVRangeMax设置为0.7,然后进行色相调整,可以变换出无数种颜色来。

Hue Shift in Unity

玩具Demo放在了Github,玩的开心 😎

关注微信公众号:timind

One response

  1. 感谢分享!已推荐到《开发者头条》:https://toutiao.io/posts/bmacc3 欢迎点赞支持!
    欢迎订阅《游戏开发杂谈》https://toutiao.io/subjects/23583

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注