下面介紹 Shader 中 gl_FragColor 的計算與轉換:html
1、顏色計算
1. 加
這裏要講講三原色和三基色:三原色通常指的是紅、綠、藍三種,簡稱 RGB,這是加色系。就是光源只含有特定的波段,自己就是色光,將不一樣顏色的光加在一塊兒造成新的顏色。典型的例子是顯示屏,關係以下:web
顯然,shader 中的顏色屬於加色系。當咱們把顏色相加時,會造成新的顏色,而且顏色會往白色靠攏。顏色的混合規律符合三原色規律。函數
顏色相加是指光的疊加,物理上是光的強度相加。例如多個光源照射到一個表面後反射至攝像機,就能夠把各個光照的反射結果相加。而題目中的例子是Phong或Blinn材質的反射模型,其意義能夠算是一種擬合,把材質的反射分解成漫反射和鏡面反射,然後把兩種反射光的結果相加。ui
![](http://static.javashuo.com/static/loading.gif)
2. 乘
講完三原色,再講講三基色:通常指的是顏料三原色,在純白光照射下顏色爲絳紅、黃、青,簡稱 CMYK,屬於減色系。它們自己不發光,靠反光被看見。因爲材料吸取特定波段的光,因此只有不被吸取的部分反射了回來。加上的顏色越多吸取的光也越多。spa
![](http://static.javashuo.com/static/loading.gif)
當咱們使用乘法來作顏色混合時,其規律符合三基色的混合規律,這個時候又是減色系。code
![](http://static.javashuo.com/static/loading.gif)
兩個顏色相乘,會算出兩個顏色中 RGB 值的乘積併合成一個新的顏色。並且顏色總會愈來愈暗,回不到原來的白色。一般將顏色和一個值相乘,來弱化這個顏色。實際應用中一般用於混合反射率、光照衰減等。cdn
顏色相乘,其實並不是數學中常見的矢量積,而應該理解為顏色的非等比縮放。例如,光通過有色玻璃時,玻璃吸取某百分比的紅、藍、綠,就能夠把光的紅藍綠強度分別乘以對應的百分比。漫反射也能夠理解成材質吸取了某百分比的入射光後向各方向反射。漫反射貼圖存的其實就是視頻
對顏色爲(1,1,1,1)的光的反射率。htm
3. 減
單純的顏色相減彷佛沒有意義,不過經過1.0-color
能夠實現顏色的反相。圖片
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
4. 真正的顏色混合
在圖片或視頻濾鏡中,通常不會直接使用加減乘除來作顏色混合。而是使用 mix() 函數,它的公式是:x*(1−a)+y*a
,其實也是顏色相加,可是算上了必定的比重。這樣不會由於一個白色的顏色和其餘顏色相加後只有白色,現實世界中也不是這樣的。
![](http://static.javashuo.com/static/loading.gif)
mix()
能夠作單通道或多通道的融合:
![](http://static.javashuo.com/static/loading.gif)
①. 簡單的顏色漸變
回到上面的案例,經過加法來表示重疊區域:
![](http://static.javashuo.com/static/loading.gif)
經過 mix()
來混合兩個顏色的過渡:
![](http://static.javashuo.com/static/loading.gif)
爲何加法和mix()
獲得的過渡顏色不同?各位能夠思考一下。
②. 複雜的顏色漸變
爲 rgb 三個通道賦以不一樣的函數變化曲線。plot 是封裝好的畫線函數,以xy
二維笛卡爾座標系作曲線的繪製,pct 表示x
軸的變化速率,當x
是線性變化時,曲線爲直線。當x
是非線性變化時,會有不同的曲線,從而致使漸變色的多樣變化:
![](http://static.javashuo.com/static/loading.gif)
2、顏色轉換
1. 基於笛卡爾座標系
RGB 是對機器很友好的色彩模式,但並不夠人性化,由於咱們對色彩的認識每每是」什麼顏色?鮮豔不鮮豔?亮仍是暗?」。HSL 模式和 HSV(HSB) 都是基於 RGB 的,是做爲一個更方便友好的方法建立出來的 —— refer
- HSL 爲 色相,飽和度,亮度
- HSV 爲色相,飽和度,明度
- HSB 爲 色相,飽和度,明度
下圖表達了兩種顏色模型對人類來講的易理解程度:
![](http://static.javashuo.com/static/loading.gif)
HSL 和 HSB/HSV 又有一些區別:
![](http://static.javashuo.com/static/loading.gif)
這裏提供轉換公式:
// 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):
![](http://static.javashuo.com/static/loading.gif)
假設讓亮度也同樣從0~1
,看看效果會如何:
![](http://static.javashuo.com/static/loading.gif)
你會發現水平方向的亮度變化很差看,若是是垂直方向的呢?
![](http://static.javashuo.com/static/loading.gif)
再改一下垂直方向的飽和度,你會發現有了 HSB,一切顏色變化都更好理解了:
![](http://static.javashuo.com/static/loading.gif)
2. 極座標系
HSB 本來是在極座標下產生的(以半徑和角度定義)而並不是在笛卡爾座標系(基於xy定義)下。將 HSB 映射到極座標咱們須要取得角度和到像素屏中點的距離。由此咱們運用 length() 函數和 atan(y,x) 函數。
當用到矢量和三角學函數時,vec2, vec3 和 vec4 被當作向量對待,即便有時候他們表明顏色。咱們開始把顏色和向量同等的對待,事實上你會慢慢發現這種理念的靈活性有着至關強大的用途。—— refer
![](http://static.javashuo.com/static/loading.gif)