2013-06-30 75 views
2

我正在用OpenGL和C++編寫一個簡單的2D框架,現在遇到了與透明紋理和混合有關的問題。我已經將我的問題減少到了以下。OpenGL背景清晰的顏色滲入透明紋理

我有兩個紋理:地磚和魚骨。後者包含透明像素。我把我的OpenGL鮮明的色彩,以「綠色透明」,使深度測試和混合是這樣的:

glClearColor(0, 1, 0, 0) 
glEnable(GL_DEPTH_TEST); 
glEnable(GL_BLEND); 
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 

有兩個調用glDrawElements()我畫魚,然後在地板上。魚具有較高的Z值,因此應放置在地磚前面。 This is the result

很顯然,我不希望這樣的魚周圍有綠色的盒子。我認爲會發生什麼情況是,魚的像素與繪製時幀緩衝區的顏色渲染緩衝區中的任何內容混合,並且恰好是純綠色(由於glClearColorglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT))。對於魚紋理中的每個透明像素,我都希望這種混合能夠解析爲透明(因爲我已經設置了透明的透明顏色),但正如你所看到的那樣,這不是發生了什麼。

如果我先畫地板,然後是魚,它的作品as expected

我的片段着色器是死的簡單:

varying lowp vec2 TexCoordOut; 
uniform sampler2D Texture; 

void main(void) { 
    gl_FragColor = texture2D(Texture, TexCoordOut); 
} 

難道我真的要管理繪製順序手動(用Z排序座標)或者是有辦法解決這個問題? OpenGL深度緩衝系統不是專爲解決這個問題而設計的嗎?

我正在通過Xcode在iOS模擬器上測試我的程序。

回答

2

我確實認爲深度排序是必要的 - 因爲即使混合的結果像素是透明的,深度緩衝區也是寫入的。因此,任何要繪製的背景(更高深度)都會被丟棄。不幸的是,深度緩衝區並未考慮透明度。

如果紋理中沒有任何半透明像素,則可以使用alpha測試,如果它是透明的,則會丟棄像素,因此它不會寫入深度緩衝區。這對於半透明像素顯然不起作用,因爲它們要麼變得完全不透明,要麼根據您的實現/設置而被丟棄。

varying lowp vec2 TexCoordOut; 
uniform sampler2D Texture; 

void main(void) { 
    vec4 tc = texture2D(Texture, TexCoordOut); 
    if (tc.a < 0.5) //for example, change to any value suitable 
    discard; 
    gl_FragColor = tc; 
} 

除此之外沒有辦法,我知道的修復與深度緩衝透明度除了排序:你可以很容易地通過改變你的着色器來實現它。 http://www.opengl.org/wiki/Transparency_Sorting

+0

有些方法可以在不進行排序的情況下進行透明化(例如http://www.eng.utah.edu/~cs5610/lectures/OrderIndependentTransparency.pdf),但我認爲它們對於這裏描述的情況是過度的,所以我認爲你的答案是好的。 – GuyRT

0

Z值用於滅殺:

可以在透明性排序和alpha測試在這裏閱讀更多的細節。如果已經有另一個具有較小z值的片段或者它位於視錐體之外,則不會繪製片段。但是所有的頂點緩衝區對象都是按順序繪製的。對於2D,您可以使用任何排序「by z」算法。如果您希望稍後添加一些濾鏡(如模糊或邊緣消除鋸齒),則丟棄碎片將會產生問題。

1

有這個確切的問題,並嘗試各種糾正它沒有堅實的結果試圖與大多數圍繞改變計算正在進行的建議工作。最後它非常簡單!

在我的代碼的罪魁禍首是這樣的:

glClearColor(1, 0, 1, 0); 
glClear(GL_COLOR_BUFFER_BIT); 

儘管它是透明的,當它的背景和主題會流血的顏色之間的混合。對我來說固定的是包裝這個代碼來掩蓋glClear步驟。它看起來像這樣:

glColorMask(false, false, false, true); 
glClearColor(1, 0, 1, 0); 
glClear(GL_COLOR_BUFFER_BIT); 
glColorMask(true, true, true, true); 

這似乎通過消除清除過程中除alpha通道以外的所有流血問題來消除流血問題。