一、簡單介紹
blendMode 翻譯過來也就是大家常說的顏色混合模式,或者大家在 PS 裏見過得圖層之間的混合模式。具體概念就不在這裏詳談了,不太明白的可以先搜索一下,只要有普通的概念就好了,接下來看看 WebGL 是如何處理一個個的圖像,並正確顯示它們混合之後的顏色的。
二、webgl 中的 blendMode 函數
(這一章看完可能會不懂,結合第三章再反過來查閱這一章,就會明白。所以這一章只是API參考,跟很多講 webgl 、 opengl 的書籍一樣,需要結合栗子甚至實際操作結合才能理解、明白這些概念)
在 webgl 裏有如下幾個函數控制 blendMode :
1. gl.blendEquation(enum mode)
2. gl.blendEquationSeprate(enum modeRGB,enum modeAlpha)
3. gl.blendFunc(enum src, enum dst)
4. gl.blendFuncSeprate(enum srcRGB, enum dstRGB, enum srcAlpha, enum dstAlpha)
5. gl.blendColor(r,g,b,a)
2.1 blendEquation
其中 函數 1 和 2 是做同一件事情。
gl.blendEquation(gl.FUNC_ADD) 等同於 gl.blendEquation(gl.FUNC_ADD,gl.FUNC_ADD)。
gl.blendEquation 的可選參數如圖
2.2 blendFunc
函數3 和 4 是做同一件事。
gl.blendFunc(gl.ONE,gl.ZERO) 就相當於 gl.blendFuncSeprate(gl.ONE,gl.ZERO,gl.ONE,gl.ZERO)。
gl.blendFunc 的可選參數如圖
R、G、B、A 分別都有下標,這些下標是指:
首先明確一個概念,假設 webgl 裏面有一塊顏色畫板 (dst),這個時候我們要畫一個對象 M (src) 上去,這樣可以得到更新的畫板,下次再畫對象 N (src)時,取最新的畫板顏色 (dst) 進行混合就可以得到下一次的混合底色 (dst) 或者 最終顏色 。
s 即 src,也就是要要疊加的對象的顏色。
d 即 dst,也就是畫板上得顏色。
c 即 const,也就是 gl.blendColor 指定的顏色,默認情況下 gl.blendColor 的顏色爲 (1,1,1,1)
畫板初始的顏色全部爲 (0,0,0,0),如果調用過 gl.clearColor(r,g,b,a) 就是 gl.clear 刷新過的 (r,g,b,a)。
三、栗子
接下來看個實際的栗子,看看這些函數到底是怎麼控制顏色混合的。
例如文字 FPS,放大後我們可以看到它的邊緣有一些半透明的顏色(抗鋸齒效果,不至於全是實線,實線轉彎的地方鋸齒很嚴重):
接下來看看幾種情況下繪製的結果和我們的推算。
情況一:
gl.clearColor(0,0,0,0);
繪製文字("FPS");
這裏並沒有調用任何 blendMode 相關的函數,也就是各個情況都是默認的。也就是相當於:
gl.blendColor(1,1,1,1)
gl.blendEquationSeprate(gl.FUNC_ADD, gl.FUNC_ADD)
gl.blendFuncSeprate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA)
取文字FPS邊緣的一個半透明像素考慮 (F上面那一橫,用QQ截圖就能看到顏色,截圖會看到那一行的像素顏色爲(113,113,113)),像素顏色爲 (0,0,0,143/255)。
1. 在調用 gl.clearColor(0,0,0,0) 後,所有的顏色清除爲 (0,0,0,0)
2. 繪製文字 FPS,那麼 src 的顏色爲 (0,0,0,0.5),dst 的顏色爲 (0,0,0,0)
3. 採用混合參數可以知道 (參考第二章的混合參數設置,中間的 + 來自 gl.blendEquationSeprate 的第一個參數)
r = srcR * srcAlpha + dstR * (1 - srcAlpha) = 0 * 143/255 + 0 * (1 -143/255) = 0
g = srcG * srcAlpha + dstG * (1 - srcAlpha) = 0 *143/255 + 0 * (1 -143/255) = 0
b = srcB * srcAlpha + dstB * (1 - srcAlpha) = 0 *143/255 + 0 * (1 -143/255) = 0
a = srcA * 1 + dstA * (1 - srcAlpha) =143/255 * 1 + 0 * (1 -143/255) =143/255
4. 混合之後的顏色爲 (0,0,0,143/255)
5. 由於網頁背景色是 (1,1,1,1),所以網頁背景色再跟 (0,0,0,143/255) 做混合就可以得到
r = srcR * srcAlpha + dstR * (1 - srcAlpha) = 0 *143/255 + 1 * (1 -143/255) = 113/255
g = srcG * srcAlpha + dstG * (1 - srcAlpha) = 0 *143/255 + 1 * (1 -143/255) =113/255
b = srcB * srcAlpha + dstB * (1 - srcAlpha) = 0 *143/255 + 1 * (1 -143/255) =113/255
a = srcA * 1 + dstA * (1 - 143/255) = 143/255 * 1 + 1 * (1 - 143/255) = 1
可能有人會說這樣推出的結果其實不靠譜,因爲我又不知道 F 上面那橫如果沒有任何顏色疊加真正的顏色是什麼,其實可以在 PS 裏看到,這個 F 的字體是 Heletica ,24 號字體,放大了4倍。
當然我們可以繼續用別的顏色混合看看結果是否正確(情況二)。
不過我可以明確的說明,這裏我沒有在 PS 裏取色,而是用了混合公式反推出的原始顏色。
情況二:
gl.clearColor(1,0,0,0);
繪製文字("FPS");
先看看結果:
結果表明,在文字有顏色的地方會顯示黑色和紅色(半透明的邊緣像素),沒有顏色的地方是白色。
先取文字FPS邊緣的一個半透明像素 (0,0,0,143/255) 做混合後顯示的顏色爲:
1. 經過 gl.clearColor(1,0,0,0) 之後像素顏色爲 (1,0,0,0)
2. 疊加顏色 (0,0,0,143/255) 之後
r = srcR * srcAlpha + dstR * (1 - srcAlpha) = 0 *143/255 + 1 * (1 -143/255) =113/255
g = srcG * srcAlpha + dstG * (1 - srcAlpha) = 0 *143/255 + 0 * (1 -143/255) = 0
b = srcB * srcAlpha + dstB * (1 - srcAlpha) = 0 *143/255 + 0 * (1 -143/255) = 0
a = srcA * 1 + dstA * (1 - srcAlpha) =143/255 * 1 + 0 * (1 -143/255) =143/255
3. 混合的顏色爲 (113/255,0,0,143/255)
4. 混合網頁底色 (1,1,1,1) 和 (113/256,0,0,143/255) 之後
r = srcR * srcAlpha + dstR * (1 - srcAlpha) = (113/255) * (143/255) + 1 * (1 - 143/255) = 206/255
g = srcG * srcAlpha + dstG * (1 - srcAlpha) = 0 *143/255 + 1 * (1 -143/255) = 113/255
b = srcB * srcAlpha + dstB * (1 - srcAlpha) = 0 *143/255+ 1 * (1 -143/255) = 113/255
a = srcA * 1 + dstA * (1 - srcAlpha) = 143/255 * 1 + 1 * (1 - 143/255) = 1
5. 混合之後的顏色爲 (206/255,113/255,113/255,1),QQ 截圖之後發現顏色爲 (233,112,115),之後又測試了純色塊的 (0,0,0,143/255) 發現顏色爲 (226,113,113)。