友快網

導航選單

Qt OpenGL 旗幟效果(飄動的紋理)

這次教程中,我將教大家如何建立一個飄動的旗幟。我們所要建立的旗幟,說白了就是一個以正弦波方式運動的紋理對映影象。雖然不會很難,但效果確實很不錯,希望大家能喜歡。當然這次教程是基於第06課的,希望大家確保已經掌握了前6課再進入本次教程。

程式執行時效果如下:

下面進入教程:

我們這次將在第06課的基礎上修改程式碼,我們只會解釋增加部分的程式碼,首先開啟myglwidget。h檔案,將類宣告更改如下:

【領QT開發教程學習資料,點選下方連結莬費領取↓↓,先碼住不迷路~】

點選→領取「連結」

1 #ifndef MYGLWIDGET_H 2 #define MYGLWIDGET_H 3 4 #include 5 #include 6 7 class MyGLWidget : public QGLWidget 8 { 9 Q_OBJECT10 public:11 explicit MyGLWidget(QWidget *parent = 0);12 ~MyGLWidget();13 14 protected:15 //對3個純虛擬函式的重定義16 void initializeGL();17 void resizeGL(int w, int h);18 void paintGL();19 20 void keyPressEvent(QKeyEvent *event); //處理鍵盤按下事件21 22 private:23 bool fullscreen; //是否全屏顯示24 25 GLfloat m_xRot; //繞x軸旋轉的角度26 GLfloat m_yRot; //繞y軸旋轉的角度27 GLfloat m_zRot; //繞z軸旋轉的角度28 QString m_FileName; //圖片的路徑及檔名29 GLuint m_Texture; //儲存一個紋理30 31 float m_Points[45][45][3]; //儲存網格頂點的陣列32 int m_WiggleCount; //用於控制旗幟波浪運動動畫33 };34 35 #endif // MYGLWIDGET_H

我們增加了m_Points三維陣列來存放網格各頂點獨立的x、y、z座標,這裡網格由45×45點形成,換句話說也就是由44格×44格的小方格子組成的。另一個新增變數m_WiggleCount用來使產生紋理波浪運動動畫,每2幀一次變換波動形狀看起來很不錯。

接下來,我們需要開啟myglwidget。cpp,加上宣告#include ,在建構函式對新增變數資料進行初始化,具體程式碼如下:

1 MyGLWidget::MyGLWidget(QWidget *parent) : 2 QGLWidget(parent) 3 { 4 fullscreen = false; 5 m_xRot = 0。0f; 6 m_yRot = 0。0f; 7 m_zRot = 0。0f; 8 m_FileName = “D:/QtOpenGL/QtImage/Tim。bmp”; //應根據實際存放圖片的路徑進行修改 9 10 for (int x=0; x<45; x++) //初始化陣列產生波浪效果(靜止)11 {12 for (int y=0; y<45; y++)13 {14 m_Points[x][y][0] = float((x / 5。0f) - 4。5f);15 m_Points[x][y][1] = float((y / 5。0f) - 4。5f);16 m_Points[x][y][2] = float(sin((((x/5。0f)*40。0f)/360。0f)*3。141592654*2。0f));17 }18 }19 m_WiggleCount = 0;20 21 QTimer *timer = new QTimer(this); //建立一個定時器22 //將定時器的計時訊號與updateGL()繫結23 connect(timer, SIGNAL(timeout()), this, SLOT(updateGL()));24 timer->start(10); //以10ms為一個計時週期25 }

增加的程式碼就是一個迴圈,利用迴圈來新增波浪效果(只是讓旗幟看起來有起伏效果,還不能達到波動動畫的目的)。值得注意的是,我們在求m_Points[x][y][0]和m_Points[x][y][1]時,都是用x、y除以5。0f,如果除以5的話,由於整數除法取整,會導致畫面出現鋸齒效果,這顯然不是我們想要的。最後減去4。5f這樣使得計算結果落在區間[-4。5, 4。5],也就讓我們的波浪可以“居中”了。點m_Points[x][y][2]最後的值就是一個sin()函式計算的結果(因為我們模擬的是正弦波運動),×8。0f是求相應角度(360度平分到45個點就是8度一個點了),最後角度轉換到弧度制我就不多做解釋了。

然後在initializeGL()函式中,請大家修改程式碼如下:

【領QT開發教程學習資料,點選下方連結莬費領取↓↓,先碼住不迷路~】

點選→領取「連結」

1 void MyGLWidget::initializeGL() //此處開始對OpenGL進行所以設定 2 { 3 m_Texture = bindTexture(QPixmap(m_FileName)); //載入點陣圖並轉換成紋理 4 glEnable(GL_TEXTURE_2D); //啟用紋理對映 5 6 glClearColor(0。0, 0。0, 0。0, 0。0); //黑色背景 7 glShadeModel(GL_SMOOTH); //啟用陰影平滑 8 glClearDepth(1。0); //設定深度快取 9 glEnable(GL_DEPTH_TEST); //啟用深度測試10 glDepthFunc(GL_LEQUAL); //所作深度測試的型別11 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //告訴系統對透視進行修正12 13 glPolygonMode(GL_BACK, GL_FILL); //後表面完全填充14 glPolygonMode(GL_FRONT, GL_LINE); //前表面使用線條繪製15 }

最後加了兩行程式碼,用來指定使用完全填充模式來填充多邊形區域的後表面,而多邊形的前表面則使用輪廓線填充,這些方式完全取決於你的個人喜好,這裡我們只是為了區分前後表面罷了。

最後,我們將重寫整個paintGL()函式,當然這依舊是重點,程式碼如下:

1 void MyGLWidget::paintGL() //從這裡開始進行所以的繪製 2 { 3 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除螢幕和深度快取 4 glLoadIdentity(); //重置當前的模型觀察矩陣 5 6 glTranslatef(0。0f, 0。0f, -15。0f); //移入螢幕15。0單位 7 glRotatef(m_xRot, 1。0f, 0。0f, 0。0f); //繞x旋轉 8 glRotatef(m_yRot, 0。0f, 1。0f, 0。0f); //繞y旋轉 9 glRotatef(m_zRot, 0。0f, 0。0f, 1。0f); //繞z旋轉10 11 glBindTexture(GL_TEXTURE_2D, m_Texture); //旋轉紋理12 float flag_x1, flag_y1, flag_x2, flag_y2; //用來將紋理分割成小的四邊形方便紋理對映13 glBegin(GL_QUADS);14 for (int x=0; x<44; x++)15 {16 for (int y=0; y<44; y++)17 {18 //分割紋理19 flag_x1 = float(x) / 44。0f;20 flag_y1 = float(y) / 44。0f;21 flag_x2 = float(x+1) / 44。0f;22 flag_y2 = float(y+1) / 44。0f;23 24 //繪製一個小的四邊形25 glTexCoord2f(flag_x1, flag_y1);26 glVertex3f(m_Points[x][y][0], m_Points[x][y][1], m_Points[x][y][2]);27 glTexCoord2f(flag_x1, flag_y2);28 glVertex3f(m_Points[x][y+1][0], m_Points[x][y+1][1], m_Points[x][y+1][2]);29 glTexCoord2f(flag_x2, flag_y2);30 glVertex3f(m_Points[x+1][y+1][0], m_Points[x+1][y+1][1], m_Points[x+1][y+1][2]);31 glTexCoord2f(flag_x2, flag_y1);32 glVertex3f(m_Points[x+1][y][0], m_Points[x+1][y][1], m_Points[x+1][y][2]);33 }34 }35 glEnd();36 37 if (m_WiggleCount == 3) //用來變換波浪形狀(每2幀一次)產生波浪動畫38 {39 //利用迴圈使波浪值集體左移,最左側波浪值到了最右側40 for (int y=0; y<45; y++)41 {42 float temp = m_Points[0][y][2];43 for (int x=0; x<44; x++)44 {45 m_Points[x][y][2] = m_Points[x+1][y][2];46 }47 m_Points[44][y][2] = temp;48 }49 m_WiggleCount = 0; //計數器清零50 }51 m_WiggleCount++; //計數器加一52 53 m_xRot += 0。3f;54 m_yRot += 0。2f;55 m_zRot += 0。4f;56 }

我們建立了四個浮點臨時變數並利用迴圈和除法,將紋理分割成小的四邊形,使得我們能準確的對應進行紋理對映,然後畫出全部的四邊形拼到一起就是一個波動狀態的旗幟了。

接著我們判斷一下m_WiggleCount是否為2,如果是,就將波浪值m_Points[x][y][2]集體迴圈左移(最左側波浪值會到最右側)。這樣我們相當於每2幀一次變化了旗幟的波動狀態,看起來就是一個飄動的旗幟,不是靜止的了(大家可以嘗試著註釋掉某一部分程式碼看看發生什麼改變)。然後計數器清零加一什麼的就不過多解釋了!

現在就可以執行程式檢視效果了!

上一篇:實體店舉步艱難,堪比守寡,為什麼大家還在營業
下一篇:入戶就是廚房,試試這3家的方案,有效又實用,改完兩處都更敞亮