變換矩陣在左右座標系的轉換

[TOC]bash

疑惑

Max導出的fbx模型文件加載到客戶端,對變換矩陣作了以下的轉換,把Z-up右手座標系的變換矩陣換到Y-up左手座標系的變換矩陣。咋一看至關懵逼~ui

FORCEINLINE void _DxMatrixToApexMatrix(physx::PxMat44& matrix, const XMFLOAT4X4& xmMatrix)
{
    XMFLOAT4X4 mat = xmMatrix;    

    std::swap(mat._21, mat._31);
    std::swap(mat._22, mat._32);
    std::swap(mat._23, mat._33);
    std::swap(mat._24, mat._34);

    std::swap(mat._12, mat._13);
    std::swap(mat._22, mat._23);
    std::swap(mat._32, mat._33);
    std::swap(mat._42, mat._43);

    memcpy((void*)matrix.front(), &mat._11, sizeof(float) * 16);    
}
複製代碼

座標系的不一樣

coordinate

  • max max裏面是Z朝上的右手座標系,如圖(a)所示.spa

  • DX11 客戶端用的DX11是Y軸朝上的左手座標系,如圖(b)所示.翻譯

座標系轉換

  • 錯誤的作法

一開始想的是把Y和Z換一下就行了,那麼矩陣裏面把第二行和第三行換一下不就好了。代碼應該是這樣:code

FORCEINLINE void _DxMatrixToApexMatrix(physx::PxMat44& matrix, const XMFLOAT4X4& xmMatrix)
{
    XMFLOAT4X4 mat = xmMatrix;    

    std::swap(mat._21, mat._31);
    std::swap(mat._22, mat._32);
    std::swap(mat._23, mat._33);
    std::swap(mat._24, mat._34);

    memcpy((void*)matrix.front(), &mat._11, sizeof(float) * 16);    
}
複製代碼

結果爲何還要換一下第二列和第三列呢? 把Y和Z換一下這個是對的,好比一個向量(x, y, z)變成(x, z, y)。可是,變換矩陣卻不能這樣操做!個人理解是,矩陣裏面有旋轉、縮放、平移,針對的是模型上的全部點。只換第二行和第三行是包括了部分縮放和旋轉信息,最後對模型上點進行轉換的時候都不知道結果是什麼。cdn

  • 驗證 假設在Z-up右手座標系有一個點P(x, y, z),和這個點的變換矩陣:
M = 
    \begin{bmatrix}
    m_{11} & m_{12} & m_{13} & m_{14} \\
    m_{21} & m_{22} & m_{23} & m_{24} \\
    m_{31} & m_{32} & m_{33} & m_{34} \\
    m_{41} & m_{42} & m_{43} & m_{44} \\
    \end{bmatrix}

算一下點P在Z-up右手座標系變換後的點,和點P1在Y-up左手座標系變換後的點是否是依舊是同一個點!其中P1=(x, z, y),爲P在Y-up座標系中相同的點,換了一下Y和Zblog

注意:在Y-up的變換矩陣下P也應該在該座標系下面,即P1 = (x, z, y)get

(1)點P在Z-up右手座標系變換以後的點爲:P*M數學

P*M = (x, y, z)M = (xm_{11}+ym_{21}+zm_{31}+m_{41}, xm_{12}+ym_{22}+zm_{32}+m_{42}, xm_{13}+ym_{23}+zm_{33}+m_{43})

(2)點P在錯誤的Y-up左手座標系變換以後的點爲:P1*M1it

M1 = 
    \begin{bmatrix}
    m_{11} & m_{12} & m_{13} & m_{14} \\
    m_{31} & m_{32} & m_{33} & m_{34} \\
    m_{21} & m_{22} & m_{23} & m_{24} \\
    m_{41} & m_{42} & m_{43} & m_{44} \\
    \end{bmatrix}

P1*M1 = (x, z, y)M1 = (xm_{11}+zm_{31}+ym_{21}+m_{41}, xm_{12}+zm_{32}+ym_{22}+m_{42}, xm_{13}+zm_{33}+ym_{23}+m_{43})

(3)點P在正確的Y-up左手座標系變換矩陣變換以後的嗲哪位:P1*M2

M2 = 
    \begin{bmatrix}
    m_{11} & m_{13} & m_{12} & m_{14} \\
    m_{31} & m_{33} & m_{32} & m_{34} \\
    m_{21} & m_{23} & m_{22} & m_{24} \\
    m_{41} & m_{42} & m_{43} & m_{44} \\
    \end{bmatrix}

P1*M2 = (x, z, y)M2 = (xm_{11}+zm_{31}+ym_{21}+m_{41}, xm_{13}+zm_{33}+ym_{23}+m_{43}, xm_{12}+zm_{32}+ym_{22}+m_{42})

小結:

(1)能夠看到,PM和P1M2的結果換一下Y和Z軸就是同樣的,這也說明M2纔是正確的變換矩陣!

(2)同時,能夠看到P1M1的結果和PM的結果是同樣的,這就奇怪了,P1在Y-up左手座標系用這個矩陣變換後又回到了Z-up右手座標系裏面的座標(等於沒有變換了)

原理

參考[1]中給出了說明,翻譯一下以下:

M_YZ右手 = ...// 變換YZ座標獲得在Z-up右手座標系的點
M_YZ左手 = 求逆(M_YZ右手)  // 變換YZ座標從新獲得在Y-up左手座標系的座標
M右手 = ...  // 在Z-up右手座標系下的一個變換矩陣
M左手 = M_YZ右手 * M右手 * M_YZ左手
複製代碼

簡單說明一下:

  • 理解上就是不能在不一樣的座標系下面矩陣變換。如今是已知在Z-up下面的變換矩陣,求在Y-up下面的變換矩陣。那麼就先把點變換到Z-up右手座標系中,進行矩陣變換,獲得點在Z-up右手座標系新的位置,而後再把這個點換YZ座標從新獲得在Y-up左手座標系的座標。
  • M_YZ右手指的是在Z-up右手座標系裏面的把Y和Z換一下,也就是把Z-UP右手座標系裏面的點變換到了Y-up左手座標系裏面的點
M_{YZ-Right} = 
    \begin{bmatrix}
    1 & 0 & 0 & 0 \\
    0 & 0 & 1 & 0 \\
    0 & 1 & 0 & 0 \\
    0 & 0 & 0 &1 \\
    \end{bmatrix}
  • M_YZ左手是相反的操做,其實就是M_YZ右手的逆矩陣,而這裏二者是相等的,簡單驗證就是M_{YZ-Left}  * {M_{YZ-Right}}^{-1}爲單位矩陣
M_{YZ-Left}  = {M_{YZ-Right}}^{-1} = 
    \begin{bmatrix}
    1 & 0 & 0 & 0 \\
    0 & 0 & 1 & 0 \\
    0 & 1 & 0 & 0 \\
    0 & 0 & 0 &1 \\
    \end{bmatrix}

結論

  • 數學大法好啊

參考

[1]Changing a matrix from right-handed to left-handed coordinate system

相關文章
相關標籤/搜索