GLKit
框架提供的视图和视图控制器类(消除了 OpenGL ES绘图和动画内容要求的安装和维护的代码)。GLKView
类管理的OpenGL ES的基础设施 提供书写绘图代码的地方,GLKViewController
类提供了一个可以平滑的动画GLKView内容的渲染循环。这些类扩展标准UIKit设计模式的内容和管理视图查看演示。结果,你可以把你的精力集中在你的OpenGL ES渲染主要 代码和得到您的应用程序的快速启动和运行。的glkit框架还提供了其他功能 OpenGL ES 2和3易发展。
GLKit View 按要求绘制OpenGL ES 内容
GLKView类提供了一个以 OpenGL ES为基础的和UIView等同的绘图循环。一个UIView的实例自动配置它的图形上下文,所有你只需要实现drawRect:
方法 书写Quartz 2D绘图命令,同样地一个GLKView
实例自动配置本身,所有你的绘图的方法只需要执行OpenGL ES绘图命令 。glkview
类提供了这个功能,是通过保持一个framebuffer对象,这个framebuffer对象保存你的OpenGL ES绘图命令的结果,一旦你的绘图方法结束就自动的把这些结果送到CoreAnimation
。
像一个标准的UIKit视图,一个GLKit
view 渲染安装命令渲染。当您的视图第一次显示时,它调用您的绘图方法-核心动画缓存渲染输出,当你的view显示的时候就展示它。当你想改变你的view的内容,调用setNeedsDisplay
方法和view再次调用你的绘图方法,得到的图像缓存,并呈现在屏幕上。当渲染图像很少变化或仅响应用户操作时,这种方法非常有用。只在需要时才呈现新视图内容,您就可以在设备上保存电池电量,并为设备执行其他操作留出更多的时间。
创建和配置一个GLkit View
您可以创建和配置一个glkview对象以编程方式或使用界面生成器。在你绘制之前,你必须把它关联一个上下文context。
- 当创建一个view时,首先创建一个context,然后把它传递给视图的
initWithFrame:context:
方法。 - After loading a view from a storyboard, create a context and set it as the value of the view’s context property.
一个glkitview自动创建和配置自己的OpenGL ES framebuffer对象和渲染缓存renderbuffers。你通过view 的drawable 属性去控制这些对象的属性,如清单3-1。如果你改变大小,规模因素,或一个glkit观冲性能,当下一次渲染内容的时候它会自动删除并重新创建适当的帧缓冲对象和渲染缓存。
- (void)viewDidLoad
{
[super viewDidLoad];
// Create an OpenGL ES context and assign it to the view loaded from storyboard
GLKView *view = (GLKView *)self.view;
view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
// Configure renderbuffers created by the view
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
view.drawableStencilFormat = GLKViewDrawableStencilFormat8;
// Enable multisampling
view.drawableMultisample = GLKViewDrawableMultisample4X;
}
您可以开源glkview实例的多重采样使用的drawablemultisample属性。方法是一种反锯齿,锯齿状边缘平滑,改善图像质量在大多数3D应用程序在使用更多的内存和片段处理的时间成本如果您启用了多采样,总是测试您的应用程序的性能以确保它仍然是可以接受的。
绘制GLKit View
上图概述了OpenGL ES绘图 内容的三个步骤:准备OpenGL ES的基础设施 ,发行的绘图命令,并将呈现的内容为核心的动画显示。glkview类实现的第一个和第三个步骤。对于第二步,您将在清单3-2中实现示例方法的绘图方法。
- (void)drawRect:(CGRect)rect
{
// Clear the framebuffer
glClearColor(0.0f, 0.0f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw using previously configured texture, shader, uniforms, and vertex array
glBindTexture(GL_TEXTURE_2D, _planetTexture);
glUseProgram(_diffuseShading);
glUniformMatrix4fv(_uniformModelViewProjectionMatrix, 1, 0, _modelViewProjectionMatrix.m);
glBindVertexArrayOES(_planetMesh);
glDrawElements(GL_TRIANGLE_STRIP, 256, GL_UNSIGNED_SHORT);
}
OpenGL ES glClear函数暗示,任何现有的帧缓冲区的内容可以被丢弃,避免昂贵的内存操作以前的内容加载到内存中。为了确保最佳性能,您应该在绘图前调用此函数。
glkview类能够提供 OpenGL ES绘制简单的接口是因为它管理OpenGL ES渲染过程的标准部分:
- 在调用 绘制方法前
- 设置上下文
- 根据当前的大小,绘制属性,创建framebuffer 和renderbuffers 对象
- 绑定framebuffers对象为当前的绘制命令的目标
- 根据framebuffer的大小设置viewport
- 绘制方法return后
- 解决多重采样buffers
- 丢弃 内容不再需要rederbuffers
- 把renderbuffer 内容提交到核心动画缓存和展示
用代理绘制
许多OpenGL app 在子类中实现绘制代码。这个方式的好处是可以通过定义不同的子类实现多种绘制算法。
GLKit 适应这种方式。你可以把你的渲染对象设置成标准的GLKView对象的代理。与子类化GLKView和实现drawRect方法相反,你的渲染类遵循GLKViewDelegate协议并实现
glkView:drawInRect:
方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Create a context so we can test for features
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
[EAGLContext setCurrentContext:context];
// Choose a rendering class based on device features
GLint maxTextureSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
if (maxTextureSize > 2048)
self.renderer = [[MyBigTextureRenderer alloc] initWithContext:context];
else
self.renderer = [[MyRenderer alloc] initWithContext:context];
// Make the renderer the delegate for the view loaded from the main storyboard
GLKView *view = (GLKView *)self.window.rootViewController.view;
view.delegate = self.renderer;
// Give the OpenGL ES context to the view so it can draw
view.context = context;
return YES;
}
一个GLKit View Controller 动画OpenGL ES 内容
默认的,一个glkview 对象按照命令渲染内容。就是说,使用OpenGL ES 绘制的一个关键好处是可以使用GPU去处理复杂场景的连续的动画,比如游戏。
对于这些情况,该glkit框架提供了一个视图控制器类,复杂对glkview维护一个动画循环。这个循环遵循游戏和模拟中常见的设计模式,分为两个阶段:更新和显示。图3-2显示了动画循环的简化示例:
理解这个动画循环
在更新阶段,视图控制器调用自己的update方法(或其委托的glkviewcontrollerupdate:方法)。在这方法中,您应该准备绘制下一帧。例如,一个游戏可能会使用这种方法来确定玩家和敌人的角色的基础上收到的输入事件在上一帧的基础上,和一个科学的可视化可能会使用这种方法来运行其模拟的一个步骤。如果你需要时间信息来确定下一帧你的应用程序的状态,使用一个视图控制器的时序特性,如timesincelastupdate属性。
对于显示阶段,视图控制器调用视图的display方法,该方法反过来调用绘制方法。在你的绘图方法,你提交的OpenGL ES 绘图命令GPU渲染你的内容。为获得最佳性能,您的应用程序应该修改OpenGL ES渲染 对象在一个新的框架开始,并提交绘图命令之后。在图3-2中,显示阶段将着色器程序中的统一变量设置为在更新阶段计算的矩阵,然后提交绘图命令以呈现新内容。
这个动画循环在这两种状态中来回切换,根据vc的framesPerSecond属性来设置速度。你可以通过设置preferredFramesPerSecond
属性来设置frame rate,但是vc会自动选择一个最优的frame rate 尽可能靠近你的选择。
为了最好的结果: 选择一个 你的app 能一直保持的frame rate 。一个平滑的持续的frame rate 比一个不规律的变化的frame rate 有更好的用户体验。
使用GLKit 视图 控制器
清单3-4显示典型的策略 OpenGL ES渲染动画的内容进行glkviewcontroller类和glkview实例。
清单3-4 使用glkit视图和视图控制器来绘制和动画OpenGL ES的内容
@implementation PlanetViewController // subclass of GLKViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Create an OpenGL ES context and assign it to the view loaded from storyboard
GLKView *view = (GLKView *)self.view;
view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
// Set animation frame rate
self.preferredFramesPerSecond = 60;
// Not shown: load shaders, textures and vertex arrays, set up projection matrix
[self setupGL];
}
- (void)update
{
_rotation += self.timeSinceLastUpdate * M_PI_2; // one quarter rotation per second
// Set up transform matrices for the rotating planet
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeRotation(_rotation, 0.0f, 1.0f, 0.0f);
_normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL);
_modelViewProjectionMatrix = GLKMatrix4Multiply(_projectionMatrix, modelViewMatrix);
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
// Clear the framebuffer
glClearColor(0.0f, 0.0f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Set shader uniforms to values calculated in -update
glUseProgram(_diffuseShading);
glUniformMatrix4fv(_uniformModelViewProjectionMatrix, 1, 0, _modelViewProjectionMatrix.m);
glUniformMatrix3fv(_uniformNormalMatrix, 1, 0, _normalMatrix.m);
// Draw using previously configured texture and vertex array
glBindTexture(GL_TEXTURE_2D, _planetTexture);
glBindVertexArrayOES(_planetMesh);
glDrawElements(GL_TRIANGLE_STRIP, 256, GL_UNSIGNED_SHORT, 0);
}
@end
在这个例子中,planetviewcontroller类的一个实例(一个自定义glkviewcontroller子类)是从sb中加载,有一个GLKView 实例属性和绘制属性。viewDidLoad方法中创建一个OpenGL ES context 并设置view,并设置动画循环的framerate。
vc自动设置成view的delegate,因此它实现了动画循环的更新和显示阶段的方法。在update方法中,它计算显示旋转行星所需的变换矩阵。在glkview:drawinrect:
方法中,它提供了这些矩阵的着色器程序并提交绘图命令来渲染地球几何。