- 验证是否支持OpenGLES2.0
//检查设备是否支持OpenGL ES 2.0
final ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
final boolean supportES2 = configurationInfo.reqGlEsVersion >= 0x00020000;
确保可用,在manifest里面添加验证
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
- 定义
vertex_shader.glsl
和fragment_shader.glsl
到res/raw
里面
vertex_shader.glsl
attribute vec4 vPosition;
void main(){
gl_Position = vPosition;
}
fragment_shader.glsl
precision mediump float;
uniform vec4 vColor;
void main(){
gl_FragColor = vColor;
}
OpenGL ES Shader的三种变量类型uniform,attribute和varying
- 定义形状
import android.content.Context;
import android.opengl.GLES20;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
public class Triangle {
//坐标本地内存地址
private FloatBuffer vertexBuffer;
//每一次取点的时候取几个点
static final int COORDS_PER_VERTEX = 3;
//绘制坐标
static float triangleCoords[] = { // in counterclockwise order:
0.0f, 0.622008459f, 0.0f, // top
-0.5f, -0.311004243f, 0.0f, // bottom left
0.5f, -0.311004243f, 0.0f // bottom right
};
// Set color with red, green, blue and alpha (opacity) values
float color[] = {0.63671875f, 0.76953125f, 0.22265625f, 1.0f};
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
//每一次取的总的点 大小
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
public Triangle(Context context) {
//为坐标分配本地内存地址
vertexBuffer = ByteBuffer
.allocateDirect(triangleCoords.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(triangleCoords);
vertexBuffer.position(0);
//根据shader代码和fragment代码 获取到一个渲染程序
mProgram = ShaderUtil.createProgram(ShaderUtil.readRawTxt(context, R.raw.vertex_shader),
ShaderUtil.readRawTxt(context, R.raw.fragment_shader));
if (mProgram > 0) {
//获取vertex shader的属性vPosition 的地址
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
//获取fragment shader的属性vColor 的地址
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
}
}
public void draw() {
//使用渲染程序
GLES20.glUseProgram(mProgram);
// 使顶点属性数组有效
GLES20.glEnableVertexAttribArray(mPositionHandle);
// 为顶点属性赋值
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
// 设置颜色
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
// 绘制图形
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
// 禁用顶点数组
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
}
ShaderUtil.java
import android.content.Context;
import android.opengl.GLES20;
import android.util.Log;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class ShaderUtil {
private static final String TAG = "ShaderUtil";
public static String readRawTxt(Context context, int rawId) {
InputStream inputStream = context.getResources().openRawResource(rawId);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuffer sb = new StringBuffer();
String line;
try {
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
public static int loadShader(int shaderType, String source) {
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(shaderType);
if (shader != 0) {
//添加代码到shader
GLES20.glShaderSource(shader, source);
//编译shader
GLES20.glCompileShader(shader);
int[] compile = new int[1];
//检测是否编译成功
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compile, 0);
if (compile[0] != GLES20.GL_TRUE) {
Log.d(TAG, "shader compile error");
GLES20.glDeleteShader(shader);
shader = 0;
}
}
return shader;
}
public static int createProgram(String vertexSource, String fragmentSource) {
//获取vertex shader
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
if (vertexShader == 0) {
return 0;
}
//获取fragment shader
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
if (fragmentShader == 0) {
return 0;
}
//创建一个空的渲染程序
int program = GLES20.glCreateProgram();
if (program != 0) {
//添加vertexShader到渲染程序
GLES20.glAttachShader(program, vertexShader);
//添加fragmentShader到渲染程序
GLES20.glAttachShader(program, fragmentShader);
//关联为可执行渲染程序
GLES20.glLinkProgram(program);
int[] linsStatus = new int[1];
//检测是否关联成功
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linsStatus, 0);
if (linsStatus[0] != GLES20.GL_TRUE) {
Log.d(TAG, "link program error");
GLES20.glDeleteProgram(program);
program = 0;
}
}
return program;
}
}
- 定义shader
import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class MyRender implements GLSurfaceView.Renderer {
private Context context;
private Triangle triangle;
public MyRender(Context context) {
this.context = context;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
triangle = new Triangle(context);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
//宽高
GLES20.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
//清空颜色
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
//设置背景颜色
// GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
triangle.draw();
}
}
- 设置
shader
到GLSurfaceView
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
public class MyGLSurfaceView extends GLSurfaceView{
public MyGLSurfaceView(Context context) {
this(context, null);
}
public MyGLSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
setEGLContextClientVersion(2);
setRenderer(new MyRender(context));
}
}
上述三角形已经绘制成功。
- 绘制四边形
绘制四边形的方式是由两个三角形形成一个四边形,所以顶点位置一定要注意。
调用GLES20.glDrawArrays
的时候设置flog
可以设置为GLES20.GL_TRIANGLE_STRIP
和GLES20.GL_TRIANGLES
,前者复用坐标,后者分别取几个坐标。