iPad 的玩家大概都用过 StarWalk 这款应用——强力到无以附加的星图软件。StarWalk 里的世界其实就是虚拟了一个环绕用户的天球,当然还能够与真实的天球对应得上,当用户举着 iPad 对向不同方位时,能够从 iPad 屏幕上看到天球上对应的那一方向上的区域,就如同真的在用望远镜观察天球一样。这里面的原理其实很简单,整个虚拟的天球就是游戏世界,主摄像机就在这个游戏世界的正中心点,当 iPad 屏幕正对的方位发生变化时,主摄像机根据获取到的重力感应输入和罗盘输入计算出新的朝向,并转向正确的方向。
重力感应:iPad 重力感应的 X,Y,Z 三方向分量分布为:以 Home 按键在下的屏幕摆放方式为基准,垂直屏幕向外的方向为 +Z 轴,沿屏幕边缘向上的方向为 +Y 轴,沿屏幕边缘向右的方向为 +X 轴。想象在 iPad 屏幕正中央栓了一个重锤,重锤指向的方向自然永远是真实世界的重力方向,也是 iPad 重力感应器所接收到的重力方向。现在,把重力感应方向映射到前面重力感应三方向分量组成的坐标系中去,就可以用三分量来描述这个重力输入方向了,分量的取值范围是 (-1,1)。
当 iPad 屏幕朝上平躺放置时,重力方向描述为 (0,-1);当 iPad 的 Home 按键朝下,做屏幕竖立放置时,重力方向描述为 (0,-1,0);当 iPad 的 Home 按键在左,做屏幕侧立放置时,重力方向描述为 (1,0)。如下图:
同理,当 iPad 屏幕朝下平躺时,重力方向为 (0,1);当 iPad 倒竖放置(Home 键在上竖立放置)时,重力方向为 (0,1,0);当 iPad 侧立放置,Home 键在右时,重力方向为 (-1,0)。这六种摆放下重力与某一坐标轴重合,当 iPad 以其他角度摆放时,只需将重力输入看作一个大小为 1 单位的矢量来做坐标轴映射。 当然,这个映射不需要自己计算,因为我们可以——
获得重力输入:要获得重力输入很简单,使用 input.acceleration 即可获得最近一次的重力输入,其值是一个 Vector3 型变量,也就是重力输入方向在上述坐标系下的映射三分量。我们可以通过一个简单的脚本来观察当 iPad 翻转时,这个重力输入的三分量数值会如何变化:
using UnityEngine;using System.Collections;using System;public class ShowGSensorValue : MonoBehavIoUr{ // Use this for initialization voID Start() { } // Update is called once per frame voID Update() { } voID OnGUI() { GUI.Box(new Rect(5,5,100,20),String.Format("{0:0.000}",input.acceleration.x)); GUI.Box(new Rect(5,30,input.acceleration.y)); GUI.Box(new Rect(5,55,input.acceleration.z)); }}
上面这个脚本中,通过在屏幕左上角绘制纵向排列的三个 Box 控件,每个空间显示一个分量,来实时显示当前游戏帧内重力输入方向的三个分量大小。如下图所示:
仅仅是拿来观察重力输入分量,那么直接取 input.acceleration 就足够了。但是,如果要利用重力输入来影响游戏世界里的物体,那么这里就产生了一个问题:重力输入的分量是以上面提到的用 iPad 屏幕为标准的坐标系进行表述的,但是游戏世界坐标系与 iPad 屏幕坐标系并不一致。就医上面这截图里的球来说,它所处的坐标系的三坐标轴方向是下面这个样子的:
绿色是 +Y 轴,红色是 +X 轴,蓝色是 +Z 轴。或者我们把游戏的主摄像机调整一个角度,好看得更清楚一点:
把摄像机挪到球的正上方,现在球的坐标系看起来跟 iPad 的屏幕坐标系很像了,但显然这里的 +Y 轴和 +Z 轴方向与 iPad 屏幕坐标系不一样。现在切换到摄像机:
其实 iPad 屏幕坐标系就是 Z 轴反向的主摄像机本地坐标系:
所以,如果直接取 input.acceleration 的方向来对这个球施加作用力的话,它不会按照我们所预期的那样运动。这就需要做——
坐标变换:iPad 玩游戏时,是通过游戏里的主摄像机在观察游戏世界,而屏幕就是主摄像机的镜头,因此在主摄像机的指向方向没有发生变化时,可以认为整个游戏世界是“粘在” iPad 屏幕“后头”的,而屏幕就是一块透明玻璃,我们正透过这块玻璃观察粘在玻璃后头的游戏世界。
而坐标变换就是把屏幕,也就是这块玻璃的坐标系换算成玻璃后面游戏世界的坐标系。最简单的一种坐标变换,就是当摄像机像上面例子中那样从游戏世界的正上方向下俯视,此时只需要简单的把 +Y 换成 +Z 轴,+Z 轴换成 +Y 轴即可。例如把上面的代码修改一下:
using UnityEngine;using System.Collections;using System;public class ShowGSensorValue : MonoBehavIoUr{ public RigIDbody Target = null; public float ForceFactor = 10.0f; // Use this for initialization voID Start() { } // Update is called once per frame voID FixedUpdate() { if (Target != null) { Target.AddForce(new Vector3(input.acceleration.x,input.acceleration.z,input.acceleration.y) * ForceFactor,ForceMode.Force); } } voID OnGUI() { GUI.Box(new Rect(5,input.acceleration.z)); }}
而更复杂的时候,屏幕坐标系与游戏世界坐标系之间有倾斜角,不能直接调换坐标分量完事,需要用三角函数计算;更更复杂的时候,屏幕坐标系和游戏世界坐标系之间的相对关系是时刻在变化的,因为,我们的主摄像机时刻在移动和旋转,这时需要更为复杂的坐标变换。
备注:iPad 用以支持重力感应的硬件设备是加速度计,当 iPad 除了重力加速度之外不承受其他加速度时,从加速度计上读取的数值可以认为是当前重力加速度,归一化之后即可认为是当前地理位置的重力方向。因此,如果 iPad 设备处于复杂加速环境中,那么从加速度计上读入的数据就不能作为判断重力方向的依据。Unity 3D 3.5 版本后开始支持陀螺仪,看 API 文档里专门有一项 gravity 属性,说明是重力加速度方向,但是手头没有 iPad 2 也没有 iPhone 4 无法实验。
总结以上是内存溢出为你收集整理的[Unity 3D] 重力感应与罗盘(一)全部内容,希望文章能够帮你解决[Unity 3D] 重力感应与罗盘(一)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)