作者:星隕
來源:
音視訊開發進階在 Android 中有一個類 PorterDuffXfermode ,它是用來設定顔色混合方式的,也就是在已有顔色的基礎上再繪制一筆顔色,這兩個顔色是如何進行混合的,是新繪制的顔色覆寫了原有顔色,還是新繪制的顔色和原有顔色混合組成另一種顔色呢。
在 OpenGL 中同樣有這樣顔色混合的問題。
在 OpenGL 的世界模型中是有深度的概念的,也就是由 z 軸坐标值來決定物體距離坐标原地的遠近,但到最後世界模型裡的物體都要投影到近平面,最後映射到視口上。而且,距離相機也就是視口越近的物體,就會遮住後面的物體,就和用肉眼去觀察物體一下,後面的形狀會被前面的形狀擋住。
但和肉眼觀察不同的是,OpenGL 裡最終呈現的顔色,是将兩個片元混合之後計算的值,我們可以改變這片元混合的方式,這就和前面 Android 裡面提到的 PorterDuffXfermode 混合模式一樣。
顔色混合基礎知識
OpenGL 中的顔色混合就是将通過各種測試準備進入幀緩沖的片元(源片元)與幀緩沖中的原有片元(目标片元)按照設定的比例權重計算最終片元的顔色值。新片元不一定是直接覆寫緩沖區中的源片元。
混合因子
OpenGL 通過設定混合因子來指定兩個片元的權重比例,每次都需要給出兩個混合因子:
- 源因子,用于确定将進入幀緩沖的片元在最終片元中的比例
- 目标因子,用于确定原幀緩沖中的片元在最終片元中的比例
由于 OpenGL 中每個顔色值包括 4 個色彩通道,是以,兩種混子因子都有 4 個分量值,分别對應一個色彩通道,具體混合計算細節如下:
- 設源因子和目标因子分别為 和
OpenGL 中的顔色混合和使用顔色混合基礎知識混合因子混合方程式源因子和目标因子設定混合的方法常用混合組合具體使用 ,S 表示是源因子,D 表示是目标因子,r,g,b,a 下标分别表示 紅、綠、藍、透明度 4 個色彩通道。OpenGL 中的顔色混合和使用顔色混合基礎知識混合因子混合方程式源因子和目标因子設定混合的方法常用混合組合具體使用 - 設源片元和目标片元的顔色值分别為
OpenGL 中的顔色混合和使用顔色混合基礎知識混合因子混合方程式源因子和目标因子設定混合的方法常用混合組合具體使用 ,R,G,B,A 分别表示紅、綠、藍、透明度 4 個色彩通道,s 下标表示源片元,d 下标表示目标片元。OpenGL 中的顔色混合和使用顔色混合基礎知識混合因子混合方程式源因子和目标因子設定混合的方法常用混合組合具體使用 - 混合後最終片元顔色各個色彩通道的值是由顔色混合方程式計算而來,系統提供的常用顔色混合方程式如下:
混合方程式
預設情況下,系統會自動調用 GL_FUNC_ADD 混合方程式來計算最終片元顔色各個色彩通道的值,如果想要調用其他混合方程式來計算最終的片元顔色,系統也有提供對應的方法:
方法簽名 說明
源因子和目标因子
對于顔色混合來說,標明了混合方程式,接下來最重要的就是設定混合因子了。
在 OpenGL 中預置了一些混合因子,如下表:
其中,常量名稱中有 SRC 代表各通道值來自源片元,有 DST 代表各通道值來自目标片元,另外 GL_SRC_ALPHA_SATURATE 隻能用作源因子。
對于常量名中有 CONSTANT 的代表使用預設顔色常量值對應色彩通道的值作為相應的因子值,其中的 R_c、G_c、B_c、A_c 分别代表預設顔色常量值的 RGBA 通道的值,如果沒有設定則預設值為
。
設定顔色常量值使用的是 glBlendColor 方法,如下:
1 public static native void glBlendColor(
2 float red,
3 float green,
4 float blue,
5 float alpha
6 );
設定混合的方法
有了混合因子,接下來就是設定混合因子了,OpenGL 提供了如下方法來設定:
常用混合組合
對于混合因子和混合 方程式的組合太多了,恰當的組合可以産生很好的效果,下面給出兩組常用的組合:
- 源因子 GL_SRC_ALPHA ,目标因子 GL_ONE_MINUS_SRC_ALPHA ,即源因子和目标因子分别為
OpenGL 中的顔色混合和使用顔色混合基礎知識混合因子混合方程式源因子和目标因子設定混合的方法常用混合組合具體使用 。此組合實作的是最典型的半透明遮擋效果。若源片元是透明的,則根據透明度透過後面的内容;若源片元不透明,則僅能看到源片元,是以,使用此組合時往往會采用半透明的紋理或顔色對源片元着色。OpenGL 中的顔色混合和使用顔色混合基礎知識混合因子混合方程式源因子和目标因子設定混合的方法常用混合組合具體使用 - 源因子 GL_SRC_COLOR ,目标因子 GL_ONE_MINUS_SRC_COLOR ,即源因子和目标因子分别為
OpenGL 中的顔色混合和使用顔色混合基礎知識混合因子混合方程式源因子和目标因子設定混合的方法常用混合組合具體使用 。此組合可以實作濾光鏡效果,也就是平時透過有色眼鏡或玻璃觀察事物的感覺。與第一種常用組合不同,此組合不要求應用于源片元的顔色或者紋理是半透明的。OpenGL 中的顔色混合和使用顔色混合基礎知識混合因子混合方程式源因子和目标因子設定混合的方法常用混合組合具體使用
具體使用
前面講了這麼多理論,其實就是闡述兩個顔色的 RGBA 值如何計算得到最後的 RGBA 值,并且每一個 R、G、B、A 分量都是兩個顔色的 R、G、B、A 對應乘以不同的混合因子後相加得到的,這個混合因子的設定可以根據源片元的顔色來設定,也可以根據目标片元的顔色來設定。
先假設有這樣的場景:
通過這樣的圖檔經過混合後去檢視後面的内容,類似于刺激戰場上開鏡效果,
顯然,圖檔的黑色區域是要可以透過看到後面内容的,綠色區域也是一樣,不然就全遮蓋住後面内容了。
這裡就可以用到上面的混合因子組合,源因子 GL_SRC_COLOR,目标因子 GL_ONE_MINUS_SRC_COLOR ,這個混合因子是根據源片元的顔色來設定的。
根據這兩個混合因子和混合方程式計算,可以得出最後的顔色值。
根據源因子 GL_SRC_COLOR 計算,由于黑色的 RGB 值都為 0 ,RGB 混合因子都為 0,也就是透明的,源片元不會進入到最終片元。
根據源因子 GL_ONE_MINUS_SRC_COLOR 計算,由于黑色的 RGB 值都為 0 ,那麼目标顔色的混合因子都為 1,也就是目标顔色都會被顯示,可以看到後面的物體。
對于綠色部分,就不存在為0 或者為 1 的情況了,就是兩個顔色按照混合因子計算後的值了。
具體的使用過程很簡單,大緻代碼如下:
1 // 先繪制好背景内容
2 // 開啟顔色混合進行繪制
3 GLES20.glEnable(GLES20.GL_BLEND)
4 // 設定混合因子
5 GLES20.glBlendFunc(GLES20.GL_SRC_COLOR, GLES20.GL_ONE_MINUS_SRC_COLOR)
6 // 繪制操作
7 rect!!.drawSelf(textureId)
8 MatrixState.popMatrix()
最後效果如下:
當然,還可以使用另外一種混合因子組合 GL_SRC_ALPHA 和 GL_ONE_MINUS_SRC_ALPHA,根據源因子的透明度來設定混合因子。
關于如何使用 GL_SRC_ALPHA 和 GL_ONE_MINUS_SRC_ALPHA 混合因子,可以參考之前的文章 用 OpenGL 對視訊幀内容進行替換,大概原理都一樣的,就是圖檔換成帶透明度的,并且更改一下混合因子組合,就不贅述了。
具體的實作可以參考我的 Github 項目,求一波 Star 。
https://github.com/glumes/AndroidOpenGLTutorial OpenGL 系列文章「視訊雲技術」你最值得關注的音視訊技術公衆号,每周推送來自阿裡雲一線的實踐技術文章,在這裡與音視訊領域一流工程師交流切磋。