用OpenGL ES and GLKit绘制 译文

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视图,一个GLKitview 渲染安装命令渲染。当您的视图第一次显示时,它调用您的绘图方法-核心动画缓存渲染输出,当你的view显示的时候就展示它。当你想改变你的view的内容,调用setNeedsDisplay方法和view再次调用你的绘图方法,得到的图像缓存,并呈现在屏幕上。当渲染图像很少变化或仅响应用户操作时,这种方法非常有用。只在需要时才呈现新视图内容,您就可以在设备上保存电池电量,并为设备执行其他操作留出更多的时间。

图片发自简书App

创建和配置一个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渲染过程的标准部分:

  1. 在调用 绘制方法前
    1. 设置上下文
    2. 根据当前的大小,绘制属性,创建framebuffer 和renderbuffers 对象
    3. 绑定framebuffers对象为当前的绘制命令的目标
    4. 根据framebuffer的大小设置viewport
  1. 绘制方法return后
    1. 解决多重采样buffers
    2. 丢弃 内容不再需要rederbuffers
    3. 把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显示了动画循环的简化示例:

图片发自简书App

理解这个动画循环

在更新阶段,视图控制器调用自己的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:方法中,它提供了这些矩阵的着色器程序并提交绘图命令来渲染地球几何。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容