iOS OpenGL ES屏幕旋转,而后台应用栏可见 [英] iOS OpenGL ES screen rotation while background apps bar visible

查看:129
本文介绍了iOS OpenGL ES屏幕旋转,而后台应用栏可见的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用使用 GLKit OpenGL ES 呈现3D场景。



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



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



我'在Apple指南中找到(适用于iOS的OpenGL ES编程指南/实现支持多任务的OpenGL ES应用程序)在收到 -applicationWillResignActive:应用程序后,应停止GL渲染或终止。所以看起来一切都还好,除了旋转后的糟糕渲染:)



我检查了一些OpenGL游戏。当显示此栏时,它们也会暂停,但不知何故正确更新设备旋转时暂停的场景。他们是如何实现这一目标的?

解决方案

tl; dr:可能你只需要设置 GLKView 's contentMode to UIViewContentModeRedraw



<首先,我不认为您的应用程序实际进入后台,我认为它只会变为非活动状态。 applicationWillResignActive applicationDidEnterBackground 委托方法之间的区别。假设应用程序仅处于非活动状态,请使用以下内容,以防它实际放入后台,然后参见下文。



Apple文档说你应该减少OpenGL ES框架当 applicationWillResignActive 被调用时,不会允许OpenGL ES调用,只有在应用程序进入后台后才会发生。



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


  1. GLKView 's contentMode 设置为 UIViewContentModeRedraw

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

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


  1. GLKViewController中的主框架循环 暂停属性会暂时使视图无效。

  2. GLKView contentMode 可能是默认的'UIViewContetModeScaleToFill'

作为 GLKView drawRect 方法可能甚至没有查看暂停的属性,只是更改 contentMode 可能已足够。






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



您需要执行所有OpenGL ES调用以支持您的操作在你输入背景之前想要。



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


  1. 暂停游戏循环(通过设置 GLKViewController 暂停

  2. 暂停渲染循环(通过设置 GLKViewController 暂停

  3. 获取当前方向状态的当前帧缓冲区

  4. 使用帧缓冲区和视口再次渲染当前游戏状态对应于旋转的方向状态并抓住该帧缓冲区

此外,您需要 GLKView contentMode 设置为 UIViewContentModeRedraw 以便 drawRect 方法实际上是通过方向更改更改了视图框架后调用。



最后在 GLKView drawRect 您需要检查暂停的方法是还是 NO NO 的情况下,正常情况下,在 YES 的情况下进行渲染取一个保存在 applicationWillResignActive 中的帧缓冲区,并使用常规 UIKit 调用将其绘制到视图中。



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


My app uses GLKit to render 3D scene with OpenGL ES.

All works fine, except one thing. When I launch my app in iPad and display background apps bar (with double "Home" button click) and then change device's orientation, scene is updated wrongly (last rendered image is simply stretched to fill new rectangle).

I found the reason. When background apps bar appears, GLKViewController's paused is set to YES automatically (application delegate receives -applicationWillResignActive:) and no rendering happens until this bar is closed.

I've found in Apple guides (OpenGL ES Programming Guide for iOS / Implementing a Multitasking-aware OpenGL ES Application) that after receiving -applicationWillResignActive: application should stop GL rendering or will be terminated. So it seems that all is ok, except bad rendering after rotation :)

I checked some OpenGL games. They also became "paused" when this bar displayed, but somehow correctly update paused scene on device rotation. How do they achieve this?

解决方案

tl;dr: possibly you only need to set the GLKView's contentMode to UIViewContentModeRedraw

Firstly I don't think that your application actually enters into the background, I think it only becomes inactive. The distinction between the applicationWillResignActive and applicationDidEnterBackground delegate methods. Assuming that the application is only inactive use the following, in case it actually gets put in the background then see below.

The apple documentation says that you should "throttle down OpenGL ES framerates" when applicationWillResignActive gets called, not that OpenGL ES calls are not allowed, that only happens after the application goes into the background.

This means that GLKit's GLKView/GLKViewController may be a bit overzealous in this regard. To fix it you need to make sure that:

  1. The GLKView's contentMode is set to UIViewContentModeRedraw
  2. The GLKView's drawRect method does draw the frame even when the application is inactive but the frame is changed, but does not draw the frame (that is use OpenGL ES calls) when the application is in the background.

However, my presumption is that the drawRect method does not even get called when the application is in the background, so you probably don't really have to worry about the OpenGL ES calls in the glkView:drawInRect delegate method. The reason however that this function does not get called in your situation is that the view does not get invalidated. The reason for not being invalidated is twofold:

  1. The main frame loop in GLKViewController that invalidates the view periodically is paused by the paused property.
  2. The GLKView contentMode is probably the default 'UIViewContetModeScaleToFill'

As the GLKView drawRect method is probably not even looking at the paused property, just changing the contentMode may already be enough.


I would propose the following solution if the application actually does go into the background. As you're not allowed to use OpenGL ES calls while running in the background the solution is pretty straightforward:

Do all OpenGL ES calls you need to do to support what you want before you enter the background.

That is, in applicationWillResignActive do the following:

  1. Pause your game loop (done by setting GLKViewController's paused)
  2. Pause your render loop (done by setting GLKViewController's paused)
  3. Grab the current framebuffer for the current orientation state
  4. Render the current game state one more time with a framebuffer and viewport that correspond to the rotated orientation state and grab that framebuffer

Furthermore you need GLKView's contentMode to be set to UIViewContentModeRedraw so that the drawRect method is actually called after the view's frame has been changed by the orientation change.

Finally in GLKView's drawRect method you need to check whether paused is YES or NO in the NO case do the rendering as normal, in the YES case take one of the framebuffers saved in applicationWillResignActive and draw it to the view with regular UIKit calls.

I'm not sure how well this hackish solution would integrate with GLKit, you might need some subclassing.

这篇关于iOS OpenGL ES屏幕旋转,而后台应用栏可见的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆