iOS OpenGL ES屏幕旋转,而后台应用程序栏可见
我的应用程序使用GLKit
来渲染3D场景与OpenGL ES
。
一切正常,除了一件事。 当我在iPad中启动我的应用程序并显示后台应用程序栏(双“Home”button单击),然后更改设备的方向时,场景更新错误(最后渲染的图像被简单地拉伸以填充新的矩形)。
我find了原因。 当后台应用程序栏出现时, GLKViewController's
paused
被自动设置为YES
(应用程序委托接收到-applicationWillResignActive:
并且在该栏closures之前不会进行渲染。
我在苹果指南( iOS的OpenGL ES编程指南/实现多任务感知的OpenGL ES应用程序 )中发现,在收到-applicationWillResignActive:
应用程序应停止GL呈现或将被终止。 所以似乎一切都好,除了转动后的糟糕的渲染
我检查了一些OpenGL游戏。 当显示这个栏时,它们也变成了“暂停”,但是正确地更新了设备旋转中暂停的场景。 他们如何实现这一目标?
tl; dr:可能你只需要将GLKView
的contentMode
为UIViewContentModeRedraw
首先我不认为你的应用程序真的进入了后台,我认为它只是变得不活跃。 applicationWillResignActive
和applicationDidEnterBackground
委托方法之间的区别。 假设应用程序仅处于非活动状态,请使用以下内容,以防其实际被置于后台,请参阅下文。
苹果文档说,当调用applicationWillResignActive
时,应该“调低OpenGL ES帧速率”,而不是OpenGL ES调用不被允许,只有在应用程序进入后台后才会发生。
这意味着GLKit
的GLKView
/ GLKViewController
在这方面可能有点过分。 要解决它,你需要确保:
-
GLKView
的contentMode
设置为UIViewContentModeRedraw
-
GLKView
的drawRect
方法即使在应用程序处于非活动状态时也绘制框架,但框架已更改,但在应用程序处于后台时不绘制框架(即使用OpenGL ES调用)。
不过,我的推测是drawRect
方法在应用程序处于后台时甚至不会被调用,因此您可能不必担心glkView:drawInRect
委托方法中的OpenGL ES调用。 然而,这个函数在你的情况下不被调用的原因是视图不会失效。 不失效的原因是双重的:
-
GLKViewController
中定期使视图无效的主框架循环由paused
属性paused
。 -
GLKView
contentMode
可能是默认的“UIViewContetModeScaleToFill”
由于GLKView
drawRect
方法可能甚至没有看paused
属性,只是改变contentMode
可能已经足够了。
如果应用程序确实进入后台,我会提出以下解决scheme。 由于在后台运行时不允许使用OpenGL ES调用,因此解决scheme非常简单:
在进入后台之前,您需要执行所有OpenGL ES调用以支持所需的操作。
也就是说,在applicationWillResignActive
执行以下操作:
- 暂停你的游戏循环(通过设置
GLKViewController
的paused
) - 暂停你的渲染循环(通过设置
GLKViewController
的paused
) - 抓取当前方向状态的当前帧缓冲区
- 使用与旋转的方向状态对应的帧缓冲区和视口再次渲染当前游戏状态,并抓取该帧缓冲区
此外,您需要将GLKView
的contentMode
设置为UIViewContentModeRedraw
以便在通过方向更改更改视图的框架之后实际调用drawRect
方法。
最后,在GLKView
的drawRect
方法中,您需要检查在paused
是YES
还是NO
的情况下,在正常的情况下,在YES
情况下,保存在applicationWillResignActive
中的帧缓冲区之一,并使用常规UIKit
调用将其绘制到视图。
我不确定这个GLKit
解决scheme与GLKit
整合的GLKit
,你可能需要一些子类。
实现委托方法(如果你还没有完成)
-(void)applicationWillEnterForeground
并从那里取消暂停GLKViewController
。
从我所了解的问题中,您可以保持游戏暂停,但是也可以用这种方法调整glView的大小,但是看不到任何代码也很难真正看到发生了什么。