Java OpenGL ES 2.0/3.0中存在多个对象时alpha混合问题

Java OpenGL ES 2.0/3.0中存在多个对象时alpha混合问题,java,android,opengl-es,opengl-es-2.0,opengl-es-3.0,Java,Android,Opengl Es,Opengl Es 2.0,Opengl Es 3.0,游戏3D场景有许多对象(背景、小行星、火箭): 小行星和火箭的对象使用alpha混合: public class IceAsteroid extends Object3D implements Asteroid { ... GLES20.glEnable(GLES20.GL_BLEND); GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); ... // draw an o

游戏3D场景有许多对象(背景、小行星、火箭):

小行星和火箭的对象使用alpha混合:

public class IceAsteroid extends Object3D implements Asteroid {
    ...
    GLES20.glEnable(GLES20.GL_BLEND);
    GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
    ... // draw an object with a texture
    GLES20.glDisable(GLES20.GL_BLEND);
    ...
}

public class Rocket extends Object3D {
    ...
    GLES20.glEnable(GLES20.GL_BLEND);
    GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
    ... // draw an object without a texture
    GLES20.glDisable(GLES20.GL_BLEND);
    ...
}
一般来说,半透明对于3D场景效果很好,但当火箭位于小行星后面时,它们(火箭)不可见。虽然小行星背后的背景是可见的,但此时小行星的透明度似乎不起作用。有人能提出为什么在小行星后面看不到火箭吗?提前谢谢

注意:我尝试这样做:

background.draw();
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
for (Asteroid asteroid: asteroids) asteroid.draw(); // draw all asteroids
for (Rocket rocket: rockets) rocket.draw(); // draw all rockets
GLES20.glDisable(GLES20.GL_BLEND);
但这并没有解决问题

解决方案:根据Rabbi76的建议,我将所有半透明对象按从后到前的顺序进行排序:

Comparator<Object3D> comparatorByZ = (objectA, objectB) -> {
    Float z1 = objectA.getZ();
    Float z2 = objectB.getZ();
    return z1.compareTo(z2);
};
...
background.draw();
Collections.sort(transparentObjects, comparatorByZ);
for (Object3D object3D: transparentObjects) object3D.draw();
Comparator comparatorByZ=(objectA,objectB)->{
Float z1=objectA.getZ();
Float z2=objectB.getZ();
返回z1.compareTo(z2);
};
...
background.draw();
Collections.sort(transparentObjects,comparatorByZ);
对于(Object3D Object3D:transparentObjects)Object3D.draw();
在我的情况下,这就足够了。

你不能同时拥有这两个方面,也不能同时拥有这项技术的好处。您必须在两个过程中绘制场景。首先在启用深度测试并禁用混合的情况下绘制不透明对象,然后在启用深度测试但未写入深度缓冲区并启用混合的情况下绘制透明对象,按从后到前的顺序进行排序。看

  • 启用深度测试并禁用混合
  • 绘制不透明对象

  • 启用深度测试,禁用写入深度缓冲区并启用混合

  • 按从后到前的顺序绘制透明对象

  • 如果透明对象未排序,则与不透明对象相比,透明对象仍将正确排列,但透明对象本身可能排列不正确。使用混合时,顺序很重要。混合功能不可用,如果覆盖透明对象的顺序改变,结果会不同。

    是否禁用?@rabbi76感谢您对该问题的关注!深度测试打开onDrawFrame()方法的开头。(添加到问题中)。@rabbi76很抱歉这么重要,但是如果你禁用深度测试:GLES20.glDisable(GLES20.GL_depth_测试),那么火箭将始终显示在小行星前面。或者是否需要在其他位置启用/禁用它?
    Comparator<Object3D> comparatorByZ = (objectA, objectB) -> {
        Float z1 = objectA.getZ();
        Float z2 = objectB.getZ();
        return z1.compareTo(z2);
    };
    ...
    background.draw();
    Collections.sort(transparentObjects, comparatorByZ);
    for (Object3D object3D: transparentObjects) object3D.draw();
    
    GLES20.glEnable(GLES20.GL_DEPTH_TEST);
    GLES20.glDepthMask(GLES20.GL_TRUE);
    GLES20.glDisable(GLES20.GL_BLEND);
    
    GLES20.glEnable(GLES20.GL_DEPTH_TEST);
    GLES20.glDepthMask(GLES20.GL_FALSE);
    GLES20.glEnable(GLES20.GL_BLEND);