为了实现一个全景图片展示的功能,需要借助手机的姿态传感器,实现一个这样的功能:当手机旋转时,视角也跟着旋转(读者若理解不能,可以参考下现在流行的 VR 应用,使用陀螺仪模式时的效果,亦可称作“单目 VR 效果”)。这个功能的实现原理为:利用手机传感器得到手机的当前的姿态的信息(可以是用各种方式来描述的),然后调整投影的参数,实现最终的图像跟着手机旋转的效果。

手机姿态获取

Android

Android 平台有各种各样的传感器(Sensor),不止一个 sensor 可以实现前文提到的目的。在 Android SDK API Guides 中可以找到所有可用的 sensors。

1 gyroscope

这个就是陀螺仪了,是硬件传感器(hardware sensor),可以提供设备绕 xyz 三个轴旋转的角速度。注意这里的坐标系就是设备自身的,短边 x 轴,长边 y 轴,z 轴穿越手机屏幕。为实现旋转效果需要的数据是旋转的角度(用以计算旋转矩阵),所以如果要用 gyroscope 则需要对数据进行积分,最好加上滤波使效果平稳。

若欲得到角度变化量而非角速度,那麽,官方提供一个例子,可以通过乘上时间差并通过计算得到一个四元数,来代表角度的变化量。实际上使用发现的问题是,该传感器得到的数据完全就是以设备为参考坐标的,当设备竖直朝向和横向的时候,其表现是不变的,也就是说没有将真實世界作为参考,这个对我的需求来说是不满足的。

2 orientation

这是一个软件传感器(software sensor),返回的数据不是传感器硬件直接采集得到的,而是根据硬件的数据进行合适的计算得到的。

阅读文档即可得知,此用于获取设备在 Yaw,Pitch and Roll 三个方向的旋转的角度,根据这三个角度也就可以确定其姿态了。但是官方文档不推荐这样使用,而是推荐 rotation vector sensor 并配合 getRotationMatrix() 来计算出这三个参数,至于原因,官方文档只说现在留着这个传感器类型是历史原因,让大家不要用了,没解释其他的。具体原因后面解释。

3 rotation vector

这个 sensor 和上面的 orientation 一样,都是软件传感器。这个表示的仍然是设备的姿态,但是与上面的不同,这个用一个四元数来表示设备的旋转,旋转的参考坐标系是真实的物理世界。

在应用該传感器提供的数据时,值得注意的是,有可能传感器返回的数据不一定是四个数据,也有可能是三个参数,比较安全的做法是这样做:

        @Override
public void onSensorChanged(SensorEvent event) {
float[] quat = new float[4];
SensorManager.getQuaternionFromVector(quat, event.values);
// use the quaternion
// ...
}

可参考:TYPE_ROTATION_VECTOR

比较

那么这两个传感器似乎都能用,到底用哪个呢?显而易见,第一个用起来不太方便。那么后两者区别在哪?

实际上,官方就不推荐使用 orientation,已经将其标记为 deprecated,并且提供了另一个方法叫做 getOrientation(),用法较复杂一点,从加速度计和地磁传感器获取数据,根据此计算得旋转矩阵,然后在根据旋转矩阵计算三个方向的旋转角度。个人感觉就是放弃了帮助开发者去计算这个数据,而是告诉大家应该怎么样算,自己去算吧。为什么要废弃呢,根据这里的解释,旧版传感器的问题主要是万向节锁,当某一个轴转动 90 度,就很难准确描述另外两个轴的转动了,对万向节锁的理解可以看我之前的文章:万向节锁(Gimbal Lock)的理解。Android API 文档这样说:

The orientation sensor derives its data by processing the raw sensor data from the accelerometer and the geomagnetic field sensor. Because of the heavy processing that is involved, the accuracy and precision of the orientation sensor is diminished.

Specifically, this sensor is reliable only when the roll angle is 0. As a result, the orientation sensor was deprecated in Android 2.2 (API level 8), and the orientation sensor type was deprecated in Android 4.4W (API level 20).

相比较,rotation vector 用四元数来描述旋转,避免了这个问题,所以我采用这个传感器来采集设备姿态的信息。

iOS

iOS 平台稍微简单一些,没有那么多具体的传感器。deviceMotion 就很好用,获取 deviceMotion.attitude 这是一个CMAttitude对象,可以直接获取用四元数表示的设备的姿态信息。

其实 CoreMotion 这个 Framework 也是可以提供裸陀螺仪数据等等,但是 CMDeviceMotion 下面的 attitude 这个属性返回的数据是更加准确的,如果需要精确的数据,推荐使用这个方法。

实现旋转

这里我先简单阐述一下一个旋转的意义:当我们看着一张图片的时候,如果要实现旋转这张图的效果,有两个办法:

  1. 将图片转一下(调整物体的模型的参数)
  2. 我的脑袋转一下(调整摄像机的参数,也就是改变观察矩阵(即 look at matrix)的参数)

实际上这两种方法都可以实现,实际应用的时候随便选一个更合适自己的就可以了。我这里要说明的是如果采用后一个办法,不能简单地将两个矩阵相乘就算数了,我们要从实际情况去考虑这个问题,考虑 OpenGL 的观察矩阵的计算:

// GLU
gluLookAt(x0, y0, z0, xref, yref, zref, Vx, Vy, Vz) // glm
GLM_FUNC_DECL tmat4x4<T, P> glm::lookAt ( tvec3< T, P > const & eye,
tvec3< T, P > const & center,
tvec3< T, P > const & up
)

两种是一样的,分别指定观察坐标系的原点(eye),参考点(即视点,相机瞄准的点,center),和向上向量(up)。当旋转相机時,需要将 center 和 up 同时应用这个相应的旋转。我之前犯过的一个错误是:我仅仅把旋转应用到了 center 上面,而没有应用到 up vector,up vector 一直设置的是(0, 1, 0)。直观点说就是:视点转了,但是头顶朝向没有变化,这个是不符合逻辑的,我们需要让视线N:P_0 - P_ref和 up vector 保持垂直。

问题解决

在实际实践中,Android 的坑还真是特别的多,我发现使用 rotation vector 计算出旋转矩阵,会根据手机当前和真实世界的关系产生一定偏移,也就是说手机朝向北方和朝向南方得到的数据是不一样的,而我希望的是得到一个与手机初始的朝向无关(也就是手机绕真实世界的南北极组成的轴旋转的角度),而与手机与地平线的夹角有关的这么一个数据。总的来说就是 rotation vector 做了一些我不想要的校正。同时我找到另一个 sensor:GAME_ROTATION_VECTOR,其介绍如下:

Identical to TYPE_ROTATION_VECTOR except that it doesn't use the geomagnetic field. Therefore the Y axis doesn't point north, but instead to some other reference, that reference is allowed to drift by the same order of magnitude as the gyroscope drift around the Z axis.

In the ideal case, a phone rotated and returning to the same real-world orientation will report the same game rotation vector (without using the earth's geomagnetic field). However, the orientation may drift somewhat over time. See TYPE_ROTATION_VECTOR for a detailed description of the values. This sensor will not have the estimated heading accuracy value.

使用这个我基本上实现我想要的效果,所以以后要用这个 Rotation vector 的时候,要考虑清楚到底要用哪一个。另外还有一个 Geomagnetic Rotation Vector 实际使用效果较差,精度较低,但是省电。

OpenGL: Rotation vector sensor of Android and Device motion of iOS的更多相关文章

  1. 打开android虚拟机时出现a repairable android virtual device

    打开android虚拟机时出现a repairable android virtual device,虚拟机可以打开但是一直处于开机状态,具体解决方案如下: 解决方案1:换个版本,不要选 CPU/AB ...

  2. Create new Android Virtual Device时不能创建

    在Create new Android Virtual Device时不能创建... 因为之前有重装过系统,ADT和java都没有更换,不知道是不是有哪里的环境(C盘中的配置)出错了... LOG在下 ...

  3. eclipse安装ADT插件重启后不显示Android SDK Manager和Android Virtual Device Manager图标的一种解决办法

    通常安装,搭建安卓环境后,不显示Android SDK Manager和Android Virtual Device Manager ize解决方法:Eclipse ->window->c ...

  4. eclipse中调出android sdk manager和android virtual device manager图标

    有时候在安装ADT插件后,eclipse菜单栏上不会显示android sdk manager和android virtual device manager两个图标, 这个时候,如果安装ADT插件的步 ...

  5. ADT后windows菜单未找到Android SDK Manager和Android Virtual Device Manager该解决方案的选择

    打开今天凌晨ADT准备编译androidproject的时候,突然发现windows菜单下的Android SDK Manager和Android Virtual Device Manager选项不见 ...

  6. AVD启动报错:Running an x86 based Android Virtual Device (AVD) is 10x faster

    1.cmd窗口中输入emulator -avd test 启动AVD时报错: Running an x86 based Android Virtual Device (AVD) is 10x fast ...

  7. No compatible targets were found Do you wish to a add new Android Virtual Device ?

    运行一个Android小程序时提示: No compatible targets were found Do you wish to a add new Android Virtual Device ...

  8. Xamarin.Android 4.10.01068 & Xamarin.iOS 1.8.361

    Xamarin.Android 4.10.01068 & Xamarin.iOS 1.8.361 NEW support for Visual Studio 2013 & Portab ...

  9. Android 4.3实现类似iOS在音乐播放过程中如果有来电则音乐声音渐小铃声渐大的效果

    目前Android的实现是:有来电时,音乐声音直接停止,铃声直接直接使用设置的铃声音量进行铃声播放. Android 4.3实现类似iOS在音乐播放过程中如果有来电则音乐声音渐小铃声渐大的效果. 如果 ...

随机推荐

  1. 手机自动化测试:appium源码分析之bootstrap十四

    手机自动化测试:appium源码分析之bootstrap十四   poptest(www.poptest.cn)是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开 ...

  2. 玩转 SSH(一):使用 Struts 搭建简单站点

    我们将使用 Struts 搭建一个简单的应用,当用户发送 HTTP 请求时,Action 类响应并设置返回信息,JSP 页面显示 Action 类中设置的信息. 首先,我们使用 Maven 的 mav ...

  3. Ubuntu 分辨率调整及操作问题解决

    步骤: 1.在控制窗口上:点击  设备--->安装则鞥强功能:如图1: 若点击后出现图2的情况,则在左边找到光盘图标,右键-->弹出(图3): 然后再重复本步骤: 图1 图2 图3 2.在 ...

  4. 使用SQL存储过程有什么好处 用视图有什么好处

    随便胡乱说几点,大家补充一下.1.预编译,已优化,效率较高.避免了SQL语句在网络中传输然后再解释的低效率.2.如果公司有专门的DBA,写存储过程可以他来做,程序员只要按他提供的接口调用就好了.这样分 ...

  5. Oracle wm_concat()函数

    oracle wm_concat(column)函数使我们经常会使用到的,下面就教您如何使用oraclewm_concat(column)函数实现字段合并 如: shopping:   ------- ...

  6. oracle定时执行一个存储过程

    首先需要新建存储过程 一 存储过程: create or replace procedure Insertdata is begin INSERT INTO tab_dayta select * fr ...

  7. 用 js 的 selection range 操作选择区域内容和图片

    原创文章,转载请注明出处并保留地址.原文地址:http://www.cnblogs.com/muge10/p/6723894.html 最近在做编辑器相关的东西,遇到一个需求,用户在编辑器中插入或者粘 ...

  8. 记一次 Newtonsoft.Json 巧妙的用法(C#)

    数据添加的功能 有一个表格提交数据如下: 是否选择和文本值.分开保存到数据库太麻烦.取得时候也麻烦 想到了存成json数据.一个字段就可以了. html代码: <table class=&quo ...

  9. Eclipse 中 Java 项目中 .settings 文件夹作用

    今天工作时,因对 .settings 文件夹误操作,耗时 6 个多小时,才了解到原因就出在 .settings 文件夹.经查阅资料,对 .settings 做如下整理: 就如setting这个名字,就 ...

  10. elasticsearch系列(一) 术语

    elasticsearch(以下简称es)是一款开源的搜索引擎,基于apach lucene.最近在做nlp的时候顺便研究一下. 下面是官方列举的术语解释 Near Realtime 接近实时的查询, ...