How can I use Multiple GLSurfaceView components in the same Layout?

后端 未结 6 1798
挽巷
挽巷 2020-12-29 23:07

I\'m writing an Information Visualization API for Android and ran into a problem trying to place two units of a custom GLSurfaceView into a Layout. The Custom <

相关标签:
6条回答
  • 2020-12-29 23:51

    What's the implementation for CoordinateSystemRenderer?

    I met the same requirement today and tried, it actually works that means, you can put 2 GLSurfaceView into same activity.

    Something need to be noticed,

    1. In GLRender, when onSurfaceChanged is invoked, you must resize your viewport
    2. With 2 GLSurfaceView, the render thread will be 2, so synchronize issue will be occurred. It depends on your implementation of onDrawFrame.

    There is a quick test to use Android API demo in SDK GLSurfaceViewActivity

    /*
     * 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;
    }
    
    0 讨论(0)
  • 2020-12-29 23:52

    You may may want to investigate overlaying/under-laying your models in the 'correct' area of the screen using a full screen GLSurfaceView. You may want to put together some sort of layout framework to make this simpler, or perhaps using multiple Viewports on the full screen GLSurfaceView. Haven't tried these in OpenGL ES, but generally either of these methods would be the used to render multiple views of the same or even many different models in a single application on a desktop system rather than using multiple GLContexts (if that is what is going on behind the scenes here).

    0 讨论(0)
  • 2020-12-29 23:52

    Here's an alternative way of doing it. Download the sample from the Android docs here: http://developer.android.com/shareables/training/OpenGLES.zip In this zip file you will see 2 projects. Open the project: HelloOpenGLES20 and replace the 'MyGLRenderer' Class with my one listed below and run the project.

    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;
        }
    
    }
    

    From what I understand, OpenGLES is designed to use only One view but with potentially multiple Render targets. Though I must admin I'm not sure that what your trying to do is wrong or not. I'm a bit of a newb to OpenGLES myself. I have an OpenGL open source library in bitbucket. You may be able to get some ideas from it: https://bitbucket.org/warwick/hacergestov2, it's a gesture library.

    0 讨论(0)
  • 2020-12-29 23:53

    You can have multiple GLSurfaceViews active and visible in an Activity. Each view gets its own GL context.

    0 讨论(0)
  • 2020-12-29 23:57

    [UPDATE: This answer is no longer correct, as of Android 5.0 (Lollipop). See fadden's answer for a discussion, and links. It was also incorrect as of Android 2.0, and apparently was only an issue for OVERLAPPING surfaces even before then.]

    You cannot place 2 SurfaceViews(SV) into one Activity. For understand why you should know how SVs works.

    When you create it and place on activity it doesnt actually will be placed in activity (or top of it), instead it will be created behind of current activity with "transparent" view created in that activity.

    In Android 4.0 (API 14) there are new View called TextureView There are no way to create something like that View on older platforms.

    0 讨论(0)
  • 2020-12-30 00:02

    There is a lot going behind the GLSurfaceView including managing GLContext, I'm pretty sure you won't be able to make it work, even if you succeed you might get into more unexpected issues later on. So I really believe it is not the right application architecture.

    0 讨论(0)
提交回复
热议问题