在游戏的战斗中,两军对垒,需要让玩家区分敌我,颜色是一个很重要的标识。
上图是一个蓝方骑士和一个红方骑士,可以看出他们除了标识颜色不一样外,其余完全一样。假使在游戏内的士兵用序列帧动画来实现,如果两个阵营用两套序列帧来实现的话。首先美术工序变得复杂,其次会导致游戏内存消耗增大,最后还会使包体积变大。
真实的情况是图片只有蓝方骑士,红色骑士只不过在运行时通过色相转换(Hue Shift)得到的。
在了解如何进行色相转换之前,我们有必要了解什么是色彩空间。
色彩空间
色彩空间是描述使用一组值表示颜色方法的抽象数学模型,比如绝大多数人都知道的三原色模型就是一种色彩空间。
RGB
RGB色彩空间指的是用红(Red)绿(Green)蓝(Blue)这三种原色描述任意颜色的色彩空间。
为什么采用红绿蓝作为三原色?是因为人的眼睛的锥形感光细胞对红绿蓝的光线比较敏感。
通常在计算机内部用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和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,即指定了可以进行调整的色相范围。
根据色相条,可以知道蓝色的色相范围大概在180到260间,如果按0-1表示,则在0.5到0.7间。
所以我们把_HSVRangeMin
设置为0.5,把_HSVRangeMax
设置为0.7,然后进行色相调整,可以变换出无数种颜色来。
玩具Demo放在了Github,玩的开心 😎
感谢分享!已推荐到《开发者头条》:https://toutiao.io/posts/bmacc3 欢迎点赞支持!
欢迎订阅《游戏开发杂谈》https://toutiao.io/subjects/23583