- A+
所属分类:android OpenGL ES3
《OpenGL ES 2 for Android》第4章代码改用OpenGL ES 3实现
Contents
主要文件
-- AirHockeyActivity.java
-- AirHockeyRender.java
-- util >>> LoggerConfig.java
-- util >>> ShaderHelper.java
-- util >>> TextResourceReader.java
-- res >> raw >>> simple_vertex_shader.glsl
-- res >> raw >>> simple_fragment_shader.glsl
AirHockeyActivity类
// example/airhockey/AirHockeyActivity.java
package com.example.airhockey;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ConfigurationInfo;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class AirHockeyActivity extends AppCompatActivity {
private GLSurfaceView glSurfaceView;
private boolean renderSet = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
glSurfaceView = new GLSurfaceView(this);
final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
String v = configurationInfo.getGlEsVersion();
if (v.equalsIgnoreCase("3.0")) {
glSurfaceView.setEGLContextClientVersion(3);
glSurfaceView.setRenderer(new AirHockeyRender(this));
renderSet = true;
} else {
Toast.makeText(this, "This device does not support OpenGL ES 3.0.",
Toast.LENGTH_LONG).show();
return;
}
setContentView(glSurfaceView);
}
@Override
protected void onPause() {
super.onPause();
if (renderSet) {
glSurfaceView.onPause();
}
}
@Override
protected void onResume() {
super.onResume();
if (renderSet) {
glSurfaceView.onResume();
}
}
}
AirHockeyRender类
// example/airhockey/AirHockeyRender.java
package com.example.airhockey;
import android.content.Context;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import com.example.airhockey.util.LoggerConfig;
import com.example.airhockey.util.ShaderHelper;
import com.example.airhockey.util.TextResourceReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class AirHockeyRender implements GLSurfaceView.Renderer {
private static final int POSITION_COMPONENT_COUNT = 2;
private static final int BYTES_PER_FLOAT = 4;
private final FloatBuffer vertexData;
private final Context context;
private int program;
private static final int COLOR_COMPONENT_COUNT = 3;
private static final int STRIDE = (POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT) * BYTES_PER_FLOAT;
public AirHockeyRender(Context context) {
this.context = context;
float[] tableVerticesWithTriangles = {
// Order of coordinates: X, Y, R, G, B
// Triangle Fan
0f, 0f, 1f, 1f, 1f,
-0.5f, -0.5f, 0.7f, 0.7f, 0.7f,
0.5f, -0.5f, 0.7f, 0.7f, 0.7f,
0.5f,0.5f, 0.7f, 0.7f, 0.7f,
-0.5f, 0.5f, 0.7f, 0.7f, 0.7f,
-0.5f, -0.5f, 0.7f, 0.7f, 0.7f,
// Line 1
-0.5f, 0f, 1f, 0f, 0f,
0.5f, 0f, 0f, 0f, 1f,
// Mallets
0f, -0.25f, 0f, 0f, 1f,
0f, 0.25f, 1f, 0f, 0f
};
vertexData = ByteBuffer.allocateDirect(tableVerticesWithTriangles.length * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
vertexData.put(tableVerticesWithTriangles);
}
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
GLES30.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
String vertexShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.simple_vertex_shader);
String fragmentShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.simple_fragment_shader);
int vertexShader = ShaderHelper.compileVertexShader(vertexShaderSource);
int fragmentShader = ShaderHelper.compileFragmentShader(fragmentShaderSource);
program = ShaderHelper.linkProgram(vertexShader, fragmentShader);
if (LoggerConfig.ON) {
ShaderHelper.validateProgram(program);
}
GLES30.glUseProgram(program);
vertexData.position(0);
GLES30.glVertexAttribPointer(0, POSITION_COMPONENT_COUNT, GLES30.GL_FLOAT, false, STRIDE, vertexData);
GLES30.glEnableVertexAttribArray(0);
vertexData.position(POSITION_COMPONENT_COUNT);
GLES30.glVertexAttribPointer(1, COLOR_COMPONENT_COUNT, GLES30.GL_FLOAT, false, STRIDE, vertexData);
GLES30.glEnableVertexAttribArray(1);
}
@Override
public void onSurfaceChanged(GL10 gl10, int i, int i1) {
GLES30.glViewport(0, 0, i, i1);
}
@Override
public void onDrawFrame(GL10 gl10) {
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
// GLES30.glUniform4f(uColorLocation, 1.0f, 1.0f, 1.0f, 1.0f);
GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, 6);
// GLES30.glUniform4f(uColorLocation, 1.0f, 0.0f, 0.0f, 1.0f);
GLES30.glDrawArrays(GLES30.GL_LINES, 6, 2);
// GLES30.glUniform4f(uColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);
GLES30.glDrawArrays(GLES30.GL_POINTS, 8, 1);
//
// GLES30.glUniform4f(uColorLocation, 1.0f, 0.0f, 0.0f, 1.0f);
GLES30.glDrawArrays(GLES30.GL_POINTS, 9, 1);
}
}
ShaderHelper类
// example/airhockey/util/ShaderHelper.java
package com.example.airhockey.util;
import android.opengl.GLES30;
import android.util.Log;
public class ShaderHelper {
private static final String TAG = "ShaderHelper";
public static int compileVertexShader(String shaderCode) {
return compileShader(GLES30.GL_VERTEX_SHADER, shaderCode);
}
public static int compileFragmentShader(String shaderCode) {
return compileShader(GLES30.GL_FRAGMENT_SHADER, shaderCode);
}
private static int compileShader(int type, String shaderCode) {
final int shaderObjectId = GLES30.glCreateShader(type);
if (shaderObjectId == 0) {
if (LoggerConfig.ON) {
Log.w(TAG, "Could not create new shader.");
}
return 0;
}
GLES30.glShaderSource(shaderObjectId, shaderCode);
GLES30.glCompileShader(shaderObjectId);
final int[] compileStatus = new int[1];
GLES30.glGetShaderiv(shaderObjectId, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
if (LoggerConfig.ON) {
Log.v(TAG, "Results of compiling source:" + "\n" + shaderCode + "\n" + GLES30.glGetShaderInfoLog(shaderObjectId));
}
if (compileStatus[0] == 0) {
GLES30.glDeleteShader(shaderObjectId);
if (LoggerConfig.ON) {
Log.w(TAG, "Compilation of shader failed.");
}
return 0;
}
return shaderObjectId;
}
public static int linkProgram(int vertexShaderId, int fragmentShaderId) {
final int programObjectId = GLES30.glCreateProgram();
if (programObjectId == 0) {
if (LoggerConfig.ON) {
Log.w(TAG, "Could not create new program");
}
return 0;
}
GLES30.glAttachShader(programObjectId, vertexShaderId);
GLES30.glAttachShader(programObjectId, fragmentShaderId);
GLES30.glLinkProgram(programObjectId);
final int[] linkStatus = new int[1];
GLES30.glGetProgramiv(programObjectId, GLES30.GL_LINK_STATUS, linkStatus, 0);
if (LoggerConfig.ON) {
Log.v(TAG, "Results of linking program:\n" + GLES30.glGetProgramInfoLog(programObjectId));
}
if (linkStatus[0] == 0) {
GLES30.glDeleteProgram(programObjectId);
if (LoggerConfig.ON) {
Log.w(TAG, "Linking of program failed.");
}
return 0;
}
return programObjectId;
}
public static boolean validateProgram(int programObjectId) {
GLES30.glValidateProgram(programObjectId);
final int[] validateStatus = new int[1];
GLES30.glGetProgramiv(programObjectId, GLES30.GL_VALIDATE_STATUS, validateStatus, 0);
Log.v(TAG, "Results of validating program:" + validateStatus[0] + "\nLog" + GLES30.glGetProgramInfoLog(programObjectId));
return validateStatus[0] != 0;
}
}
TextResourceReader类
// example/airhockey/util/TextResourceReader.java
package com.example.airhockey.util;
import android.content.Context;
import android.content.res.Resources;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class TextResourceReader {
public static String readTextFileFromResource(Context context, int resourceId) {
StringBuilder body = new StringBuilder();
try {
InputStream inputStream = context.getResources().openRawResource(resourceId);
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String nextLine;
while ((nextLine = bufferedReader.readLine()) != null) {
body.append(nextLine);
body.append('\n');
}
} catch (IOException e) {
throw new RuntimeException("Could not open resource: " + resourceId, e);
} catch (Resources.NotFoundException nfe) {
throw new RuntimeException("Resource not found: " + resourceId, nfe);
}
return body.toString();
}
}
LoggerConfig类
// example/airhockey/util/LoggerConfig.java
package com.example.airhockey.util;
public class LoggerConfig {
public static final boolean ON = true;
}
顶点着色器
// app/src/main/res/raw/simple_vertex_shader.glsl
#version 300 es
layout(location = 0) in vec4 a_Position;
layout(location = 1) in vec4 a_Color;
out vec4 v_Color;
void main()
{
gl_Position = a_Position;
gl_PointSize = 10.0;
v_Color = a_Color;
}
片段着色器
// app/src/main/res/raw/simple_fragment_shader.glsl
#version 300 es
precision mediump float;
in vec4 v_Color;
out vec4 fragColor;
void main() {
fragColor = v_Color;
}