版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.07.22 |
前言
OpenGL 图形库项目中一直也没用过,最近也想学着使用这个图形库,感觉还是很有意思,也就自然想着好好的总结一下。首先要给大家介绍个学习网站。
1. 欢迎来到OpenGL的世界
2.系列教程
3.教程代码
4.落影简书
OpenGL ES基础
OpenGL ES
是一套多功能开放标准的用于嵌入系统的C-based
的图形库,用于2D
和3D
数据的可视化。OpenGL
被设计用来转换一组图形调用功能到底层图形硬件(GPU)
,由GPU
执行图形命令,用来实现复杂的图形操作和运算,从而能够高性能、高帧率利用GPU
提供的2D
和3D
绘制能力。
OpenGL ES
规范本身不定义绘制表面和绘制窗口,因此ios为了使用它必须提供和创建一个OpenGL ES
的呈现环境,创建和配置存储绘制命令结果的framebuffer
及创建和配置一个或多个呈现目标。在 iOS中使用EAGL
提供的EAGLContext
类 来实现和提供一个呈现环境,用来保持OpenGLES
使用到的硬件状态。 EAGL
是一个Objective-C API
,提供使OpenGL ES
与Core Animation
和UIKIT
集成的接口。
在调用任何OpenGL ES
功能之前必须首先初始化一个EAGLContext
对象。每一个iOS应用的每一个线程都有一个当前context
,在调用OpenGLES
函数时,使用或改变此context
中的状态。EAGLContext
的类方法setCurrentContext:
用来设置当前线程的当前context
。EAGLContext
的类方法currentContext
返回当前线程的当前context
。在切换相同线程的两个上下文之前,必须调用glFlush
函数来确保先前已提交的命令被提交到图形硬件中。
可以采用不同的方式使用OpenGL ES
以便呈现OpenGL ES
内容到不同的目标:GLKit
和CAEAGLLayer
。为了创建全屏幕的视图或使OpenGL ES
内容与UIKit
视图集成,可以使用GLKit
。在使用GLKit
时,GLKit
提供的类GLKView
类本身实现呈现目标及创建和维护一个framebuffer
。
为了使OpenGL ES
内容作为一个Core Animation
层的部分内容时,可以使用CAEAGLLayer
作为呈现目标,并需要另外创建framebuffer
以及自己实现和控制整个绘制流程。
GLKit
是一组objective-c
类,为使用OpenGL ES
提供一个面向对象接口,用来简化OpenGL ES
应用的开发。GLKit
支持四个3D
应用开发的关键领域:
-
GLKView
和GLKViewController
类提供一个标准的OpenGL ES
视图和相关联的呈现循环。GLKView
可以作为OpenGL ES
内容的呈现目标,GLKViewController
提供内容呈现的控制和动画。视图管理和维护一个framebuffer
,应用只需在framebuffer
进行绘画即可。 -
GLKTextureLoader
为应用提供从iOS支持的各种图像格式的源自动加载纹理图像到OpenGL ES
图像环境的方式,并能够进行适当的转换,并支持同步和异步加载方式。 - 数学运算库,提供向量、矩阵、四元数的实现和矩阵堆栈操作等
OpenGL ES 1.1
功能。 -
Effect
效果类提供标准的公共着色效果的实现。能够配置效果和相关的顶点数据,然后创建和加载适当的着色器。GLKit
包括三个可配置着色效果类:GLKBaseEffect
实现OpenGL ES 1.1
规范中的关键的灯光和材料模式,GLKSkyboxEffect
提供一个skybox
效果的实现,GLKReflectionMapEffect
在GLKBaseEffect
基础上包括反射映射支持。
GLKView和OpenGL ES绘制过程
使用GLKView和OpenGLES进行绘制过程:
创建一个
GLKView
对象。
GLKView
对象可以编程或使用Interface Builder
来创建和配置。在采用编程方式时,首先创建一个context
然后调用initWithFrame:context:
方法。使用Interface Builder
方式时,在从storyboard
加载一个GLKView
后,创建一个context
和设置它作为视图的context
属性。在iOS
中GLKit
的使用需要创建OpenGL ES 2.0
以上的图形环境context
。GLKit
视图自动创建和配置它所有的OpenGLES framebuffer
对象和renderbuffers
,可以通过修改视图的drawable
属性来控制这些对象的属性。-
绘制
OpenGL
内容(发布绘制命令)
使用GLKit
视图绘制OpenGL
内容需要三个子步骤:- 准备
OpenGL ES
基础; - 发布绘制命令;
- 呈现显示内容到
Core Animation
。
- 准备
GLKit
类本身已经实现了第一个和第三个步骤,用户只需实现第二个步骤,在视图的方法drawRect
或视图的代理对象的glkView:drawInRect:
中调用适当的OpenGL ES
绘制命令进行内容绘制。GLKViewController
类维护一个animation
呈现循环(包含两个方法update
和display
),用来实现连续的动画复杂的场景。animation
呈现循环的交替速率由GLKViewController
的属性framesPerSecond
指示,并使用preferredFramesPerSecond
属性来修改它。
OpenGL ES版本
iOS
系统默认支持OpenGl ES1.0
、ES2.0
以及ES3.0
3个版本,三者之间并不是简单的版本升级,设计理念甚至完全不同,在开发OpenGL
项目前,需要根据业务需求选择合适的版本。在学习OpenGL
代码的时候也需要知道它对应着哪个版本,在ES1
中执行ES2
代码是看不到任何效果的,你可以在初始化EAGLContext
时指定ES
版本号。
指定版本方法如下所示。
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
OpenGL ES坐标系
OpenGL ES
坐标系和UI
的坐标系是不同的,具体如下所示。
UI
是以左上角为原点的,而OpenGL ES
坐标系是以屏幕中心为原点的。除了方向,还有一点需要注意,默认情况各个方向坐标值范围为(-1,1)
,而不是UIKit
中的(0,320)
。当绘制点(320,0)
时,它并不会出现在屏幕右上角。在ES1
中,可以通过以下代码将坐标系转化为熟悉的(320,480)
。下面我们看代码。
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glViewport(0, 0, rect.size.width * 2, rect.size.height * 2);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(0, 320, 0, 480, -1024, 1024);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
几个重要的类
下面介绍几个重要的类。
1. GLKViewController & GLKView
为了方便大家更快的开发,系统为OpenGL
提供了简单的封装,继承GLKViewController
定义自己的ViewController
,GLKViewController
的view
为GLKView
类,GLKView
的delegate
定义了绘制回调函数。
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
GLKViewController
定义数据刷新函数,当子类实现-(void)update
方法,glkViewControllerUpdate
方法将不再被调用。
- (void)glkViewControllerUpdate:(GLKViewController *)controller
需要补充一点,默认情况下,GLKViewController
渲染RunLoop
并非NSRunLoopCommonModes
,而是NSDefaultRunLoopMode
,因此在UIKit
中使用GLKViewController
,当滑动界面时,OpenGL
是不会渲染的。
2. EAGLContext
在介绍选择版本时已经提到EAGLContext
,与UIKit
中CGContextRef
相似,EAGLContext
相当于OpenGL
绘制句柄或者上下文,在绘制试图之前,需要指定使用创建的上下文绘制。
[EAGLContext setCurrentContext:view.context];
当一个APP可能存在多个EAGLContext
时,需要处理并存冲突等问题,比如大家所熟知的GPUImage,都会使用到EAGLContext
。因此,在使用中要记得及时释放。有兴趣的朋友可以看看这篇文章。
这里还需要记住的是:当App退到后台时, 切记暂停OpenGL
绘制,否则可能导致crash
。
后记
这篇主要是基本的介绍和几个基础概念,后面还会继续给大家扩展,毕竟基础的部分是固定的。未完,待续~~~