首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >OpenGL背景透明颜色渗入透明纹理

OpenGL背景透明颜色渗入透明纹理
EN

Stack Overflow用户
提问于 2013-06-30 19:51:29
回答 3查看 3.5K关注 0票数 3

我正在用OpenGL和C++编写一个简单的2D框架,现在遇到了一个与透明纹理和混合相关的问题。我已经将我的问题简化为以下几点。

我有两个纹理:地砖和鱼骨。后者包含透明像素。我将OpenGL的透明颜色设置为“透明绿色”,并启用了深度测试和混合,如下所示:

代码语言:javascript
复制
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))。对于fish纹理中的每个透明像素,我原本希望这种混合能够解析为透明(因为我已经设置了透明透明的颜色),但正如你所看到的,这并不是正在发生的事情。

如果我先画地板,然后画鱼,它就能工作as expected

我的片段着色器非常简单:

代码语言:javascript
复制
varying lowp vec2 TexCoordOut;
uniform sampler2D Texture;

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

我是否真的需要手动管理绘图顺序(按Z坐标排序),或者是否有解决此问题的方法?OpenGL深度缓冲系统不就是为解决这个问题而设计的吗?

我正在通过Xcode在iOS模拟器上测试我的程序。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-06-30 20:55:32

我确实认为深度排序是必要的-因为即使从混合得到的像素是透明的,深度缓冲区也是写入的。因此,在这些透明像素(更高深度)后面绘制的任何内容都将被简单地丢弃。不幸的是,深度缓冲区没有考虑透明度。

如果你的纹理中没有任何半透明的像素,你可以使用alpha测试,如果一个像素是透明的,它就会丢弃它,所以它不会写入深度缓冲区。这显然不适用于半透明像素,因为它们要么变得完全不透明,要么被丢弃,这取决于您的实现/设置。您可以通过将着色器更改为:

代码语言:javascript
复制
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;
}

除此之外,据我所知,除了排序之外,没有任何方法可以用深度缓冲来修复透明度。

您可以在此处阅读有关透明度排序和alpha测试的更多详细信息:http://www.opengl.org/wiki/Transparency_Sorting

票数 3
EN

Stack Overflow用户

发布于 2015-12-23 03:29:00

确实存在这个问题,并尝试了各种方法来纠正它,但没有得到可靠的结果,试图与大多数以改变计算为中心的建议合作。最后,它是相当简单的!

我的代码中的罪魁祸首是这样的:

代码语言:javascript
复制
glClearColor(1, 0, 1, 0);
glClear(GL_COLOR_BUFFER_BIT);

尽管它是透明的,但当它在背景和被摄体的颜色之间混合时,它会出血。对我来说,修复它的方法是包装这段代码来屏蔽glClear步骤。它看起来是这样的:

代码语言:javascript
复制
glColorMask(false, false, false, true);
glClearColor(1, 0, 1, 0);
glClear(GL_COLOR_BUFFER_BIT);
glColorMask(true, true, true, true);

这似乎通过从清除过程中消除除alpha通道之外的所有通道来消除出血问题。

票数 2
EN

Stack Overflow用户

发布于 2013-07-01 23:03:41

Z值用于剔除。如果已经存在具有较小z值的另一个片段,或者该片段位于视图锥体之外,则不会绘制该片段。但所有顶点缓冲区对象都是按顺序绘制的。对于2D,您可以使用任何“按z排序”算法。如果你想在以后添加一些滤镜,比如模糊或边缘抗锯齿,丢弃碎片将是有问题的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17390071

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档