实用Shader样例详解1——色相、饱和度、对比度、亮度调节

发表于2016-05-20
评论1 7.1k浏览
  Shader的出现极大地提高了OpenGL的应用广度,可编程顶点和片元处理器的引入使得应用程序可以利用底层的图形硬件来实现更为广泛的渲染效果。并且可以使用专门的图形硬件所提供的硬件加速来实现,渲染的性能可以得到很大的提升,同时还能减轻CPU的负担。
  Shader学习的过程其实是比较长线的,这一系列的文章主要跟大家分享之前项目中一些比较常用跟实用的Shader样例,旨在在激发大家对于Shader学习的热情,同时有需要的童鞋也可以在自己的项目中酌情使用。(这部分代码都是在实际项目中应用过的,并非单纯的调试代码~)  
  色相、饱和度、对比度、亮度调节 
  这个Shader是在做染色系统的时候写的,游戏中的服装系统的资源很大,如果使用添加资源的方式来做染色系统,客户端的资源量会有很大的冗余,而且不方便后期系统的扩展,我们希望用更加灵活的方式来做服装的染色效果。在GPUGem中推荐了使用LUT颜色映射来实现调色的效果,效率非常的高,而且在调色精度不是太高的情况下,LUT文件的大小也是很方便进行更新。这里我们采用了另一种方法,修改色相、饱和度、对比度和亮度,利用颜色空间的映射,把颜色输入从RGB转换到HSV,对色调,饱和度和明度进行修改后,即可实现染色效果,再把颜色空间转换到RGB,对颜色对比度进行微调即可得到任意的染色效果。这四个参数可以让美术在PS中针对原图进行调色后提供对应染色效果的参数即可。


  色调H:取值范围0——360,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。
  饱和度S:表示颜色接近光谱色的程度,一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高。 
  明度V:明度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白)。 
  对比度:一幅图像中明暗区域最亮的白和最暗的黑之间不同亮度层级的测量,差异范围越大代表对比越大,差异范围越小代表对比越小。 
  下面我们可以直接动手来实现这个Shader,修改片元着色器,将RGB转换为HSV,对相应参数进行修改后再转换为RGB,根据传入的对比度参数对颜色进行微调,赋给相应的片元即可。
  片元着色器: 
uniform sampler2D tex;
uniform float u_hue;
uniform float u_saturation;
uniform float u_value;
uniform float u_contrast;
vec3 rgbtohsv(vec3 rgb)
{
    float R = rgb.x;
    float G = rgb.y;
    float B = rgb.z;
    vec3 hsv;
    float max1 = max(R, max(G, B));
    float min1 = min(R, min(G, B));
    if (R == max1)
    {
        hsv.x = (G - B) / (max1 - min1);
    }
    if (G == max1)
    {
        hsv.x = 2.0 + (B - R) / (max1 - min1);
    }
    if (B == max1)
    {
        hsv.x = 4.0 + (R - G) / (max1 - min1);
    }
    hsv.x = hsv.x * 60.0;
    if (hsv.x  < 0.0)
    {
        hsv.x = hsv.x + 360.0;
    }
    hsv.z = max1;
    hsv.y = (max1 - min1) / max1;
    return hsv;
}
vec3 hsvtorgb(vec3 hsv)
{
    float R;
    float G;
    float B;
    if (hsv.y == 0.0)
    {
        R = G = B = hsv.z;
    }
    else
    {
        hsv.x = hsv.x / 60.0;
        int i = int(hsv.x);
        float f = hsv.x - float(i);
        float a = hsv.z * (1.0 - hsv.y);
        float b = hsv.z * (1.0 - hsv.y * f);
        float c = hsv.z * (1.0 - hsv.y * (1.0 - f));
        if (i == 0)
        {
            R = hsv.z;
            G = c;
            B = a;
        }
        else if (i == 1)
        {
            R = b;
            G = hsv.z;
            B = a;
        }
        else if (i == 2)
        {
            R = a;
            G = hsv.z;
            B = c;
        }
        else if (i == 3)
        {
            R = a;
            G = b;
            B = hsv.z;
        }
        else if (i == 4)
        {
            R = c;
            G = a;
            B = hsv.z;
        }
        else
        {
            R = hsv.z;
            G = a;
            B = b;
        }
    }
    return vec3(R, G, B);
}
void main()
{
    vec4 pixColor = texture2D(tex, gl_TexCoord[0].xy);
    vec3 hsv;
    hsv.xyz = rgbtohsv(pixColor.rgb);
    hsv.x += u_hue;
    hsv.x = mod(hsv.x, 360.0);
    hsv.y *= u_saturation;
    hsv.z *= u_value;
    vec3 f_color = hsvtorgb(hsv);
    f_color = ((f_color - 0.5) * max(u_contrast+1.0, 0.0)) + 0.5;
    gl_FragColor = gl_Color * vec4(f_color, pixColor.a);
}
  OpenGL Shader Builder中的效果如下:


如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引