天天看點

坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考

原文位址:https://www.cnblogs.com/graphics/archive/2012/08/10/2627458.html

繞任意軸旋轉

繞坐标軸旋轉

關于最常見的繞坐标軸旋轉,可以看看前一篇-幾何變換詳解。

繞任意軸旋轉

繞任意軸旋轉的情況比較複雜,主要分為兩種情況,一種是平行于坐标軸的,一種是不平行于坐标軸的,對于平行于坐标軸的,我們首先将旋轉軸平移至與坐标軸重合,然後進行旋轉,最後再平移回去。

  • 将旋轉軸平移至與坐标軸重合,對應平移操作
    坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考
  • 旋轉,對應操作
    坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考
  • 步驟1的逆過程,對應操作 
    坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考

整個過程就是

坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考

對于不平行于坐标軸的,可按如下方法處理。(該方法實際上涵蓋了上面的情況)

  1. 将旋轉軸平移至原點
  2. 将旋轉軸旋轉至YOZ平面
  3. 将旋轉軸旋轉至于Z軸重合
  4. 繞Z軸旋轉θ度
  5. 執行步驟3的逆過程
  6. 執行步驟2的逆過程
  7. 執行步驟1的逆過程

假設用v1(a1, b2, c2)和v2(a2, b2, c2)來表示旋轉軸,θ表示旋轉角度。為了友善推導,暫時使用右手系并使用列向量,待得出矩陣後轉置一下即可,上面步驟對應的流程圖如下。

坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考

步驟1是一個平移操作,将v1v2平移至原點,對應的矩陣為

坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考

步驟2是一個旋轉操作,将p(p = v2 -v1)旋轉至XOZ平面,步驟3也是一個旋轉操作,将p旋轉至與Z軸重合,這兩個操作對應的圖如下。

坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考

做點p在平面YOZ上的投影點q。再過q做Z軸垂線,則r是p繞X軸旋轉所得,且旋轉角度為α,且

坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考

,    

坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考

于是旋轉矩陣為

坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考

現在将r繞Y軸旋轉至與Z軸重合,旋轉的角度為-beta(方向為順時針),且

坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考

,     

坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考

于是得到旋轉矩陣為

坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考

最後是繞Z軸旋轉,對應的矩陣如下

坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考

如果旋轉軸是過原點的,那麼第一步和最後一步的平移操作可以省略,也就是把中間五個矩陣連乘起來,再轉置一下,得到下面的繞任意軸旋轉的矩陣

坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考

坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考

對應的函數代碼如下。

void RotateArbitraryAxis(D3DXMATRIX* pOut, D3DXVECTOR3* axis, float theta)
{
    D3DXVec3Normalize(axis, axis);
    float u = axis->x;
    float v = axis->y;
    float w = axis->z;

    pOut->m[0][0] = cosf(theta) + (u * u) * (1 - cosf(theta));
    pOut->m[0][1] = u * v * (1 - cosf(theta)) + w * sinf(theta);
    pOut->m[0][2] = u * w * (1 - cosf(theta)) - v * sinf(theta);
    pOut->m[0][3] = 0;

    pOut->m[1][0] = u * v * (1 - cosf(theta)) - w * sinf(theta);
    pOut->m[1][1] = cosf(theta) + v * v * (1 - cosf(theta));
    pOut->m[1][2] = w * v * (1 - cosf(theta)) + u * sinf(theta);
    pOut->m[1][3] = 0;

    pOut->m[2][0] = u * w * (1 - cosf(theta)) + v * sinf(theta);
    pOut->m[2][1] = v * w * (1 - cosf(theta)) - u * sinf(theta);
    pOut->m[2][2] = cosf(theta) + w * w * (1 - cosf(theta));
    pOut->m[2][3] = 0;

    pOut->m[3][0] = 0;
    pOut->m[3][1] = 0;
    pOut->m[3][2] = 0;
    pOut->m[3][3] = 1;
           

如果旋轉軸是不過原點的,那麼第一步和最後一步就不能省略,将所有七個矩陣連乘起來,得到如下變換矩陣

坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考

對應如下這個超長的矩陣,在這裡(u, v, w) = (a2, b2, c2) - (a1, b1, c1),且是機關向量,a, b, c分别表示(a1, b1, c1)

坐标變換 旋轉矩陣繞坐标軸旋轉繞任意軸旋轉參考

将上面的過程寫成函數,該函數接受四個參數,第一個參數是一個輸出參數,用來儲存得到的旋轉矩陣,第二個和第三個參數是旋轉軸的兩個端點,最後一個參數是旋轉角度θ,注意,在函數中我們已經将上面的矩陣轉置了,因為上面是按照列向量計算的。

void RotateArbitraryLine(D3DXMATRIX* pOut, D3DXVECTOR3* v1, D3DXVECTOR3* v2, float theta)
{
    float a = v1->x;
    float b = v1->y;
    float c = v1->z;

    D3DXVECTOR3 p = *v2 - *v1;
    D3DXVec3Normalize(&p, &p);
    float u = p.x;
    float v = p.y;
    float w = p.z;

    float uu = u * u;
    float uv = u * v;
    float uw = u * w;
    float vv = v * v;
    float vw = v * w;
    float ww = w * w;
    float au = a * u;
    float av = a * v;
    float aw = a * w;
    float bu = b * u;
    float bv = b * v;
    float bw = b * w;
    float cu = c * u;
    float cv = c * v;
    float cw = c * w;

    float costheta = cosf(theta);
    float sintheta = sinf(theta);

    pOut->m[0][0] = uu + (vv + ww) * costheta;
    pOut->m[0][1] = uv * (1 - costheta) + w * sintheta;
    pOut->m[0][2] = uw * (1 - costheta) - v * sintheta;
    pOut->m[0][3] = 0;

    pOut->m[1][0] = uv * (1 - costheta) - w * sintheta;
    pOut->m[1][1] = vv + (uu + ww) * costheta;
    pOut->m[1][2] = vw * (1 - costheta) + u * sintheta;
    pOut->m[1][3] = 0;

    pOut->m[2][0] = uw * (1 - costheta) + v * sintheta;
    pOut->m[2][1] = vw * (1 - costheta) - u * sintheta;
    pOut->m[2][2] = ww + (uu + vv) * costheta;
    pOut->m[2][3] = 0;

    pOut->m[3][0] = (a * (vv + ww) - u * (bv + cw)) * (1 - costheta) + (bw - cv) * sintheta;
    pOut->m[3][1] = (b * (uu + ww) - v * (au + cw)) * (1 - costheta) + (cu - aw) * sintheta;
    pOut->m[3][2] = (c * (uu + vv) - w * (au + bv)) * (1 - costheta) + (av - bu) * sintheta;
    pOut->m[3][3] = 1;
}
           

參考

http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/

http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle

http://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula

== Happy Coding ==

繼續閱讀