Android 在两个单独的着色器程序之间共享混合和Z缓冲区?

Android 在两个单独的着色器程序之间共享混合和Z缓冲区?,android,opengl-es,opengl-es-2.0,Android,Opengl Es,Opengl Es 2.0,我有两个着色器程序-一个用于渲染带有纹理的精灵,另一个用于渲染多边形。我启用了混合和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.glDepthM

我有两个着色器程序-一个用于渲染带有纹理的精灵,另一个用于渲染多边形。我启用了混合和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;
我的渲染包括两个渲染调用(GLDrainElements):一个用于精灵,紧接着一个用于具有足够着色器程序的多边形。。。将对象数据(顶点等)发送到着色器的顺序是从对象的最低Z值排序到最高Z值,我还必须将此类指令添加到我的精灵着色器:

if(gl_FragColor.a == 0.0)
    discard;
现在,混合和Z缓冲区工作正常,但一次只能在一个着色器的范围内。第一个着色器绘制的对象的混合似乎与第二个着色器无关。。。下面是一个例子:

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


有人知道解决这个问题的好办法吗?我曾考虑将两个着色器程序合并为一个,然后只有一个渲染调用,我希望可以解决这个问题,但我更愿意为精灵和多边形保留两个单独的着色器程序…

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

深度缓冲区每像素仅保存一个深度。部分透明的像素结合了两种不同深度的颜色。但它只能指定一个深度。这就是更接近的像素的深度

在一个理想的世界里,如果你画了一些遥远而不透明的东西,然后画了一些接近而透明的东西,然后画了一些介于两者之间且不透明的东西,那么最终的输出将是介于两者之间的东西和附近的东西的混合体。实际上,透明的东西会将其深度设置为深度缓冲区。当你画中间的东西时,不会输出任何像素,因为它比深度缓冲区中最近的东西更远。因此,你最终会发现远处的东西和近处的东西混在一起,就好像中间的东西从来没有被画过一样

有一系列的解决方案取决于您希望达到的精确程度、几何体的多少部分至少是部分透明的以及您有多少时间

首先,如果你有一个完全不透明的几何体,那么你可以先画所有的几何体,以最有效的顺序

最明显的解决方案是对透明几何体进行排序并前后渲染。这很好,但不是所有的几何体都可以通过返回到前面来正确绘制(请参见相互重叠),在最简单的实现中,您的GL状态更改可能会非常昂贵,而不是使用一个着色器绘制50000个三角形,然后切换并使用第二个着色器绘制50000个三角形,开关、牵引、开关、牵引等,用于99999开关

如果附加透明度是可以接受的,那么您可以按照任何旧顺序填充透明内容,而不必写入深度缓冲区

Nvidia提出的一些建议是利用多重采样,但可能会稍微提高一点。想象一下,每个像素的组合更像是8x8或16x16像素采样。在这种情况下,您不是通过从帧缓冲区读取、混合并再次写入来绘制透明度,而是通过仅写入(例如,如果透明度为50%,则每个单元格中仅写入一半样本)来绘制透明度。你随便挑一半。这样,随着单元格大小的增加,与订单无关的透明度将提高质量


假设你的多边形总是不透明的,并且你的精灵都可能是部分透明的,那么,就像我想你现在正在做的那样,先画多边形,然后按从后到前的顺序画精灵。

你大概是先画精灵?哦,我的天。。。我在考虑一些愚蠢的复杂解决方案,结果证明,唯一需要改变的是在渲染精灵之前渲染多边形。我不知道为什么我以前没试过。。。谢谢!英伟达的方法,你描述的声音像alpha覆盖,是标准的OpenGL。嗯,大多数硬件的MSAA级别可能没有您提到的那么高,但该功能是可用的。@RetoKoradi谷歌搜索后,似乎Nvidia在所有主要方法(随机、a缓冲、深度剥离等)上都有幻灯片但这是有道理的,因为真正的NVidia的工作只是宣传最新的硬件可以做什么。但我特别想到的是,;根据它,“[c]当前硬件已经支持alpha-to-coverage(a2c)模式,该模式可以实现这一点……[u]幸运的是,屏蔽门掩码始终是相同的;随着alpha的增加,样本会按指定的顺序添加到其中。”@AndonM.Coleman这样做可能很荒谬,但不去考虑它,答案取决于经典帧缓冲区中深度与像素的一对一关系。这可能不是你所追求的解决方案,但我认为这是有帮助的。好的,是的,alpha-to-coverage的模式是固定的。有时候,它看起来像是在多个(4?)相邻像素上有一些分布,几乎像某种形式的抖动。但绝对不是随机的。我确信人们已经尝试改进基本方法。@Tommy:事实上,我看错了。你的提议完全不同。但如果您的硬件支持显式多采样(多采样纹理),则有一种更实用的方法称为“模具路由a缓冲”,它可以仅使用4x MSAA实现。