OpenGL入門學習(二) 【轉】

 本次課程所要講的是繪製簡單的幾何圖形,在實際繪製之前,讓我們先熟悉一些概念。

一、點、直線和多邊形
我們知道數學(具體的說,是幾何學)中有點、直線和多邊形的概念,但這些概念在計算機中會有所不同。
數學上的點,只有位置,沒有大小。但在計算機中,無論計算精度如何提高,始終不能表示一個無窮小的點。另一方面,無論圖形輸出設備(例如,顯示器)如何精確,始終不能輸出一個無窮小的點。一般情況下,OpenGL中的點將被畫成單個的像素(像素的概念,請自己搜索之~),雖然它可能足夠小,但並不會是無窮小。同一像素上,OpenGL可以繪製許多座標只有稍微不同的點,但該像素的具體顏色將取決於OpenGL的實現。當然,過度的注意細節就是鑽牛角尖,我們大可不必花費過多的精力去研究“多個點如何畫到同一像素上”。
同樣的,數學上的直線沒有寬度,但OpenGL的直線則是有寬度的。同時,OpenGL的直線必須是有限長度,而不是像數學概念那樣是無限的。可以認爲,OpenGL的“直線”概念與數學上的“線段”接近,它可以由兩個端點來確定。
多邊形是由多條線段首尾相連而形成的閉合區域。OpenGL規定,一個多邊形必須是一個“凸多邊形”(其定義爲:多邊形內任意兩點所確定的線段都在多邊形內,由此也可以推導出,凸多邊形不能是空心的)。多邊形可以由其邊的端點(這裏可稱爲頂點)來確定。(注意:如果使用的多邊形不是凸多邊形,則最後輸出的效果是未定義的——OpenGL爲了效率,放寬了檢查,這可能導致顯示錯誤。要避免這個錯誤,儘量使用三角形,因爲三角形都是凸多邊形)

可以想象,通過點、直線和多邊形,就可以組合成各種幾何圖形。甚至於,你可以把一段弧看成是很多短的直線段相連,這些直線段足夠短,以至於其長度小於一個像素的寬度。這樣一來弧和圓也可以表示出來了。通過位於不同平面的相連的小多邊形,我們還可以組成一個“曲面”。

二、在OpenGL中指定頂點
由以上的討論可以知道,“點”是一切的基礎。
如何指定一個點呢?OpenGL提供了一系列函數。它們都以glVertex開頭,後面跟一個數字和1~2個字母。例如:
glVertex2d
glVertex2f
glVertex3f
glVertex3fv
等等。
數字表示參數的個數,2表示有兩個參數,3表示三個,4表示四個(我知道有點羅嗦~)。
字母表示參數的類型,s表示16位整數(OpenGL中將這個類型定義爲GLshort),
                   i表示32位整數(OpenGL中將這個類型定義爲GLint和GLsizei),
                   f表示32位浮點數(OpenGL中將這個類型定義爲GLfloat和GLclampf),
                   d表示64位浮點數(OpenGL中將這個類型定義爲GLdouble和GLclampd)。
                   v表示傳遞的幾個參數將使用指針的方式,見下面的例子。
這些函數除了參數的類型和個數不同以外,功能是相同的。例如,以下五個代碼段的功能是等效的:
(一)glVertex2i(1, 3);
(二)glVertex2f(1.0f, 3.0f);
(三)glVertex3f(1.0f, 3.0f, 0.0f);
(四)glVertex4f(1.0f, 3.0f, 0.0f, 1.0f);
(五)GLfloat VertexArr3[] = {1.0f, 3.0f, 0.0f};
      glVertex3fv(VertexArr3);
以後我們將用glVertex*來表示這一系列函數。
注意:OpenGL的很多函數都是採用這樣的形式,一個相同的前綴再加上參數說明標記,這一點會隨着學習的深入而有更多的體會。


三、開始繪製
假設現在我已經指定了若干頂點,那麼OpenGL是如何知道我想拿這些頂點來幹什麼呢?是一個一個的畫出來,還是連成線?或者構成一個多邊形?或者做其它什麼事情?
爲了解決這一問題,OpenGL要求:指定頂點的命令必須包含在glBegin函數之後,glEnd函數之前(否則指定的頂點將被忽略)。並由glBegin來指明如何使用這些點。
例如我寫:
glBegin(GL_POINTS);
     glVertex2f(0.0f, 0.0f);
     glVertex2f(0.5f, 0.0f);
glEnd();
則這兩個點將分別被畫出來。如果將GL_POINTS替換成GL_LINES,則兩個點將被認爲是直線的兩個端點,OpenGL將會畫出一條直線。
我們還可以指定更多的頂點,然後畫出更復雜的圖形。
另一方面,glBegin支持的方式除了GL_POINTS和GL_LINES,還有GL_LINE_STRIP,GL_LINE_LOOP,GL_TRIANGLES,GL_TRIANGLE_STRIP,GL_TRIANGLE_FAN等,每種方式的大致效果見下圖:
http://blog.programfan.com/upfile/200607/200607311604018.gif
聲明:該圖片來自www.opengl.org,該圖片是《OpenGL編程指南》一書的附圖,由於該書的舊版(第一版,1994年)已經流傳於網絡,我希望沒有觸及到版權問題。

我並不準備在glBegin的各種方式上大作文章。大家可以自己嘗試改變glBegin的方式和頂點的位置,生成一些有趣的圖案。

程序代碼:
void myDisplay(void)
{
     glClear(GL_COLOR_BUFFER_BIT);
     glBegin( /* 在這裏填上你所希望的模式 */ );
        /* 在這裏使用glVertex*系列函數 */
        /* 指定你所希望的頂點位置 */
     glEnd();
     glFlush();
}
把這段代碼改成你喜歡的樣子,然後用它替換第一課中的myDisplay函數,編譯後即可運行。



兩個例子
例一、畫一個圓
/*
正四邊形,正五邊形,正六邊形,……,直到正n邊形,當n越大時,這個圖形就越接近圓
當n大到一定程度後,人眼將無法把它跟真正的圓相區別
這時我們已經成功的畫出了一個“圓”
(注:畫圓的方法很多,這裏使用的是比較簡單,但效率較低的一種)
試修改下面的const int n的值,觀察當n=3,4,5,8,10,15,20,30,50等不同數值時輸出的變化情況
將GL_POLYGON改爲GL_LINE_LOOP、GL_POINTS等其它方式,觀察輸出的變化情況
*/
#include <math.h>
const int n = 20;
const GLfloat R = 0.5f;
const GLfloat Pi = 3.1415926536f;
void myDisplay(void)
{
     int i;
     glClear(GL_COLOR_BUFFER_BIT);
     glBegin(GL_POLYGON);
     for(i=0; i<n; ++i)
         glVertex2f(R*cos(2*Pi/n*i), R*sin(2*Pi/n*i));
     glEnd();
     glFlush();
}


例二、畫一個五角星
/*
設五角星的五個頂點分佈位置關係如下:
      A
E        B

    D    C
首先,根據餘弦定理列方程,計算五角星的中心到頂點的距離a
(假設五角星對應正五邊形的邊長爲.0)
a = 1 / (2-2*cos(72*Pi/180));
然後,根據正弦和餘弦的定義,計算B的x座標bx和y座標by,以及C的y座標
(假設五角星的中心在座標原點)
bx = a * cos(18 * Pi/180);
by = a * sin(18 * Pi/180);
cy = -a * cos(18 * Pi/180);
五個點的座標就可以通過以上四個量和一些常數簡單的表示出來
*/
#include <math.h>
const GLfloat Pi = 3.1415926536f;
void myDisplay(void)
{
     GLfloat a = 1 / (2-2*cos(72*Pi/180));
     GLfloat bx = a * cos(18 * Pi/180);
     GLfloat by = a * sin(18 * Pi/180);
     GLfloat cy = -a * cos(18 * Pi/180);
     GLfloat
         PointA[2] = { 0, a },
         PointB[2] = { bx, by },
         PointC[2] = { 0.5, cy },
         PointD[2] = { -0.5, cy },
         PointE[2] = { -bx, by };

     glClear(GL_COLOR_BUFFER_BIT);
     // 按照A->C->E->B->D->A的順序,可以一筆將五角星畫出
     glBegin(GL_LINE_LOOP);
         glVertex2fv(PointA);
         glVertex2fv(PointC);
         glVertex2fv(PointE);
         glVertex2fv(PointB);
         glVertex2fv(PointD);
     glEnd();
     glFlush();
}


例三、畫出正弦函數的圖形
/*
由於OpenGL默認座標值只能從-1到1,(可以修改,但方法留到以後講)
所以我們設置一個因子factor,把所有的座標值等比例縮小,
這樣就可以畫出更多個正弦週期
試修改factor的值,觀察變化情況
*/
#include <math.h>
const GLfloat factor = 0.1f;
void myDisplay(void)
{
     GLfloat x;
     glClear(GL_COLOR_BUFFER_BIT);
     glBegin(GL_LINES);
         glVertex2f(-1.0f, 0.0f);
         glVertex2f(1.0f, 0.0f);         // 以上兩個點可以畫x軸
         glVertex2f(0.0f, -1.0f);
         glVertex2f(0.0f, 1.0f);         // 以上兩個點可以畫y軸
     glEnd();
     glBegin(GL_LINE_STRIP);
     for(x=-1.0f/factor; x<1.0f/factor; x+=0.01f)
     {
         glVertex2f(x*factor, sin(x)*factor);
     }
     glEnd();
     glFlush();
}


小結
本課講述了點、直線和多邊形的概念,以及如何使用OpenGL來描述點,並使用點來描述幾何圖形。
大家可以發揮自己的想象,畫出各種幾何圖形,當然,也可以用GL_LINE_STRIP把很多位置相近的點連接起來,構成函數圖象。如果有興趣,也可以去找一些圖象比較美觀的函數,自己動手,用OpenGL把它畫出來。
發佈了8 篇原創文章 · 獲贊 0 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章