转自:http://hanwei0143.blog.163.com/blog/static/519269932007112591355562/
3D图形的渲染中数据处理主要是按照这样流程处理:
模型空间->世界空间->摄像机空间->剪裁空间->屏幕空间
其中,从模型空间到世界空间的变换,在DX中就是IDirect3DDevice9::SetTranform(D3DTS_WORLD, &matrix),matrix矩阵可以做旋转、缩放和平移变换,注意是变换的顺序,是先旋转后平移,当然想实现某种特殊的效果除外.
从世界空间到摄像机空间的变换就是DX中所说的视图空间变换,一般情况下为了是投影变换(即由摄像机空间到剪裁空间的变换)减少计算量,所以将摄像机变换到世界坐标戏的原点并把摄像机的方向转到Z轴的正方向,当然世界坐标系中所有物体都将随着摄像机的变换做相同的变换。在DX中就是使用IDirect3DDevice9::SetTranform(D3DTS_VIEW, &view),view是摄像机变换到原点的矩阵。
一般情况下,描述摄像机的量共有四个,即right vector、up vector、look vector和position vecctor,其中right描述摄像机向右的方向,look描述摄像机向前看的方向,up是摄像机垂直向上的方向,这三个方向相互垂直,而且由于只是描述摄像机的方向向量,所以向量的长度的长度为单位长度,所以三个向量为标准正教基。
如果要将摄像机平移到世界空间的原点是特别容易的,摄像机的位置在[px, py, pz]的话,只要将摄像机平移[-px, -py, -pz]即可,即平移矩阵为
1 0 0 0
T= 0 1 0 0
0 0 1 0
-px -py -pz 1
为了将摄像机的方向调整为世界坐标系下的x,y,z的正方向,分别对应摄像机方向向量中的right,up,look这三个向量,那么
_00 _01 _02 _03
[rx, ry, rz, 0] * _10 _11 _12 _13 = [1, 0, 0, 0]
_20 _21 _22 _23
_30 _31 _32 _33
_00 _01 _02 _03
[ux, uy, uz, 0] * _10 _11 _12 _13 = [0, 1, 0, 0]
_20 _21 _22 _23
_30 _31 _32 _33
_00 _01 _02 _03
[lx, ly, lz, 0] * _10 _11 _12 _13 = [0, 0, 1, 0]
_20 _21 _22 _23
_30 _31 _32 _33
则,
rx ry rz 0 _00 _01 _02 _03 1 0 0 0
ux uy uz 0 _10 _11 _12 _13 = 0 1 0 0
lx ly lz 0 _20 _21 _22 _23 0 0 1 0
0 0 0 1 _30 _31 _32 _33 0 0 0 1
由于单位向量是标准正交基,那么求这个矩阵的只要求它的转置矩阵即可。
将平移和旋转部分合并起来就是视图变换矩阵,如下:
1 0 0 0 rx ux dx 0 rx ux dx 0
0 1 0 0 * ry uy dy 0 = ry uy dy 0
0 0 1 0 rz uz dz 0 rz uz dz 0
-px -py -pz 1 0 0 0 1 -pr -pu -pd 1
我们看DX9帮助文档中,D3DXMatrixLookAtLH函数的计算公式也是这样的:
zaxis = normal(At - Eye)
xaxis = normal(cross(Up, zaxis))
yaxis = cross(zaxis, xaxis)
xaxis.x yaxis.x zaxis.x 0
xaxis.y yaxis.y zaxis.y 0
xaxis.z yaxis.z zaxis.z 0
-dot(xaxis, eye) -dot(yaxis, eye) -dot(zaxis, eye) 1
唯一的不同就是D3DXMatrixLookAtLH的函数参数只有四个,即摄像机位置Eye、摄像机朝向At、摄像机上向量Up,通过简单的运算就可以转换成我们上面所说的那四个描述量了,在这里就不赘言了。