Inside out: Camera

王朝other·作者佚名  2006-02-01
窄屏简体版  字體: |||超大  

Inside out: Camera

丁欧南

Keyword:[OpenGL Camera][FPS 场景][第一人称射击场景]

我是一名OpenGL初学者,刚刚弄懂Camera的实作方法,愿与初学者共享,与高手探讨.如需要此文完整代码,或要转载,请发邮件给我.

A.约定

1. sin cos 等的引数全用弧度制

2. 使用OpenGL

右手定则

3. 矩阵(Matrix)书写规范:

平移(Translation)部分位于最后一行,你可以不加修改地把矩阵写入自己的OpenGL 代码

例:

[A11 A12 A13 A14]

[A21 A22 A23 A24]

[A31 A32 A33 A34]

[A41 A42 A43 A44]

float matrix[]={A11,A12,A13,A14,A21,A22,A23,A24,A31,A32,A33,A34,A41,A42,A43,A44};

4. *:点积(Dot

Product) ×:叉积(Cross

Product)

B.概念

大家都知道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.绕任意轴旋转一条向量

Vup⊥Vperp |Vup|=|Vperp|=|Vaux| Vproj⊥Vperp n∥Vproj n为单位向量

绕n旋转V θ度到V’,

求V’

Vproj=|Vproj|/|n| n

n*V=|n||V|cosβ

cosβ=|Vproj|/|V| |Vproj|=|V|cosβ

n*V=|n||Vproj| |Vproj|=(n*V)/|n|

Vproj=(n*V)/|n|2

n 因为

n 为单位向量

所以

Vproj=n*V n

Vperp=V-Vproj=V-n*V

n

Vup=Vperp×n=(V-n*V n)×n=V×n-n*V(n×n)=V×n

Vaux=-sin(θ-90)Vperp+cos(θ-90)Vup=sin(90-θ)Vperp+cos(90-θ)Vup

=cosθVperp+sinθVup=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

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
© 2005- 王朝網路 版權所有 導航