OpenGL ES2 Alpha测试问题

时间:2014-04-24 22:01:58

标签: java android 3d opengl-es-2.0 depth-buffer

我在3D中渲染具有alpha纹理的多个对象。所有的纹理加载都很好但是当我尝试将它们渲染在彼此的前面时,我得到以下结果:

Left is what I have. Right is what I want

左边是我的。它应该是正确的。网格只是为了帮助可视化透视。

红色圆圈纹理前面的纹理被剪裁。我四处寻找答案,它告诉我使用:

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测试深度缓冲区工作?

2 个答案:

答案 0 :(得分:27)

以下概述了在OpenGL中使用透明度进行渲染的几种方法,每种方法各有优缺点。

Alpha测试

这是一种非常有限的方法,但足以满足海报所询问的特定情况。显示的示例并不真正需要透明度,因为所有内容都是完全不透明或完全透明(alpha = 1.0或alpha = 0.0)。

在OpenGL中曾经有过针对此目的的alpha测试,但这是一个不推荐使用的功能,当然不在ES中。您可以在片段着色器中模拟相同的内容,它看起来像这样:

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

优点:

  • 简单。
  • 在app方面没有额外的工作。

缺点:

  • 仅适用于完全不透明度/透明度,不能处理半透明度。
  • 可能会影响性能,因为它通常意味着必须禁用片段着色器之前的深度测试。

排序和混合

渲染透明度是混合的主要用例。最常见的方法是将混合函数设置为SRC_ALPHA, ONE_MINUS_SRC_ALPHA,启用混合,并使用包含所需不透明度的渲染片段的alpha分量进行渲染。

如果场景包含完全不透明的对象和具有透明度的对象的混合,则可以首先渲染完全不透明的对象,而无需对它们进行排序。只需要对具有透明度的对象进行排序。然后是序列:

  1. 渲染完全不透明的几何体。
  2. 渲染非透明几何体,并排序回前方。
  3. 优点:

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

    缺点:

    • 需要排序以获得正确的结果。对于上面提到的混合函数,几何体必须呈现在前面。根据应用程序的不同,这可能没什么大不了的。例如,要正确渲染相交的几何体,您可能必须开始分割三角形,这很不具吸引力。

    深度剥离

    这是一个非常巧妙的使用OpenGL功能,恕我直言,并且可以是一个很好的实用解决方案。它确实需要多次渲染过程。简单形式需要3次通过:

    1. 使用常规设置渲染场景(启用深度测试,深度功能LESS,启用颜色和深度写入),但仅渲染完全不透明的几何体。如果不透明度是每个对象,则可以通过跳过非不透明对象的绘制调用来处理它。否则,您将不得不使用类似于上面Alpha测试下的着色器丢弃非不透明片段。
    2. 使用与上面相同的设置渲染非不透明几何体,但禁用颜色写入除外。
    3. 再次渲染非不透明几何体,但这次使用深度函数EQUAL,再次启用颜色写入,禁用深度写入,并使用混合。
    4. 最小着色器可用于第2遍,因为它不需要产生任何有效的片段颜色。

      优点:

      • 易于实施。
      • 合理有效,不需要分类。
      • 正确处理半透明度。

      缺点:

      • 简单形式仅绘制最前面的透明几何图层。这可能听起来像一个主要的限制,但结果实际上看起来非常好。还有更多高级表单,其中使用其他通道呈现其他图层。除了这些额外传递的开销之外,它也变得更加复杂,因为它需要多个深度缓冲区。我相信在NVIDIA网站上有一篇关于它的白皮书。

      Alpha to Coverage

      我自己没有使用过,所以以下是基于我有限的理论理解。它看起来像另一个有趣的方法。这需要多次采样渲染。该功能已使用glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE)启用,然后将alpha值转换为coverage掩码,从而导致仅根据alpha值编写部分样本。当多样本缓冲区被下采样到最终颜色缓冲区时,这会产生透明效果。

      优点:

      • 可以处理半透明度。
      • 正确处理多层透明度。
      • 高效,尤其是无论如何都会使用MSAA。无需排序。

      缺点:

      • 需要MSAA。现代GPU在MSAA渲染方面非常有效,因此这不是什么大问题。很多时候,你可能还是想要使用MSAA。
      • 除非我遗漏了某些东西,否则有效的alpha值分辨率非常小。例如,对于4x MSAA,您只能表示5个可能的alpha值(在coverage掩码中设置0,1,2,3,4个样本)。

答案 1 :(得分:-1)

接受的答案并未涵盖。

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

如果你需要一系列alpha值,着色器丢弃是一个看起来很糟糕的黑客。

相关问题