如何在同一布局中使用多个GLSurfaceView组件?

时间:2011-02-14 10:31:11

标签: android android-layout opengl-es glsurfaceview

我正在为Android编写信息可视化API,并且在尝试将两个自定义GLSurfaceView单元放入布局时遇到了问题。此时自定义GLSurfaceView只是GLSurfaceView的扩展,以消除自定义方法可能导致的错误。

当我在布局中添加了两个组件并启动它运行的应用程序时。但没有任何东西被绘制,似乎它进入了一个无限循环。因为Renderers中的调试消息被打印到LogCat中。但是,如果我只使用其中一个自定义GLSurfaceView组件,那么它的工作正常。

我读到在多个活动中使用GLSurfaceView时出现问题,我想在同时使用其中两个组件时也适用。我已经尝试了here发布的解决方法,但似乎无法使其工作。

我将不胜感激任何帮助。我选择使用openGL来获得更好的性能,但如果我不能同时使用多个组件,我想我将不得不使用Canvas。

清单如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextView android:text="@string/hello" android:id="@+id/TextView01"
        android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    <com.syntronic.vtadlib.VisualizationView android:id="@+id/glview"
        android:layout_width="fill_parent" android:layout_height="300px" />


    <TextView android:text="@string/hello" android:id="@+id/TextView02"
        android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    <LinearLayout 
        android:orientation="vertical" android:layout_width="fill_parent"
        android:layout_height="fill_parent">

        <com.syntronic.vtadlib.VisualizationView android:id="@+id/glview2"
            android:layout_width="fill_parent" android:layout_height="fill_parent" />

    </LinearLayout>

</LinearLayout>

从活动中,代码如下:

@Override
public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    mSurfaceView = (VisualizationView) findViewById(R.id.glview);
    mSurfaceView2 = (VisualizationView) findViewById(R.id.glview2);

    //Enables debug flags for Errors
    //mSurfaceView.setDebugFlags(GLSurfaceView.DEBUG_CHECK_GL_ERROR);   
    //mSurfaceView2.setDebugFlags(GLSurfaceView.DEBUG_CHECK_GL_ERROR);  

    mSurfaceView.setRenderer(new CoordinateSystemRenderer());
    mSurfaceView2.setRenderer(new CoordinateSystemRenderer());

}

@Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    mSurfaceView.onPause();
    mSurfaceView2.onPause();
}

@Override
protected void onResume() {
    // TODO Auto-generated method stub
    super.onResume();
    mSurfaceView.onResume();
    mSurfaceView2.onResume();
}

我错过了一些明显的东西吗?或者有人可以解释为什么它不起作用?

6 个答案:

答案 0 :(得分:8)

[更新:此答案不再正确,如Android 5.0(Lollipop)。有关讨论,请参阅fadden's answer和链接。 It was also incorrect as of Android 2.0, and apparently was only an issue for OVERLAPPING surfaces even before then.]

您不能将2个SurfaceViews(SV)放入一个Activity中。 了解为什么你应该知道SV是如何工作的。

当你创建它并放置在活动上时,它实际上并不会放在活动中(或者它的顶部),而是在当前活动的后面创建,并在该活动中创建“透明”视图。

在Android 4.0(API 14)中有一个名为TextureView的新视图 没有办法在较旧的平台上创建类似View的东西。

答案 1 :(得分:2)

CoordinateSystemRenderer的实施方式是什么?

我今天遇到了同样的要求并尝试过,实际上这意味着,您可以将2 GLSurfaceView置于相同的活动中。

需要注意的事情,

  1. GLRender中,当调用onSurfaceChanged时,您必须调整视口大小
  2. 使用2 GLSurfaceView,渲染线程将为2,因此将发生同步问题。这取决于您onDrawFrame
  3. 的实施情况

    在SDK GLSurfaceViewActivity

    中使用Android API演示进行快速测试
    /*
     * Copyright (C) 2007 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package com.example.android.apis.graphics;
    
    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.opengles.GL10;
    
    import android.opengl.GLSurfaceView;
    
    /**
     * Render a pair of tumbling cubes.
     */
    
    public class CubeRenderer implements GLSurfaceView.Renderer
    {
        boolean isReverse = false;
    
        public CubeRenderer(boolean useTranslucentBackground, boolean isReverse)
        {
            mTranslucentBackground = useTranslucentBackground;
            mCube = new Cube();
            this.isReverse = isReverse;
        }
    
        public CubeRenderer(boolean useTranslucentBackground)
        {
            this(useTranslucentBackground, false);
        }
    
        public void onDrawFrame(GL10 gl)
        {
            /*
             * Usually, the first thing one might want to do is to clear the screen. The most efficient way of doing this is
             * to use glClear().
             */
    
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    
            /*
             * Now we're ready to draw some 3D objects
             */
    
            gl.glMatrixMode(GL10.GL_MODELVIEW);
            gl.glLoadIdentity();
            gl.glTranslatef(0, 0, -3.0f);
            gl.glRotatef(mAngle, 0, 1, 0);
            gl.glRotatef(mAngle * 0.25f, 1, 0, 0);
    
            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
    
            mCube.draw(gl);
    
            gl.glRotatef(mAngle * 2.0f, 0, 1, 1);
            gl.glTranslatef(0.5f, 0.5f, 0.5f);
    
            mCube.draw(gl);
    
            if (isReverse)
            {
                mAngle -= 1.2f;
            }
            else
            {
                mAngle += 1.2f;
            }
        }
    
        public void onSurfaceChanged(GL10 gl, int width, int height)
        {
            System.out.println("Joey's Log width : " + width + " height : " + height);
            gl.glViewport(0, 0, width, height);
    
            /*
             * Set our projection matrix. This doesn't have to be done each time we draw, but usually a new projection needs
             * to be set when the viewport is resized.
             */
    
            float ratio = (float) width / height;
            gl.glMatrixMode(GL10.GL_PROJECTION);
            gl.glLoadIdentity();
            gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
        }
    
        public void onSurfaceCreated(GL10 gl, EGLConfig config)
        {
            /*
             * By default, OpenGL enables features that improve quality but reduce performance. One might want to tweak that
             * especially on software renderer.
             */
            gl.glDisable(GL10.GL_DITHER);
    
            /*
             * Some one-time OpenGL initialization can be made here probably based on features of this particular context
             */
            gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
    
            if (mTranslucentBackground)
            {
                gl.glClearColor(0, 0, 0, 0);
            }
            else
            {
                gl.glClearColor(1, 1, 1, 1);
            }
            gl.glEnable(GL10.GL_CULL_FACE);
            gl.glShadeModel(GL10.GL_SMOOTH);
            gl.glEnable(GL10.GL_DEPTH_TEST);
        }
    
        private boolean mTranslucentBackground;
    
        private Cube mCube;
    
        private float mAngle;
    }
    
    
    ------------------------------------------------------------------------------------------
    /*
     * Copyright (C) 2007 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package com.example.android.apis.graphics;
    
    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.opengles.GL10;
    
    import android.opengl.GLSurfaceView;
    
    /**
     * Render a pair of tumbling cubes.
     */
    
    public class CubeRenderer implements GLSurfaceView.Renderer {
        boolean isReverse = false;
        public CubeRenderer(boolean useTranslucentBackground,boolean isReverse) {
            mTranslucentBackground = useTranslucentBackground;
            mCube = new Cube();
            this.isReverse = isReverse;
        }
    
        public CubeRenderer(boolean useTranslucentBackground)
        {
            this(useTranslucentBackground, false);
        }
    
        public void onDrawFrame(GL10 gl) {
            /*
             * Usually, the first thing one might want to do is to clear
             * the screen. The most efficient way of doing this is to use
             * glClear().
             */
    
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    
            /*
             * Now we're ready to draw some 3D objects
             */
    
            gl.glMatrixMode(GL10.GL_MODELVIEW);
            gl.glLoadIdentity();
            gl.glTranslatef(0, 0, -3.0f);
            gl.glRotatef(mAngle,        0, 1, 0);
            gl.glRotatef(mAngle*0.25f,  1, 0, 0);
    
            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
    
            mCube.draw(gl);
    
            gl.glRotatef(mAngle*2.0f, 0, 1, 1);
            gl.glTranslatef(0.5f, 0.5f, 0.5f);
    
            mCube.draw(gl);
    
            if (isReverse)
            {
                mAngle -= 1.2f;
            }
            else
            {
                mAngle += 1.2f;
            }
        }
    
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            System.out.println("Joey's Log width : " + width + " height : " + height);
             gl.glViewport(0, 0, width, height);
    
             /*
              * Set our projection matrix. This doesn't have to be done
              * each time we draw, but usually a new projection needs to
              * be set when the viewport is resized.
              */
    
             float ratio = (float) width / height;
             gl.glMatrixMode(GL10.GL_PROJECTION);
             gl.glLoadIdentity();
             gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
        }
    
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            /*
             * By default, OpenGL enables features that improve quality
             * but reduce performance. One might want to tweak that
             * especially on software renderer.
             */
            gl.glDisable(GL10.GL_DITHER);
    
            /*
             * Some one-time OpenGL initialization can be made here
             * probably based on features of this particular context
             */
             gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
                     GL10.GL_FASTEST);
    
             if (mTranslucentBackground) {
                 gl.glClearColor(0,0,0,0);
             } else {
                 gl.glClearColor(1,1,1,1);
             }
             gl.glEnable(GL10.GL_CULL_FACE);
             gl.glShadeModel(GL10.GL_SMOOTH);
             gl.glEnable(GL10.GL_DEPTH_TEST);
        }
        private boolean mTranslucentBackground;
        private Cube mCube;
        private float mAngle;
    }
    

答案 2 :(得分:0)

GLSurfaceView背后有很多东西,包括管理GLContext,我很确定你无法使它工作,即使你成功了,你可能会在以后遇到更多意想不到的问题。所以我真的相信它不是正确的应用程序架构。

答案 3 :(得分:0)

您可能希望使用全屏GLSurfaceView调查在屏幕的“正确”区域中叠加/覆盖模型。您可能希望将某种布局框架放在一起以使这更简单,或者可能在全屏GLSurfaceView上使用多个视口。尚未在OpenGL ES中尝试过这些,但通常这些方法中的任何一个都可用于在桌面系统上的单个应用程序中呈现相同甚至许多不同模型的多个视图,而不是使用多个GLContexts(如果是这样的话)在这里幕后工作)。

答案 4 :(得分:0)

这是另一种方法。从Android文档中下载示例:http://developer.android.com/shareables/training/OpenGLES.zip 在此zip文件中,您将看到2个项目。打开项目:HelloOpenGLES20并将'MyGLRenderer'类替换为下面列出的类并运行项目。

package com.example.android.opengl;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.util.Log;

public class MyGLRenderer implements GLSurfaceView.Renderer {

    private static final String TAG = "MyGLRenderer";
    private Triangle[] mTriangle = new Triangle[2];
    private final float[] mMVPMatrix = new float[16];
    private final float[] mProjectionMatrix = new float[16];
    private final float[] mViewMatrix = new float[16];
    private final float[] mRotationMatrix = new float[16];

    private float mAngle;

    @Override
    public void onSurfaceCreated(GL10 unused, EGLConfig config) {

        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        mTriangle[0] = new Triangle();
        mTriangle[1] = new Triangle();

    }

    @Override
    public void onDrawFrame(GL10 unused) {

        final float[] scratch = new float[16];

        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

        Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);

        for(int i = 0; i < 2; i++) {

            if(i % 2 == 0) {

                Matrix.setRotateM(mRotationMatrix, 0, mAngle / 2f, 0, 0, 1.0f);

            }
            else {

                Matrix.setRotateM(mRotationMatrix, 0, mAngle / 4f, 0, 0, 1.0f);

            }

            Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);

            mTriangle[i].draw(scratch);

        }//End for(int i = 0; i < 2; i++)

    }//End public void onDrawFrame(GL10 unused)

    @Override
    public void onSurfaceChanged(GL10 unused, int width, int height) {

        GLES20.glViewport(0, 0, width, height);
        float ratio = (float) width / height;
        Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);

    }

    public static int loadShader(int type, String shaderCode){

        int shader = GLES20.glCreateShader(type);
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);

        return shader;

    }

    public static void checkGlError(String glOperation) {

        int error;

        while((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {

            Log.e(TAG, glOperation + ": glError " + error);
            throw new RuntimeException(glOperation + ": glError " + error);

        }

    }

    public float getAngle() {
        return mAngle;
    }


    public void setAngle(float angle) {
        mAngle = angle;
    }

}

据我所知,OpenGLES只能使用一个视图但可能有多个Render目标。虽然我必须管理员,但我不确定你尝试做的事情是否错误。我自己对OpenGLES有点新意。我在bitbucket中有一个OpenGL开源库。您可以从中获得一些想法:https://bitbucket.org/warwick/hacergestov2,它是一个手势库。

答案 5 :(得分:-1)

您可以在活动中激活多个GLSurfaceViews并显示。每个视图都有自己的GL上下文。