本文截取自作者计算机图形学课程设计中的一部分。
1.坐标系转换的基本原理
接下来将演示如何将世界坐标系转换为观察坐标系。
首先给出一个右手系的世界坐标系展示,如下图.
先对世界坐标系进行平移变换,平移矩阵为[1 0 0 a;0 1 0 b;0 0 1 c; 0 0 0 1]即使原点移动了(a,b,c)。如下图所示。
然后进行将平移变换后的矩阵中的Z轴绕Y轴进行旋转,使得Z轴与两个坐标系原点构成的直线在同一个平面上,这里假设旋转角度是q,变化矩阵为[cosq 0 -sinq 0;0 1 0 0;sinq 0 cosq 0;0 0 0 1].如下图所示。
平移之后,PZ与观察向量PA共面,此时将PZ即Z轴绕X轴向下旋转p度后与PA观察向量共线。这里的旋转变化矩阵为[1 0 0 0;0 cosp sinp 0;0 -sinp cosp 0;0 0 0 1]。旋转变换后如下图2.6所示。
至此,在世界坐标系和观察坐标系为同右手坐标系的情况下的坐标系转换就完成了,同左手坐标系的情况同理可得。但若是观察坐标系为左手坐标系的情况下,只需将X轴对称变化即可,变化矩阵为[-1 0 0 0;0 1 0 0;0 0 1 0;0 0 0 1]。
总结如下,在该例中当世界坐标系和观察坐标系同手系的情况下,需要经过以下变化:
- 平移变换T1 = [1 0 0 a;0 1 0 b;0 0 1 c; 0 0 0 1]
- 旋转变换R1 = [cosq 0 -sinq 0;0 1 0 0;sinq 0 cosq 0;0 0 0 1]
- 旋转变换R2 = [1 0 0 0;0 cosp sinp 0;0 -sinp cosp 0;0 0 0 1]
最终变换矩阵为Final_Matrix = R2R1T1。
当世界坐标系和观察坐标系不同手系的情况下,需要经过以下变化:
- 平移变换T1 = [1 0 0 a;0 1 0 b;0 0 1 c; 0 0 0 1]
- 旋转变换R1 = [cosq 0 -sinq 0;0 1 0 0;sinq 0 cosq 0;0 0 0 1]
- 旋转变换R2 = [1 0 0 0;0 cosp sinp 0;0 -sinp cosp 0;0 0 0 1]
- 对称变换S1 = [-1 0 0 0;0 1 0 0;0 0 1 0;0 0 0 1]
最终变换矩阵为Final_Matrix = S1R2R1*T1。
而世界坐标系到观察坐标系的转换无非就是世界矩阵中的一个输入参数InputParam,左乘Final_Matrix最终变换矩阵,输出得到的结果值OuputParam就是InputParam在观察坐标系中表示。这里坐标系转换的关键就是Final_Matrix最终变换矩阵,以此可推理出坐标系转换的核心即是矩阵变化。
2.三维摄像机的初始化
1.要进行摄像机的初始化,即构建一个正交坐标系为观察坐标系,通过创建三个向量,分别为:LeftVector(1.0f,0.0f,0.0f)作X轴,UpVector(0.0f,1.0f,0.0f)作Y轴,LookVector(0.0f,0.0f,1.0f)作Z轴.
2.再设置摄像机的位置(0.0f,500.0f,-2700.0f)和观察目标(0.0f,500.0f,0.0f)的位置
3.取景矩阵的初始化,这里设置Direct3D中的取景变化矩阵,可以根据用户传入的指定对摄像机进行相应的平移,旋转,比例变化。这里需要实时计算取景变化矩阵,因为用户操作的输入是随机的,根据输入改变观察坐标系的三个基向量,取景变化中根据三个基向量计算最终的取景变化矩阵,如下所示。
//确保摄像机的每个向量正交
D3DXVec3Normalize(&m_vLookVector,&m_vLookVector);//Z轴发生变换,规范化Z轴
D3DXVec3Cross(&m_vUpVector,&m_vLookVector,&m_vRightVector); //叉乘获取垂直于平面的向量
D3DXVec3Normalize(&m_vUpVector,&m_vUpVector); //规范化Y轴
D3DXVec3Cross(&m_vRightVector,&m_vUpVector,&m_vLookVector);
D3DXVec3Normalize(&m_vRightVector,&m_vRightVector); //规范化X轴
//创建取景变化矩阵,传入的是摄像机的X,Y,YZ轴
//X轴
pViewMatrix ->_11 = m_vRightVector.x;
pViewMatrix->_21 = m_vRightVector.y;
pViewMatrix->_31 = m_vRightVector.z;
pViewMatrix->_41 = -D3DXVec3Dot(&m_vRightVector,&m_vCameraPosition); //点乘,比例变化,Right向量和CameraPostition向量方向相反,所以要乘负号
//Y轴
pViewMatrix->_12 = m_vUpVector.x;
pViewMatrix ->_22=m_vUpVector.y;
pViewMatrix->_32= m_vUpVector.z;
pViewMatrix->_42 =-D3DXVec3Dot(&m_vUpVector,&m_vCameraPosition);
//Z轴
pViewMatrix->_13 = m_vLookVector.x;
pViewMatrix->_23 = m_vLookVector.y;
pViewMatrix->_33 = m_vLookVector.z;
pViewMatrix->_43 = -D3DXVec3Dot(&m_vLookVector,&m_vCameraPosition);
//第四列
pViewMatrix->_14 = 0.0f;
pViewMatrix->_24 = 0.0f;
pViewMatrix->_34 = 0.0f;
pViewMatrix->_44 = 1.0f;
4.然后需要初始化的就是透视变化矩阵,世界坐标系在观察坐标系上的展示,需要在Direct3D中设置类型为PROJECTION的透视矩阵,换而言之即初始化观察坐标系,所以需要现指定观察坐标系的手系,由于Direct3D9中默认的世界坐标系为左手坐标系,所以这里的观察坐标系也设为左手坐标系,避免使矩阵的计算变得复杂。
5.下图是取景变化和投影变化的示例图,该图节选自毛星云大佬的《逐梦旅程:Windows游戏编程之从零开始》
3.世界坐标系-观察坐标系的转换
根据上述三维摄像机初始化的过程中,不难看出,所谓的世界坐标系-观察坐标系等等,无非就是矩阵的变化。通过取景变化矩阵,透视变化矩阵等等变化矩阵算出最终矩阵。列坐标的表示情况下,世界坐标系中人物的当前变化矩阵左乘这个最终矩阵便可转化为观察坐标系中的人物进行展示了。所以坐标系之间的转化实际就是变化矩阵的计算。
4.后言
实际项目可看以下链接:
项目展示
感谢阅读,如有错误还请斧正。