OpenGL 入門10

原帖地址:
http://ogldev.atspace.co.uk/www/tutorial11/tutorial11.html
http://blog.csdn.net/cordova/article/details/52571920

複合變換

在之前的教程中,我們已經學會了如何使用變換矩陣來移動場景中的物體,如何縮放你的物體到合適的大小,以及旋轉物體到合適的角度。不過我們每次都只進行了一種操作。通過讓頂點與各個變換矩陣相乘來得到最終的位置,縮放或旋轉角度。
M3*(M2*(M1*v)) = V

通過乘法的結合律,我們可以將M3,M2,M1相乘的結果再乘以v,進而得到與上式相同的結果。
N = M3*M2*M1
N*v = V
這意味這我們可以一次性的計算出N,然後在把這個N傳給shader中的uniform variable。我們的頂點是從乘以矩陣M1開始的,然後依次從右向左乘以M2,M3。在3D圖形之中,我們通常會先縮放物體,然後旋轉物體最後再移動物體。對最終的物體進行相機變換以及投影到2D屏幕的計算,得到的繪製結果。如果我們對一個物體先執行旋轉操作,在執行移動操作的話,如圖:
這裏寫圖片描述

如果先移動,再旋轉的話,結果如下:
這裏寫圖片描述
正如上圖中看到的那樣,如果我們先對一個物體移動之後在旋轉的話,將會很難去設定他的位置,因爲我們的旋轉是以原點爲參照點的,如果最後異步是旋轉,因爲物體已經原理原點了,這次的旋轉操作將會促使物體發生移動,也就是說這個操作既有旋轉又有移動,這就會變得很難操控。通過先旋轉在移動的方式,我們保存了這兩種操作的獨立性。

代碼

#define ToRadian(x) ((x) * M_PI / 180.0f)
#define ToDegree(x) ((x) * 180.0f / M_PI)

定義了兩個宏,用來完成度和弧度之間的轉換。

inline Matrix4f operator*(const Matrix4f& Right) const
{
    Matrix4f Ret;
    for (unsigned int i = 0 ; i < 4 ; i++) {
       for (unsigned int j = 0 ; j < 4 ; j++) {
           Ret.m[i][j] = m[i][0] * Right.m[0][j] +
                         m[i][1] * Right.m[1][j] +
                         m[i][2] * Right.m[2][j] +
                         m[i][3] * Right.m[3][j];
       }
    }

    return Ret;
}

我們重載了*運算符,用來完成矩陣的乘法運算。

class Pipeline
{
    public:
       Pipeline() { ... }
       void Scale(float ScaleX, float ScaleY, float ScaleZ) { ... }
       void WorldPos(float x, float y, float z) { ... }
       void Rotate(float RotateX, float RotateY, float RotateZ) { ... }
       const Matrix4f* GetTrans();
    private:
       Vector3f m_scale;
       Vector3f m_worldPos;
       Vector3f m_rotateInfo;
       Matrix4f m_transformation;
};

定義一個叫做Pipeline的類用來管理我們的縮放矩陣,平移矩陣以及旋轉矩陣,m_transformation代表我們的各個變換矩陣相乘後的結果。記得m_transformation = m_worldPos*m_rotateInfo*m_scale,相乘的順序很重要。

const Matrix4f* Pipeline::GetTrans()
{
    Matrix4f ScaleTrans, RotateTrans, TranslationTrans;
    InitScaleTransform(ScaleTrans);
    InitRotateTransform(RotateTrans);
    InitTranslationTransform(TranslationTrans);
    m_transformation = TranslationTrans * RotateTrans * ScaleTrans;
    return &m_transformation;
}

用於獲取我們的變換矩陣的函數。

Pipeline p;
p.Scale(sinf(Scale * 0.1f), sinf(Scale * 0.1f), sinf(Scale * 0.1f));
p.WorldPos(sinf(Scale), 0.0f, 0.0f);
p.Rotate(sinf(Scale) * 90.0f, sinf(Scale) * 90.0f, sinf(Scale) * 90.0f);
glUniformMatrix4fv(gWorldLocation, 1, GL_TRUE, (const GLfloat*)p.GetTrans());

我們定義了一個Pipeline類型的p變量,這個變量的縮放矩陣,平移矩陣以及旋轉矩陣傳入的參數都包括Scale變量,所以每一幀這些矩陣都在變化,也就是說每一幀我們傳給vertex shader的矩陣都不一樣,這就會導致我們渲染出來的圖形出現動畫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章