OpenGL ES2 Alpha测试问题

sgt*_*ale 9 java 3d android depth-buffer opengl-es-2.0

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

左边是我的. 对,就是我想要的

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

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

GLES20.glEnable( GLES20.GL_BLEND );
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA );
Run Code Online (Sandbox Code Playgroud)

但我使用它仍然无法正常工作.我在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 );
Run Code Online (Sandbox Code Playgroud)

我的片段着色器是:

uniform sampler2D texture;
varying vec2 texCoord;  
void main(){ 
   gl_FragColor = texture2D( texture, texCoord );
} 
Run Code Online (Sandbox Code Playgroud)

我是否必须在Android清单中包含任何内容才能启用Alpha测试?我不想最终必须手动组织我的多边形或使用alpha discard(),因为我需要并希望一些像素是半透明的.

如何让3D alpha测试深度缓冲区工作?

Ret*_*adi 28

下面概述了在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;
}
Run Code Online (Sandbox Code Playgroud)

好处:

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

缺点:

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

排序和混合

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

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

  1. 渲染完全不透明的几何体.
  2. 渲染非不透明几何体,按顺序排序.

好处:

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

缺点:

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

深度剥皮

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

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

最小着色器可用于第2遍,因为它不需要产生任何有效的片段颜色.

好处:

  • 易于实施.
  • 合理有效,不需要排序.
  • 正确处理半透明度.

缺点:

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

Alpha覆盖范围

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

好处:

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

缺点:

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