OpenGL ES2 Alpha测试问题

12

我正在以3D方式呈现具有alpha的多个纹理对象。 所有纹理都能正常加载,但当我尝试在彼此前面呈现它们时,我会得到以下结果:

左边是我所拥有的,右边则是我想要的

左边是我所拥有的,右边则是我想要的。 网格只是为了帮助可视化透视图。

在红色圆形纹理的前面的纹理被剪辑了。 我搜索了答案,它说让我使用:

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

但是我正在使用它,它仍然无法工作。我正确放置在onSurfaceCreated()函数中的设置如下:

GLES20.glClearColor( 0.75f, 0.85f, 1f, 1.0f );
GLES20.glEnable( GLES20.GL_BLEND );
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA );
GLES20.glEnable( GLES20.GL_DEPTH_TEST );
GLES20.glDepthFunc( GLES20.GL_LEQUAL );
GLES20.glDepthMask( true );
GLES20.glClearDepthf( 1f );

我的片段着色器是:

uniform sampler2D texture;
varying vec2 texCoord;  
void main(){ 
   gl_FragColor = texture2D( texture, texCoord );
} 

我需要在Android清单中包含什么才能启用Alpha测试吗? 我不想最终不得不手动组织我的多边形或使用alpha discard(),因为我需要并希望一些像素是半透明的。

我该如何使3D Alpha测试深度缓冲区起作用?


你确定你的帧缓冲附加了深度渲染缓冲吗? - Martijn Courteaux
你必须这样做吗?我以为这对于Android是自动的。我该怎么做呢? - sgtHale
我从未在Android上使用过OpenGL,只在iOS上使用过,但我猜它应该是一样的,因为你也使用OpenGL ES 2.0。不过,我想你可以搜索一下教程...你有任何类似这样的代码吗?http://puu.sh/8m7i7.png - Martijn Courteaux
也可以看一下这个问题:https://dev59.com/dWfWa4cB1Zd3GeqPdAyO - Martijn Courteaux
我刚刚尝试在我的应用程序开始时创建视图并设置view.setEGLConfigChooser(true),就像问题一开始所说的那样,但仍然没有成功。此外,我没有任何genFrameBuffer代码。虽然我在Windows引擎上有这个代码,但我相当确定Android会自动创建一个。否则,我就无法开始渲染红色和蓝色的纹理了。 - sgtHale
显示剩余6条评论
2个回答

34

下面是几种在OpenGL中实现透明度渲染的概述,每种方法都有其优缺点。

Alpha Testing

这是一种非常有限的方法,但足以满足提问者所需。所显示的示例不需要透明度,因为所有内容都是完全不透明或完全透明(alpha = 1.0或alpha = 0.0)。

在OpenGL中曾经有一个用于此目的的alpha测试,但它是一个已过时的功能,并且当然没有ES版。您可以在片段着色器中模拟相同的效果,代码如下:

vec4 val = texture2D(tex, texCoord);
if (val.a > 0.5) {
    gl_FragColor = val;
} else {
    discard;
}

优点:

  • 简单。
  • 无需对应用程序进行额外的工作。

缺点:

  • 只适用于完全不透明/透明,不能处理半透明。
  • 可能会降低性能,因为通常需要在片段着色器之前禁用深度测试。

排序和混合

混合是处理透明的主要用例。最常见的方法是将混合功能设置为SRC_ALPHA,ONE_MINUS_SRC_ALPHA,启用混合,并使用所渲染碎片的alpha分量来包含所需的不透明度。

如果场景包含一些完全不透明的对象和具有透明属性的对象,则可以先渲染完全不透明的对象,而无需对它们进行排序。只有具有透明度的对象需要排序。然后顺序如下:

  1. 渲染完全不透明的几何体。
  2. 渲染非不透明的几何体,按从后向前排序。

优点:

  • 可以处理半透明。
  • 可以处理多层透明几何体。
  • 渲染本身非常高效。

缺点:

  • 需要正确的排序才能获得正确的结果。对于上述混合函数,几何体必须从后往前渲染。根据应用程序的不同,这可能会有些困难甚至几乎不可能。例如,要正确地渲染重叠的几何体,您可能需要开始拆分三角形,这远非令人满意。

深度剥离

这是OpenGL功能的一个非常聪明的用法,我个人认为它是一个不错的实际解决方案。需要多次渲染。简单形式需要3次通行证:

  1. 使用通常的设置(启用深度测试,深度函数为LESS,启用颜色和深度写入),但只渲染完全不透明的几何体。如果不透明度是按对象计算的,则可以通过跳过非不透明对象的绘制调用来处理它。否则,您将不得不使用类似于上面Alpha Testing下的着色器丢弃非不透明片段。
  2. 使用与上述相同的设置渲染非不透明几何体,除了禁用颜色写入外。
  3. 再次渲染非不透明几何体,但这次使用EQUAL深度函数,重新启用颜色写入,禁用深度写入,并使用混合。

第2步可以使用最小着色器,因为它不需要生成任何有效的片段颜色。

优点:

  • 实现简单。
  • 相当高效,不需要排序。
  • 正确处理半透明。

缺点:

  • 简单形式只绘制前面最靠近的透明几何体。这听起来可能是一个主要限制,但实际上结果可能看起来非常好。还有更高级的形式,其中使用额外的通行证渲染更多层。除了这些额外通行证的开销之外,它也变得更加复杂,因为它需要

很棒的分析。我猜Alpha测试对于Android来说已经足够了。 - sgtHale
请注意,alpha测试对性能非常不利,因为您需要进行分支。在片段着色器中使用if或循环通常是非常糟糕的。 - Martijn Courteaux
@MartijnCourteaux:显然你不会想要不必要的分支。但如果你需要它们,我认为性能不会太差。你在现代硬件上进行了基准测试吗?实际上,我更担心丢弃的性能影响,因为它通常需要禁用早期深度测试。 - Reto Koradi
@T_01:对于“排序和混合”中提到的排序,这是你必须在自己的代码中完成的任务。你可以使用任何喜欢的排序算法。如果需要概述,请从这里开始:http://en.wikipedia.org/wiki/Sorting_algorithm。 - Reto Koradi
实际上,由于sgtHale在谈论Android,他可能正在使用PowerVR/Adreno/Mali GPU。在这种情况下,不仅不需要对不透明几何物体进行排序,而且这样做实际上是一件愚蠢的事情。当TBDR GPU执行延迟平铺时,它们会对不透明几何进行排序,因此,从CPU执行前向后排序可能会产生的任何好处都只是浪费CPU周期的表现;丢弃操作还会破坏TBDR GPU的效率,因为它们基本上相当于早期深度测试的增强版。 - Andon M. Coleman

-1

被接受的答案并没有涵盖它。

在您的情况下,解决方案是禁用深度测试,并可能颠倒您绘制的顺序。

着色器丢弃是一种hack方法,如果您需要一系列alpha值,它看起来会很糟糕。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接