OpenGL的混合模式炎辨,解決半透明像素渲染問題

要命的陰影

事情是這樣的捕透,近日查一個問題聪姿,半透明的素材視頻 或者 圖片,渲染到屏幕的時候半透明部分會有一圈深色陰影乙嘀。

原圖.png

渲染到屏幕時末购,星星的邊緣有一圈深色陰影

原圖渲染.png
原視頻.png
原視頻.png
原視頻渲染.png

混合模式

基于以上問題,先來復習一下混合模式虎谢。OpenGL使用混合(Blending)技術來完成半透明圖像的渲染盟榴。
步驟如下:

// 1.開啟混合模式
glEnable(GLES20.GL_BLEND); 
// 2.設置函數(shù):源因子,目標因子
glBlendFunc(int sfactor, int dfactor);
// 3.渲染目標
// 4.渲染源   
// 5.關閉混合模式
glDisable(GLES20.GL_BLEND);  

混合模式的公式婴噩,一定要注意好哪個是源擎场,哪個是目標。

Cˉresult=Cˉsource?Fsource+Cˉdestination?Fdestination
Cˉsource:源顏色向量几莽。這是來自紋理的本來的顏色向量迅办。
Cˉdestination:目標顏色向量。這是儲存在顏色緩沖中當前位置的顏色向量章蚣。
Fsource:源因子站欺。設置了對源顏色的alpha值影響。
Fdestination:目標因子纤垂。設置了對目標顏色的alpha影響矾策。

混合因子可選值如下:

選項
GL_ZERO 0
GL_ONE 1
GL_SRC_COLOR 源顏色向量Cˉsource
GL_ONE_MINUS_SRC_COLOR 1?Cˉsource
GL_DST_COLOR 目標顏色向量Cˉdestination
GL_ONE_MINUS_DST_COLOR 1?Cˉdestination
GL_SRC_ALPHA Cˉsource的alpha值
GL_ONE_MINUS_SRC_ALPHA 1? Cˉsource的alpha值
GL_DST_ALPHA Cˉdestination的alpha值
GL_ONE_MINUS_DST_ALPHA 1? Cˉdestination的alpha值
GL_CONSTANT_COLOR 常顏色向量Cˉconstant
GL_ONE_MINUS_CONSTANT_COLOR 1?Cˉconstant
GL_CONSTANT_ALPHA Cˉconstant的alpha值
GL_ONE_MINUS_CONSTANT_ALPHA 1? Cˉconstant的alpha值

當然還可以使用glBlendFuncSeparate( int srcRGB, int dstRGB, int srcAlpha, int dstAlpha );來分別對RGB 和 alpha 設置不同的因子。
使用glBlendEquation( int mode ); & glBlendEquationSeparate( int modeRGB, int modeAlpha ); 配置混合函數(shù)運算符峭沦。

舉幾個例子贾虽,我們重點關注alpha的變化。(此時我還沒意識到預乘Premultiplied Alpha的作用)
源(1吼鱼,1蓬豁,0履磨,0.6),目標(0.6庆尘,0.6剃诅,0.5,1)

  1. glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA)
    result.r = 1 * 0.6 + 0.6 * (1 - 0.6)= 0.84
    result.g = 1 * 0.6 + 0.6 * (1 - 0.6)= 0.84
    result.b = 0 * 0.6 + 0.5 * (1 - 0.6)= 0.2
    result.a = 0.6 * 0.6 + 1 * (1 - 0.6)= 0.76
  2. .glBlendFuncSeparate(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA, GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA)
    result.r = 1 * 0.6 + 0.6 * (1 - 0.6)= 0.84
    result.g = 1 * 0.6 + 0.6 * (1 - 0.6)= 0.84
    result.b = 0 * 0.6 + 0.5 * (1 - 0.6)= 0.2
    result.a = 0.6 * 1 + 1 * (1 - 0.6)= 1
  3. glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA)
    result.r = 1 * 1 + 0.6 * (1 - 0.6)= 1.24
    result.g = 1 * 1 + 0.6 * (1 - 0.6)= 1.24
    result.b = 0 * 1 + 0.5 * (1 - 0.6)= 0.2
    result.a = 0.6 * 1 + 1 * (1 - 0.6)= 1
GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA
GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA, GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA
GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA

實際上驶忌,Bitmap在加載圖像的時候矛辕,會進行預乘,預乘就是將alpha通道的值分別與r付魔、g聊品、b的值相乘,得到新的r几苍、g翻屈、b的值,所以預乘后如果源使用GLES20.GL_SRC_ALPHA顯然值是不正確的妻坝,就需要使用GLES20.GL_ONE得到正確的值伸眶。

比如像素值(1,1刽宪,0厘贼,0.6)預乘后像素值(0.6,0.6圣拄,0嘴秸,0.6)

看到這幾個圖的效果應該也知道問題怎么解決了,那么繼續(xù)看下前面的問題庇谆。

我項目中會有多個層級的混合岳掐,部分采用blendFunc、部分采用shader饭耳,此處是使用shader mix 混合的串述,mix的混合模式等同于GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);

mix(a, b, c) = a * (1-c) + b * c

由上述可知,采用GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);可解決黑色陰影問題哥攘。對應公式:

resultColor = blendColor * 1.0 + baseColor * (1.0 - blendColor.a);
為防止曝光剖煌,我們增加min函數(shù):
resultColor = min(resultColor, vec4(1.0));

shader.png

為什么是黑色陰影
你會發(fā)現(xiàn),無論你清屏顏色設置的是什么逝淹,最后的半透明處的顏色都不是清屏顏色耕姊,但 當你設置給控件背景色時,你會發(fā)現(xiàn)栅葡,半透明的顏色會跟背景色變化

如下是修復后的效果:

原圖修復后渲染.png
原視頻修復后渲染.png

另需要注意的是茉兰,源使用GLES20.GL_ONE對與貼圖設置alpha<1(著色器中的像素值 * alpha)會顯示異常,alpha不生效欣簇,仍需要使用GLES20.GL_SRC_ALPHA规脸,所以我們要根據(jù)自己的層級情況選擇設置什么混合模式或者shader中的計算公式坯约。

更多資料

creater關于blend,關于預乘premultiply alpha莫鸭,關于圖片白邊灰邊的幾點疑問
圖片Premultiplied Alpha
紋理混合遇到的問題 pre-multiplying OpenGL Android iOS

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末闹丐,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子被因,更是在濱河造成了極大的恐慌卿拴,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梨与,死亡現(xiàn)場離奇詭異堕花,居然都是意外死亡,警方通過查閱死者的電腦和手機粥鞋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門缘挽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人呻粹,你說我怎么就攤上這事壕曼。” “怎么了尚猿?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵窝稿,是天一觀的道長。 經(jīng)常有香客問我凿掂,道長,這世上最難降的妖魔是什么纹蝴? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任庄萎,我火速辦了婚禮,結果婚禮上塘安,老公的妹妹穿的比我還像新娘糠涛。我一直安慰自己,他們只是感情好兼犯,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布忍捡。 她就那樣靜靜地躺著,像睡著了一般切黔。 火紅的嫁衣襯著肌膚如雪砸脊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天纬霞,我揣著相機與錄音凌埂,去河邊找鬼。 笑死诗芜,一個胖子當著我的面吹牛瞳抓,可吹牛的內(nèi)容都是我干的埃疫。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼孩哑,長吁一口氣:“原來是場噩夢啊……” “哼栓霜!你這毒婦竟也來了?” 一聲冷哼從身側響起横蜒,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤叙淌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后愁铺,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鹰霍,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年茵乱,在試婚紗的時候發(fā)現(xiàn)自己被綠了茂洒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡瓶竭,死狀恐怖督勺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情斤贰,我是刑警寧澤智哀,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站荧恍,受9級特大地震影響瓷叫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜送巡,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一摹菠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧骗爆,春花似錦次氨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至犀呼,卻和暖如春幸撕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背圆凰。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工杈帐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓挑童,卻偏偏與公主長得像累铅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子站叼,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容