上一篇讲到如何使用OpenGL ES绘制一个3D场景,这一篇我们会配合使用iOS提供的CoreMotion框架把虚拟世界中的摄像机的位置朝向和设备实际的位置朝向绑定起来。本文还对防抖做了处理。

  首先说明几个容易混淆的问题:

    1. OpenGL ES的摄像机,位置固定在世界坐标系原点,Up方向和世界坐标系y轴重合,Right方向和世界坐标系x轴重合,Look方向和世界坐标系负z轴重合
      2. 为了抽象一个可以缩放,旋转,移动的摄像机,我们可以在OpenGL ES的的矩阵操作中通过左乘这个摄像机的变换矩阵的逆矩阵来实现
      3. CoreMotion框架中,可以从API中获取代表朝向的欧拉角或者四元数数据,因为欧拉角存在万向节死锁的问题,所以我们取四元数
      4. 注意CoreMotion的初始朝向问题,本文采用CMAttitudeReferenceFrameXMagneticNorthZVertical(Right方向和南重合,Up方向指向垂直上方)作为初始朝向
  1. 初始化CoreMotion的代码
    1. // 启用陀螺仪
      motionManager = [[CMMotionManager alloc]init];
      if (motionManager.deviceMotionAvailable) {
      motionManager.deviceMotionUpdateInterval = motionInterval; [motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXMagneticNorthZVertical toQueue:[NSOperationQueue currentQueue] withHandler:^(CMDeviceMotion *motion, NSError *error) {
      if(motion){
      CMRotationRate rotationRate = motion.rotationRate;
      double rotationX = rotationRate.x;
      double rotationY = rotationRate.y;
      double rotationZ = rotationRate.z; double value = rotationX * rotationX + rotationY * rotationY + rotationZ * rotationZ; // 防抖处理,阀值以下的朝向改变将被忽略
      if (value > 0.01) {
      CMAttitude *attitude = motion.attitude;
      t = 0.0f;
      s = 0.0f; // 从当前朝向以固定加速度像目标朝向进行四元数插值
      srcQuaternion = curQuaternion;
      desQuaternion = GLKQuaternionNormalize(GLKQuaternionMake(attitude.quaternion.x, attitude.quaternion.y, attitude.quaternion.z, -attitude.quaternion.w));
      }
      }
      }]; }
  2. 为了防抖处理,需要将当前朝向平滑过渡到目标朝向
    1. if (s <= ) {
      t += 0.05;
      // 以固定初速度和加速度对原朝向和目标朝向进行插值
      s = v0 *t + a * t * t / ;
      curQuaternion = GLKQuaternionNormalize(GLKQuaternionSlerp(srcQuaternion, desQuaternion, s));
      }
  3. 上文已经提到了虚拟摄像机的初始朝向,为了将设备的实际朝向和虚拟摄像机的朝向绑定到一起,我们先将摄像机的坐标轴转动到与CMAttitudeReferenceFrameXMagneticNorthZVertical代表的坐标轴重合,再用上文得到的curQuaternion转动到设备的实际朝向,最后求上述转动的逆即可
    1. 摄像机初始朝向到设备初始朝向的旋转矩阵
      1. _worldTrasform[] = 0.0;
        _worldTrasform[] = 0.0;
        _worldTrasform[] =1.0;
        _worldTrasform[] = 0.0;
        _worldTrasform[] = 1.0;
        _worldTrasform[] = 0.0;
        _worldTrasform[] = 0.0;
        _worldTrasform[] = 0.0;
        _worldTrasform[] = 0.0;
        _worldTrasform[] = 1.0;
        _worldTrasform[] = 0.0;
        _worldTrasform[] = 0.0;
        _worldTrasform[] = 0.0;
        _worldTrasform[] = 0.0;
        _worldTrasform[] = 0.0;
        _worldTrasform[] = 1.0;  
    2. 将四元数转换为矩阵
      1. GLfloat x = curQuaternion.x;
        GLfloat y = curQuaternion.y;
        GLfloat z = curQuaternion.z;
        GLfloat w = curQuaternion.w;
        _worldTrasform[] = -*y*y-*z*z;
        _worldTrasform[] = *x*y-*w*z;
        _worldTrasform[] = *x*z+*w*y;
        _worldTrasform[] = 0.0;
        _worldTrasform[] = *x*y+*w*z;
        _worldTrasform[] = -*x*-*z*z;
        _worldTrasform[] = *y*z-*w*x;
        _worldTrasform[] = 0.0;
        _worldTrasform[] = *x*z-*w*y;
        _worldTrasform[] = *y*z+*w*z;
        _worldTrasform[] = -*x*x-*y*y;
        _worldTrasform[] = 0.0;
        _worldTrasform[] = _position.x;
        _worldTrasform[] = _position.y;
        _worldTrasform[] = _position.z;
        _worldTrasform[] = 1.0;
    3. 将上面两个矩阵顺次相乘并根据正交矩阵的性质求逆矩阵并左乘当前带渲染实体的世界变换矩阵
      1. glMatrixMode(GL_MODELVIEW_MATRIX);
        glLoadIdentity();
        glLoadMatrixf(cameraMatrix); // 将模型矩阵设置为摄像机世界矩阵的逆矩阵
        glMultMatrixf(transform); // 右乘模型的世界矩阵

  这样,我们就把虚拟摄像机的朝向和设备的朝向绑定在了一起。

通过OpenGL ES在iOS平台实践增强现实(二)的更多相关文章

  1. 通过OpenGL ES在iOS平台实践增强现实

    http://www.cnblogs.com/elvisyzhao/p/3398250.html 本文采用OpenGL ES 1固定渲染管线实现,目标为在设备拍摄到的现实世界中,绘制世界坐标轴,并根据 ...

  2. 通过OpenGL ES在iOS平台实践增强现实(一)

    http://ios.9tech.cn/news/2013/1108/38495.html 1.本文采用OpenGL ES 1固定渲染管线实现,目标为在设备拍摄到的现实世界中,绘制世界坐标轴,并根据设 ...

  3. OpenGL ES 2.0 Shader 调试新思路(二): 做一个可用的原型

    OpenGL ES 2.0 Shader 调试新思路(二): 做一个可用的原型 目录 背景介绍 请参考前文OpenGL ES 2.0 Shader 调试新思路(一): 改变提问方式 优化 ledCha ...

  4. [iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之二:lib3ds加载模型

    [iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之二:lib3ds加载模型 作者:u0u0 - iTyran 在上一节中,我们分析了OBJ格式.OBJ格式优点是文本形式,可读 ...

  5. WebGL 在 OpenGL ES 指令 iOS 在 C 分歧版指令分析

    WebGL 中 OpenGL ES 指令与 iOS 中 C 版指令的差异简析 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途 ...

  6. OpenGL ES on iOS --- 统一变量(Uniform)和统一变量块(UBO)

    简介 Uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式,但uniform和顶点属性有些不同. 首先,uniform是全局的(Global).全局意味着uniform变量必须在每个着 ...

  7. OpenGL ES应用开发实践指南:iOS卷

    <OpenGL ES应用开发实践指南:iOS卷> 基本信息 原书名:Learning OpenGL ES for iOS:A Hands-On Guide to Modern 3D Gra ...

  8. iOS 中OpenGL ES 优化 笔记 1

    1,避免同步和Flushing操作 OpenGL ES的命令执行通常是在command buffer中积累一定量的命令后,再做批处理执行,这样效率会更高:但是一些OpenGL ES命令必须flush ...

  9. (转)规划从 OpenGL ES 2.0 到 Direct3D 的移植

    如果你移植 iOS 或 Android 平台中的游戏,那么你可能需要在 OpenGL ES 2.0 方面进行大量投资.如果你准备将你的图形管道代码库移动到 Direct3D 11 和 Windows ...

随机推荐

  1. 【Python学习之六】高阶函数2(map、reduce、filter、sorted)

    3.filter filter()也接收一个函数和一个序列.和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素.相当于一 ...

  2. 共享服务-FTP基础(二)

    续接上一篇 使用pam(Pluggable Authentication Modules)完成用户认证 pam_service_name=vsftpd pam配置文件:/etc/pam.d/vsftp ...

  3. 配置wamp开发环境之mysql的配置

    此前我已经将wamp配置的Apache.PHP.phpmyadmin全部配置完成,以上三种配置参照 配置wamp开发环境 下面我们来看看mysql的配置,这里用的是mysql5.5.20,下载地址: ...

  4. Applied Nonparametric Statistics-lec3

    Ref: https://onlinecourses.science.psu.edu/stat464/print/book/export/html/4 使用非参数方法的优势: 1. 对总体分布做的假设 ...

  5. 用decimal模块增加python的浮点数精度

    浮点数python默认是17位精度,也就是小数点后16位(16位以后的全部四舍五入了),虽然有16位,但是这个精度越往后越不准. 如果有特殊需求,需要更多的精度,可以用decimal模块,通过更改其里 ...

  6. 某比赛小记1- 挑选第N大数字

    题目:给1000个数字(有重复),从小到大排列后,挑选第N个数字. 数字文件如下:numbers.rar ,挑选第727个数字. java版本: //数组初始化 String str = " ...

  7. WPF触控程序的开发(一)——有用的资源

    迟来的一篇博文,每次都要撞到月末,这个月实在太忙了,除了在公司上班,还接了个单子,用wpf做一个触屏软件,类似iphone的相册功能.先说搭建开发环境吧,我是不可能去买个平板来的,再说基于win7的程 ...

  8. LA 7048 Coprime 莫比乌斯反演

    题意: 给出\(n(n \leq 10^5)\)个数字\(a_i(a_i \leq 10^5)\),从中选出\(3\)个数,使得这\(3\)个数两两互质或者两两不互质 分析: 可以说这是<训练指 ...

  9. CodeForces 379F 树的直径 New Year Tree

    题意:每次操作新加两个叶子节点,每次操作完以后询问树的直径. 维护树的直径的两个端点U,V,每次计算一下新加进来的叶子节点到U,V两点的距离,如果有更长的就更新. 因为根据树的直径的求法,若出现新的直 ...

  10. EXCEL常用命令

    查找和选择:定位条件(定位空值.错误值) 选择性粘贴