opengl 教程(11) 平移/旋轉/縮放


原帖地址:http://ogldev.atspace.co.uk/www/tutorial11/tutorial11.html

      在前面的教程中,我們通過矩陣變化實現了物體在三維空間的平移、旋轉、縮放操作。在本篇教程中,我們來實現這三種的變化的組合操作。通常情況下,我們會先縮放三維模型,使得它和其它物體大小相匹配,然后會旋轉該物體,使得它朝向正確的方向,最后則是平移操作。為了實現上述操作,我們只需把三個變化矩陣相乘,就得到了最終的變化矩陣,該矩陣乘以頂點坐標向量,就得到變化后的坐標位置。

看下面的公式:

Mn * Mn-1 * ... * M0 * V = (Mn* Mn-1 * ... * M0) * V
N = Mn * Mn-1 * ... * M0
那么
Mn * Mn-1 * ... * M0 * V = N * V

      所以我們只需在cpu上計算組合矩陣,然后做為uniform變量,傳輸到shader中區。在頂點shader中,用該矩陣來乘頂點位置,得到最終的坐標。

     前面說了,通常情況下,先縮放,再旋轉,最后平移,矩陣相乘的方式,也是按照這個順序,如果順序反了或者不對,就會得到不同的結果,比如下面的圖是先旋轉,然后平移的效果。

rot_trans

下面的圖則是先平移,后旋轉的結果,可見順序不同,最終的結果也不同。

trans_rot

      在本教程的程序中,我們引入了pipeline類,該類隱藏矩陣變化的細節,我們只要傳入縮放、旋轉、平移的參數,就可以得到最終的變化矩陣。

主要代碼:

在math_3d.h中增加了矩陣類,主要用來實現矩陣的乘法操作。

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

首先定義了2個角度弧度轉化的宏。

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;
}

重載矩陣相乘操作符,實現2個4x4矩陣的乘法操作。


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類抽象了單個物體矩陣變化的所有細節。

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變量,分別調用它的三個類,傳入縮放、旋轉、平移參數,然后得到最終的變化矩陣,並把它傳送到shader中去。

     下面是程序運行后的效果,一個四面體在窗口內飛來飛去:

image


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM