我们先了解一下 iOS 中管理 OpenGL ES 渲染循环的视图控制器 - GLKViewController
A GLKViewController object works in conjunction with a GLKView object to display frames of animation in the view, and also provides standard view controller functionality.
To use this class, allocate and initialize a new GLKViewController subclass and set its view property to point to a GLKView object. Then, configure the view controller’s preferredFramesPerSecond property to the desired frame rate your application requires. You can set a delegate or configure other properties on the view controller, such as whether the animation loop is automatically paused or resumed when the application moves into the background.
Subclassing Notes
Your application should subclass GLKViewController and override the viewDidLoad and viewDidUnload methods. Your viewDidLoad method should set up your context and any drawable properties and can perform other resource allocation and initialization. Similarly, your class’s viewDidUnload method should delete the drawable object and free any unneeded resources.
As an alternative to implementing a glkViewControllerUpdate: method in a delegate, your subclass can provide an update method instead. The method must have the following signature:
子类注意:
你的应用程序应该集成自 GLKViewController,并且重写 viewDidLoad 和 viewDidUnload 方法。在 viewDidLoad 中设置视图的上下文和初始化任何绘画可执行属性。同样,在 viewDidUnload 方法中可以删除绘制对象和释放不必要的资源。
glkViewControllerUpdate 作为一个可供选择实现的方法,在代理方法中,子类可以提供一个更新的方法代替,方法必须具备以前特征: - (void)update
属性:
preferredFramesPerSecond: 设置视图更新内容的速率, 默认值为 30
framesPerSecond: 视图更新内容实际速率, 只读属性
delegate: 设置代理对象
paused:bool 值,设置暂停
pauseOnWillResignActive: bool 值,表示当控制器挂起状态时是否自动暂停渲染循环,默认 YES
resumeOnDidBecomeActive: bool 值,表示当控制器激活时是否自动恢复渲染循环,默认 YES
获取关于视图更新的信息(可读属性)
framesDisplayed:视图控制器自创建以来已发送的帧更新数。
timeSinceFirstResume:自第一次视图控制器恢复发送更新事件以来所经过的时间量。
timeSinceLastResume:自上一次视图控制器恢复发送更新事件以来所经过的时间量。
timeSinceLastUpdate:自从上次视图控制器调用代理方法 glkviewcontrollerupdate 经过的时间量
timeSinceLastDraw:自上次视图控制器调用视图的 display 方法以来所经过的时间量。
** OpenGL ES 渲染视图 **
GLKView:使用 opengl 绘制内容的默认实现视图
剩下两个代理属性:GLKViewDelegate 和 GLKViewControllerDelegate
关于 GLKViewController 就说这么多,接下来的 OpenGL ES 学习我们都是基于 GLKViewController 环境实现的,因为苹果的封装我们可以省掉一些基本的配置,比如生成默认的 FrameBufferObject
开始项目:
在新建工程完毕,我们需要做几处修改。首先导入 GLKit,修改当前控制器集成自 GLKViewController,如下:
然后修改 Main.storyboard 中控制器 view 的 class 为 GLKView,如下
这里我们了解一下 OpenGL 的渲染流程:
最开始的输入是顶点数据。比如三角形,就是三个点。每个顶点数据可以包含任意数量的信息,最基本的有位置,颜色。后面介绍贴图时还会包含 UV 信息。经过各种处理,最终放入 FrameBuffer。
第一步定义顶点坐标数据:
// 定义C结构体用来保存GLKVector3类型的成员position
typedef struct {
GLKVector3 position;
} Vertex;
// C数组存储三角形顶点坐标,每个GLKVector3变量代表一个坐标点的X、Y和Z
static const Vertex vertices[] = {
{{ 0.0, 0.5, 0.0}},
{{ -0.5, -0.5, 0.0}},
{{ 0.5, -0.5, 0.0}},
};
第二步初始化和设置当前视图的 EAGLContext 对象:
// 将当前view强制转换为GLKView
GLKView *view = (GLKView *)self.view;
// 断言,检测用storyboard加载的视图是否是GLKView
NSAssert([view isKindOfClass:[GLKView class]], @"View controller's View is not a GLKView");
// 初始化context为OpenGL ES 2.0
view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
// 在任何其他的OpenGL ES配置或者渲染发生前,应用的GLKView实例的上下文属性都需要设置为当前
[EAGLContext setCurrentContext:view.context];
还需要出实话baseEffect属性,
/*
GLKBaseEffect 是GLKit提供的另一个内建类。GLKBaseEffect的存在是为了简化OpenGL ES的很多常用操作。
在OpenGL ES 2.0中,如果没有GLKit和GLKBaseEffect类,完成这个简单的例子需要用着色器语言编写一个GPU程序。
*/
@property (nonatomic, strong) GLKBaseEffect *baseEffect;
self.baseEffect = [[GLKBaseEffect alloc] init];
self.baseEffect.useConstantColor = GL_TRUE;
self.baseEffect.constantColor = GLKVector4Make(1.0, // red
0.0, // green
0.0, // blue
0.0); // alpha
// 设置当前OpenGL ES的上下文"清除颜色",用于在上下文的帧缓存被清除时初始化每个想色的颜色值
glClearColor(0.0, 0.0, 0.0, 1.0);
GLKBaseEffect 类提供了不依赖所使用的 OpenGL ES 版本的控制 OpenGL ES 渲染方法,会在需要的时候自动地构建 GPU 程序并极大地简化本例。控制渲染像素颜色的方式有很多中,这个应用的 GLKBaseEffect 使用恒定红色来渲染三角形,所以三角形中的每一个像素都是相同的颜色。上面的 constantColor 定义为 C 数据结构体 GLKVector4Make 设置的 4 个颜色元素值。
// 声明GLuint类型变量,用于存放本例中顶点数据的缓存标识符
GLuint vertexBufferID;
glGenBuffers(1, &vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);