下面介绍 Shader 中 gl_FragColor 的计算与转换:html
1、颜色计算
1. 加
这里要讲讲三原色和三基色:三原色通常指的是红、绿、蓝三种,简称 RGB,这是加色系。就是光源只含有特定的波段,自己就是色光,将不一样颜色的光加在一块儿造成新的颜色。典型的例子是显示屏,关系以下:web
显然,shader 中的颜色属于加色系。当咱们把颜色相加时,会造成新的颜色,而且颜色会往白色靠拢。颜色的混合规律符合三原色规律。函数
顏色相加是指光的疊加,物理上是光的強度相加。例如多個光源照射到一個表面後反射至攝像機,就能够把各個光照的反射結果相加。而題目中的例子是Phong或Blinn材質的反射模型,其意義能够算是一種擬合,把材質的反射分解成漫反射和鏡面反射,然後把兩種反射光的結果相加。ui

2. 乘
讲完三原色,再讲讲三基色:通常指的是颜料三原色,在纯白光照射下颜色为绛红、黄、青,简称 CMYK,属于减色系。它们自己不发光,靠反光被看见。因为材料吸取特定波段的光,因此只有不被吸取的部分反射了回来。加上的颜色越多吸取的光也越多。spa

当咱们使用乘法来作颜色混合时,其规律符合三基色的混合规律,这个时候又是减色系。code

两个颜色相乘,会算出两个颜色中 RGB 值的乘积并合成一个新的颜色。并且颜色总会愈来愈暗,回不到原来的白色。一般将颜色和一个值相乘,来弱化这个颜色。实际应用中一般用于混合反射率、光照衰减等。cdn
顏色相乘,其實並不是數學中常見的矢量積,而應該理解為顏色的非等比縮放。例如,光通過有色玻璃時,玻璃吸取某百分比的紅、藍、綠,就能够把光的紅藍綠強度分別乘以對應的百分比。漫反射也能够理解成材質吸取了某百分比的入射光後向各方向反射。漫反射贴图存的其实就是视频
对颜色为(1,1,1,1)的光的反射率。htm
3. 减
单纯的颜色相减彷佛没有意义,不过经过1.0-color
能够实现颜色的反相。图片


4. 真正的颜色混合
在图片或视频滤镜中,通常不会直接使用加减乘除来作颜色混合。而是使用 mix() 函数,它的公式是:x*(1−a)+y*a
,其实也是颜色相加,可是算上了必定的比重。这样不会由于一个白色的颜色和其余颜色相加后只有白色,现实世界中也不是这样的。

mix()
能够作单通道或多通道的融合:

①. 简单的颜色渐变
回到上面的案例,经过加法来表示重叠区域:

经过 mix()
来混合两个颜色的过渡:

为何加法和mix()
获得的过渡颜色不同?各位能够思考一下。
②. 复杂的颜色渐变
为 rgb 三个通道赋以不一样的函数变化曲线。plot 是封装好的画线函数,以xy
二维笛卡尔坐标系作曲线的绘制,pct 表示x
轴的变化速率,当x
是线性变化时,曲线为直线。当x
是非线性变化时,会有不同的曲线,从而致使渐变色的多样变化:

2、颜色转换
1. 基于笛卡尔坐标系
RGB 是对机器很友好的色彩模式,但并不够人性化,由于咱们对色彩的认识每每是”什么颜色?鲜艳不鲜艳?亮仍是暗?”。HSL 模式和 HSV(HSB) 都是基于 RGB 的,是做为一个更方便友好的方法建立出来的 —— refer
- HSL 为 色相,饱和度,亮度
- HSV 为色相,饱和度,明度
- HSB 为 色相,饱和度,明度
下图表达了两种颜色模型对人类来讲的易理解程度:

HSL 和 HSB/HSV 又有一些区别:

这里提供转换公式:
// RGB 转 HSB 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); } // HSB 转 RGB // Function from Iñigo Quiles // https://www.shadertoy.com/view/MsS3Wc vec3 hsb2rgb( 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); return c.z * mix(vec3(1.0), rgb, c.y); } 复制代码
那咱们能够怎么应用 HSB 颜色呢?
当咱们让色相 Hue 从0~1
递增时,你会发现全部颜色都一一取到了(这里的饱和度和亮度都设置为 1):

假设让亮度也同样从0~1
,看看效果会如何:

你会发现水平方向的亮度变化很差看,若是是垂直方向的呢?

再改一下垂直方向的饱和度,你会发现有了 HSB,一切颜色变化都更好理解了:

2. 极坐标系
HSB 本来是在极坐标下产生的(以半径和角度定义)而并不是在笛卡尔坐标系(基于xy定义)下。将 HSB 映射到极坐标咱们须要取得角度和到像素屏中点的距离。由此咱们运用 length() 函数和 atan(y,x) 函数。
当用到矢量和三角学函数时,vec2, vec3 和 vec4 被当作向量对待,即便有时候他们表明颜色。咱们开始把颜色和向量同等的对待,事实上你会慢慢发现这种理念的灵活性有着至关强大的用途。—— refer
