OpenGL 顏色混合、圖元的反走樣(五)


顏色混合

?

使用混合的原因:

我們把OpenGL渲染時會把顏?值存在顏?緩存區(qū)中,每個?段的深度值也是放在深度緩沖區(qū)。當深度緩沖區(qū)被關(guān)閉時,新的顏?將簡單的覆蓋原來顏?緩存區(qū)存在的顏?值;當深度緩沖區(qū)再次打開時,新的顏??段只是當它們?原來的值更接近鄰近的裁剪平?才會替換原來的顏??段。

那么如果開啟深度測試后,當出現(xiàn)2個重疊的圖層情況,有?個圖層是半透明的,另?個圖層是?半透明的,那么此時就不能進?單純的?較深度值,然后進?覆蓋。?是需要將2個圖層的顏?進?計算后得到應該顯示顏色,這個過程叫“混合”。

blend_1.png

?

通常使用場景:

  • 如果只是單純的2個圖層重疊時進?混合,只需要開啟混合,設置混合方式(設置后在固定著?器或可編程著?器中它會自動混合)。
  • 比如一些濾鏡效果的制作,需要在可編程管線的?元著?器的著色時,套?公式或自定義進?顏?混合?程式計算,得到新的顏色值。例如將處理圖?原圖顏?加上薄薄的綠?,可以得到更好的視覺效果。

?

混合的具體使用:

?標顏?: 已經(jīng)存儲在顏?緩存區(qū)的顏?值。
源顏?: 作為當前渲染命令結(jié)果進?顏?緩存區(qū)的顏?值。


// 在OpenGL中默認是關(guān)閉的,需要開啟GL_BLEND來啟用混合功能:
glEnable(GL_BlEND); 

// 設置混合因?。S:源混合因?;D:?標混合因?。
glBlendFunc(GLenum S,GLenum D);

?

OpenGL混合計算方程式:

開啟混合后,我們通過glBlendFunc函數(shù)告訴OpenGL使用什么混合因子來進行計算,而默認計算方程式是固定的,只需要改變因子來變換計算參數(shù),得到不同的使用效果。


// 當混合功能被啟動時,源顏?和?標顏?的組合?式是混合?程式控制的。
// 在默認情況下,混合?程式如下所示:

Cf = (Cs * S) + (Cd * D)

Cf :最終計算參數(shù)的顏?
Cs : 源顏?
Cd :?標顏? 
S:源混合因?
D:?標混合因?

?

OpenGL混合因子表:

表中表示的都是計算方程式中參數(shù)的計算規(guī)則。
表中R、G、B、A 分別代表 紅、綠、藍、alpha。
表中下標S、D,分別代表源、?標。
表中C 代表常量顏?(默認??)。

?

混合計算例子:

下?通過?個常?的混合函數(shù)組合來說明問題:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


如果顏?緩存區(qū)已經(jīng)有?種顏?紅?(1.0f,0.0f,0.0f,1.0f),這個?標顏?Cd;
如果在這上???種alpha為0.6的藍?(0.0f,0.0f,1.0f,0.6f)。 

Cd (?標顏?) = (1.0f,0.0f,0.0f,1.0f); 
Cs (源顏?) = (0.0f,0.0f,1.0f,0.6f); 
S = 源alpha值 = 0.6f 
D = 1 - 源alpha值= 1-0.6f = 0.4f 

?程式 Cf = (Cs * S) + (Cd * D) 
等價于 = (Blue * 0.6f) + (Red * 0.4f)

blend_3.jpg

?

修改混合?程式:

默認混合?程式為:Cf = (Cs * S) + (Cd * D)
實際上遠不?這?種混合?程式,我們可以從5個不同的?程式中進?選擇:


//選擇混合?程式的函數(shù):
glbBlendEquation(GLenum mode);

模式 函數(shù)
GL_FUNC_ADD Cf = (Cs * S) + (Cd * D)
GL_FUNC_SUBTRACT Cf = (Cs * S) - (Cd * D)
GL_FUNC_REVERSE_SUBTRACT Cf = (Cd * D) - (Cs * S)
GL_MIN Cf = min (Cs, Cd)
GL_MAX Cf = max (Cs, Cd)

?

修改常量混合顏?:

在混合因?表中,GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR, GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT值允許混合?程式中引??個常量混合顏?。默認初始化為??(0.0f,0.0f,0.0f,1.0f),但是還是可以修改這個常量混合顏?。


常量混合顏?,默認初始化為??(0.0f,0.0f,0.0f,1.0f),但是還是可以修改這個常量混合顏?。
void glBlendColor(GLclampf red ,GLclampf green ,GLclampf blue ,GLclam pf alpha );

?

設置混合因子:
  • glBlendFunc函數(shù)可以指定源和?標RGBA值的混合因子。
  • glBlendFuncSeparate函數(shù)則允許為RGB和Alpha成分單獨指定混合因子。

glBlendFunc (GLenum sfactor, GLenum dfactor) 

sfactor:源混合因?;
dfactor:?標混合因?。

 
// 相對glBlendFunc來設置混合因子,glBlendFuncSeparate更靈活:
void glBlendFuncSeparate(GLenum strRGB,GLenum dstRGB ,GLenum strAlpha,GLenum dstAlpha);

strRGB: 源顏色的混合因子
dstRGB: ?標顏色的混合因子=
strAlpha: 源顏色的Alpha因子
dstAlpha: ?標顏色的Alpha因子



反走樣

?

為什么走樣:

我們都知道,在數(shù)學的定義中一條線段是由兩個端點確定的,而線段是沒有寬度和面積的。但在計算機圖形領(lǐng)域中,為了讓人的肉眼能夠看到,必須給線段一定的寬度,所以我們的線段通常是由兩個端點和一個寬度參數(shù)確定的,而我們計算機中圖形的寬度通常都是以像素為單位的,因此我們的線段寬度有可能是1像素也有可能是n像素。

使用OpenGL進行渲染后,我們很容易發(fā)現(xiàn)渲染圖像的線存在鋸齒問題。之所以產(chǎn)生這種鋸齒,是因為一條理想的直線是通過像素網(wǎng)格上的一系列像素點去逼近的。由此產(chǎn)生的鋸齒問題叫做走樣(sliasing),而消除這種鋸齒的過程就是我們所說的反走樣。

sliasing_1.png

?

反走樣方式一:

上圖所示為兩條相交的線,分別是走樣的情形和反走樣的情形。圖像進行了適當放大處理以突出顯示效果。右側(cè)寬度為1個像素的對角線段覆蓋了比一般線段更多的像素塊。事實上,當我們實現(xiàn)反走樣的時候,OpenGL會根據(jù)屏幕上每個像素塊所覆蓋的范圍來計算每個片元的覆蓋值。OpenGL會將片元alpha值與這個覆蓋值相乘。然后我們就可以使用alpha值來實現(xiàn)片元與幀緩存中已有像素的融混操作了。

覆蓋值計算的細節(jié)是非常復雜的,很難概要地進行講述。事實上,不同的 OpenGL實現(xiàn)中的計算方法也是存在細微差別的。我們可以使用gIHint()來進行進一步的控制,在圖像質(zhì)量和速度上做出權(quán)衡,不過并不是所有的設備實現(xiàn)都會受到這個函數(shù)的影響。


// glHint控制OpenGL的一些具體特性。
// hint參數(shù)的解析方式是與平臺相關(guān)的,有些OpenGL的實現(xiàn)可能會完全忽略它們的影響。

void glHint(GLenum target, GLenum hint);

?

glHint的參數(shù)target用來設置要控制的特性類型:

target參數(shù) 描述
GL_POINT_SMOOTH_HINT 點的反走樣質(zhì)量
GL_LINE_SMOOTH_HINT 線的反走樣質(zhì)量
GL_POLYGON_SMOOTH_HINT 多邊形邊的反走樣質(zhì)量
GL_TEXTURE_COMPRESSION_HINT 紋理圖像壓縮的質(zhì)量和性能
GL_FRAGMENT_SHADER_DERIVATIVE_HINT 片元處理內(nèi)置函數(shù)的導數(shù)精度,包括 dFdx、dFdx 以及 fwidth

?

glHint的參數(shù)hint用來設置要控制的質(zhì)量最高類型:

hint參數(shù) 描述
GL_FASTEST 使用效率最高的方式
GL_NICEST 使用質(zhì)量最高的方式
GL_DONT_CARE 表示沒有偏好

?

反走樣方式二:

如果程序中十分需要多重采樣的效果,那么對線段和多邊形反走樣的另一種方法就是通過gIEnable()開啟反走樣,然后將GL_LINE_SMOOTH或者 GL_POLYGON_SMOOTH作為參數(shù)傳入。你可能也需要通過gIHint()來設置一個質(zhì)量參考值。

?

點的反走樣:


glEnable(GL_POINT_SMOOTH); 
glHint(GL_POINT_SMOOTH,GL_NICEST);

?

線段的反走樣:

首先,需要開啟融混。融混參數(shù)通??梢栽O置為 GL_SRC_ALPHA(源)和GL_ONE_MINUS_SRC_ALPHA(目標)。或者也可以使用GL_ONE作為目標參數(shù),這樣線段相交的地方會顯得更亮?,F(xiàn)在我們可以使用反走樣的方式來繪制點和線段了。如果用的alpha值足夠高,那么反走樣效果是非常明顯的。注意當你設置使用融混時,需要考慮好渲染的順序。不過大多數(shù)情況下,忽略順序也不會帶來很明顯的問題。


glEnable(GL_LINE_SMOOTH); 
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);

?

多邊形的反走樣:


glEnable(GL_POLYGON_SMOOTH); 
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE); 
glHint(GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE);

填充多邊形的邊的反走樣與線段的反走樣過程相似。由于不同的多邊形的邊之間存在著交疊,因此我們需要適當?shù)貙︻伾颠M行融混。

為了對多邊形進行反走樣,需要使用alpha值來表達多邊形邊的覆蓋值。通過glIEnable()設置參數(shù)GL_POLYGON_SMOOTH來開啟多邊形的反走樣功能。這樣多邊形邊上的像素就會根據(jù)覆蓋率來設置alpha值,這一點與線段的反走樣是一致的。當然,如果需要的話,我們也可以設置 GL_POLYGON_SMOOTH_HINT的質(zhì)量值。

為了確保邊的融混方式恰當,我們可以設置顏色混合參數(shù)為 GL_SRC_ALPHA_SATURATE(源)和 GL_ONE(目標)。通過這個特定的融混函數(shù),得到的最終顏色將是目標顏色和成比例的源顏色的總和;比例系數(shù)其實就是以下兩者中的較小者:輸入源的alpha值、1減去目標alpha值。這也就是說,對于一個alpha值很大的像素,連續(xù)輸入像素對于最終顏色的影響很小,因為1減去目標alpha幾乎為0。通過這種方式,多邊形邊的像素就可以與之后繪制的其他多邊形的顏色很好地融合在一起了。

最后,還需要對場景中的所有多邊形進行排序,保證它們按照從前往后的順序排列后再渲染。

深度緩存對于反走樣的使用有一定的負面影響,因為某些像素可能本來需要融混,但是卻在深度測試后被拋棄了。如果要保證融混和反走樣的正確性,那么我們也許需要禁止深度緩存。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容