You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenGL ES 2.0/3.0多对象场景Alpha混合异常:火箭被遮挡问题

解决3D场景半透明对象遮挡显示异常问题

最近我在开发一款包含3D场景的游戏,场景里有背景、小行星和火箭三类对象,其中小行星和火箭都用了Alpha混合来实现半透明效果。

初始实现代码

先给大家看看最初的对象定义和绘制逻辑:

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(); // 绘制所有小行星
    for (Rocket rocket: rockets) rocket.draw(); // 绘制所有火箭
    ...
}

小行星和火箭的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);
    ... // 绘制带纹理的对象
    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);
    ... // 绘制无纹理的对象
    GLES20.glDisable(GLES20.GL_BLEND);
    ...
}

遇到的异常问题

场景整体的半透明效果看起来没毛病,但出现了一个奇怪的现象:当火箭处于小行星后方时,火箭完全看不到,可小行星后方的背景却能正常显示。我试过全局开启混合,问题还是没解决。

最终解决方案

后来按照Rabbid76的建议,把所有半透明对象按Z轴从后到前排序后再绘制,问题直接就解决了!具体实现是把小行星和火箭统一放到半透明对象集合里,用Z轴坐标做排序依据:

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

核心原理其实很直白:半透明对象的绘制顺序会直接影响混合结果,深度测试会挡住后方对象,但半透明需要让后方颜色透过来,所以必须先绘制最远的半透明对象,再依次绘制近的,这样混合计算才会正确。

内容的提问来源于stack exchange,提问作者alexrnov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 18:13:10