混合和Z缓冲共享两个单独的着色器程序?

时间:2014-12-24 12:07:44

标签: android opengl-es opengl-es-2.0

我有2个着色器程序 - 一个用于渲染带有纹理的精灵,另一个用于渲染多边形。我已经启用了混合和Z缓冲区,如下所示:

GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);

GLES20.glEnable( GLES20.GL_DEPTH_TEST );
GLES20.glDepthFunc( GLES20.GL_LEQUAL );
GLES20.glDepthMask( true ); 
GLES20.glDepthRangef(0,  maxZDepth); //maxZDepth = 100f;

我的渲染包括2个渲染调用(glDrawElements):一个用于精灵,右边用于具有足够着色器程序的多边形...将对象的数据(顶点等等)发送到着色器的顺序从对象的最低Z值到最高,我还必须在我的精灵着色器中添加这样的指令:

if(gl_FragColor.a == 0.0)
    discard;

现在,混合和Z缓冲区正常工作,但一次只能在一个着色器的范围内。第一个着色器绘制的对象的混合似乎与第二个着色器无关......以下是一个示例:

enter image description here

这里的精灵比其下方的棕色多边形具有更高的Z值,这就是为什么它在多边形上绘制但是混合失败,你可以看到精灵周围的灰色背景(由glClearColor创建)......

有人知道这个问题的一些好方法吗?我想将2个着色器程序合并为一个,然后只有1个渲染调用,我希望能解决它,但我更喜欢为精灵和多边形保留2个单独的着色器程序......

1 个答案:

答案 0 :(得分:2)

根据简短评论讨论,问题是:

深度缓冲区每个像素只保留一个深度。部分透明的像素组合了来自不同深度的两种颜色。但它只能分配一个深度。最终成为更近像素的深度。

在一个理想的世界里,如果你把东西画得很远并且不透明,那么接近透明的东西,然后介于两者之间并且不透明的东西,那么最终的输出将是两者之间的东西和附近的东西的混合。实际发生的是透明的东西会将其深度设置为深度缓冲区。当您在两者之间绘制时,不会输出像素,因为它比深度缓冲区中最近的东西更远。因此,你最终会把远处的东西与近处的东西混合在一起,好像它之间的东西从未被画过。

有很多解决方案取决于您希望的准确程度,您的几何图形至少部分透明以及您有多少时间。

首先,如果您有任何绝对完全不透明的几何体,那么您可以先以最有效的顺序绘制所有这些几何体。

对透明几何体进行排序和渲染回到前面是最明显的解决方案。这很好,除了不是所有的几何体都可以通过回到前面来正确绘制(参见例如相互重叠),并且在最天真的实现中,你的GL状态变化可能最终变得非常昂贵,因为可能不是绘制50,000个三角形使用一个着色器,然后用一秒钟切换和绘制50,000,绘制三角形,切换,绘制,切换,绘制等,用于99,999个开关。

如果可以接受添加剂透明度,那么您可以按任何旧订单填写透明内容,而无需写入深度缓冲区。

Nvidia提议的东西正在利用多次采样,但可能会略微增加。想象一下,更像是为每个像素组合8x8或16x16像素样本。在这种情况下,您不是通过从帧缓冲区读取,混合和再次写出来绘制透明度,而是仅通过例如写入如果透明度为50%,则每个单元格中只有一半样本。你随机挑选一半。这为您提供了与订单无关的透明度,可以在增加单元格大小时提高质量。

假设您的多边形总是不透明的,并且您的精灵可能部分透明,那么,正如我认为您现在正在做的那样,先绘制多边形,然后按照从前到后的顺序绘制精灵。