java - programacion - Android-OpenGL ES 2.0: Emulador(funciona)-Dispositivo(no)
manual de android en pdf (1)
La solución a este problema particular:
Entonces, agregué esta línea a mi sombreador de fragmentos:
precision mediump float;
Para darnos:
Fragmento Shader
precision mediump float;
uniform vec4 vColor;
void main() {
gl_FragColor = vColor;
}
Por qué funcionó esto, me avergüenza decir que no sé. Si alguien está dispuesto a dar más detalles, por favor, tengo curiosidad. Todavía estoy aprendiendo OpenGL ES 2.0. En mi lectura de OpenGL ES 2.0 Programming Guide ( Good Book ), encontré esa línea. Y señalaron: "En OpenGL ES 2.0, no se puede dibujar nada a menos que se haya cargado un vértice y un sombreador de fragmentos válidos". El tutorial de Android también incluyó esta línea, así que sé que es crítico.
¡Buen día!
Estoy haciendo algunas pruebas simples con OpenGL ES 2.0 para Android. Estoy usando un cargador de modelos que funciona bien en el emulador. Sin embargo, cuando intento 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 mucha experiencia en OpenGL ES 2.0 y Android me ayude. Perdón por la verborrea, realmente no tengo idea de por qué no funciona en el teléfono. Aquí está la fuente (soy un novato 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>
Vertex Shader
attribute vec4 vPosition;
uniform mat4 uMVPMatrix;
void main() {
gl_Position = uMVPMatrix * vPosition;
}
Fragmento Shader
uniform vec4 vColor;
void main() {
gl_FragColor = vColor;
}