在OpenGL ES 2.03.0中,当有许多对象时,alpha混合的问题。

问题描述 投票:2回答:1

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

private Background background;
private Asteroid[] asteroids = new Asteroid[NUMBER_ASTEROIDS];
private Rocket[] rockets = new Rocket[NUMBER_ROCKETS];
...
public void onDrawFrame(GL10 glUnused) {
    GLES20.glEnable(GLES20.GL_DEPTH_TEST);
    ...
    background.draw();
    for (Asteroid asteroid: asteroids) asteroid.draw(); // draw all asteroids
    for (Rocket rocket: rockets) rocket.draw(); // draw all rockets
    ...
}

小行星和火箭的对象使用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);

但这并不能解决这个问题。

解决办法。 根据Rabbid76的建议,我把所有的半透明物体按照从后面到前面的顺序排列。

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();

对我来说,这就足够了

java android opengl-es-2.0 opengl-es-3.0
1个回答
2
投票

你不可能同时拥有两个。搅拌 的好处 深度测试. 你必须分两次绘制场景。首先绘制不透明的对象,深度测试打开,混合关闭,然后绘制透明的对象,深度测试打开,但不写入深度缓冲区,混合打开,按照从后面到前面的顺序。请看 透明度排序.

  1. 启用深度测试和禁用混合
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
GLES20.glDepthMask(GLES20.GL_TRUE);
GLES20.glDisable(GLES20.GL_BLEND);
  1. 绘制不透明对象

  2. 启用深度测试,禁止向深度缓冲区写入,启用混合。

GLES20.glEnable(GLES20.GL_DEPTH_TEST);
GLES20.glDepthMask(GLES20.GL_FALSE);
GLES20.glEnable(GLES20.GL_BLEND);
  1. 按照从后面到前面的顺序画出透明对象,如果透明对象没有排序,那么与不透明对象相比,透明对象仍然会正确排列,但透明对象本身可能不会正确排列。

如果透明对象没有排序,那么透明对象与不透明对象相比仍然会正确排列,但透明对象本身可能不会正确排列。当你使用混合功能时,那么顺序就很重要。混合功能不是 交换如果改变覆盖透明物体的顺序,结果就会不同。

© www.soinside.com 2019 - 2024. All rights reserved.