gluLookAt,它有三类(每类3个)共9个引数:
void gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,
GLdouble centerx,GLdouble centery,GLdouble centerz,
GLdouble upx,GLdouble upy,GLdouble upz);
你需要分别指定这三类引数,才能完成Camera变换.
1.
视线:你不用在gluLookAt中指定视线(从眼到被视物体的向量),但在变换视点(尤其是旋转时),
所作的许多操 作都是针对它进行的,
后面将给出如何计算视线向量的公式.
a.
视点:即gluLookAt中eye*的那三个引数,视点指的是一条从原点到眼位置的向量.
从你的座位上站起来,这时你改变的就是视点.
b.
视目标:即gluLookAt中center*的那三个引数,视目标指的是一条从原点到被视物体的向量.
水平转动你的脖子,这时你所作的就是改变视目标.
c.
仰视向量:即gluLookAt中up*的那三个引数,仰视向量指的是头顶的朝向.
竖直抬起头(‘向上看’),这时改变的就是仰视向量.
[一般来讲,仰视向量用(0,1,0)就可以了,不用再仔细考虑它]
2.很明显,由向量减法 视线 view,视点 pos,视目标 tar
view=tar-pos;
3.Camera的变换也就是改变视线位置(前进或后退),方向(转头)
4.Camera变换Pipeline:
Ⅰ 由pos,tar 计算出 view
Ⅱ 变换view
Ⅲ 将view的x,y,z分量传回pos和tar
Ⅳ 将pos,tar,up传给gluLookAt
C.平移
平移是最简单的,它起的作用是游戏者的前进与后退,你会发现平移其实就是平行移动视线,方向不变.
如下图:
代码讲解:
void Move(float speed) { //speed:指定每按一下键前进多少,我取的是0.3
Vector view=tar-pos; //取得view,Vector不是std::vector
pos.x+=speed*view.x; pos.z+=speed*view.z;
tar.x+=speed*view.x; tar.z+=speed*view.z;
}
//我只希望在平面上移动,所以没有y分量的事.
D.旋转
旋转就是转头操作,比较复杂,一点一点来.
D1.绕任意轴旋转一条向量
V
up⊥V
perp
|V
up|=|V
perp|=|V
aux| V
proj⊥V
perp
n∥V
proj
n为单位向量
绕n旋转V θ度到V’, 求V’
V
proj=|V
proj|/|n| n
n*V=|n||V|cosβ cosβ=|Vproj|/|V| |Vproj|=|V|cosβ
n*V=|n||V
proj| |V
proj|=(n*V)/|n|
Vproj=(n*V)/|n|2 n 因为 n 为单位向量
所以 Vproj=n*V n
Vperp=V-Vproj=V-n*V n
V
up=V
perp×n=(V-n*V n)×n=V×n-n*V(n×n)=V×n
V
aux=-sin(θ-90)V
perp+cos(θ-90)V
up=sin(90-θ)V
perp+cos(90-θ)V
up
=cosθV
perp+sinθV
up=cosθ(V-n*V n)+sinθ(V×n)
V’=Vperp+Vaux=n*v n+cosθ(V-n*V n)+sinθ(V×n)
D2.水平转头
水平转头即在XZ平面上绕竖直方向旋转view向量
可看出pos无变化,y分量亦无变化.
XZ平面的旋转矩阵:
[ cosθ 0 -sinθ ]
[ 0 1 0 ]
[ sinθ 0 cosθ ]
取得view: view=tar-pos;
旋转view:
[cosθ 0 -sinθ ]
[view.x view.y view.z] [0 1 0 ]
[sinθ 0 cosθ]
=[view.x*cosθ+view.z*sinθ view.y -view.x*sinθ+view.z*cosθ]
传回tar值:
tar’=pos+view’;
D3.竖直转头
竖直转头即在YZ平面上以垂直于view的直线为轴旋转view向量
侧视示意图:
鸟瞰示意图
取得view: view=tar-pos;
取得 axis: 即旋转view (-π/2)
[0 0 1]
[view.x view.y view.z] [0 1 0]
[-1 0 0]
=[-view.z view.y view.x]
为了用上D1中求得的公式,把axis归一化(Normalize)
绕axis旋转view: (套用D1最后得出的公式)
view’=axis*view axis+cosθ(view-axis*view axis)+sinθ(view×axis);
更新tar值:
tar’=pos+view;
E.鼠标滑动角度计算
我们注意到进行旋转Camera时,需要向程序提供转过的角度(2个)
一个是水平转动角度(转头),一个是竖直转动角度(抬头或低头)
这样计算:
鼠标滑过的距离其实是view向量终点滑过的距离
用滑过的距离(s),view向量的长度(l),求得水平角(a),竖直角(b)
a=arc tan s.x/l b=arc tan s.y/l