让世界旋转起来:
游戏世界的主摄像机就是我们在游戏里的“眼睛”,为了让“眼睛”能够与手持 iPad 的我们保持协调,跟随着我们自己转身而转动,好像我们自己就站在游戏世界里用自己的眼睛观察游戏世界一样,这里就需要解决几个数学问题。
既然要旋转主摄像机,那么首先需要找到旋转的参照,因为我们旋转主摄像机的目的是为了观察游戏世界,那么这个参照自然选取游戏世界坐标系。主摄像机的 +Z 轴朝向就是我们通过 iPad 屏幕观察游戏世界时“眼睛”的观察方向,因此,只要我们能够找到主摄像机 +Z 轴方向向量与游戏世界坐标系下某个固定方向向量之间的角度关系,我们就可以通过 Quaternion(四元数,Unity 3D 里用四元数来描述空间旋转)来将主摄像机旋转到我们所期望的任意方位。
先有重力:
上一节里说到重力感应的方向分量,iPad 接受到的重力输入是永远指向真实世界重力方向的,那么,假如我们创造的是一个正常的游戏世界的话,重力输入的方向其实就是游戏世界的 -Y 坐标轴方向,那么其反方向就是 +Y 轴方向。顺理成章,我们旋转主摄像机所需要的“游戏世界坐标系下某个固定方向向量”就是这个重力输入方向了。但是在计算主摄像机 +Z 轴方向与重力输入方向之间角度关系之前,还需要一个小换算,因为重力输入方向是以 iPad 屏幕坐标系度量的,而 iPad 屏幕坐标系与主摄像机自身坐标系之间 Z 轴是反向的,所以需要进行一次坐标变换,将重力输入方向向量从 iPad 屏幕坐标系变换到主摄像机坐标系。变换方法很简单:
Vector3 g = new Vector3(Input.acceleration.x, Input.acceleration.y, -Input.acceleration.z);
现在我们可以计算主摄像机 +Z 轴方向向量(0, 0, 1)与 g 之间的夹角,进而计算出主摄像机 +Z 轴方向向量变换到游戏世界坐标系下时的方向向量。这一扒拉计算需要用到球坐标系,寻找球坐标系坐标(r, θ, φ)对应直角坐标系下坐标点的步骤为:从原点出发,向 +Z 方向前进 r,然后依据右手定则,大拇指指向 +Y 轴方向,向其他四指的握转方向旋转 θ 角度,再依据右手定则,大拇指指向 +Z 轴方向,向其他四指握转方向旋转 φ 角度。如下图:
主摄像机 +Z 轴方向向量与 g 的夹角就是 π-θ,换言之 θ=π-夹角。现在这里出现了一个问题:θ 是知道了,那 φ 在哪?非常遗憾,如果我们用来定位的依据只有重力输入方向这一项数据的话,无法确定 φ。其实 θ 就是“天顶角”,也就是俯仰角,φ 是“方位角”,重力方向只能帮助我们确定俯仰角,方位角它是无能为力的,这需要借助罗盘或者陀螺仪。这在后文中会进一步解说,现在我们只需要先给 φ 定一个定值即可,比如 240度。
仔细观察上图中的坐标系,又会发现一个问题:这个坐标系与我们使用的游戏世界坐标系长的不一样啊?没错,这个坐标系的 +Z 轴是游戏世界坐标系的 +Y 轴,它的 +Y 轴是游戏世界坐标系的 +Z 轴,刚好 +Z 和 +Y 轴调了一个个儿。没有关系,只需要将 x,y,z 的计算公式调整一下就行:
x = r sinθ cosφ y = r cosθ z = r sinθ sinφ |
代码也很简单:
using UnityEngine;
using System.Collections;
using System;
public class GSensorContoller : MonoBehaviour
{
private Transform myTransform = null;
private float x = 0.0f;
private float y = 0.0f;
private float z = 0.0f;
private Vector3 g;
private float theta = 0.0f;
private flo