iOS下使用OpenGL 如果使用GLKit View 那么不用担心屏幕旋转的问题,说明如下:

If you change the size, scale factor, or drawable properties of a GLKit view, it automatically deletes and re-creates the appropriate framebuffer objects and renderbuffers the next time its contents are drawn.

GLKit view 自动设置好了 framebuffer 和 renderbuffer 对象,使用者直接设置具体的OpenGL 参数即可。但是GLKit view 在iOS10 下存在一些问题,不能使用,只能继承最简单的UIView,那么所有相关的设置都需要自己完成。

屏幕旋转时需要做的事

现在要自己处理屏幕旋转的事件。这一部分主要讲在屏幕旋转后我们需要做什么事情来让原来的图像以新的屏幕尺寸显示出来。如果参考Android的设计,解决思路就是在屏幕旋转的时候将所有的对象销毁再根据当前的屏幕状态重新创建。简单粗暴但是效率不行。我想不销毁对象的情况下,直接重新设置宽高数据让OpenGL绘制出正确的图像。于是我调用了如下的函数:

    glViewport(0, 0, (GLsizei) (size.width * scale), (GLsizei) (size.height * scale));
_renderController->InitUniforms((int) (size.width * scale), (int) (size.height * scale));

首先设置viewport 然后第二行 InitUniforms 函数具体做的事情就是重新设置投影矩阵。很遗憾,这样的做法没有效果,将屏幕从竖屏旋转到横屏时,得到的结果如下:

上半部分什么也没有,下半部分扭曲严重。

问题出在 renderbuffer

Yes, the renderbuffer must be recreated when the interface is rotated, and set to the new size.

来源

所以还需要重新创建renderbuffer,

// first DELETE buffers
glDeleteRenderbuffers(...);
glDeleteFramebuffers(...);
// recreate
glGenFramebuffers(1, &_framebuffer);
glGenRenderbuffers(1, &_renderbuffer); // bind buffer and set framebuffer and renderbuffer...

具体代码可以参考Recreating the render buffer causes a crash on 3GS device (OpenGL ES 1.1)

在何处做上述的事情?

这一部分讲如何编码来准确监听屏幕旋转事件,来插入上面的那些代码。我们自定义我们的view(UIView),上级的view controller使用 [self.view addSubview:_subView]; 来将自定义view加进来。但是当旋转的事件通知到上级的view controller时, 他没有办法去通知subview。我们要自己找个时间点去通知底下的subview.看官方文档:

Instead, rotations are treated as a change in the size of the view controller’s view and are therefore reported using the viewWillTransitionToSize:withTransitionCoordinator: method. When the interface orientation changes, UIKit calls this method on the window’s root view controller. That view controller then notifies its child view controllers, propagating the message throughout the view controller hierarchy.

The viewWillLayoutSubviews method is also called after the view is resized and positioned by its parent.

如果你需要监听旋转从开始之前到结束的整个过程,推荐使用viewWillTransitionToSize:withTransitionCoordinator: 用法示例:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; // Code here will execute before the rotation begins.
// Equivalent to placing it in the deprecated method -[willRotateToInterfaceOrientation:duration:] [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) { // Place code here to perform animations during the rotation.
// You can pass nil or leave this block empty if not necessary. } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) { // Code here will execute after the rotation has finished.
// Equivalent to placing it in the deprecated method -[didRotateFromInterfaceOrientation:] }];
}

来自 SO What is the “right” way to handle orientation changes in iOS 8?

另外一个,旋转完成后,调用 viewWillLayoutSubviews 方法。很有意思,上面的方法的 completion 回调也是在旋转完成以后被调用的,那么用哪个更合适呢?我自己试验了一下,会早于comletion回调,这个方法其实是在上级的view将要去layoutSubview的时候调用的,还没有完成呢!而且实践表明,如果在comletion回调中做,其实是错误的图像已经显示出来了,然后又去改变他,这里的最终的旋转效果就很糟糕了。

我的代码如下:

/**
Called just after the view controller's view's layoutSubviews method is invoked.
*/
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
_subView.frame = self.view.frame;
[_subView layoutIfNeeded];
}

设置subview的frame尺寸以后,强制让他layout,会调用到subView自己的layoutSubviews方法,在里面做具体的操作即可。

值得参考的文档,来自大神,目前还是草稿状态:【草稿】iOS OpenGL ES 3 编程 2:绘制三角形、屏幕旋转与架构设计

OpenGL ES: iOS 自定义 UIView 响应屏幕旋转的更多相关文章

  1. OpenGL ES 响应屏幕旋转 iOS

    iOS下使用OpenGL 如果使用GLKit View 那么不用担心屏幕旋转的问题,说明如下: If you change the size, scale factor, or drawable pr ...

  2. 【Android 应用开发】OpenGL ES 2.0 -- 制作 3D 彩色旋转三角形 - 顶点着色器 片元着色器 使用详解

    最近开始关注OpenGL ES 2.0 这是真正意义上的理解的第一个3D程序 , 从零开始学习 . 案例下载地址 : http://download.csdn.net/detail/han120201 ...

  3. OpenGL ES 2.0 -- 制作 3D 彩色旋转三角形 - 顶点着色器 片元着色器 使用详解

    最近开始关注OpenGL ES 2.0 这是真正意义上的理解的第一个3D程序 , 从零开始学习 . 案例下载地址 : http://download.csdn.net/detail/han120201 ...

  4. IOS开发——手动设置屏幕旋转

    在移动开发过程.您可能需要跨越看看你的手机.有可能是所有的接口必须跨越,有可能是一个交叉通过电话,当用户当,你的接口也希望他能跨越.还有可能的是,界面的一部分需要被侧向显示.视情况而定,有不同的方法来 ...

  5. IOS自定义UIView

    IOS中一般会用到几种方式自定义UIView 1.继承之UIView的存代码的自定义View 2.使用xib和代码一起使用的自定义View 3.存xib的自定义View(不需要业务处理的那种) 本文主 ...

  6. iOs 自定义UIView 日历的实现 Swift2.1

    学习Swift有一个月了,动手写一个UIView吧. 所有源代码在最后,直接用就可以了,第一次写Swift,和C#,Java还是有区别的 (博客园可以考虑在代码插入中添加Swift的着色了) 1  函 ...

  7. Android屏幕旋转

    一个手机最基本的旋转方向有上面4种,而在Android开发中,涉及到屏幕旋转的地方很多,而且各个函数给出的角度值都不一样,比如 Activity的getRotate,Camera的setDisplay ...

  8. ##DAY3 自定义视图、视图控制器、视图控制器指定视图、loadView、 viewDidLoad、MVC、屏幕旋转、内存警告

    ##DAY3 自定义视图.视图控制器.视图控制器指定视图.loadView. viewDidLoad.MVC.屏幕旋转.内存警告 #pragma mark ———————自定义视图的步骤 —————— ...

  9. IOS 中openGL使用教程1(openGL ES 入门篇 | 搭建openGL环境)

    OpenGL版本 iOS系统默认支持OpenGl ES1.0.ES2.0以及ES3.0 3个版本,三者之间并不是简单的版本升级,设计理念甚至完全不同,在开发OpenGL项目前,需要根据业务需求选择合适 ...

随机推荐

  1. centos安装tree命令

    centos安装tree命令 sudo yum -y install tree windows安装tree命令 我的另一篇

  2. springMVC自定义全局异常

    SpringMVC通过HandlerExceptionResolver处理程序异常,包括Handler映射,数据绑定以及目标方法执行时所发生的异常. SpringMVC中默认是没有加装载Handler ...

  3. cmake find_package 中,include_directories,target_link_libraries 的值怎么知道?

    拿Sophus库为例: find_package(Sophus REQUIRED) include_directories(${Sophus_INCLUDE_DIRS}) target_link_li ...

  4. AS3中的单件(Singleton)模式

    单件(singleton)模式在c#中是最容易实现的模式,其主要用意就在于限制使用者用new来创建多个实例.但在as3中,构造函数必须是public的(语法本身要求的),而且也不能在构造函数中抛出异常 ...

  5. 如何将 jar 包导入Maven 本地仓库

    案例:oracle jar包由于在maven 远程仓库中找不到,需要先将oracle jar 文件下载到本地,然后导入maven本地仓库,就可以通过 pom 进行依赖 例如:下载后的 jar 地址 D ...

  6. GitLab代码行数统计--统计增加与删除行数

    #!/bin/bashmaster_dev='master'date_star='2018-11-01'date_end='2018-11-30'path1=`find /home/gitlab_da ...

  7. Linux上web服务器搭建

    安装php依赖包: yum -y install gcc gcc++ libxml2 libxml2-devel yum install gcc make gd-devel libjpeg-devel ...

  8. Codeforces Round #552 (Div. 3) A题

    题目网址:http://codeforces.com/contest/1154/problem/ 题目意思:就是给你四个数,这四个数是a+b,a+c,b+c,a+b+c,次序未知要反求出a,b,c,d ...

  9. Failed to connect to 127.0.0.1 port 1080: Connection refused package 问题解决方法

    错误: fatal: unable to access 'https://github.com/******': Failed to connect to 127.0.0.1 port 1080: C ...

  10. 2,postman的tests的断言写法

    tests的断言主要是分为三类 状态码,header内容和波body内容的测试,波body的不常用( 不容易控制) pm.expect(pm.response).to.have.status(&quo ...