1. 程式人生 > >統一D3D與OpenGL坐標系統

統一D3D與OpenGL坐標系統

dir none open 轉置 .net 結構 順序 -m 坐標變換

作者:遊藍海(http://blog.csdn.net/you_lan_hai


DirectX 3D與OpenGL坐標系統的差異性,給我們帶來非常大的麻煩。讓跨平臺編程的新手非常困惑。近期在做一個跨平臺的遊戲,細致看了下兩者的矩陣。發現並沒有什麽大差別,將d3d左手系的矩陣傳遞給opengl shader全然能夠正常工作。

先說一下兩者一些概念上的差別:

1)坐標系統不同

d3d左手坐標系,opengl右手坐標系

2)矩陣行序不同

d3d行優先,opengl列優先。這兩個不同,直接導致了坐標變換順序與矩陣乘法順序的相反性。假設是先縮放。再旋轉,最後平移。相應的矩陣分別為S、R、T,則d3d的終於矩陣為M = S * R * T。opengl為M = T * R * S

3)裁減空間z取值範圍不同

d3d是[0, 1]。opengl是[-1, 1]


表面上來看,兩者矩陣區別非常大。但事實上不然。

1.左右手坐標系

對於顯卡設備來說,設備坐標系是左手坐標系,即z軸指向屏幕裏面。z值越大表示距離視線越遠。

因此,opengl的右手系,在進入裁減空間的時候。會轉換成左手系。

這也就是說。在渲染管線內部。坐標系是統一的。無論是左手坐標系矩陣,還是右手坐標系矩陣。僅僅要變換到裁減空間中的點是左手系就能夠了。


2.矩陣行序

行矩陣和列矩陣,在邏輯上一個是還有一個的轉置。但在物理存貯結構上卻是全然一致的。如一個平移變換(x, y, z):

技術分享

須要註意的是,矩陣乘法並不關心矩陣是行矩陣還是列矩陣。都是依照第一個矩陣的行去乘以第二個矩陣的列。對於列矩陣而言,這正是其蹩腳的地方,為了保證乘法意義的有效性,其坐標變換順序跟矩陣乘法順序恰好相反。

還要註意一點,在shader中,opengl的矩陣乘法規則跟d3d是不同的。

依照矩陣乘法規則(第一個矩陣行*第二個矩陣列):

d3d矩陣乘法: Ma(0 1 2 3) * Mb(0 4 8 12)

opengl矩陣乘法: Ma(0 4 8 12) * Mb(0 1 2 3)

因此。對於opengl shader而言。變換順序跟矩陣乘法順序依舊是反的。假設我們能將傳入opengl shader的矩陣做一次轉置。那麽opengl shader的矩陣乘法意義將跟d3d shader全然一致!


3.改動投影矩陣

因為opengl的裁減空間z取值範圍為[-1, 1]跟d3d的[0, 1]不同,我們不能簡單的使用d3d投影矩陣。必須又一次定義d3d投影矩陣。

void Matrix::perspectiveProjectionLH2( float fov, float aspectRatio,
        float nearPlane, float farPlane )
{
        float h = (1.0f / tanf(fov * 0.5f));
        float w = h / aspectRatio;

        float a = (farPlane + nearPlane) / (farPlane - nearPlane);
        float b = -2.0f * farPlane * nearPlane / (farPlane - nearPlane);
        
        m[0][0] = w; m[0][1] = 0; m[0][2] = 0; m[0][3] = 0;
        m[1][0] = 0; m[1][1] = h; m[1][2] = 0; m[1][3] = 0;
        m[2][0] = 0; m[2][1] = 0; m[2][2] = a; m[2][3] = 1;
        m[3][0] = 0; m[3][1] = 0; m[3][2] = b; m[3][3] = 0;
}


4.總結

使用左手系變換來統一兩個平臺是比較方便的。總結一下改動opengl渲染管線的步驟:

(1)在c++層統一使用左手坐標系變換。

(2)改動投影矩陣。以適應裁減空間z坐標範圍[-1, 1];

(3)矩陣在傳入shader的時候,將矩陣的轉置矩陣傳入;

(4)在shader層,統一使用左手坐標系變換。

假設,不想改動shader中的變換,僅僅用做到(1)和(2)就夠了。


5.很多其它閱讀

推導投影矩陣 http://blog.csdn.net/popy007/article/details/4091967

跨越opengl和d3d的鴻溝 http://www.cppblog.com/topjackhjj/articles/157038.html


統一D3D與OpenGL坐標系統