安卓OpenGL ES透明背景

28

我正在开发一款利用OpenGL的Android应用程序。目前,我的代码会动态生成 GLSurfaceView 的背景,并将其作为纹理加载,在使用 glDrawTexfOES 绘制出来。这个方案还可以,但是我可以简单地将图像显示在自己的表面上(不使用OpenGL),这样可以更加流畅。有没有办法让 GLSurfaceView 的背景透明?我听到一些谣言说可以通过 setEGLConfigChooser 实现,但我没有找到任何证实。最终,我想把我正在绘制的表面放在 GLSurfaceView 上,以达到分层效果。

我知道这很棘手,很可能不可行,但任何建议都将不胜感激。提前致谢!


我对Open GL不是很了解,但如果您查看API示例,会发现在包com.example.android.apis.graphics中有一个名为TranslucentGLSurfaceViewActivity的类。这有帮助吗? - Ally
5个回答

46

我只做了一些简单的更改让它能够工作。

在我的GLSurfaceView.Renderer上:

public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    gl.glDisable(GL10.GL_DITHER);
    gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
            GL10.GL_FASTEST);

     gl.glClearColor(0,0,0,0);
     gl.glEnable(GL10.GL_CULL_FACE);
     gl.glShadeModel(GL10.GL_SMOOTH);
     gl.glEnable(GL10.GL_DEPTH_TEST);
}

在我的GLSurfaceView上:

setEGLConfigChooser(8, 8, 8, 8, 16, 0);
getHolder().setFormat(PixelFormat.TRANSLUCENT);

3
我已按照你写的方式设置了GLSurfaceView,并将上述代码放在我的自定义GL渲染器中,但我仍然得到黑色背景。你对此有何想法? - zidarsk8
2
这对我有用。但是,我的视图内容也变成了空白。只有一个白色画布,没有任何绘制的东西。需要帮助吗? - Umair
2
我刚刚从 onSurfaceCreated() 方法中删除了给定的代码,它按照我想要的方式工作。现在我只在 GLSurfaceViewinit() 方法中使用了这两行代码。 - Umair

23

您的GLSurfaceView还需要setZOrderOnTop(true);


需要最低SDK级别为6。 - efeyc
这将解决问题,但是如果需要在GLSurfaceView之上显示任何其他视图,则无法实现。 - Yasitha Waduge
我昨天花了整整一天的时间来解决这个问题。解决方案是实现Romain的答案https://groups.google.com/forum/#!topic/android-developers/U5RXFGpAHPE,并确保在视图的构造函数中调用setOpacity(false),以及通过其他答案启用alpha(此解决方案不需要setZOrderOnTop())。 - Fab Castel

9
我使用自己的GLSurfaceView类来展示图表(透明背景/覆盖层)。 我的扩展GLSurfaceView通过XML嵌入到弹出窗口中。
<com.dsignmatters.iq_fitfunlite.GLPieChartView          
    android:id="@+id/gameprogress_chart"
    android:layout_height="wrap_content" 
    android:layout_width="wrap_content"
    ...

作为这个活动的一部分,我添加了以下代码:
mGamesuccessPieChart = (GLSurfaceView) gameprogressView.findViewById(R.id.gameprogress_chart);
mGamesuccessPieChart.setZOrderOnTop(true);

最后,我的GLSurfaceView看起来像这样:
public class GLPieChartView extends GLSurfaceView {
    public GLPieChartView(Context context) {
        super(context);
        initGL();
    }

    public GLPieChartView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initGL();
    }

    void initGL() {
        setEGLContextClientVersion(2);
        setEGLConfigChooser(8,8,8,8,16,0);
        setRenderer(new GLPieChartRenderer());
        setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
        getHolder().setFormat(PixelFormat.TRANSLUCENT);     
    } 
}

我的渲染器类 GLPieChartRenderer 根本没有调用 glClearColor


2
请不要在问题之间重复回答。如果其中一个问题是另一个问题的副本,则标记它以关闭(或留下评论表明它是副本 - 更高的声望用户将标记或投票关闭它)。如果这些问题确实不同,请根据每个问题提出定制的答案。 - George Stocker

5

以下代码示例是为了在 GLSurfaceView 中启用透明度。但在使用透明度之前,请考虑以下负面因素。

  1. 启用透明度需要在 GLSurfaceView 上使用 setZOrderOnTop。这将阻止您将任何其他视图(例如 TextView)放置在透明的 GLSurfaceView 上方。即使导航抽屉也不能滑动到透明的 GLSurfaceView 上方(忽略技巧 )。无论透明与否,GLSurfaceView 只能存在于其他 Android 视图之上或之下,而不能存在于它们之间。
  2. 透明度要求您像下面的示例一样使用 setEGLConfigChoosersetFormat。那意味着,您不能获取系统选择的默认格式,这可能是特定设备的最佳格式。更重要的是,您需要确保设备具有支持的格式,并选择备选格式(例如此 gsoc 示例)。

透明度的其他选项

  1. 在 Android 中运行 opengl 的 Tracer 将显示活动的背景图像被绘制为 opengl 纹理。因此,如果可能的话,您可以将您的背景作为 opengl 纹理在 GLSurfaceView 中呈现,而不是使 GLSurfaceView 透明。
  2. 另外, alpha 通道或表面上的透明度不是 opengl 中 alpha 混合的前提条件。两者是独立的。
  3. TextureView技巧)是一个很好的选择,如果您的 opengl 组件要嵌入在其他视图之间。这个 打砖块 游戏是在 Android 中使用 GLSurfaceView 进行二维绘图的很好的例子。

下面是带有布局 XML 和代码的透明 GLSurfaceView 示例。

  1. Layout xml file with green color background

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:background="#00FFFF">
    
    <android.opengl.GLSurfaceView
        android:id="@+id/mySurfaceView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    
    </RelativeLayout>
    
  2. MainActivity.java file. Change ALPHA variable from 0.0 to 1.0 to see surface color red mixing with background activity color green

    package com.example.transparentsurfaceview;
    
    import android.app.Activity;
    import android.graphics.PixelFormat;
    import android.opengl.GLES20;
    import android.opengl.GLSurfaceView;
    import android.os.Bundle;
    
    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.opengles.GL10;
    
    public class MainActivity extends Activity {
    
        private GLSurfaceView mSurfaceView;
        private static float ALPHA = 0.5f;
        private static float RED   = 1.0f;
        private static float GREEN = 0.0f;
        private static float BLUE  = 0.0f;
    
        protected void onCreate( Bundle savedInstanceState ) {
            super.onCreate( savedInstanceState );
            setContentView( R.layout.activity_main );
            mSurfaceView = (GLSurfaceView)findViewById( R.id.mySurfaceView );
    
            mSurfaceView.setEGLContextClientVersion( 2 );
            mSurfaceView.setZOrderOnTop( true );
            mSurfaceView.setEGLConfigChooser( 8, 8, 8, 8, 16, 0 );
            mSurfaceView.getHolder().setFormat( PixelFormat.RGBA_8888 );
    
            mSurfaceView.setRenderer( new GLSurfaceView.Renderer() {
                public void onSurfaceCreated( GL10 gl10, EGLConfig eglConfig ) {
                    GLES20.glClearColor( RED, GREEN, BLUE, ALPHA );
                }
    
                public void onSurfaceChanged( GL10 gl10, int i, int i2 ) {}
    
                public void onDrawFrame( GL10 gl10 ) {
                    GLES20.glClear( GLES20.GL_COLOR_BUFFER_BIT );
                }
            });
        }
    }
    

GLSurfaceViewView 的一个子类。请参见文档页面顶部的继承层次结构:http://developer.android.com/reference/android/opengl/GLSurfaceView.html。 - Reto Koradi

1

你需要确保活动背景是透明的!

如果活动的背景不透明,默认为白色,那么即使内容视图(glsurfaceview)是半透明的,它也会将活动的白色背景显示为其背景。

您可以在声明Android.manifest时设置活动背景透明度,请参阅官方API演示TranslucentGLSurfaceViewActivity以获得帮助。


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