本文主要介绍,如何使用 OpenGL ES 来渲染一张图片。内容包括:基础概念的讲解,如何使用 GLKit 来渲染纹理,如何使用 GLSL 编写的着色器来渲染纹理。
前言
OpenGL(Open Graphics Library)是 Khronos Group (一个图形软硬件行业协会,该协会主要关注图形和多媒体方面的开放标准)开发维护的一个规范,它是硬件无关的。它主要为我们定义了用来操作图形和图片的一系列函数的 API,OpenGL 本身并非 API。
**OpenGL ES(OpenGL for Embedded Systems)**是 OpenGL 的子集,针对手机、PDA 和游戏主机等嵌入式设备而设计。该规范也是由 Khronos Group 开发维护。
OpenGL ES 去除了四边形(GL_QUADS)、多边形(GL_POLYGONS)等复杂图元,以及许多非绝对必要的特性,剩下最核心有用的部分。可以理解成是一个在移动平台上能够支持 OpenGL 最基本功能的精简规范。
本人5年iOS开发经验,曾就职于阿里巴巴。 善于把艰涩的iOS知识转化为通俗易懂的白话文字,同时也欢迎大家加入小编的iOS交流群 413038000 ,群里会提供相关面试资料,书籍欢迎大家入驻!
目前 iOS 平台支持的有 OpenGL ES 1.0,2.0,3.0。OpenGL ES 3.0 加入了一些新的特性,但是它除了需要 iOS 7.0 以上之外,还需要 iPhone 5S 之后的设备才能支持。出于现有设备的考虑,我们主要使用 OpenGL ES 2.0。
**注:**下文中的 OpenGL ES 均指代 OpenGL ES 2.0。
一、概念
1、缓存是什么
OpenGL ES 部分运行在 CPU 上,部分运行在 GPU 上,为了协调这两部分的数据交换,定义了**缓存(Buffers)**的概念。CPU 和 GPU 都有独自控制的内存区域,缓存可以避免数据在这两块内存区域之间进行复制,提高效率。缓存实际上就是指一块连续的 RAM 。
2、纹理渲染的含义
纹理是一个用来保存图像颜色的元素值的缓存,渲染是指将数据生成图像的过程。纹理渲染则是将保存在内存中的颜色值等数据,生成图像的过程。
3、坐标系
1、OpenGL ES 坐标系
OpenGL ES 坐标系的范围是 -1 ~ 1,是一个三维的坐标系,通常用 X、Y、Z 来表示。Z 轴的正方向指向屏幕外。在不考虑 Z 轴的情况下,左下角为 (-1, -1, 0),右上角为 (1, 1, 0)。
2、纹理坐标系
纹理坐标系的范围是 0 ~ 1,是一个二维坐标系,横轴称为 S 轴,纵轴称为 T 轴。在坐标系中,点的横坐标一般用 U 表示,点的纵坐标一般用 V 表示。左下角为 (0, 0),右上角为 (1, 1)。
注: UIKit 坐标系的 (0, 0) 点在左上角,其纵轴的方向和纹理坐标系纵轴的方向刚好相反。
4、纹理相关的概念
- **纹素(Texel):**一个图像初始化为一个纹理缓存后,每个像素会变成一个纹素。纹理的坐标是范围是 0 ~ 1,在这个单位长度内,可能包含任意多个纹素。
- **光栅化(Rasterizing):**将几何形状数据转换为片段的渲染步骤。
- **片段(Fragment):**视口坐标中的颜色像素。没有使用纹理时,会使用对象顶点来计算片段的颜色;使用纹理时,会根据纹素来计算。
- **映射(Mapping):**对齐顶点和纹素的方式。即将顶点坐标 (X, Y, Z) 与 纹理坐标 (U, V) 对应起来。
- **取样(Sampling):**在顶点固定后,每个片段根据计算出来的 (U, V) 坐标,去找相应纹素的过程。
- **帧缓存(Frame Buffer):**一个接收渲染结果的缓冲区,为 GPU 指定存储渲染结果的区域。更通俗点,可以理解成存储屏幕上最终显示的一帧画面的区域。
注:(U, V) 可能会超出 0 ~ 1 这个范围,需要通过
glTextParameteri()
配置相应的方案,来映射到 S 轴和 T 轴。
5、怎么使用缓存
在实际应用中,我们需要使用各种各样的缓存。比如在纹理渲染之前,需要生成一块保存了图像数据的纹理缓存。下面介绍一下缓存管理的一般步骤:
使用缓存的过程可以分为 7 步:
- **生成(Generate):**生成缓存标识符
glGenBuffers()
- **绑定(Bind):**对接下来的操作,绑定一个缓存
glBindBuffer()
- **缓存数据(Buffer Data):**从CPU的内存复制数据到缓存的内存
glBufferData()
/glBufferSubData()
- **启用(Enable)或者禁止(Disable):**设置在接下来的渲染中是否要使用缓存的数据
glEnableVertexAttribArray()
/glDisableVertexAttribArray()
- **设置指针(Set Pointers):**告知缓存的数据类型,及相应数据的偏移量
glVertexAttribPointer()
- **绘图(Draw):**使用缓存的数据进行绘制
glDrawArrays()
/glDrawElements()
- **删除(Delete):**删除缓存,释放资源
glDeleteBuffers()
这 7 步很重要,现在先有个印象,后面我们在实际例子中会反复用到。
6、OpenGL ES 的上下文
OpenGL ES 是一个状态机,相关的配置信息会被保存在一个**上下文(Context)**中,这个些值会被一直保存,直到被修改。但我们可以配置多个上下文,通过调用 [EAGLContext setCurrentContext:context]
来切换。
7、OpenGL ES 中的图元
**图元(Primitive)**是指 OpenGL ES 中支持渲染的基本图形。OpenGL ES 只支持三种图元,分别是顶点、线段、三角形。复杂的图形得通过渲染多个三角形来实现。