OpenGL ES在iOS系统和Android系统上已经得到大规模的应用。两年多之前做过一些win下面的OpenGL ES的东西,第三方库用了GLEW,然后想弄到iOS系统上去,无奈没有找到之前的源码,也未曾了解过iOS下基于OpenGL ES的一些东西,于是就有了这篇文章。顺带整理一下知识点。
首先简要的梳理几个知识点:
1.CAEAGLLayer
详细的介绍参见苹果官方文档。这个Layer是你在iOS应用上绘制OpenGL内容的Layer。如果想要绘制OpenGL的话,要用这个Layer作为视图方法layerClass的返回值。CAEAGLLayer是为Core Animation封装的,并完全兼容OpenGL ES函数调用。换句话说,要使用OpenGL ES命令就要先创建这个Layer。
这个与View关联的类用于Graph Context绘制的目标。理解为画布就好了。为了减少性能消耗,一般将Layer的opaque属性设置为不透明,即TRUE。
2.EAGLContext
详细介绍参见苹果官方文档。EAGLContext对象用于管理OpenGL ES渲染上下文——例如状态信息、命令、以及需要使用OpenGL ES绘制的资源。想要执行OpenGL ES命令,你就需要创建一个EAGLContext对象。
需要渲染的资源,例如纹理以及渲染缓冲区,通过一个与context关联的EAGLShaderGroup对象管理。在渲染之前,必须绑定一个framebuffer对象到context。
3.帧缓冲区(frame buffer)
图形程序的目标大多就是在屏幕上绘制图形。屏幕是由一个矩形的像素组组成的,每个像素都可以在屏幕上的某个点显示一种颜色的小方块。光栅化阶段之后,数据就不再是像素,而是片段。每个片段具有与像素对应的坐标数据以及颜色和深度值。然后,经过一系列测试和操作,如果顺利通过这些测试和操作,片段值转换为像素。
为了绘制这些像素,需要知道它们的颜色。每个像素按照统一的方式存储时,存储所有像素的空间就叫做缓冲区。不同的缓冲区为每个像素存储的数据量可能不同。但是每个特定的缓冲区内,每个像素存储的数据量是一致的。
例如颜色缓冲区用于保存屏幕上所显示的颜色信息。假设屏幕宽度为w个像素,高度为y个像素,并使用24位完整颜色。那么这个屏幕可显示2^24(16777216)种颜色。因此颜色缓冲区必须为屏幕上的w x h个像素的每一个像素都存储24 / 3 = 8(3个字节)的数据。
颜色缓冲区只是众多缓冲区中的一种(例如还有深度缓冲区,模版缓冲区等)。系统的帧缓冲区是由所有这些缓冲区组成的。
由于各种操作需要在缓冲区之间大量的移动数据,这就是引入帧缓冲对象的原因所在,可以创建自己的帧缓冲区,并使用它们附带的渲染缓冲区来最小化数据复制并优化性能。
执行离屏渲染,更新纹理图像的时候,帧缓冲区对象非常有用。
窗口系统提供的帧缓冲区对象是你的图形服务器的显示系统可用的唯一帧缓冲区,也就是你自己屏幕上可以看到的唯一缓冲区。相较而言,应用程序创建的缓冲区不能在显示器上显示,只支持离屏渲染。
系统窗口提高的帧缓冲区和我们创建的帧缓冲区的另一个不同在于,当窗口创建的时候,系统窗口管理的那些缓冲区就分配他们的缓冲区——颜色、深度、模版等。而应用创建缓冲区对象的时候,需要创建与之相关联的其他缓冲区(颜色、深度等)。
4.颜色缓冲区(render buffer)
颜色缓冲区通常用于绘图。理解为存储绘制结果的缓冲区就好。一般清理屏幕的步骤是设置缓冲区的清除值。例如glClearColor设置清理颜色缓冲区的颜色值。然后再使用glClear传入相关的参数,指定清理的目标缓冲区。
例如清理屏幕操作
glClearColor(1.0, 1.0, 1.0, 1.0); // 设置清理颜色为RGBA都为1
glClear(GL_COLOR_BUFFER_BIT); // 指定清理颜色缓冲区
5.流程
首先使用Xcode创建一个空白的Single View Application。
然后需要创建一个相关的UIView用于绘制OpenGL ES资源。这里我创建了一个类DMGLview,继承UIView,并包含上述提到的CAEAGLLayer以及EAGLContext。
返回Layer对象为CAEAGLLayer
设置不透明
创建EAGLContext对象,并设置当前context为创建的glContext
创建颜色缓冲区以及帧缓冲区,并将颜色缓冲区绑定到帧缓冲区
其中glGenRenderbuffers函数用于分配一个颜色缓冲区编号(实际并未分配内存),glBindRenderBuffer函数用于分配一个颜色缓冲区空间并与glGenRenderbuffers函数所分配的编号关联起来。
- (BOOL)renderbufferStorage:(NSUInteger)target fromDrawable:(id)drawable 函数则用于绑定绘制对象,也就是将之前创建的Layer作为绘制目的地。
glGenFramebuffers函数以及glBindFrramebuffer函数大概意思和上面分配颜色缓冲区是一样的,只是分配的是帧缓冲区。
glFramebufferRenderBuffer是将刚才创建的颜色缓冲区和帧缓冲区对象附加联系起来。这样在颜色缓冲区绘制完成之后,通过如下操作将帧缓冲区结果复制到系统提供的帧缓冲区以显示出来。
在初始化OpenGL view的时候,我们可以将上述步骤都设置好
最后,不要忘记在应用初始化完成(即didFinishLaunchingWithOptions)之后,设置当前窗口的view为OpenGL view
设置视口、清理缓冲区颜色并清理缓冲区
然后再更新屏幕
如果没有错误的话,你会看到如下结果
可以在Github上下载到代码,运行环境为MacOS 10.12.4 Xcode 8.3.1
猛戳下载