GLSurfaceView - 如何制作半透明背景

12

我尝试使用GLSurfaceView进行渲染,根据文档,我设置了格式:

getHolder().setFormat(PixelFormat.TRANSLUCENT);

我使用GLSurfaceView.Renderer,在onDrawFrame方法中绘制:

GLES20.glClearColor(0, 0, 1, .5f);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);

然而,GLSurfaceView中的GL渲染不是半透明的,并且完全是蓝色的。如果我省略glClear调用,则完全是黑色的。

我该如何使GL渲染具有透明背景,以便与其后面绘制的视图混合?

enter image description here

EDIT: 这是我的GLSurfaceView:

class GLView extends GLSurfaceView{
   MyRenderer r;
   public GLView(Context ctx){
      super(ctx);
      setEGLContextClientVersion(2);

      getHolder().setFormat(PixelFormat.TRANSLUCENT);

      setEGLConfigChooser(8, 8, 8, 8, 16, 0);
      r = new MyRenderer(getContext());
      setRenderer(r);
   }
}
5个回答

9

好的,经过一些研究,我可以自己回答这个问题了。

最终我使用SurfaceView.setZOrderOnTop(true)使其透明绘制。但是这样我失去了在GLSurfaceView上面放置其他视图的可能性。

我得出了两种可能的结果:

behind on top

在左边是标准的GL表面,位于所有其他视图下方,无法绘制透明度,因为GL表面在应用程序窗口表面之前绘制,并且GLSurfaceView只是在其位置上打了一个punches hole,以便可以通过GL表面看到。
在右边是使用setZOrderOnTop(true)绘制的透明GL表面,因此其表面位于应用程序窗口顶部绘制。现在它是透明的,但是在视图层次结构中放置在其上的其他视图上方绘制。
因此,似乎应用程序具有一个窗口,用于其视图层次结构的表面,而SurfaceView具有用于GL的自己的表面,该表面可以位于应用程序窗口之上或之下。不幸的是,透明的GL视图无法在其他视图之上正确排序。

你为什么没有颁发你的悬赏奖励? - Sergey K.
2
我不能给自己的答案评分,而其他答案也没有满足我的要求。 - Pointer Null

6

您需要使用RGBA 8888像素格式来实现半透明效果:

private void init( boolean translucent, int depth, int stencil )
{
    /* By default, GLSurfaceView() creates a RGB_565 opaque surface.
     * If we want a translucent one, we should change the surface's
     * format here, using PixelFormat.TRANSLUCENT for GL Surfaces
     * is interpreted as any 32-bit surface with alpha by SurfaceFlinger.
     */
    this.getHolder().setFormat( PixelFormat.RGB_565 );
    if ( translucent )
    {
        this.getHolder().setFormat( PixelFormat.TRANSLUCENT );
    }

    setEGLContextFactory( new ContextFactory() );

    /* We need to choose an EGLConfig that matches the format of
     * our surface exactly. This is going to be done in our
     * custom config chooser. See ConfigChooser class definition
     * below.
     */
    setEGLConfigChooser( translucent ?
                         new ConfigChooser( 8, 8, 8, 8, depth, stencil ) :
                         new ConfigChooser( 5, 6, 5, 0, depth, stencil ) );

    setRenderer( new Renderer() );
}

正如您在我的问题中所看到的,我设置了PixelFormat.TRANSLUCENT。 - Pointer Null
你将它设置为8888了吗? - Sergey K.
是的,我也尝试过这个。但文档提到应该设置PixelFormat.TRANSLUCENT。 - Pointer Null
请问您能否展示一下与 getHolder().setFormat(PixelFormat.TRANSLUCENT) 相关的所有代码? - Sergey K.
请问您能否检查一下这个解决方案:https://dev59.com/lk3Sa4cB1Zd3GeqPx8Nm#3190604 和 https://dev59.com/YHI-5IYBdhLWcg3wCz7y#2196281。它们有帮助吗? - Sergey K.

1

您有没有考虑使用LayerDrawable并设置透明度?这是我拥有的两张图片的示例...其中一张是透明的(通过setAlpha),另一张则不是。'calendar_cell'是实心的并在后面,然后是透明的框,以显示其后面的日历单元格。这样,您可以堆叠任意数量的图像,并为它们都设置不同的透明度。

Drawable []layers = new Drawable [2];
int imageResource1 = mContext.getResources().getIdentifier("drawable/calendar_cell", null, mContext.getPackageName());
Drawable background = v.getResources().getDrawable(imageResource1);
                        layers [0]= background;

int imageResource = mContext.getResources().getIdentifier("drawable/box_" + box, null, mContext.getPackageName());
Drawable boxImg = v.getResources().getDrawable(imageResource);
    boxImg.setAlpha(100);
    layers [1]= boxImg;

LayerDrawable layerDrawable = new LayerDrawable (layers);
v.setBackground(layerDrawable)

0

我不确定问题具体是什么,但另一种方法可能是用半透明的彩色矩形覆盖屏幕,然后只清除深度缓冲区位。

是否有GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)的替代方法?

否则,请确保您的深度缓冲区位为1

稍后我会回来尝试在手机上重新创建问题。

编辑:我刚意识到它出现蓝色的原因可能是您将其设置为0.5f,因此只需要2个调用就可以完全达到1f的不透明度。这意味着在30fps下,需要1/15秒才能完全变成蓝色。

尝试将alpha透明度值降低到0.01f或0.05f


错误的理论,即使将alpha设置为0也没有改变。也许你认为清除会添加先前清除的值。然而,surface flinger 应该正确地合成屏幕表面,包括GL表面的alpha通道。 - Pointer Null

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接