Android – OpenGL ES 2.0: Emulador (Works) – Dispositivo (no)

¡Buen día!

Estoy haciendo algunas pruebas sencillas con OpenGL ES 2.0 para Android. Estoy usando un cargador de modelos que funciona bien en el Emulador. Sin embargo, cuando trato de usarlo en un ASUS ZenFone 2E (Android 5.0.1) (teléfono prepago) simplemente muestra el color claro del fondo sin modelo giratorio. Espero que alguien que tenga experiencia en OpenGL ES 2.0 y Android me ayude. Lo siento por la verbosidad, realmente no tengo ni idea de por qué no está funcionando en el teléfono. Aquí está la fuente (soy un principiante extremo):

GameView.java:

package wise.child.dials; import android.content.Context; import android.opengl.GLES20; import android.opengl.GLSurfaceView; import android.opengl.Matrix; import android.os.SystemClock; import java.io.IOException; import java.nio.FloatBuffer; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import model.Model; import render.Program; import render.Shader; import util.OBJLoader; public class GameView extends GLSurfaceView implements GLSurfaceView.Renderer { // App Context private Context mContext; // Handles private int mPositionHandle; private int mColorHandle; private int mMVPMatrixHandle; // Program & Shaders private Program testProgram; private Shader testVertexShader; private Shader testFragmentShader; // Model private Model model; private FloatBuffer vertexFloatBuffer; private int vertexCount; // Matrices private final float[] mMVPMatrix = new float[16]; private final float[] mProjectionMatrix = new float[16]; private final float[] mViewMatrix = new float[16]; private float[] mRotationMatrix = new float[16]; // Constructor public GameView(Context context) { super(context); // App Context mContext = context; // OpenGL ES 2.0 Context setEGLContextClientVersion(2); // Renderer setRenderer(this); } /*-------------------*/ /* Rendering Methods */ /*-------------------*/ // One Time Initialization @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { GLES20.glClearColor(0.95f, 0.95f, 0.95f, 1f); // Initialize Shaders testVertexShader = new Shader(GLES20.GL_VERTEX_SHADER, mContext, R.raw.test_vertex_shader); testFragmentShader = new Shader(GLES20.GL_FRAGMENT_SHADER, mContext, R.raw.test_fragment_shader); // Create Program testProgram = new Program(testVertexShader, testFragmentShader); testProgram.use(); // Get Handles - Uniforms & Attributes mPositionHandle = testProgram.getAttribute("vPosition"); mColorHandle = testProgram.getUniform("vColor"); mMVPMatrixHandle = testProgram.getUniform("uMVPMatrix"); // Model try { model = OBJLoader.loadOBJ(mContext, R.raw.spider); vertexFloatBuffer = model.getVerticesFromIndices(); vertexCount = model.getVertexCount(); } catch (IOException e) { e.printStackTrace(); } } // Drawing Call @Override public void onDrawFrame(GL10 gl) { GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); // Time and Rotation Animation float[] scratch = new float[16]; long time = SystemClock.uptimeMillis() % 4000L; float angle = 0.090f * ((int) time); Matrix.setRotateM(mRotationMatrix, 0, angle, angle, angle, angle); // Set and Bind Data GLES20.glEnableVertexAttribArray(mPositionHandle); GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 12, vertexFloatBuffer); // Set Color float[] color = {.75f, 0f, 0f, 1f}; GLES20.glUniform4fv(mColorHandle, 1, color, 0); // Camera Position - View Matrix Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -15, 0f, 0f, 0f, 0f, 1.0f, 0.0f); // Projection x View Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0); // Rotation x MVP Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0); // Final Matrix GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, scratch, 0); // Draw GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount); // Disable GLES20.glDisableVertexAttribArray(mPositionHandle); } // GLSurface Changed @Override public void onSurfaceChanged(GL10 gl, int width, int height) { // GL Viewport & Aspect Ratio GLES20.glViewport(0, 0, width, height); float aspectRatio = (float) width / height; // Calculate Projection Matrix.frustumM(mProjectionMatrix, 0, -aspectRatio, aspectRatio, -1, 1, 3, 50); } } 

Shader.java

 package render; import android.content.Context; import android.opengl.GLES20; import android.util.Log; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class Shader { // Shader Source Code public String shaderSource; // Shader Handle public int shaderHandle; public int programHandle; public Shader(int type, Context context, int resID) { try { shaderSource = loadShader(context, resID); Log.d("Shader Load", "Success!"); System.out.println(shaderSource); } catch (IOException e) { Log.d("Shader Load", "Failed."); e.printStackTrace(); } shaderHandle = GLES20.glCreateShader(type); GLES20.glShaderSource(shaderHandle, shaderSource); GLES20.glCompileShader(shaderHandle); } // Get From Raw Folder private String loadShader(Context context, int resID) throws IOException { BufferedReader reader = new BufferedReader( new InputStreamReader(context.getResources().openRawResource(resID)) ); String line, shader; StringBuilder builder = new StringBuilder(); while ((line = reader.readLine()) != null) { builder.append(line).append('\n'); } reader.close(); shader = builder.toString(); return shader; } // Associated Program public void setProgram(int handle) { programHandle = handle; } } 

Program.java

 package render; import android.opengl.GLES20; import java.util.ArrayList; import java.util.List; public class Program { public int handle; private Shader vertexShader; private Shader fragmentShader; private List<String> attributes = new ArrayList<String>(); private List<String> uniforms = new ArrayList<String>(); public Program(Shader vertexShader, Shader fragmentShader) { this.vertexShader = vertexShader; this.fragmentShader = fragmentShader; this.vertexShader.setProgram(handle); this.fragmentShader.setProgram(handle); handle = GLES20.glCreateProgram(); GLES20.glAttachShader(handle, vertexShader.shaderHandle); GLES20.glAttachShader(handle, fragmentShader.shaderHandle); GLES20.glLinkProgram(handle); } public void use() { GLES20.glUseProgram(handle); } public int getAttribute(String name) { return GLES20.glGetAttribLocation(handle, name); } public void setAttribute(String name) { } public int getUniform(String name) { return GLES20.glGetUniformLocation(handle, name); } } 

Model.java

 package model; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.util.ArrayList; import java.util.List; public class Model { private static final int NUM_OF_COORDS = 3; public List<Vertex> vertices = new ArrayList<Vertex>(); public List<Vertex> normals = new ArrayList<Vertex>(); public List<Face> faces = new ArrayList<Face>(); public Model() {} public int getVertexCount() { return faces.size() * NUM_OF_COORDS; } public FloatBuffer getVerticesFromIndices() { int numOfVertices = 3; int bytesPerFloat = 4; ByteBuffer bb = ByteBuffer.allocateDirect(faces.size() * numOfVertices * NUM_OF_COORDS * bytesPerFloat); bb.order(ByteOrder.nativeOrder()); FloatBuffer vertexFloatBuffer = bb.asFloatBuffer(); // Use indices to find proper vertex for (Face face : faces) { // VERTEX 1 vertexFloatBuffer.put(vertices.get((int) (face.vertex.x - 1)).x); vertexFloatBuffer.put(vertices.get((int) (face.vertex.x - 1)).y); vertexFloatBuffer.put(vertices.get((int)(face.vertex.x - 1)).z); // VERTEX 2 vertexFloatBuffer.put(vertices.get((int)(face.vertex.y - 1)).x); vertexFloatBuffer.put(vertices.get((int)(face.vertex.y - 1)).y); vertexFloatBuffer.put(vertices.get((int)(face.vertex.y - 1)).z); // VERTEX 3 vertexFloatBuffer.put(vertices.get((int)(face.vertex.z - 1)).x); vertexFloatBuffer.put(vertices.get((int)(face.vertex.z - 1)).y); vertexFloatBuffer.put(vertices.get((int)(face.vertex.z - 1)).z); } vertexFloatBuffer.position(0); return vertexFloatBuffer; } public FloatBuffer getNormalsFromIndices() { int numOfVertices = 3; int bytesPerFloat = 4; ByteBuffer bb = ByteBuffer.allocateDirect(faces.size() * numOfVertices * NUM_OF_COORDS * bytesPerFloat); bb.order(ByteOrder.nativeOrder()); FloatBuffer normalFloatBuffer = bb.asFloatBuffer(); // Use indices to find proper normal for (Face face : faces) { // VERTEX 1 normalFloatBuffer.put(normals.get((int) (face.normal.x - 1)).x); normalFloatBuffer.put(normals.get((int) (face.normal.x - 1)).y); normalFloatBuffer.put(normals.get((int)(face.normal.x - 1)).z); // VERTEX 2 normalFloatBuffer.put(normals.get((int)(face.normal.y - 1)).x); normalFloatBuffer.put(normals.get((int)(face.normal.y - 1)).y); normalFloatBuffer.put(normals.get((int)(face.normal.y - 1)).z); // VERTEX 3 normalFloatBuffer.put(normals.get((int)(face.normal.z - 1)).x); normalFloatBuffer.put(normals.get((int)(face.normal.z - 1)).y); normalFloatBuffer.put(normals.get((int)(face.normal.z - 1)).z); } normalFloatBuffer.position(0); return normalFloatBuffer; } } 

OBJLoader.java

 package util; import android.content.Context; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import model.Face; import model.Model; import model.Vertex; public class OBJLoader { /* loads .obj data from file in res/raw folder */ public static Model loadOBJ(Context context, int resID) throws IOException { Model model = new Model(); BufferedReader reader = new BufferedReader( new InputStreamReader(context.getResources().openRawResource(resID)) ); String line; while ((line = reader.readLine()) != null) { if (line.startsWith("v ")) { // Vertex float x = Float.valueOf(line.split(" ")[1]); float y = Float.valueOf(line.split(" ")[2]); float z = Float.valueOf(line.split(" ")[3]); model.vertices.add(new Vertex(x, y, z)); } else if (line.startsWith("vn ")) { // Normal float x = Float.valueOf(line.split(" ")[1]); float y = Float.valueOf(line.split(" ")[2]); float z = Float.valueOf(line.split(" ")[3]); model.normals.add(new Vertex(x, y, z)); } else if (line.startsWith("f ")) { // Face Vertex vertexIndices = new Vertex( Float.valueOf(line.split(" ")[1].split("/")[0]), Float.valueOf(line.split(" ")[2].split("/")[0]), Float.valueOf(line.split(" ")[3].split("/")[0]) ); Vertex normalIndices = new Vertex( Float.valueOf(line.split(" ")[1].split("/")[2]), Float.valueOf(line.split(" ")[2].split("/")[2]), Float.valueOf(line.split(" ")[3].split("/")[2]) ); model.faces.add(new Face(vertexIndices, normalIndices)); } } reader.close(); return model; } } 

MainActivity.java

 package wise.child.dials; import android.app.Activity; import android.os.Bundle; import android.view.Window; import android.view.WindowManager; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Fullscreen & No Title Bar requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // Set OpenGL ES Drawing Surface (Game View) setContentView(new GameView(this)); } } 

AndroidManifest.xml

 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="wise.child.dials"> <uses-feature android:glEsVersion="0x00020000" android:required="true" /> <supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" /> <supports-gl-texture android:name="GL_OES_compressed_paletted_texture" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MenuActivity" android:screenOrientation="landscape" android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen"> </activity> <activity android:name=".MainActivity" android:screenOrientation="landscape" android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".SplashScreen" /> </application> </manifest> 

Sombreado de vértice

 attribute vec4 vPosition; uniform mat4 uMVPMatrix; void main() { gl_Position = uMVPMatrix * vPosition; } 

Shader de fragmentos

 uniform vec4 vColor; void main() { gl_FragColor = vColor; } 

Introduzca aquí la descripción de la imagen

One Solution collect form web for “Android – OpenGL ES 2.0: Emulador (Works) – Dispositivo (no)”

La solución a este problema particular:

Por lo tanto, he añadido esta línea a mi shader fragmento:

precision mediump float;

Para darnos:

Shader de fragmentos

 precision mediump float; uniform vec4 vColor; void main() { gl_FragColor = vColor; } 

¿Por qué esto funcionó, me da vergüenza decir que no lo sé. Si alguien está dispuesto a elaborar más, por favor, soy curioso. Todavía estoy aprendiendo OpenGL ES 2.0. En mi lectura de OpenGL ES 2.0 Guía de programación ( Good Book ), me encontré con esa línea. Y observaron: "En OpenGL ES 2.0, no se puede dibujar nada a menos que se haya cargado un sombreado de vértices y fragmentos válido". El tutorial de Android también incluyó esta línea, así que sé que es crítica.

  • Android y OpenGL dan marco negro en el inicio
  • Uso de Matrix. Rotar en OpenGL ES 2.0
  • OpenGL ES 2.0 Error al asignar correctamente el atributo de color
  • Cómo dibujar círculo básico en OpenGL ES 2.0 Android
  • ¿Es posible establecer un valor inicial para un uniforme de sombreado? (Android, OpenGL ES 2.0)
  • LibGDX 0.9.9 - Aplicar cubemap en el entorno
  • GLSurfaceView con contexto de OpenGL ES 3.1
  • Convertir la textura procesada de OpenGL ES 2.0 en mapa de bits y volver
  • Activación de Android en silencio
  • Cómo dibujar / hacer una colisión de física de bala cuerpo / forma?
  • EGL trabajando en Linux pero no en Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.