1. 程式人生 > >OpenGL實驗:繪製彩色五角星

OpenGL實驗:繪製彩色五角星

OpenGL實驗:繪製彩色五角星

第二次程式設計作業內容

用配置好的OpenGL環境實現彩色五角星效果,以及把五角星作為3D物件繪製出來,通過按鍵能夠調整角度(用J、K、L三個鍵分別控制三個互相正交方向上的旋轉角度)。效果圖如下:
五角星


作為一個OpenGL程式設計新手,對許多函式的用法不是很熟悉,這次程式設計練習主要熟練了對顏色的配置和3D變換的基礎知識。

1.初始化函式

(1)Void glutInit(int*argc,char**argv)//初始化函式庫

引數:
- Argc:一個指標,指向從main()函式傳遞過來的沒更改的argc變數。

(2)Void glutInitWindowPositon(int x,int y)//設定視窗位置

引數:
- X: 距離螢幕左邊的畫素數。-1是預設值,意思就是由視窗管理程式決定窗口出現在哪裡。如果不使用預設值,那你就自己設定一個值。
- Y:距離螢幕上邊的畫素數。和X一樣。

(3)Void glutInitWindowSize(int width,int height)//設定初始視窗的大小

引數:
- Width:視窗的寬度。
- Height:視窗的高度。

(4)Void glutInitDisplayMode(unsighed int mode)//設定初始顯示模式

引數:
Mode――可以指定下列顯示模式。

對應巨集定義 意義
GLUT_RGB 0x0000 指定RGB顏色模式的視窗
GLUT_RGBA 0x0000 指定RGBA 顏色模式的視窗
GLUT_INDEX 0x0001 指定顏色索引模式的視窗
GLUT_SINGLE 0x0000 指定單快取視窗
GLUT_DOUBLE 0x0002 指定雙快取視窗
GLUT_ACCUM 0x0004 視窗使用累加快取
GLUT_ALPHA 0x0008 視窗的顏色分量包含 alpha 值
GLUT_DEPTH 0x0010 視窗使用深度快取
GLUT_STENCIL 0x0020 視窗使用模板快取
GLUT_MULTISAMPLE 0x0080 指定支援多樣本功能的視窗
GLUT_STEREO 0x0100 指定立體視窗
GLUT_LUMINANCE 0x0200 視窗使用亮度顏色模型

2.訊息事件處理

(1)void glutMainLoop(void)

讓glut程式進入事件迴圈。在一個glut程式中最多隻能呼叫一次。一旦呼叫,會直到程式結束才返回。

(2)glutReshapeFunc(void (GLUTCALLBACK *func)(int width, int height))

註冊當前視窗的形狀變化回撥函式。當改變視窗大小時,該視窗的形狀改變回調函式將被呼叫。

(3)glutDisplayFunc(void (GLUTCALLBACK *func)(void))

註冊當前視窗的顯示回撥函式,當一個視窗的影象層需要重新繪製時,GLUT將呼叫該視窗的的顯示回撥函式。顯示回撥函式不帶任何引數,它負責整個影象層的繪製。我們的大部分工作將集中在這個函式中。

(4)glutMouseFunc(void (GLUTCALLBACK *func)(int button, int state, int x, int y))

設定滑鼠器按鍵回撥函式,當滑鼠的左鍵、右鍵或中鍵被按下時觸發被註冊的函式執行。

(5)glutMotionFunc(void (GLUTCALLBACK *func)(int x, int y))

設定滑鼠器移動回撥函式,當滑鼠發生移動時執行被註冊的函式。

(6)glutKeyboardFunc(void (GLUTCALLBACK *func)(unsigned char key, int x, int y))

設定鍵盤迴調函式,當鍵盤有鍵被按下是呼叫所註冊的函式。

(7)glutIdleFunc(void (GLUTCALLBACK *func)(void))

設定空閒回撥函式,當CPU空閒時呼叫該函式。


3.其他函式

(1)void glPushMatrix(void)和void glPopMatrix(void)

第一個函式表示將所有矩陣依次壓入堆疊中,頂部矩陣是第二個矩陣的備份;壓入的矩陣數不能太多,否則出錯。第二個函式表示彈出堆疊頂部的矩陣,令原第二個矩陣成為頂部矩陣,接受當前操作,故原頂部矩陣被破壞;當堆疊中僅存一個矩陣時,不能進行彈出操作,否則出錯。

  • OpenGL中的modelview矩陣變換是一個馬爾科夫過程:上一次的變換結果對本次變換有影響,上次modelview變換後物體在世界座標系下的位置是本次modelview變換的起點。預設時本次變換和上次變換不獨立。
  • OpenGL物體建模實際上是分兩步走的。第一步,在世界座標系的原點位置繪製出該物體;第二步,通過modelview變換矩陣對世界座標系原點處的物體進行仿射變換,將該物體移動到世界座標系的目標位置處。
  • 將modelview變換放在glPushMatrix和glPopMatrix之間可以使本次變換和上次變換獨立。
  • 凡是使用glPushMatrix()和glPopMatrix()的程式一般可以判定是採用世界座標系建模。既世界座標系固定,modelview矩陣移動物體。

(2)void glLoadIdentity(void)

OpenGL為我們提供了一個非常簡單的恢復初始座標系的手段,那就是呼叫glLoadIdentity()命令。該命令是一個無參的無值函式,其功能是用一個4×4的單位矩陣來替換當前矩陣(單位矩陣就是對角線上都是1,,其餘元素皆為0的矩陣),實際上就是對當前矩陣進行初始化。將當前點移到了螢幕中心,類似於一個復位操作。

  • X座標軸從左至右,Y座標軸從下至上,Z座標軸從裡至外。
  • OpenGL螢幕中心的座標值是X和Y軸上的0.0f點。
  • 中心左面的座標值是負值,右面是正值。
  • 移向螢幕頂端是正值,移向螢幕底端是負值。
  • 移入螢幕深處是負值,移出螢幕則是正值。
  • 用單位矩陣替換當前矩陣並不改變當前矩陣模式。

(3)void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); 和 void glRotatex(GLfixed angle, GLfixed x, GLfixed y, GLfixed z);

  • angle:為旋轉的角度,單位為度。
  • x,y,z:為對應xyz軸的布林值變數。
  • 如果設定的旋轉值(x,y,z的值)為正數,那麼旋轉的方向是逆時針的,如果旋轉值是負數,那麼旋轉的方向是順時針的。
  • 按照右手原則,假設:glRotatef(45,1,0,0),想象:從座標(0,0,0)即原點,引出一條線到(1,0,0),用右手握住這條線。右手大拇指指向(0,0,0)至(1,0,0)的方向才握。另外四個手指的彎曲指向即是物體旋轉方向。

(4)void glOrtho(float left,float right,float bottom, float top,int near,int far)

  • left表示視景體左面的座標,right表示右面的座標,bottom表示下面的,top表示上面的。

(5)void glColor3f(float x, float y)

在OpenGl中設定顏色,一般可以使用glColor3f()。從函式名字就可以看出,它的引數應該有三個,型別是float型的。另外一點是它的引數值的範圍是[0.0,1.0]。一般的,可以將這三個引數值視為顏色的成分。需要注意的是,如果在glBegin()與glEnd()函式之間多次連續呼叫顏色函式,那麼,只會顯示出最後一次的顏色。


附程式碼:

#include<windows.h>
#include<GL/glut.h>
#include<cmath>

const GLfloat R = 0.5f;
const GLfloat Pi = 3.1415926536f;
float zoom = 1.0f;
GLfloat winW = 0.0f;
GLfloat winH = 0.0f;
GLfloat xRot = -35.0f;
GLfloat yRot = 15.0f;

void Render()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glPushMatrix();
    /*glLoadIdentity();*/
    glRotatef(xRot, 1.0f, 0.0f, 0.0f);
    glRotatef(yRot, 0.0f, 1.0f, 0.0f);

    float aa = cos(54.0 / 360.0 * 2 * Pi);
    float bb = aa*tan(36.0 / 360.0 * 2 * Pi);
    float cc = sin(54.0 / 360.0 * 2 * Pi) - bb;

    GLfloat point[2][10] = {};

    for (int i = 0; i<10; i += 2)
    {
        float angle = i * 36;
        point[0][i] = (R*cos(angle / 360.0*2.0*Pi) - 0.5);
        point[1][i] = (R*sin(angle / 360.0*2.0*Pi) + 0.5);
        point[0][i + 1] = (cc*R*cos((angle + 36) / 360.0*2.0*Pi) - 0.5);
        point[1][i + 1] = (cc*R*sin((angle + 36) / 360.0*2.0*Pi) + 0.5);
    }

    //確定每個點的顏色
    GLfloat Color[3][10] = { 0 };

    for (int i = 0; i < 10; i++)
    {
        if (i <= 1 || i >= 8) Color[0][i] = 1;    // 0 1 8 9 
        if (i >= 0 && i <= 5) Color[1][i] = 1;     // 0 1 2 3 4 5
        if (i >= 4 && i <= 9) Color[2][i] = 1;    // 4 5 6 7 8 9
    }


    //五角星繪製
    glBegin(GL_TRIANGLE_FAN); //開始繪製
    {
        glColor3f(1, 1, 1);
        glVertex2f(-0.5, 0.5); //中心點
        for (int i = 0; i < 10; i++)
        {
            glColor3f(Color[0][i], Color[1][i], Color[2][i]);//選擇顏色
            glVertex2f(point[0][i], point[1][i]);//頂點
        }
        glColor3f(Color[0][0], Color[1][0], Color[2][0]);
        glVertex2f(point[0][0], point[1][0]);//最後一個點要重畫


    }
    glEnd();
    glPopMatrix();
    glFlush();
}

void OnReshape(int w, int h)
{
    GLfloat aspectRatio = (GLfloat)w / (GLfloat)h;
    winW = w;
    winH = h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();//
    if (w <= h)
    {
        glOrtho(-3.0f*zoom, 3.0f*zoom, -3.0f*zoom / aspectRatio, 3.0f*zoom / aspectRatio, -10.0f*zoom, 10.0f*zoom);
    }
    else {
        glOrtho(-3.0f*zoom*aspectRatio, 3.0f*zoom*aspectRatio, -3.0f*zoom, 3.0f*zoom, -10.0f*zoom, 10.0f*zoom);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void OnMouse(int button, int state, int x, int y)
{
    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
    {
        xRot += 1;
        yRot += 1;
        glutPostRedisplay();
    }
    else if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
    {
        xRot -= 1;
        yRot -= 1;
        glutPostRedisplay();
    }
}

void OnKeyUpDown(int key, int x, int y)
{
    if (key == GLUT_KEY_UP) {
        zoom -= 0.1;
    }
    else if (key == GLUT_KEY_DOWN) {
        zoom += 0.1;

    }
    OnReshape(winW, winH);
    glutPostRedisplay();
}

int main(int argc, char *argv[])

{

    glutInit(&argc, argv);  //對GLUT進行初始化
    glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); //設定顯示方式,RGB 單快取&多快取
    glutInitWindowPosition(100, 100); //視窗在螢幕中的位置
    glutInitWindowSize(400, 400);//視窗的大小
    glutCreateWindow("Birdy's OpenGL");//建立視窗

    glutDisplayFunc(&Render);
    glutReshapeFunc(OnReshape);
    glutMouseFunc(OnMouse);
    glutSpecialFunc(OnKeyUpDown);

    glutMainLoop();//迴圈

    return 0;

}