7

我的应用程序用于GLKit渲染 3D 场景OpenGL ES

一切正常,除了一件事。当我在 iPad 中启动我的应用程序并显示背景应用程序栏(单击两次“主页”按钮)然后更改设备的方向时,场景更新错误(最后渲染的图像被简单地拉伸以填充新矩形)。

我找到了原因。当后台应用程序栏出现时,GLKViewController's paused设置为YES自动(应用程序委托接收-applicationWillResignActive:)并且在此栏关闭之前不会进行渲染。

我在 Apple 指南(iOS 的 OpenGL ES 编程指南/实现多任务感知 OpenGL ES 应用程序)中发现,在收到-applicationWillResignActive:应用程序后应该停止 GL 渲染或将被终止。所以看起来一切都很好,除了旋转后渲染不好:)

我检查了一些 OpenGL 游戏。当此栏显示时,它们也变得“暂停”,但以某种方式正确更新了设备旋转时暂停的场景。他们如何做到这一点?

4

2 回答 2

2

tl; dr:可能您只需将GLKView's设置contentModeUIViewContentModeRedraw

首先,我认为您的应用程序实际上并没有进入后台,我认为它只是变得不活动。applicationWillResignActiveapplicationDidEnterBackground委托方法的区别。假设应用程序仅处于非活动状态,请使用以下内容,以防它实际上被置于后台,请参见下文。

苹果文档说您应该在applicationWillResignActive被调用时“降低 OpenGL ES 帧速率”,而不是不允许 OpenGL ES 调用,这仅在应用程序进入后台后发生。

这意味着GLKit's GLKView/GLKViewController在这方面可能有点过分热心。要修复它,您需要确保:

  1. GLKView设置contentModeUIViewContentModeRedraw
  2. 即使应用程序处于非活动状态但框架已更改, ' 方法也会绘制框架,但在GLKView应用drawRect程序处于后台时不绘制框架(即使用 OpenGL ES 调用)。

但是,我的假设是,drawRect当应用程序在后台时,甚至不会调用该方法,因此您可能不必担心glkView:drawInRect委托方法中的 OpenGL ES 调用。但是,在您的情况下未调用此函数的原因是视图不会失效。未失效的原因有两个:

  1. 周期性地使视图无效的主框架循环GLKViewControllerpaused属性暂停。
  2. GLKView contentMode可能是默认的“UIViewContetModeScaleToFill”

由于该GLKView drawRect方法可能甚至没有查看paused属性,因此仅更改contentMode可能就足够了。


如果应用程序确实进入后台,我会提出以下解决方案。由于在后台运行时不允许使用 OpenGL ES 调用,因此解决方案非常简单:

在进入后台之前,做所有你需要做的 OpenGL ES 调用来支持你想要的东西。

也就是说,applicationWillResignActive执行以下操作:

  1. 暂停你的游戏循环(通过设置GLKViewController's完成paused
  2. 暂停渲染循环(通过设置GLKViewController's完成paused
  3. 获取当前方向状态的当前帧缓冲区
  4. 使用对应于旋转方向状态的帧缓冲区和视口再次渲染当前游戏状态并获取该帧缓冲区

此外,您需要将GLKView'scontentMode设置为,UIViewContentModeRedraw以便drawRect在视图的框架因方向更改而更改后实际调用该方法。

最后在GLKView'sdrawRect方法中,您需要检查是否paused正常进行渲染,在这种YES情况NO下,获取保存的帧缓冲区之一并通过常规调用将其绘制到视图中。NOYESapplicationWillResignActiveUIKit

我不确定这个 hackish 解决方案与 集成的效果如何GLKit,您可能需要一些子类化。

于 2013-03-13T10:39:56.743 回答
0

实现委托方法(如果你还没有这样做的话)

-(void)applicationWillEnterForegroundGLKViewController从那里取消暂停。

根据我从您的问题中了解到的情况,您可以暂停游戏,但也可以在此方法中调整 glView 的大小,但是如果没有看到任何代码,也很难真正看到发生了什么。

于 2013-03-13T09:04:54.653 回答