设计一个灵活的 Camera 类
1.Camera 类的设计
我们用 4 个摄像机向量:右向量( right vector )、上向量( up vector )、观察向量( look vector )以及位置向量( position vector )来定义摄像机相对于世界坐标系的位置和朝向。这些向量实质上为相对世界坐标系描述的摄像机定义了一个局部坐标系。由于右向量、上向量和观察向量定义了摄像机在世界坐标系中的朝向,有时我们也将这三个向量统称为方向向量。方向向量必须是标准正交的。如果一个向量集中的向量都彼此正交,且模为 1 ,则称为标准正交。
用上述 4 个向量来描述摄像机,我们可以对摄像机实施如下 6 种变换:
² 绕向量 right 的旋转(俯仰, pitch )
² 绕向量 up 的旋转(偏航, yaw )
² 绕向量 look 的旋转(滚动, roll )
² 沿向量 right 方向的扫视( strafe )
² 沿向量 up 方向的升降( fly )
² 沿向量 look 方向的平动
我们的摄像机支持两种摄像机模型—— LANDOBJECT 模型和 AIRCRAFT 模型。 AIRCRAFT 模型允许摄像机在空间自由运动,具有 6 个自由度。但是在某些游戏中,射击者是不可能飞行的。所以我们必须限制射击者只能沿某些特定轴进行移动。如果将摄像机类型指定为 LANDOBJECT ,便自动满足了上述约束。
2. 实现细节
1) 观察矩阵(取景变换矩阵, View Matrix )的计算
令向量 p = (px, py, pz) 、 r = (rx, ry, rz) 、 u = (ux, uy, uz) 、 d = (dx, dy, dz) 分别表示 position , right, up 和 look 这 4 个向量。
取景变化所解决的问题就是世界坐标系中的物体在以摄像机为中心的坐标系中如何进行描述。等价于将世界坐标系中的物体随摄像机一起进行变换,以使摄像机坐标系与世界坐标系完全重合。
所以我们希望变换矩阵 V 能够实现:
l pV = (0, 0, 0) 矩阵 V 将摄像机移至世界坐标系的原点。
l rV = (1, 0, 0) 矩阵 V 将摄像机的 right 向量与世界坐标系的 x 轴重合。
l uV = (0, 1, 0) 矩阵 V 将摄像机的 up 向量与世界坐标系的 y 轴重合。
l dV = (0, 0, 1) 矩阵 V 使摄像机的 look 向量与世界坐标系的 z 轴重合。
这样我们就可以将计算这种矩阵的任务分为两步:首先将摄像机平移到世界坐标系的原点;然后通过旋转变换使摄像机各向量与世界坐标系对应各轴重合。
第一步:平移
将摄像机的位置向量 p 平移到原点可通过将其与向量 -p 做向量加法实现,因为 p-p=0 。所以我们可以用如下矩阵来描述取景变换中的平移变换部分。
第二步:旋转
要想使摄像机各向量与世界坐标系各轴重合的工作量稍大一些。我们需要一个 3 * 3 的旋转矩阵 A 以使向量 right 、 up 和 look 分别与世界坐标系的 x, y, z 轴重合。该矩阵需要满足如下 3 个方程:
注意:我们这里使用的是 3 * 3 矩阵,因为我们不需要用齐次坐标来表示旋转。
由于这 3 个方程组都具有相同的系数矩阵 A ,联立之后我们可立即解出矩阵 A 。我们将上述 3 个方程组整合为:
矩阵 A 有多种求解方法,但是我们可以立即看出 A 其实是 B 的逆矩阵。由于矩阵 B 是标准正交矩阵,所以其逆矩阵与其转置矩阵相等。所以,使摄像机各轴与世界坐标系各轴重合的变换可用如下矩阵表示:
前两步的整合
最后,将 A 拓展为 4 * 4 矩阵,并将其取景变换的前两步整合,得到完整的观察矩阵 V 。
2) 绕任意轴的旋转
实现摄像机的旋转方法时,我们应使得能够绕任意轴进行旋转。 D3DX 库提供了如下函数实现该功能:
D3DXMATRIX *D3DXMatrixRotationAxis(
D3DXMATRIX *pOut, //returns rotation matrix
CONST D3DXVECTOR3 *pV, //axis to rotate around
FLOAT Angle //angle, in radians, to ratate
);
3) 俯仰、偏航和滚动
由于方向向量描述了摄像机在世界坐标系中的朝向,所以当摄像机发生俯仰、偏航或滚动时,我们必须指定方向向量应如何更新。下面几个图分别展示了这几种情况:
从图中可以知道,摄像机发生俯仰时,我们需要将向量 up 和 look 绕着向量 right 转动指定的角度。类似的,发生偏航时,我们需要将向量 look 和 right 绕着向量 up 转动指定的角度;发生翻滚时,我们需要将向量 right 和 up 绕着向量 look 转动指定的角度。
4) 行走、扫视和升降
这里的“行走”是指沿着摄像机的观察方向( look 方向)的平动。“扫视”是指保持观察方向不变,沿向量 right 方向从一边平移到另一边。“升降”是沿着向量 up 方向的平动。为了能够沿这些轴中的任意一个进行平动,我们只需要将摄像机当前位置和一个与该轴方向相同的向量相加即可。