Android OpenGL ES开发初探

一、什么是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)。

基本使用:

	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这个东西,是个接口,有三个方法需要自己去实现它。按照初始的调用顺序来讲下这个三个方法

 // 创建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这个区间内。据说是做归一化处理,显卡计算起来会比较方便喔。

顶点坐标系

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

  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这个区间内。

纹理坐标系

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

  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)

举个栗子:

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“打交道”的逻辑。

举一个简单的栗子:

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

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

三、总结

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

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Flutter入门

Android OpenGL ES(三)-平面图形

前两章,其实我们已经明白了绘制平面图形的套路了。 接下来我们按照套路继续画其他的图形。

2753
来自专栏IMWeb前端团队

说一说z-index容易被忽略的那些特性

前言 关于z-index,每个人都会用,但大多人都不理解其真正的生效机制。最近做项目有很多用到z-index的地方,才发现以前用的一知半解,所以上网查了一些资料...

4895
来自专栏一棹烟波

OpenGL+OpenCV实现立方体贴图

我屮艸芔茻,转眼就7月份了。 今天试了一下立方体贴图,比较简单,大概说下和平面贴图的区别。 1. 平面贴图需要的是纹理坐标vec2;立方体贴图需要的是一个方向向...

2445
来自专栏数据结构与算法

洛谷P3209 [HNOI2010]PLANAR(2-SAT)

题目描述 若能将无向图G=(V,E)画在平面上使得任意两条无重合顶点的边不相交,则称G是平面图。判定一个图是否为平面图的问题是图论中的一个重要问题。现在假设你要...

3426
来自专栏数据小魔方

sparklines迷你图系列8——Comparision(HVar & VBar)

今天继续跟大家分享sparklines迷你图系列8——Comparision图表类型中的单条形图/柱形图。 这里所指的条形图之所以称为单条形图、柱形图,是因为每...

2865
来自专栏CDA数据分析师

Excel中6个怪异的公式,你知多少?

文 | 兰色幻想-赵志东 在excel中我们有时会看到一些奇奇怪怪的公式,为了帮助新手学习,兰色今天带大家一起盘点这些公式。 公式1:=Sum(表1:表20!A...

2055
来自专栏菩提树下的杨过

Flash/Flex学习笔记(20):贝塞尔曲线

贝塞尔曲线的身影几乎在所有绘图软件中都有出现,下面的代码演示了如何用AS3.0画一段简单的贝塞尔曲线(没有使用Document文档类,想测试的朋友,直接把下面的...

2148
来自专栏MelonTeam专栏

OpenGL ES (iOS) 学习笔记 — 基础篇(一)

最近一直在做视频相关的工作,结合最近很火的AR技术,所以准备好好学习一下3D渲染的相关知识。因为一直在iOS移动端开发,所以学习一下OpenGL ES 技术。 ...

67110
来自专栏js编程在工科课程中的简单应用

3.2 矢量图的绘制

相对云图,矢量图的绘制要简单一些,绘制箭头表示矢量,而箭头可简单的由三条长短不一的直线构成。矢量图(Vector Map)通常用于描述流场流动情况,矢量图由有...

870
来自专栏desperate633

LintCode 接雨水题目分析方法三

给出 n 个非负整数,代表一张X轴上每个区域宽度为 1 的海拔图, 计算这个海拔图最多能接住多少(面积)雨水。

1932

扫码关注云+社区

领取腾讯云代金券