1 //設置投影矩陣 2 /**//* 3 這部分雖然只有少數幾行,由于我的數學全丟給老師了,結果這里是我花時間最多的地方。 4 */ 5 void 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++實現模板
1 int 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 }
|