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

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

问题描述

这最近一直困扰着我.将支持纵向和横向的 OpenGL ES 应用程序放在一起非常简单.但是在自动旋转过程中,系统似乎只是强制将渲染缓冲区拉伸到新尺寸一次,自动旋转,然后调用通常的 -layoutSubviews -> -resizeFromLayer: 等.因此可以将可绘制对象调整为新的视口尺寸.

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 的常用方法),一旦渲染缓冲区扩展"到最长屏幕尺寸的完美正方形(例如,1136px x 1136px在 iPhone 5 上) - 使其流血"离开屏幕,执行自动旋转(没有渲染缓冲区大小变化,因此没有拉伸,就像在两个横向方向之间切换时一样),最后再次调整帧缓冲区以处理不可见的, 浪费"了屏幕外边距?(当然我可以一直有一个方形的帧缓冲区,但这会降低填充率)

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天全站免登陆