2013-06-30 74 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通道以外的所有流血问题来消除流血问题。