Android OpenGL ES开发初探

2018-07-25 09:50:27 浏览数 (1)

一、什么是OpenGL ES?

网上介绍很多,这里不多讲,直接简单的讲,OpenGL是一个可以用来画二维或者三维图形库。而OpenGL ES呢,是OpenGL针对嵌入式设备搞的一个库,所以移动开发上用的基本上就是OpenGL ES了。

二、OpenGL ES的基本使用和一些概念

1. 版本

OpenGL ES 有几个版本,对于Android系统API,会有不同的要求。

OpenGL ES版本

Android系统API

OpenGL ES 1.0&1.1

Android 1.0 以上

OpenGL ES 2.0

Android 2.2以上

OpenGL ES 3.0

Android 4.3以上

OpenGL ES 3.1

Android 5.0以上

这里考虑到Android系统版本,选择OpenGL ES 2.0会是比较好。当然如果不考虑旧版本,使用3.0或者3.1更佳。

2. Android上OpenGL ES基本的类

(1) GLSurfaceView

OpenGL ES在Android开发上,是以GLSurfaceView为载体进行展示的(或者可以自己用SurfaceView实现一个,这里简单起见,直接用GLSurfaceView)。

基本使用:

代码语言:txt复制
	GLSurfaceView glView = new GLSurfaceView (context);
	// 注意,记得给它设置版本,这里用OpenGL ES 2.0,那就设置version =2;
	glVIew.setEGLContextClientVersion(version);
	 // 重点,所有的绘制逻辑,基本全在这个Renderer里了;
	glView.setRenderer(renderer);
	 // 这个看情况用,不一定需要用这个,但一般会这么用。
	 // RENDERMODE_WHEN_DIRTY意思是只有你执行requestRender方法才去渲染,会比较节省性能,否则默认隔断时间就进行渲染。
	glVIew.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

关于GLSurfaceView的生命周期方法onResumeonPause分别在ActivityonResumeonPause分别调用。

(2) GLSurfaceView.Renderer

上面讲到,这个是GLSurfaceView的“灵魂”。基本上的各种特效和图形都是在这里写出来的。

Renderer这个东西,是个接口,有三个方法需要自己去实现它。按照初始的调用顺序来讲下这个三个方法

代码语言:txt复制
 // 创建GLSurfaceView时回调的方法,主要做一些后面不会常用不变的字段进行初始化操作;
onSurfaceCreated(GL10 gl10,  EGLConfig config);
// 回调包括GLSurfaceView大小的变化或屏幕横竖变换;
onSurfaceChanged(GL10 gl10, int width, int height);
 // 看名字就知道,是绘制时会回调的方法,在这里做绘制逻辑;上面讲到requestRender,基本就是会来回调这个方法。
onDrawFrame(GL10 gl10);

3. OpenGL中的各种坐标系

1. 屏幕坐标系

众所周知,Android屏幕坐标系是以左上角为原点,横为x轴,竖为y轴。

屏幕坐标系屏幕坐标系
2. 顶点坐标系

和屏幕坐标系不太一样,OpenGL的顶点坐标是以中心为原点,横为x轴,竖为y轴,垂直于屏幕为z轴。轴的值范围都在-1, 1这个区间内。据说是做归一化处理,显卡计算起来会比较方便喔。

顶点坐标系顶点坐标系

举个栗子,定义一个三角形坐标可以这样:

代码语言:txt复制
  private static final float triangleCoords[] = {
            0f, 1.0f,      // top
            -1.0f, 0f,  // left bottom
            1.0f, 0f    // right bottom
    };
3. 纹理坐标系

同理,都不一样。OpenGL纹理的坐标系,是以左下角为原点,横为x轴,竖为y轴,轴的值范围都在0, 1这个区间内。

纹理坐标系纹理坐标系

举个例子,定义一个图片纹理坐标可以这样:

代码语言:txt复制
  private final float[] mTexCoordSrc ={
            0.0f, 0.0f,
            0.0f,  1.0f,
            1.0f,  0.0f,
            1.0f, 1.0f,
    };

4. 矩阵与屏幕

由于设备屏幕大小总会不一样,所以就存在需要将OpenGL绘制的东西的坐标与屏幕做一个投影映射。

OpenGL通过定义相机视图矩阵(V)、投影矩阵(P),通过进行矩阵相乘(转换矩阵MVP),使坐标正确地映射到Android设备的屏幕。

这里盗个图,理解起来会比较清楚:

透视投影(perspective projection)和正交投影( orthographic projection)透视投影(perspective projection)和正交投影( orthographic projection)

举个栗子:

代码语言:txt复制
private float[] mMVPMatrix = new float[16]; // 转换矩阵
private float[] mViewMatrix = new float[16]; // 相机视图矩阵
private float[] mProjectionMatrix = new float[16]; // 投影矩阵
// ......省略

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// ......省略
      Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7); // 投影矩阵->mProjectionMatrix,透视投影,正交投影用orthoM
      Matrix.setLookAtM(mViewMatrix, 0,
                0, 0, 0,
                0, 0, 0,
                0, 0, 0); // 设置相机->mViewMatrix
     Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0); // 转换矩阵->mMVPMatrix,这里做了乘法
 }

5. Shader

中文人称:着色器。用来描述如何定坐标和渲染。用了一种类C语言的编程语言来写。主要有顶点(vertex)着色器片段(fragment)着色器两种。基本上都是写OpenGL和这个两个shader打交道,通过shader去告诉OpenGL ES库,你想画在哪、填充什么颜色等等。所以,简单讲Renderer里主要是描述了和shader“打交道”的逻辑。

举一个简单的栗子:

代码语言:txt复制
// vertex shader
attribute vec4 aPosition; // 顶点坐标
uniform mat4 uMatrix; // 上面那个mMVPMatrix传进来就是这个东西
void main(){
     gl_Position = uMatrix * aPosition; // 最后算出最后的顶点坐标
}
代码语言:txt复制
// fragment shader
precision mediump float;
uniform vec4 uColor; // 填充的颜色
void main() {
    gl_FragColor = uColor;
}

简单来讲,顶点着色器用来确定坐标,片段着色器用来填充颜色或者纹理的。

三、总结

  1. OpenGL就是一个画图用的库;
  2. 在Android上,OpenGL呈现的载体是GLSurfaceView
  3. 使用shader语言去告诉OpenGL你要干嘛(画在什么位置和填充什么颜色或者纹理);

0 人点赞