1//设置投影矩阵 2/**//* 3 这部分虽然只有少数几行,由于我的数学全丢给老师了,结果这里是我花时间最多的地方。 4 */ 5void HGE_Impl::_SetProjectionMatrix(int width, int height) 6{ 7 D3DXMATRIX tmp; 8 /**//* 9 D3DXMatrixScaling产生的缩放矩阵是让我不明白地方,实际上,它仅仅起到以X轴旋转180度作用。 10 我将D3DXMatrixScaling换成D3DXMatrixRotationX(&matProj,D3DX_PI),结果不变。但这个小小的东西,造成了很大的误解。 11 12 13 虽然选旋转180度,再平移,再正交。但我们理解的顺序,却要完全反过来。 14 第一:重置坐标系,也就是用正交投影函数。在这里将坐标原点变成屏幕了左下角。这个Y轴向上,X轴向右 15 第二:平移,将原点向上平移屏幕的高度,这样原点就变成左上角了。 16 第三:以X轴旋转180度,这样Y轴向下了。 17 经过这样的变换后,我们就可以用我们习惯的屏幕坐了。 18 19 公式如下: 20 D3D的坐标矩阵 = 屏幕坐标矩阵* (旋转矩阵 * 平移矩阵 * 正交矩阵) 注:这里的顺序是不能变的 21 22 D3D的坐标矩阵是以屏幕中心为原点,x(-1,1),y(-1,1),z(0,1)的坐标系。 23 24 我们可以通过这个坐标系,可以坐标还原屏幕矩阵 25 公式如下: 26 X1为D3D坐标矩阵中的X,Y1为D3D坐标矩阵中的Y 27 X2为还原的还原屏幕X,Y2为还原的还原屏幕Y 28 X2 = (X1 + 1) * (WINDOW_WIDTH/2); 29 Y2 = WINDOW_HEIGHT - (Y1 + 1) * (WINDOW_HEIGHT/2); 30 结果你会发现,这个与你输入的结果一样。 31 32 另外,在平移过程中,HGE多平移了0.5个单位,这个应该和纹理有关,如果刚好全屏的纹理贴图,可能边缘会出现问题。 33 */ 34 D3DXMatrixScaling(&matProj, 1.0f, -1.0f, 1.0f); 35 D3DXMatrixTranslation(&tmp, -0.5f, height+0.5f, 0.0f); 36 D3DXMatrixMultiply(&matProj, &matProj, &tmp); 37 D3DXMatrixOrthoOffCenterLH(&tmp, 0, (float)width, 0, (float)height, 0.0f, 1.0f); 38 D3DXMatrixMultiply(&matProj, &matProj, &tmp); 39} 40
为了证实我理解正确,我用我实现的矩阵模板类,进行了验证。矩阵的原代码请参考我前面的随笔 矩阵C++实现模板
1int main(int argc,char * argv) 2{ 3 FloatMatrix v1(4,4),v2(4,4),v3(4,4),v(4,4); 4 FloatMatrix p(1,4),p2(1,4); 5 XMatrixRotationX(&v1,X_PI); 6 XMatrixTranslation(&v2, 0.0f, 600.0f, 0.0f); 7 XMatrixOrthoOffCenterLH(&v3, 0, 800.0f, 0, 600.0f, 0.0f, 1.0f); 8 v = v1*v2*v3; 9 p.Clear(0.0f); 10 p(1,4) = 1.0f; 11 for(int x = 0; x <= 800; x+= 100) 12 { 13 for(int y = 0; y <= 600; y+= 50) 14 { 15 p(1,1) = (float)(rand()%800); 16 p(1,2) = (float)(rand()%600); 17 p2 = p * v; 18 p2(1,1) = (p2(1,1) + 1) * 400.0f; 19 p2(1,2) = 600- (p2(1,2) + 1) * 300.0f; 20 cout<<"Src("<<p(1,1)<<","<<p(1,2)<<") Dest=("<<p2(1,1)<<","<<p2(1,2)<<")"<<endl; 21 } 22 } 23 system("pause"); 24 return 0; 25}
|