用OpenGL進行曲線、曲面的繪製

實驗目的

  • 理解Bezier曲線、曲面繪製的基本原理;理解OpenGL中一維、二維插值求值器的用法。
  • 掌握OpenGL中曲線、曲面繪圖的方法,對比不一樣參數下的繪圖效果差別;

 

代碼1:用四個控制點繪製一條三次Bezier曲線

Github地址git

#include "stdafx.h"
#include <stdlib.h>
#include <time.h>
#include <GL/glut.h>

//4個控制點的3D座標——z座標全爲0
GLfloat ctrlpoints[4][3] = {
    { -4, -4, 0 }, { -2, 4, 0 }, { 2, -4, 0 }, { 4, 4, 0 }
};

void init(void)
{
    //背景色
    glClearColor(0.0, 0.0, 0.0, 1.0);
    //將控制點座標映射爲曲線座標
    //參數1:GL_MAP1_VERTEX_3,3維點座標
    //參數2和3:控制參數t或u的取值範圍[0, 1]
    //參數4:曲線內插值點間的步長3————3維座標
    //參數5:曲線間的補償爲頂點數4個————總步長爲12
    //參數6:控制點二維數組首元素地址
    //注意: 如果在這裏設置了相關參數,後續對ctrlpoints內容更改曲線不變
    glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoints[0][0]);
    //打開開關——容許3維座標控制點到參數點轉換開關
    glEnable(GL_MAP1_VERTEX_3);
    glShadeModel(GL_FLAT);

    //代碼開關2:去掉本註釋,可啓用反走樣
    /*
    glEnable(GL_BLEND);
    glEnable(GL_LINE_SMOOTH);  //容許直線反走樣
    glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);  // Antialias the lines
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    */
}

void display(void)
{
    int i;
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);

    //代碼開關1:去掉本註釋,查看動態的曲線繪圖效果:動態更新控制點座標
    /*
    for(int t = 0; t < 4; t++) {
    for(int j = 0; j < 3; j++)
    ctrlpoints[t][j] = (rand() % 1024 / 1024.0 - 0.5) * 10;
    }
    //動態映射
    glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoints[0][0]);
    */
    glLoadIdentity();
    glColor3f(1.0, 0.0, 0.0);
    //繪製連續線段
    glBegin(GL_LINE_STRIP);
    //參數t或u取值爲i/30,共計31個點
    for (i = 0; i <= 30; i++)
        glEvalCoord1f((GLfloat)i / 30.0);   //根據4個控制點座標的參數化插值
    glEnd();
    /* 顯示控制點 */
    glPointSize(5.0);
    glBegin(GL_POINTS);
    for (i = 0; i < 4; i++)
        glVertex3fv(&ctrlpoints[i][0]);
    glEnd();

    glTranslatef(-0.1f, 0.1f, 0.0f);
    glColor3f(0.0, 1.0, 0.0);
    //glLineWidth(2.0);
    //繪製連續線段——線段數越多,曲線越光滑
    glBegin(GL_LINE_STRIP);
    //設置參數t或u取值爲i/60,共計61個點
    //實驗:若讓t從-2變化到+2,可看到什麼效果
    for (i = 0; i <= 60; i++)
        glEvalCoord1f((GLfloat)i / 60.0);  //根據4個控制點座標的參數化插值
    glEnd();

    glTranslatef(-0.1f, 0.1f, 0.0f);
    glColor3f(1.0, 1.0, 1.0);
    //繪製連續線段
    glBegin(GL_LINE_STRIP);
    //設置參數t或u取值爲i/60,共計61個點
    //實驗:若讓t從-2變化到+2,可看到什麼效果
    for (i = 0; i <= 100; i++)
        glEvalCoord1f((GLfloat)i / 100.0);
    glEnd();

    glutSwapBuffers();
}

//3D空間中繪製2D效果,採用正交投影
void reshape(GLsizei w, GLsizei h)
{
    glViewport(0, 0, w, h);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
        glOrtho(-5.0, 5.0, -5.0*(GLfloat)h / (GLfloat)w, 5.0*(GLfloat)h / (GLfloat)w, -5.0, 5.0);
    else
        glOrtho(-5.0*(GLfloat)w / (GLfloat)h, 5.0*(GLfloat)w / (GLfloat)h, -5.0, 5.0, -5.0, 5.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void keyboard(unsigned char key, int x, int y)
{
    switch (key)
    {
    case 'x':
    case 'X':
    case 27:   //ESC鍵
        exit(0);
        break;
    default:
        break;
    }
}

int main(int argc, char** argv)
{
    srand((unsigned int)time(0));
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);//使用雙緩存模式和深度緩存
    glutInitWindowSize(800, 800);
    glutInitWindowPosition(0, 0);
    glutCreateWindow("2D Bezier曲線");
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
    glutIdleFunc(display);//設置空閒時調用的函數
    glutMainLoop();
    return 0;
}

 

此時咱們打開代碼開關1,查看動態Bezier曲線繪製效果:github

 

 

 

 

 

關閉代碼開關1,打開代碼開關2,查看直線反走樣效果:算法

 

 對比剛開始的效果圖,咱們發現,使用了直線反走樣後,繪製出的曲線很光滑,看着很舒服。數組

 

代碼2:4*4個控制點繪製一個三次Bezier曲面線框模型

 Github地址緩存

#include "stdafx.h"
#include <stdlib.h>
#include <time.h>
#include <GL/glut.h>

/* 控制點的座標 */
GLfloat ctrlpoints[4][4][3] = {
    { { -1.5, -1.5, 2.0 },
    { -0.5, -1.5, 2.0 },
    { 0.5, -1.5, -1.0 },
    { 1.5, -1.5, 2.0 }
    },

    { { -1.5, -0.5, 1.0 },
    { -0.5, 1.5, 2.0 },
    { 0.5, 0.5, 1.0 },
    { 1.5, -0.5, -1.0 } },

    { { -1.5, 0.5, 2.0 },
    { -0.5, 0.5, 1.0 },
    { 0.5, 0.5, 3.0 },
    { 1.5, -1.5, 1.5 } },

    { { -1.5, 1.5, -2.0 },
    { -0.5, 1.5, -2.0 },
    { 0.5, 0.5, 1.0 },
    { 1.5, 1.5, -1.0 } } };

void init(void)
{
    //背景色
    glClearColor(0.0, 0.0, 0.0, 1.0);
    //將控制點座標映射爲曲面座標
    //參數1:GL_MAP1_VERTEX_3,3維點座標
    //參數2和3:控制參數u的取值範圍[0, 1]
    //參數4:x方向元素間的步長爲3個GLfloat
    //參數5:x方向曲線間的步長爲4個控制點——曲線由4個控制點肯定
    //參數6-7:控制參數v的取值範圍[0, 1]
    //參數8:y方向元素間的步長爲12個GLfloat元素
    //參數9:y方向每條曲線的控制點數量爲4
    //注意: 如果在這裏設置了相關參數,後續對ctrlpoints內容更改曲線不變
    glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &ctrlpoints[0][0][0]);
    //容許二維映射
    glEnable(GL_MAP2_VERTEX_3);
    //二維映射:x、y方向U和V的參數[0, 1],且中間插值數量爲各20個
    glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0);
    //容許深度測試
    glEnable(GL_DEPTH_TEST);

    //代碼開關2:啓用反走樣
    glEnable(GL_BLEND);
    glEnable(GL_LINE_SMOOTH);
    glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);  // Antialias the lines
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f(0.0, 1.0, 0.0);
    glPushMatrix();
    //代碼開關1:去掉註釋查看效果;更改旋轉角度參數,查看效果
    //glRotatef(0.1, 1.0, 1.0, 1.0);
    int i, j;
    //生成2D網格座標,以從控制點參數插值肯定網格點所對應的點集所對應的座標
    for (j = 0; j <= 8; j++)     {
        glBegin(GL_LINE_STRIP);
        for (i = 0; i <= 30; i++)
            glEvalCoord2f((GLfloat)i / 30.0, (GLfloat)j / 8.0);  //固定y座標時x方向的網格座標
        glEnd();

        glBegin(GL_LINE_STRIP);
        for (i = 0; i <= 30; i++)
            glEvalCoord2f((GLfloat)j / 8.0, (GLfloat)i / 30.0);  //固定x座標時y方向的網格座標     
        glEnd();
    }

    //查看網格所肯定的插值點(u, v)的位置
    glColor3f(1, 0, 0);
    glBegin(GL_POINTS);
    for (j = 0; j <= 8; j++)     {
        for (i = 0; i <= 30; i++)
            glVertex3f((GLfloat)i / 30.0, (GLfloat)j / 8.0, 0);
        for (i = 0; i <= 30; i++)
            glVertex3f((GLfloat)j / 8.0, (GLfloat)i / 30.0, 0);
    }
    glEnd();
    glPopMatrix();
    glutSwapBuffers();
}

void reshape(GLsizei w, GLsizei h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
        glOrtho(-5.0, 5.0, -5.0*(GLfloat)h / (GLfloat)w, 5.0*(GLfloat)h / (GLfloat)w, -5.0, 5.0);
    else
        glOrtho(-5.0*(GLfloat)w / (GLfloat)h, 5.0*(GLfloat)w / (GLfloat)h, -5.0, 5.0, -5.0, 5.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void keyboard(unsigned char key, int x, int y)
{
    switch (key)
    {
    case 'x':
    case 'X':
    case 27:   //ESC鍵
        exit(0);
        break;
    default:
        break;
    }
}

int main(int argc, char** argv)
{
    srand((unsigned int)time(0));
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);//使用雙緩存模式和深度緩存
    glutInitWindowSize(800, 800);
    glutInitWindowPosition(0, 0);
    glutCreateWindow("Bezier曲面線框模型");
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
    glutIdleFunc(display);//設置空閒時調用的函數
    glutMainLoop();
    return 0;
}

 

打開代碼開關1後的效果:網絡

 

代碼3:用4*4個控制點繪製一個三次Bezier曲面並添加光照效果

Github地址函數

#include "stdafx.h"
#include <stdlib.h>
#include <time.h>
#include <GL/glut.h>
/* 控制點的座標 */
GLfloat ctrlpoints[4][4][3] = {
    { { -1.5, -1.5, 2.0 },
    { -0.5, -1.5, 2.0 },
    { 0.5, -1.5, -1.0 },
    { 1.5, -1.5, 2.0 } },

    { { -1.5, -0.5, 1.0 },
    { -0.5, 1.5, 2.0 },
    { 0.5, 0.5, 1.0 },
    { 1.5, -0.5, -1.0 } },

    { { -1.5, 0.5, 2.0 },
    { -0.5, 0.5, 1.0 },
    { 0.5, 0.5, 3.0 },
    { 1.5, -1.5, 1.5 } },

    { { -1.5, 1.5, -2.0 },
    { -0.5, 1.5, -2.0 },
    { 0.5, 0.5, 1.0 },
    { 1.5, 1.5, -1.0 } } };

void init(void)
{
    //背景色
    glClearColor(0.0, 0.0, 0.0, 1.0);
    //將控制點座標映射爲曲面座標
    //參數1:GL_MAP1_VERTEX_3,3維點座標
    //參數2和3:控制參數u的取值範圍[0, 1]
    //參數4:x方向元素間的步長爲3個GLfloat
    //參數5:x方向曲線間的步長爲4個控制點——曲線由4個控制點肯定
    //參數6-7:控制參數v的取值範圍[0, 1]
    //參數8:y方向元素間的步長爲12個GLfloat元素
    //參數9:y方向每條曲線的控制點數量爲4
    //note: 如果在這裏設置了相關參數,後續對ctrlpoints內容更改曲線不變
    glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &ctrlpoints[0][0][0]);
    //容許二維映射
    glEnable(GL_MAP2_VERTEX_3);
    //二維映射:x、y方向U和V的參數[0, 1],且中間插值數量爲各20個
    glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0);
    //容許深度測試
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
    //代碼開關4:取消下面兩行代碼,查看曲面顯示效果差別
    //打開自動法矢量開關
    //glEnable(GL_AUTO_NORMAL);
    //容許正則化法矢量
    //glEnable(GL_NORMALIZE);

    //代碼開關3:設置材質與光源
    GLfloat ambient[] = { 0.4, 0.6, 0.2, 1.0 };
    GLfloat position[] = { 0.0, 1.0, 3.0, 1.0 };
    GLfloat mat_diffuse[] = { 0.2, 0.4, 0.8, 1.0 };
    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat mat_shininess[] = { 80.0 };
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_POSITION, position);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f(0.0, 1.0, 0.0);
    //若是不但願旋轉,則啓用push和pop矩陣命令,並註釋掉glRotatef行
    //glPushMatrix();
    //代碼開關1:去掉註釋查看效果;更改旋轉角度參數,查看效果
    glRotatef(1.0, 1.0, 1.0, 1.0);
    glEvalMesh2(GL_FILL, 0, 20, 0, 20);
    //glPopMatrix();
    glutSwapBuffers();
}

void reshape(GLsizei w, GLsizei h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
        glOrtho(-5.0, 5.0, -5.0*(GLfloat)h / (GLfloat)w, 5.0*(GLfloat)h / (GLfloat)w, -5.0, 5.0);
    else
        glOrtho(-5.0*(GLfloat)w / (GLfloat)h, 5.0*(GLfloat)w / (GLfloat)h, -5.0, 5.0, -5.0, 5.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void keyboard(unsigned char key, int x, int y)
{
    switch (key)
    {
    case 'x':
    case 'X':
    case 27:   //ESC鍵
        exit(0);
        break;
    default:
        break;
    }
}

int main(int argc, char** argv)
{
    srand((unsigned int)time(0));
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);//使用雙緩存模式和深度緩存
    glutInitWindowSize(800, 800);
    glutInitWindowPosition(0, 0);
    glutCreateWindow("Bezier曲面");
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
    glutIdleFunc(display);//設置空閒時調用的函數
    glutMainLoop();
    return 0;
}

 

 

 

說明

從貝塞爾到B樣條oop

  貝塞爾曲線由起點、終點和其餘控制點來影響曲線的形狀。在二次貝塞爾曲線和三次貝塞爾曲線中,能夠經過調整控制點的位置而獲得很好的平滑性(C2級連續性 曲率級)的曲線。當增長更多的控制點的時候,這種平滑性就被破壞了。以下圖所示,前兩個曲線很平滑(曲率級的連續性),第三個曲線在增長了一個控制點以後,曲線被拉伸了,其平滑性遭到了破壞。學習

  B樣條的工做方式相似於貝塞爾曲線,但不一樣的是曲線被分紅不少段。每段曲線的形狀只受到最近的四個控制點的影響,這樣曲線就像是4階的貝塞爾曲線拼接起來的。這樣很長的有不少控制點的曲線就會有固定的連續性,平滑性(每一段都是c2級的連續性)。測試

 

結點

  NURBS(非均勻有理B樣條)的真正威力在於,能夠調整任意一段曲線中的四個控制點的影響力,來產生較好的平滑性。這是經過一系列結點來控制的。每一個控制點都定義了兩個結點的值。結點的取值範圍是uv的定義域,並且必須是非遞減的。

  結點的值決定了落在uv參數定義域內的控制點的影響力。下圖的曲線表示控制點對一條在u參數定義域內的具備四個單位的曲線的影響。下圖表示中間點對曲線的影響更大,並且只有在[0,3]範圍內的控制點纔會對曲線產生影響。

 在uv參數定義域內的控制點對曲線的形狀會有有影響,並且咱們能夠經過結點來控制控制點的影響力。非均勻性就是指一個控制點的影響力的範圍是能夠改變的。

    節點 ( Knot ) 是一個 ( 階數 + N - 1 ) 的數字列表,N 表明控制點數目。有時候這個列表上的數字也稱爲節點矢量 ( Knot Vector ),這裏的矢量並非指 3D 方向。

    節點列表上的數字必須符合幾個條件,肯定條件是否符合的標準方式是在列表序列中,數字必需維持不變或變大,並且數字重複的次數不能夠比階數大。例如,階數 3 15 個控制點的 NURBS 曲線,列表數字爲 0,0,0,1,2,2,2,3,7,7,9,9,9 是一個符合條件的節點列表。列表數字爲 0,0,0,1,2,2,2,2,7,7,9,9,9 則不符合,由於此列表中有四個 2,而四比階數大 ( 階數爲 3 )

節點值重複的次數稱爲節點的重數 ( Multiplicity ),在上面例子中符合條件的節點列表中,節點值 0 的重數值爲三;節點值 1 的重數值爲一;節點值 2 的重數爲三;節點值 7 的重數值爲二;節點值 9 的重數值爲三。

若是節點值重複的次數和階數同樣,該節點值稱爲全復節點 ( Full-Multiplicity Knot )。在上面的例子中,節點值 029 有完整的重數,只出現一次的節點值稱爲單純節點 ( Simple Knot ),節點值 1 3 爲單純節點。

    若是在節點列表中是以全復節點開始,接下來是單純節點,再以全復節點結束,並且節點值爲等差,稱爲均勻 ( Uniform )。例如,若是階數爲 3 7 個控制點的 NURBS 曲線,其節點值爲 0,0,0,1,2,3,4,4,4,那麼該曲線有均勻的節點。若是節點值是 0,0,0,1,2,5,6,6,6 不是均勻的,稱爲非均勻 ( Non-Uniform )。在 NURBS NU 表明非均勻,意味着在一條 NURBS 曲線中節點能夠是非均勻的。

在節點值列表中段有重複節點值的 NURBS 曲線比較不平滑,最不平滑的情形是節點列表中段出現全復節點,表明曲線有銳角。所以,有些設計師喜歡在曲線插入或移除節點,而後調整控制點,使曲線的造型變得平滑或尖銳。由於節點數等於 ( N + 階數 - 1 )N 表明控制點的數量,因此插入一個節點會增長一個控制點,移除一個節點也會減小一個控制點。插入節點時能夠不改變 NURBS 曲線的形狀,但一般移除節點一定會改變 NURBS 曲線的形狀。

節點(Knot)與控制點關係:控制點和節點是一對一成對的是常見的錯誤概念,這種情形只發生在 1 階的 NURBS ( 多重直線 )。較高階數的 NURBS 的每 ( 2 x 階數 ) 個節點是一個羣組,每 ( 階數 + 1 ) 個控制點是一個羣組。例如,一條 3 7 個控制點的 NURBS 曲線,節點是 0,0,0,1,2,5,8,8,8,前四個控制點是對應至前六個節點;第二至第五個控制點是對應至第二至第七個節點 0,0,1,2,5,8;第三至第六個控制點是對應至第三至第八個節點 0,1,2,5,8,8;最後四個控制點是對應至最後六個節點

重要:NURB曲面上的裁剪、細分、鑲嵌效果,查看網頁 https://my.oschina.net/sweetdark/blog/184313

 

代碼4:用4*4個控制點繪製一個NURBS曲面並添加光照效果

Github地址

#include "stdafx.h"
#include <stdlib.h>
#include <time.h>
#include <GL/glut.h>

/* 控制點的座標 */
GLfloat ctrlpoints[4][4][3] = {
    { { -1.5, -1.5, 2.0 },
    { -0.5, -1.5, 2.0 },
    { 0.5, -1.5, -1.0 },
    { 1.5, -1.5, 2.0 } },

    { { -1.5, -0.5, 1.0 },
    { -0.5, 1.5, 2.0 },
    { 0.5, 0.5, 1.0 },
    { 1.5, -0.5, -1.0 } },

    { { -1.5, 0.5, 2.0 },
    { -0.5, 0.5, 1.0 },
    { 0.5, 0.5, 3.0 },
    { 1.5, -1.5, 1.5 } },

    { { -1.5, 1.5, -2.0 },
    { -0.5, 1.5, -2.0 },
    { 0.5, 0.5, 1.0 },
    { 1.5, 1.5, -1.0 } } };

GLUnurbsObj *theNurb; // 指向一個NURBS曲面對象的指針

void init(void)
{
    //背景色
    glClearColor(0.0, 0.0, 0.0, 1.0);
    //代碼開關3:設置材質與光源
    GLfloat ambient[] = { 0.4, 0.6, 0.2, 1.0 };
    GLfloat position[] = { 1.0, 1.0, 3.0, 1.0 };
    GLfloat mat_diffuse[] = { 0.8, 0.6, 0.3, 1.0 };
    GLfloat mat_specular[] = { 0.8, 0.6, 0.3, 1.0 };
    GLfloat mat_shininess[] = { 45.0 };

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_POSITION, position);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

    //容許深度測試
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
    //代碼開關4:取消下面兩行代碼,查看曲面顯示效果差別
    //打開自動法矢量開關
    glEnable(GL_AUTO_NORMAL);
    //容許正則化法矢量
    glEnable(GL_NORMALIZE);
    theNurb = gluNewNurbsRenderer(); // 建立一個NURBS曲面對象  
    //修改NURBS曲面對象的屬性——glu庫函數
    ////採樣sampling容錯torerance
    gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 5.0);
    gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL);
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f(0.0, 1.0, 0.0);
    //各控制點影響力參數設置
    GLfloat knots[8] = { 0.0, 0.0, 0.0, 0.0,
        1.0, 1.0, 1.0, 1.0 }; // NURBS曲面的控制向量      
    glRotatef(1.0, 0.7, -0.6, 1.0); // 旋轉變換  
    gluBeginSurface(theNurb); // 開始曲面繪製 
    //網絡查詢:參數GL_MAP2_VERTEX_3的做用?
    //
    gluNurbsSurface(theNurb, 8, knots, 8, knots, 4 * 3, 3, &ctrlpoints[0][0][0], 4, 4, GL_MAP2_VERTEX_3); // 定義曲面的數學模型,肯定其形狀  
    gluEndSurface(theNurb); // 結束曲面繪製  
    glutSwapBuffers();
}

void reshape(GLsizei w, GLsizei h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
        glOrtho(-5.0, 5.0, -5.0*(GLfloat)h / (GLfloat)w, 5.0*(GLfloat)h / (GLfloat)w, -5.0, 5.0);
    else
        glOrtho(-5.0*(GLfloat)w / (GLfloat)h, 5.0*(GLfloat)w / (GLfloat)h, -5.0, 5.0, -5.0, 5.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void keyboard(unsigned char key, int x, int y)
{
    switch (key)
    {
    case 'x':
    case 'X':
    case 27:   //ESC鍵
        exit(0);
        break;
    default:
        break;
    }
}

int main(int argc, char** argv)
{
    srand((unsigned int)time(0));
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);//使用雙緩存模式和深度緩存
    glutInitWindowSize(800, 800);
    glutInitWindowPosition(0, 0);
    glutCreateWindow("Bezier曲面");

    init();

    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
    glutIdleFunc(display);//設置空閒時調用的函數

    glutMainLoop();
    return 0;
}

 

 

 

寫在最後

此文是源自學校圖形學課程的實驗教學內容,我很喜歡這節內容,因而將其源代碼和原理整理了出來供感興趣的人一塊兒學習探討。

圖形學的課程結束後,個人心裏卻久久不能平靜,由於此次課程我彷佛找到了我感興趣的方向——圖形學,它給個人感受就像是技術和藝術的結合。

記得剛開始上圖形學課程,老師一直在推導公式,講解每個算法中所蘊含的數學原理,使我不由感受在上一堂數學課,不過也正由於如此,我才逐漸體會到高等數學和線性代數的做用,爲此更加激起了我學習數學的興趣。

我一直相信——學習和作事的本質是相通的:熟能生巧,勤能補拙,念念不忘,必有迴響。^_^

相關文章
相關標籤/搜索