OpenGL 程式設計/透明度



在計算機圖形學中,不透明物體很容易繪製。如果我們觀察螢幕上的特定畫素,場景中可能會有零個、一個或多個與該畫素重疊的物體。由於深度緩衝區的存在,您不必擔心哪個物體在最上面。您只需開始繪製該畫素上的第一個物體,記住它的深度,當您到達下一個物體時,將第二個物體的深度與之前物體的深度進行比較,如果它更小,則用第二個物體的顏色覆蓋畫素,否則什麼也不做。
對於半透明物體,事情就更復雜了。GPU 不能僅僅根據深度值選擇覆蓋畫素的顏色或保留它。相反,GPU 需要將透明物體的顏色與它後面的物體的顏色混合。但是,如果它還沒有繪製後面的物體,它就無法知道後面的物體的顏色。深度緩衝區在這裡就無濟於事;您繪製物體的順序突然變得非常重要。
這個問題有很多解決方案。顯而易見的解決方案是對所有物體從最遠到最近進行排序(或者說是這樣?)。但是排序的成本可能非常高,尤其是在每次場景發生變化時都需要重新排序,包括每次相機移動時。幸運的是,有一些技術可以避免這樣做,但它們都有侷限性。
我們可以使用累積緩衝區來模擬透明度。例如,想象一個包含不透明物體和一塊 50% 透明的彩色玻璃的場景。我們將使用的技巧是,我們將渲染此場景兩次:一次是將所有物體(包括玻璃)都繪製成完全不透明的。第二次我們只渲染不透明物體,並跳過渲染透明物體。使用累積緩衝區,我們計算兩個幀的平均值。結果將是,在玻璃窗格所在的位置,它後面物體的 50% 的光線會穿透。
透過在累積緩衝區中平均兩個以上的幀,或透過用不同的值乘以每個幀,您可以輕鬆地改變透明度。然而,這種技術的侷限性在於,當您有兩個或多個透明物體直接彼此重疊時,它無法正常工作。在現實生活中,兩塊 50% 透明的玻璃窗格只會使它們後面物體的 25% 的光線穿透。然而,使用累積緩衝區技巧,您仍然可以看到它們後面物體的 50%。
使物體透明的常用方法是更改其紋理中的 alpha 通道。因此,從一個只查詢紋理的非常簡單的片段著色器開始,我們引入了 alpha 通道的可配置截止值。如果 alpha 值低於截止值,我們就只繪製該片段,否則我們將它繪製成不透明的。
varying vec2 texcoord;
uniform sampler2D texture;
uniform float alpha_cutoff;
void main(void) {
vec4 color = texture2D(texture, texcoord);
// Don't draw pixels with an alpha value lower than the cutoff
if(color.a < alpha_cutoff)
discard;
gl_FragColor = color;
}
然後,我們將場景繪製兩次。一次使用 1/3 的截止值。透明度為 50% 的物體將在第一次傳遞中繪製。第二次我們使用 2/3 的截止值。透明度為 50% 的物體不會在這次傳遞中繪製。然後我們從累積緩衝區獲取兩次傳遞的平均值並將其傳送到螢幕。
glUniform1f(uniform_alpha_cutoff, 1.0 / 3.0);
draw_scene();
glAccum(GL_LOAD, 0.5);
glUniform1f(uniform_alpha_cutoff, 2.0 / 3.0);
draw_scene();
glAccum(GL_ACCUM, 0.5);
glAccum(GL_RETURN, 1);
glSwapBuffers();
- 修改上面的程式碼,使其仍然只繪製場景兩次,但使其適用於 80% 透明的物體。
- 修改上面的程式碼,使其繪製場景超過兩次,使其適用於所有透明度為 25%、50% 或 75% 的物體。
- 嘗試在任何以前的教程中實現這種技術。
- 你能將這種技術與抗鋸齒、運動模糊和/或景深有效地結合起來嗎?
- 對物體進行排序似乎是完美的方法。但是,物體可以具有奇怪的形狀,並且兩個物體之間可能沒有明確的順序。例如,考慮兩個互鎖的圓環。但是,對所有單個三角形進行排序怎麼樣?