如何避免iOS OpenGL ES应用程序自动旋转的瞬间拉伸 [英] How to avoid momentary stretching on autorotation of iOS OpenGL ES apps

查看:329
本文介绍了如何避免iOS OpenGL ES应用程序自动旋转的瞬间拉伸的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这最近让我烦恼。将一个支持纵向和横向的OpenGL ES应用程序组合在一起非常简单。
但是在自动旋转期间,系统似乎只是强制将渲染缓冲区拉伸到新维度一次,自动旋转,然后调用通常的 -layoutSubviews - > -resizeFromLayer:等因此可以将drawables调整为新的视口尺寸。

This has been bugging me recently. It is quite straightforward to put together an OpenGL ES app that supports both portrait and landscape. But during autorotation, the system seems to just forcibly stretch the render buffer to the new dimensions once, autorotate, and then call the usual -layoutSubviews -> -resizeFromLayer: etc. so the drawables can be adjusted to the new viewport dimensions.

我见过的大多数应用程序支持肖像和风景似乎都适合这种简单的方法。但是我想知道我能不能做得更好......

Most apps I've seen that support both portrait and landscape seem to settle for this easy approach. But I wonder if I can do better...

也许我应该在它发生之前拦截自转(使用 UIViewController 通常的方法),一旦渲染缓冲区扩展到最长屏幕尺寸的完美正方形(例如,iPhone 5上的1136px x 1136px) - 这样它就会脱离屏幕,执行自动旋转(无渲染缓冲区)尺寸变化,因此没有拉伸,就像你在两个横向方向之间切换一样),最后再次调整帧缓冲,将屏幕上隐形的浪费边缘处理掉? (当然我可以一直有一个方形的帧缓冲,但这样的填充效率会很低)

Perhaps I should intercept the autorotation before it happens (using UIViewController's usual methods), "expand" once the render buffer to a perfect square of the longest screen size (e.g., 1136px x 1136px on an iPhone 5) - so that it 'bleeds' off screen, perform the autorrotation (no renderbuffer size change and hence no stretching, just as when you switch between e.g. two landscape orientations), and finally adjust the framebuffer again to dispose the invisible, "wasted" margins off screen? (of course I could have a square framebuffer all along, but that would be inefficient fillrate-wise)

有什么建议吗?有没有想过要做到这一点的更好的方法?

Any suggestions? Any better way to accomplish this that I haven't thought about?

编辑

我修改了我的 -resizeFromLayer:代码,如下所示:

I modified my -resizeFromLayer: code as follows:

CGRect bounds = [layer bounds];

// Enlarge layer to square of the longest side:
if (bounds.size.width < bounds.size.height) {
    bounds.size.width = bounds.size.height;
}
else{
    bounds.size.height = bounds.size.width;
}

[layer setBounds:bounds];


// Adjust size to match view's layer:
[_mainContext renderbufferStorage:GL_RENDERBUFFER
                         fromDrawable:(CAEAGLLayer*) [_view layer]];

// Query the new size:
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH,  &_backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);

// (etc., you know the drill...)

......它的确有效!就目前而言,我一直有一个浪费的,屏幕外的方形渲染缓冲区,但这只是一个概念证明。
在生产代码上,我会在自动旋转之前执行调整大小调整,然后重新调整屏幕尺寸。

...And it works! As it stands right now, I have a wasteful, off-screen-bleeding square renderbuffer all along, but this is just a proof of concept. On production code, I would perform said resizing-to-square just before autorotation, and resize back to screen dimensions afterwards.

推荐答案

我设法通过从GLKView presentationLayer 获取视图大小,在我的3D应用程序中相当容易地解决了这个问题。这将在旋转动画期间给出当前视图大小,并且可以在更新步骤期间基于该大小计算正确的投影矩阵。这可以防止任何不正确的宽高比失真。

I managed to fix this fairly easily in my 3D app by fetching the view size from the GLKView presentationLayer. This will give the current view size during the rotation animation, and the correct projection matrix can be calculated based on this size during the update step. This prevents any incorrect aspect ratio distortion.

如果您想尝试这个,可以在Xcode中将以下行添加到OpenGL Game模板中:

If you want to try this, you can add the following lines to the OpenGL Game template in Xcode:

- (void)update
{
    // get the size from the presentation layer, so that animating does not squish
    CALayer *presentationLayer = [self.view.layer presentationLayer];
    CGSize layerSize = presentationLayer.bounds.size;
    float aspect = fabsf(layerSize.width / layerSize.height);
    GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 0.1f, 100.0f);

    ...
}

这篇关于如何避免iOS OpenGL ES应用程序自动旋转的瞬间拉伸的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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