我们知道在DX中,坐标的转换是通过与矩阵相乘实现的,一个坐标乘一个转换矩阵得到的新坐标就是转换后的坐标(平移,旋转,缩放后的坐标)
物体的屏幕坐标 = 自身坐标系坐标 * 世界坐标系转换矩阵 * 观察坐标系转换矩阵 * 投影矩阵 * 视口转换矩阵
自身坐标系坐标 * 世界坐标系转换矩阵 可以的到物体在3D世界中的位置,相当于你把一个物体放在了3D世界中
然后你只要设置不同的观察坐标系转换矩阵就就可以实现在不同的地方、角度观察3D世界(就是实现你在3D世界中移动)
至于之后再乘 投影矩阵 * 视口转换矩阵 就是将3D世界转换成2D平面显示在2D的屏幕上
而要完成一个摄像机类,观察坐标系转换矩阵的获得是必不可少的,我们在渲染之前调用IDirect3DDevice9::SetTransfrom(D3DTS_VIEW,&观察坐标系转换矩阵)把观察坐标系转换矩阵告诉DX,这个矩阵就是从我们的摄像机类得到的。通过它,我们可以实现在游戏场景中的漫游。
观察坐标系就是以我们的眼睛为原点,右手方向为X轴正方向,头顶方向为Y轴正方向,正前方为Z轴正方向去描述物体位置坐标的坐标系(注意这个坐标系是左手系),看下面的图:
而我们的眼睛又处于世界坐标系中,所以可以用世界坐标系的坐标去表示观察坐标系的三个坐标轴和眼睛的位置。看下面的图:
(哈哈,注意到了吧,我们不一定是立正在地上的,还可能是歪着身体甚至躺着的......)
那让我们看看怎么得到“将物体从世界坐标系变换到观察坐标系”的转换矩阵:
如果是真的从一个物体在两个坐标系之间的变换去考虑的话,问题会变得十分复杂,所以我们换个思路去考虑。
如果我们的眼睛正好在世界坐标系的原点,右手方向正好为在世界坐标系的X轴正方向,头顶方向正好为在世界坐标系的Y轴正方向,又刚刚好向世界坐标系的Z轴正方向看去,那么观察坐标系不就和世界坐标系重合了吗?不就不用转换了吗?(实在太省事了....)
可惜事与愿违,那么多的巧合是在很难遇到,而且我们又太好动,总是走来走去,那这种假设就更加不科学了。
但就算眼睛的位置是随意的,我们也可以把它移到我们想要的位置啊!
看,如果我们让所有的物体都跟着我们一起动,当我们自己走到世界的原点,然后再立正站好,不就可以了吗?(整个世界跟着你动的感觉......实在太牛逼了。但实际上因为每个物体在变换时都会乘以你所提供的转换矩阵,相当于跟着你在动,所以这种假设是十分形象的。)
你原来的位置
走到世界的原点
转向正确的方向
(原谅我只画了俯视图—,—)
所以我们只要做两步:
1.先走到世界的原点
在DX里,移动是通过和矩阵相乘来实现的(如果你连这个都不理解,最好去补一补基础)
假设我们的位置在 [ posX posY posZ ],那我们只需要往X负方向走posX的距离,往Y负方向走posY的距离,往Z负方向走posZ的距离。
所以我们可以用这个用这个转换矩阵去到我们到达世界的原点:
验证一下,看我们的位置坐标去与之相乘:
(为了实现DX里的平移变换运算,坐标都是 [x,y,z,w] 形式的四维坐标,我们只需要知道xyz坐标就是三维世界里的xyz坐标,w就让他等于1就好了。当然如果你表示的是向量,就要让w为0,因为DX里规定向量的起点在原点,所以不能对向量进行平移操作,何况向量是指方向的,可以旋转和收缩就足够了。)
2.立正站好
我们虽然已经到了世界的原点,但可能是爬过去的,你正面着大地.....
来,让我们假设我们的右手方向原先是 [ Rx Ry Rz ] ,头顶方向原先是 [ Ux Uy Uz ],原来我们面向 [ Lx Ly Lz ],而且它们都是单位化的
我们要想办法立正,就是说让我们的右手指向 [ 1 0 0 ],头向 [ 0 1 0 ],面向 [ 0 0 1 ]
翻译成数学的语言就是乘以一个变换矩阵:
把它们合起来:
我们要做的就是求这个矩阵的逆矩阵。
由于 [ Rx Ry Rz ] ,[ Ux Uy Uz ],[ Lx Ly Lz ] 都是单位化的(长度为1),实际上它是单位正交阵,所以它的逆就是它的转置矩阵
(这是线性代数的东西了,上课睡觉和逃课的同学去翻下书吧)
所以就可以得到:
当然,DX里的矩阵都是4乘4的,所以我们把它扩展一下(这个扩展还真不太好解释,记住就好,也不难吧)
好我们将两步连起来做一遍:
-pos·R = -posX * Rx - posY * Ry - posZ * Rz
-pos·U = -posX * Ux - posY * Uy - posZ *Uz
-pos·L = -posX * Lx - posY * Ly - posZ * Lz
(就是将两矩阵相乘,注意顺序,先走到原点再转向)
好了,这样我们就得到一个观察坐标系转换矩阵了。
通过上面这么长一段东西,我们发现,只要知道:
1.眼睛在世界坐标系中的位置
2.右手方向在世界坐标系中的向量表示
3.头顶方向在世界坐标系中的向量表示
4.正前方方向在世界坐标系中的向量表示
就能求出观察坐标系转换矩阵了
上篇到此为止,最重要的理论部分已经讲完了。在下篇里我会具体讲讲这个摄像机类的代码实现
PS:参考书——《DirectX 9.0 3D游戏开发编程基础》