转载请注明出处
本文出自Hansion的博客
1.初始化形状
绘制前,需要初始化并加载绘制的图形。如果图形的坐标不会在执行过程中发生变化,可以在onSurfaceCreated()中进行初始化和加载工作,这样会更省内存,提高执行效率。
public class MyGLRenderer implements GLSurfaceView.Renderer {
...
private Triangle mTriangle;
private Square mSquare;
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
...
// 初始化三角形
mTriangle = new Triangle();
// 初始化矩形
mSquare = new Square();
}
...
}
2.绘制形状
使用 OpenGL ES 2.0 绘制图像需要你提供一些渲染细节,包括:
顶点着色器(Vertex Shader ):用来渲染形状顶点的 OpenGL ES 代码
片元着色器(Fragment Shader):使用颜色或纹理渲染形状表象的 OpenGL ES 代码
程序
(Program):一个包含绘制一个或多个形状的着色器(shader)的OpenGL ES对象
至少需要一个顶点着色器绘制一个形状,以及一个片元着色器为该形状上色。这些shader必须要被编译然后再添加到一个OpenGL ES program中,并利用这个 progrem 来绘制形状。
着色器写法举例:
public class Triangle {
//顶点着色器
private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = vPosition;" +
"}";
//片元着色器
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
...
}
/**
* 加载并编译着色器代码
* @param type 渲染器类型 {GLES20.GL_VERTEX_SHADER, GLES20.GL_FRAGMENT_SHADER}
* @param shaderCode GLSL渲染器代码
* @return
*/
public static int loadShader(int type, String shaderCode){
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
接下来我们就编译色器代码并将它们添加至一个 OpenGL ES Program 对象中,然后执行链接方法。
但这一系列操作非常消耗CPU,所以最好写在形状的构造方法中,避免多次调用。如果执行时不知道着色器的内容,可以创建一次后进行缓存供以后使用。
public class Triangle() {
...
private final int mProgram;
public Triangle() {
...
int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);
// 编译着色器代码
int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);
// 创建一个OpenGL ES Program
mProgram = GLES20.glCreateProgram();
// 添加顶点着色器到Program
GLES20.glAttachShader(mProgram, vertexShader);
// 添加片元着色器到Program
GLES20.glAttachShader(mProgram, fragmentShader);
// 链接创建OpenGL ES可执行文件
GLES20.glLinkProgram(mProgram);
}
}
至此,我们已经准备好了被绘制的形状信息,要让OpenGL ES绘制,我们就要告诉它要绘制什么以及如何绘制。因为每个形状的绘图设置可能有所不同,所以最好将绘图逻辑写在形状自己的类里面。
我们创建一个draw()方法进行指定并绘制:
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 void draw() {
// 将Program添加至OpenGL ES环境
GLES20.glUseProgram(mProgram);
// 获取顶点着色器的vPosition成员
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// 启用顶点属性数组。如果启用,那么当glDrawArrays或者glDrawElements被调用时,顶点属性数组会被使用。
GLES20.glEnableVertexAttribArray(mPositionHandle);
// 准备形状坐标数据
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
// 获取片元着色器的vColor成员
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
// 设置绘制颜色
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
// 绘制形状
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
// 禁用顶点属性数组
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
然后我们在渲染器的onDrawFrame方法中,调用draw()方法即可进行绘制
public void onDrawFrame(GL10 unused) {
...
mTriangle.draw();
}
参考: