专栏首页Android原创Android OpenGL ES开发初探
原创

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 条评论
登录 后参与评论

相关文章

  • 小程序开发踩坑指南

    小程序组件分为原生组件和非原生组件,原生组件属于客户端的组件,在WebView的渲染流程之外的,且层级在所有非原生组件之上(无论你如何改z-index都没用的)...

    Clayman Twinkle
  • 写一个Gradle插件

    我们在Android Studio中创建的app项目中,build.gradle常有如下这行代码:

    Clayman Twinkle
  • 现有项目接入Kotlin开发实战

    众所周知,Google强力推出了Kotlin作为Android开发的第一语言,那么我们现有用Java语言开发的项目,如何去接入Kotlin开发呢?

    Clayman Twinkle
  • 成都银联面经

    牛客网
  • 【编程语言】Java虚拟机垃圾回收算法,2020年的面试你准备好了吗

    熟悉 Java 的朋友一定知道 Java 虚拟机了,熟练掌握 Java 虚拟机是一个高级工程师的基础素养哦,当然面试官在问到 Java 虚拟机的时候,一定会问到...

    kk大数据
  • js中原型(prototype)

    * 每个函数都有一个prototype属性, 它默认指向一个Object空对象(即称为: 原型对象)

    李才哥
  • SAP WebClient UI配置决定(configuration)的逻辑介绍

    This blog will try to introduce the Webclient UI Configuration determination log...

    Jerry Wang
  • vs2017错误:当前页面的脚本发生错误

    解决:在vs中选择调试-->选项-->不选中“调试时启动诊断工具”,点击确定。重启vs生效。

    跟着阿笨一起玩NET
  • JVM垃圾收集详解

    为每个对象标记一个引用数量,当这个对象被另外一个对象引用时它的引用数据就加一,当另外一个对象释放了对它的引用它的引用数量就减一。当它的引用变为0时意味着没有对象...

    Java学习录
  • 018 自动仓储物流系统中的“自我闭环”

    最近关注到一个词“闭环系统”,是现代工业控制系统理论里的一个很重要的理论基础,从百度科普看到如下:

    老King

扫码关注云+社区

领取腾讯云代金券