OpenGL之旗幟飄揚

OpenGL之旗幟飄揚

讓旗幟飄揚的核心是波浪算法,使用sin()函式將旗幟頂點初此化為波紋,然後每幀移動波紋

演示程式:下載

  1. 按方向鍵移動相機
  2. 按ESC鍵相機返回原點

算法如下:

  1. 將旗幟定義為長方形,橫向(x軸)36個頂點,縱向(y軸)20個頂點,35*19個網格
  2. 波紋算法: z = sin((x * height * 360) * 2 * π)
  3. 每幀沿Z軸往右移動波紋來模擬波浪運動,最右端的Z座標移動到最左端
  4. 在繪畫旗幟時從左下角開此,一次繪畫一個GL_QUAD按逆時針繪畫紋理座標與頂點座標
  5. 紋理座標:『s=x/width』『t=y/height』
  6. 旗幟『紋理』定義為正方形,分辨率越大越好,『紋理載入
旗幟結構 簡介
typedef struct FLAG_TAG{
float       points[36][20][3]; 頂點數據36*20個頂點,每個頂點3(xyz)個分量
int         time_start; 啟動時間用於控制波浪移動速度
}FLAG, *FLAG_PTR;

 

初此化旗幟使用sin()波紋函式來初此化旗幟

bool Init_Flag(FLAG_PTR flag)

{

if (flag == NULL)

return false;

for (int x = 0; x < 36; ++x)

{

for (int y = 0; y < 20; ++y)

{

flag->points[x][y][0] = (float)x;// X軸

flag->points[x][y][1] = (float)y;// Y軸

float value = (x*20.0f / 360.0f) * 2.0f * 3.14159f;

flag->points[x][y][2] = (float)sin(value);// 正弦計算

}

}

return true;

}

繪畫旗幟

void Draw_Flag(FLAG_PTR flag,float xPos,float yPos,float zPos,float xRot,float yRot,float zRot)

{

int x, y;

float left, right, top, bottom;

glPushMatrix();// 當前矩陣堆棧壓棧

glBindTexture(GL_TEXTURE_2D, Flag_Texture.ID);// 綁定紋理

glTranslatef(xPos, yPos, zPos);// 移動旗幟座標

glRotatef(xRot, 1.0f, 0.0f, 0.0f); // 繞X軸旋轉旗幟

glRotatef(yRot, 0.0f, 1.0f, 0.0f); // 繞Y軸旋轉旗幟

glRotatef(zRot, 0.0f, 0.0f, 1.0f); // 繞Z軸旋轉旗幟

glBegin(GL_QUADS);// 繪畫木箱頂面紋理座標和頂點座標

// 遍歷旗幟所有頂點,除了方向上的最後兩個點

// 因為只是用它來繪製每個方向上最後的GL_QUAD

for (x = 0; x < 35; ++x)

{

for (y = 0; y < 18; ++y)

{   // 為當前的四邊形計算紋理座標

left = (float)x / 35.0f;  //四邊形左則的紋理座標

bottom = (float)y / 18.0f ;//四邊形頂則的紋理座標

right = (float)(x+1) / 35.0f; //四邊形右則的紋理座標

top = (float)(y+1) / 18.0f ;   //四邊形底則的紋理座標

// 設定四邊形左下角的紋理座標與頂點座標

glTexCoord2f(left, bottom);// 紋理座標

glVertex3f(flag->points[x][y][0],

flag->points[x][y][1],

flag->points[x][y][2]);//頂點座標

// 設定四邊形右下角的紋理座標與頂點座標

glTexCoord2f(right, bottom);// 紋理座標

glVertex3f(flag->points[x+1][y][0],

flag->points[x+1][y][1],

flag->points[x+1][y][2]);//頂點座標

// 設定四邊形右上角的紋理座標與頂點座標

glTexCoord2f(right, top);// 紋理座標

glVertex3f(flag->points[x+1][y+1][0],

flag->points[x+1][y+1][1],

flag->points[x+1][y+1][2]);//頂點座標

// 設定四邊形左上角的紋理座標與頂點座標

glTexCoord2f(left, top);// 紋理座標

glVertex3f(flag->points[x][y+1][0],

flag->points[x][y+1][1],

flag->points[x][y+1][2]);//頂點座標

}

}

glEnd();

DWORD tick = GetTickCount(); //返回從操作系統啟動所經過的毫秒數

if ((tick – flag->time_start) > 100)

{

flag->time_start = tick;

float wrap;

// 生成旗幟的運動

// 訪問旗幟中的每一點,將每點的Z軸座標向右移動一位來模擬波浪運動

for (y = 0; y < 19; ++y)// Y軸方向循環

{// 存儲此行中最右端頂點的Z座標

wrap = flag->points[35][y][2];

for (x = 35; x >= 0; –x)// X軸方向循環

{// 將當前頂點Z座標設為前一頂點的Z座標值

flag->points[x][y][2] = flag->points[x-1][y][2];

}

// 將最左端頂點的Z座標設為先前所存儲的wrap

flag->points[0][y][2] = wrap;

}

}

glPopMatrix();// 當前矩陣堆棧出棧

}

 

評論