¿Cómo puedo utilizar varios componentes GLSurfaceView en el mismo Layout?
Estoy escribiendo una API de visualización de información para Android y me encontré con un problema al intentar colocar dos unidades de un GLSurfaceView
personalizado en un Layout. El GLSurfaceView
personalizado en este punto es simplemente una extensión de GLSurfaceView
para eliminar posibles errores causados por métodos personalizados.
Cuando tengo los dos componentes agregados en el diseño e iniciar la aplicación se ejecuta. Pero nada se dibuja, parece que entra en un bucle infinito. Porque los mensajes de depuración dentro de los procesadores se imprimen en el LogCat. Sin embargo, funciona perfectamente bien si sólo uso uno de los componentes GLSurfaceView
personalizados.
- ¿Mejor velocidad de cuadro que dibuja los mapas de bits en una lona?
- Android personalizado XferMode / PorterDuff.Mode
- Transformación de perspectiva
- ¿Por dónde empezar para el efecto Flip de página en android?
- Opengl ES 1.1 / Android - La debacle de la textura-mapeo-a-uno-cuadrado de 2011
He leído que hay un problema con GLSurfaceView
en múltiples actividades y supongo que también se aplica cuando se utilizan dos de esos componentes al mismo tiempo. He intentado el workaround fijado aquí pero no puedo parecer conseguirlo trabajar tampoco.
Apreciaría cualquier ayuda. Opto por usar openGL para el mejor rendimiento, pero si no puedo usar múltiples componentes a la vez supongo que tendré que usar Canvas en su lugar.
El manifiesto tiene la siguiente apariencia:
<?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>
De la actividad el código es como esto:
@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(); }
¿Estoy perdiendo algo obvio? ¿O alguien puede explicar por qué no funciona?
- Modificación de la salida de la cámara con SurfaceTexture y OpenGL
- Uso seguro de glMapBufferRange () en Android / Java
- Cómo cargar y mostrar el archivo .obj en Android con OpenGL-ES 2
- SoftKeyboard para Android
- Cómo grabar la pantalla de actividad de la webview con Android MediaCodec?
- Página curl con vista pager
- Verificar si el punto está dentro de un cono en el espacio 3D
- ¿Por qué la muestra de documentación se divide por 2 para calcular inSampleSize para la carga de mapa de bits?
[UPDATE: Esta respuesta ya no es correcta, a partir de Android 5.0 (Lollipop) . Vea la respuesta de fadden para una discusión, y los acoplamientos. También era incorrecto a partir de Android 2.0, y al parecer sólo era un problema para las superficies OVERLAPPING incluso antes de entonces. ]
No puede colocar 2 SurfaceViews (SV) en una actividad. Para entender por qué usted debe saber cómo funciona SVs.
Cuando se crea y se coloca en la actividad que realmente no se colocará en la actividad (o parte superior de ella), sino que se creará detrás de la actividad actual con la vista "transparente" creada en esa actividad.
En Android 4.0 (API 14) hay una nueva vista llamada TextureView No hay forma de crear algo parecido a eso Ver en las plataformas más antiguas.
¿Cuál es la implementación de CoordinateSystemRenderer
?
Conocí el mismo requisito hoy y lo intenté, realmente funciona eso significa, puedes poner 2 GLSurfaceView
en la misma actividad.
Algo necesita ser notado,
- En
GLRender
, cuandoonSurfaceChanged
se invoca, debe cambiar el tamaño de su ventana de visualización - Con 2
GLSurfaceView
, el hilo de render será 2, así que se sincronizará el problema. Depende de su implementación deonDrawFrame
.
Hay una prueba rápida para usar la demostración de Android API en 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; }
Hay mucho que va detrás del GLSurfaceView incluyendo la gestión de GLContext, estoy bastante seguro de que no será capaz de hacer que funcione, incluso si tiene éxito que podría entrar en más inesperado problemas más adelante. Así que realmente creo que no es la arquitectura de aplicación correcta.
Es posible que desee investigar la superposición / subconjunto de sus modelos en el área "correcta" de la pantalla con una pantalla completa GLSurfaceView. Es posible que desee montar algún tipo de marco de diseño para hacer esto más simple, o tal vez utilizando múltiples vistas en la pantalla completa GLSurfaceView. No han probado estos en OpenGL ES, pero generalmente cualquiera de estos métodos sería el utilizado para procesar múltiples vistas del mismo o incluso muchos modelos diferentes en una sola aplicación en un sistema de escritorio en lugar de utilizar GLContexts múltiples (si eso es lo que es Pasando por detrás de las escenas aquí).
Aquí está una manera alternativa de hacerlo. Descargue el ejemplo de los documentos Android aquí: http://developer.android.com/shareables/training/OpenGLES.zip En este archivo zip verá 2 proyectos. Abra el proyecto: HelloOpenGLES20 y reemplace la clase 'MyGLRenderer' por la que aparece a continuación y ejecute el proyecto.
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; } }
Por lo que entiendo, OpenGLES está diseñado para utilizar sólo una vista, pero con potencialmente múltiples objetivos de renderizado. Aunque debo admin no estoy seguro de que lo que estás tratando de hacer está mal o no. Soy un poco un newb para OpenGLES yo mismo. Tengo una biblioteca abierta de OpenGL en bitbucket. Usted puede ser capaz de obtener algunas ideas de ella: https://bitbucket.org/warwick/hacergestov2 , es una biblioteca de gestos.
Puede tener varias GLSurfaceViews
activas y visibles en una actividad. Cada vista obtiene su propio contexto GL.