初识OpenGL ES2.0

概述

要在Android应用中使用OpenGL ES绘制图形就必须为它们创建一个视图容器,使用该容器这边就需要引入GLSurfaceView和GLSurfaceView.Renderer.GLSurfaceView是使用OpenGL和GLSurfaceView.Renderer绘制的图形的视图容器,用于控制在该视图中绘制内容.
下面就介绍如何使用GLSurfaceView和GLSurfceView.Renderer完成简单的三角形绘制.

清单文件中声明OpenGL的使用

如果我们的应用程序需要使用OpenGL ES2.0API,就需要在清单文件中进行声明

1
2
3
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />

创建activity

1
2
3
4
5
6
7
8
9
public class OpenGlActivity extends AppCompatActivity {
private MyGlSurfaceView mGLView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLView=new MyGlSurfaceView(OpenGlActivity.this);
setContentView(mGLView);
}
}

创建GLSurfaceView对象

GLSurfaceView是一个专门的视图,在上面可以绘制OpenGL ES图形,本身并没有太大的作用,实际的对象绘制是在GLSurfaceView.Renderer中进行控制的.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MyGlSurfaceView extends GLSurfaceView implements View.OnTouchListener{

private final MyGLRender render;

public MyGlSurfaceView(Context context) {
super(context);
//设置openGL ES 版本
setEGLContextClientVersion(2);
render=new MyGLRender();
//设置渲染器
setRenderer(render);
//绘图数据发生更改时渲染视图
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
}

创建渲染器Renderer

Renderer控制在于其关联的SurfaceView上绘制内容,Renderer有三个方法供Android系统调用.
(1) onSurfaceCreated() 调用一次,设置OpenGL ES环境.
(2) onDrawFrame() 每次重绘进行时调用
(3) onSurfaceChange() 视图几何图形发生改变时进行调用(eg:设备的屏幕方向发生改变)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class MyRenerer implements GLSurfaceView.Renderer{
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig){
//设置背景颜色
GLES20.glClearColor(0f,0f,0f,1f);
}
@Override
public void onSurfaceChanged(GL10 gl10, int i, int i1) {
//设置背景大小
GLES20.glViewport(0,0,i,i1);
}

@Override
public void onDrawFrame(GL10 gl10) {
//重绘背景颜色
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
}
}

定义三角形

OpenGL ES允许使用三维空间中的坐标定义绘制对象,所以在定义三角形之前,必须先定义其坐标.在OpenGL中,执行此操作的典型方法是为坐标定义浮点数的顶点数组。为了获得最大效率,可以将这些坐标写入ByteBuffer,并将其传递到OpenGL ES图形管道进行处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Triangle{
private FloatBuffer vertexBuffer;
//数组中每个顶点的坐标
private static final int COOR_PER_VERTEX=3;
//按逆时针顺序
private static final float triangleCoords[]={
0.0f,0.5f,0.0f,//顶点
-0.5f,-0.5f,0.0f,//左顶点
0.5f,-0.5f,0f//右顶点
};
float color[]={0.0f,0.0f,0.0f,0.0f};
public Trangle(){
//为三角形坐标初始化顶点字节缓冲区
//(坐标值的数量*每一个浮点数4个字节)
ByteBuffer byteBuffer=ByteBuffer.allocateDirect(
trangleCoords.length*4);
//使用本机硬件的本机字节顺序
byteBuffer.order(ByteOrder.nativeOrder());
//从ByteBuffer创建一个浮点缓冲区
vertexBuffer = byteBuffer.asFloatBuffer();
//将坐标添加到FloatBuffer
vertexBuffer.put(triangleCoords);
//设置缓冲区读取第一个坐标
vertexBuffer.position(0);
}
}

初始化三角形

在进行绘图之前,必须初始化并加载计划绘制的形状,除非程序中使用的形状的结构(原始坐标)在执行过程中发生变化,否则应在渲染器的onSurfaceCreated()方法中初始化它们,以获得内存和处理效率

1
2
3
4
5
6
7
8
9
10
public class MyGLRender implements GLSurfaceView.Renderer{
private Triangle mTriangle;
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig){
//设置背景颜色
GLES20.glClearColor(0f,0f,0f,1f);
mTriangle=new Triangle();
}

}

绘制三角形

首先需要定义如下内容:
(1) Vertex Shader -顶点着色器,用于渲染形状顶点的OpenGL ES图形代码。
(2)Fragment Shader -OpenGL ES代码,用于渲染具有颜色或纹理的形状的面。
(3) Program -一个OpenGL ES对象,包含要用于绘制一个或多个形状的着色器。
我们需要至少一个顶点着色器来绘制形状,并使用一个片段着色器为该形状着色。必须编译这些着色器,然后将其添加到OpenGL ES程序中,然后使用该程序绘制形状。以下是如何定义可用于在Triangle类中绘制形状的基本着色器的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Triangle{
private final String vertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";

}

着色器包含OpenGL着色语言(GLSL)代码,必须在OpenGL ES环境中使用它之前进行编译。要编译此代码,要Renderer类中创建以下该方法:

1
2
3
4
5
6
7
8
9
10
11
12
public static int loadShader(int type, String shaderCode){

// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);

// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);

return shader;
}

创建Draw()方法绘制形状

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private int mPositionHandle;
private int mColorHandle;
private static final int COORDS_PER_VERTEX = 3;
private final int vertexCount = triangleCoords.length /COORDS_PER_VERTEX;
private final int vertexStride = COORDS_PER_VERTEX * 4;

public void draw(float[] mvpMatrix) {
//将程序添加到OpenGL ES环境
GLES20.glUseProgram(mProgram);
//获取顶点着色器位置成员的句柄
mPositionHandle=GLES20.glGetAttribLocation(mProgram, "vPosition");
//启用三角形顶点的句柄
GLES20.glEnableVertexAttribArray(mPositionHandle);
//准备三角坐标数据
GLES20.glVertexAttribPointer(mPositionHandle,COOR_PER_VERTEX,
GLES20.GL_FLOAT,false,vertexStride,vertexBuffer);
//获取片段着色器Color成员的句柄
mColorHandle=GLES20.glGetUniformLocation(mProgram,"vColor");
//设置绘制三角形的颜色
GLES20.glUniform4fv(mColorHandle,1,color,0);
//获得形状的变换矩阵的handle
mMVPMatrixHandle=GLES20.glGetUniformLocation(mProgram,"uMVPMatrix");
//把变换矩阵传给着色器
GLES20.glUniformMatrix4fv(mMVPMatrixHandle,1,false,mvpMatrix,0);
//绘制三角形
GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,vertexCount);
//禁用顶点数组
GLES20.glEnableVertexAttribArray(mPositionHandle);
}

最后在Renderer的onDrawFrame()方法中调用draw()方法.要想的三角形就出现啦!

小白一个后续更新!

Newer Post

如何高效的显示Bitmap

前言了解如何使用常用技术来处理和加载Bitmap,使我们的UI组件保持响应并避免超出应用程序内存限制。如果不小心,Bitmap可以快速消耗你的可用内存预算,导致应用程序崩溃,出现OOM.为什么在Android应用程序中加载Bitmap是件很棘手的事情?&emsp;&emsp; ①移动设备资源受限.A …

继续阅读
Older Post

浅谈Android MediaPlayer

前言MediaPlayer是Android中多媒体框架中一个重要的组件,我们通过它可以控制在线或者本地音视频的播放过程. MeidaPlayer具体方法介绍1.void setDataSource(String url)通过一个具体的路径来设置MediaPlayer的数据源,url可以是本地的一个 …

继续阅读