Guten Tag!Android - OpenGL ES 2.0: Emulator (funktioniert) - Gerät (nicht)
Ich mache ein paar einfache Tests mit OpenGL ES 2.0 für Android. Ich verwende einen Modelllader, der im Emulator gut funktioniert. Wenn ich jedoch versuche, es auf einem ASUS ZenFone 2E (Android 5.0.1) (Prepaid-Telefon) zu verwenden, zeigt es einfach die klare Farbe des Hintergrunds ohne rotierendes Modell an. Ich hoffe, dass jemand, der sowohl OpenGL ES 2.0 als auch Android gut beherrscht, mir helfen wird. Sorry für die Ausführlichkeit, ich habe wirklich keine Ahnung, warum es nicht am Telefon funktioniert. Hier ist die Quelle (ich bin einen extremen Anfänger):
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;
}
Fragment Shader
uniform vec4 vColor;
void main() {
gl_FragColor = vColor;
}
Weitere Diskussion über Shadern und Beleuchtung in Android, versuchen, dieses Buch zu: https://pragprog.com/book/kbogla/opengl-es-2 -für-android - Ich studiere es gerade und die (downloadbar als zip) Samples sind ziemlich genial und alle funktionieren gut. –