先来看一下游戏中常用的两种相机模型:欧拉相机模型和UVN相机模型。
1.欧拉相机模型
欧拉角(Euler Angles)是用来描述三维欧几里德(Euclidean)空间中的刚体方向的一种方法,即通过俯仰角(Pitch)、偏转角(Yaw)、滚动角(Roll)描述物体的方向。
注意的问题:
1) Undo
假定施加于物体上的角度变换序列为PYR,若要恢复物体原来的方向,则需要施加的变换序列为:(-R)(-Y)(-P)。
2) 万向节锁(Gimbal Lock)
在两个旋转轴重合时,就出现了万向节,此时需要删掉一个。一旦先择±90度为pitch角,就被限定在只能绕竖轴旋转。这种现象,角度为±90度的第二次旋转使得第一次和第三次旋转轴相同,成为万向锁。为了消除限制欧拉角的这种别名现象,规定万向锁情况下只能由yaw完成绕竖轴的旋转。即若pitch = ±90度,则roll = 0
2. UVN相机模型
与欧拉相机模型不同,UVN相机模型采用向量来描述相机的朝向,其中n表示相机的朝向,v为上向量,u为右向量。
注意的问题:
因为u、v和n是线性无关的,所以当改变n后,需要重新计算v和n的值:
v = n × u
u=n×v
3.小结
从两种相机模型的数据描述可以看出,两者都是以相机本身为中心,均绕相机旋转。因而适应于第一人称场景的相机控制。这两种模型的代码实现可以参考OGRE的Camera类。
而很多软件需要绕观察的物体旋转,如CAD软件中的绕物体的视图旋转操作。什么样的相机模型适合这种应用呢?
ArcBall是一种绕模型为中心旋转的相机模型。其原理相当简单:将模型假想成一个球,相机在该球上移动。
若用鼠标来控制相机的旋转,就需要将屏幕坐标(x,y)映射到球面上(x1,y1,z1)。为了简化运算,可以假定球的半径为1,球的中心点为屏幕的中心点(暂且只考虑x.y轴),
假定覆盖屏幕最大圆的半径为R,因此不难将(x,y)转换为(x1,y1):
x1 = x/R * 2 - 1;
y1 = 1 - y/R*2
又因球的半径为1,所以有:
z1*z1 = 1 - x1*x1 - y1*y1。
若鼠标移动起始坐标为(X1,Y1), 终止坐标为(X2,Y2),映射到球面上可得到两个向量V1,V2,由V1,V2便可以计算出旋转轴和旋转角度。
因此整个算法的关键思想上将屏幕上的点转换到假象的球面上。
以下为基于Direct3D数学库实现的ArcBall:
class AArcBall { public: AArcBall(){} ~AArcBall(){} void SetRect(RECT rect) void Start(int x, int y) void RotateTo(int x, int y) // compute the angle m_qCurrent = D3DXQUATERNION(vAxis.x, vAxis.y, vAxis.z, angle); void GetRotationMatrix(D3DXMATRIX* pMatRot) private: // get z private: D3DXVECTOR3 m_vStart; D3DXQUATERNION m_qCurrent; // current one }; |