OpenGL之基本圖元

本文轉載自文章:http://www.cnblogs.com/gl5773477/p/4007350.html

因爲文章較老,只需要注意圖元的繪製邏輯即可,在可編程的shader中,並沒有用到這樣的繪製方法。

在瞭解了一些基本圖元之後,要知道如何利用基本圖元來提高效率。比如當我畫一個扇形的時候,最好使用  GL_TRIANGLE_FAN 而不是GL_TRIANGLE ,因爲這樣可以提高效率。


OpenGL的基本圖元有點(Point)、線段(Line)、多邊形(Ploygon)、三角形(Triangle)、四邊形(Quadrangle)。組成關係我想大部分人都能夠理解:

  ①無數個“點”的線性排列組成----“線段”

  ②多個“線段”可以圍成一個“多邊形”

  ③多個“多邊形”在三維空間中可以圍成“多面體”

有此,可以看出,點是最基本的圖元,其他的圖元都是由頂點組合構成的,因此我們從點開始介紹。

1、點

在OpenGL中,“點”稱爲頂點(Vertex),通常用一個形如(x, y, z)的三維座標值表示。

有時候會採用齊次座標表示,就是一個形如(x, y, z, w)的四元組,可以這樣理解這個四元組,前面的(x,y,z)表示“點”所在的方向,而w表示在該方向上的距離比例,所以(x, y, z, w)表示的實際座標值就是(x/w, y/w, z/w)座標點。如果w爲0,則表示方向爲(x, y, z)的無窮遠點;如果w=10,表示取(x,y,z)的十分之一作爲座標點(x/10,y/10,z/10)。

 

一般情況 下,OpenGL 中的點將被畫成單個的像素。實際上點還可以更小,雖然它可能足夠小,但並不會是無窮小,一個像素內可以描繪多個點,取決於對點大小的設定,默認一個點的大小爲一個像素。

當然我們也可以改變點的大小,函數原型爲:

//size 必須大於 0.0f,默認值爲 1.0f,單位爲“像素”。
//對於具體的 OpenGL 實現,點的大小都有個限度的,如果設置的 size 超過最大值,則設置可能會有問題,一般情況是不在增大。
void glPointSize(GLfloat size);

代碼實現畫一個點,我們只需要在我們的繪圖函數中添加如下代碼即可:

void display(void)
{
    glPointSize(5);//在繪製之前要設置要相關參數,這裏設置點的大小爲5像素
    glBegin(GL_POINTS);
    {
        glVertex2f(0.0f, 0.0f); //OpenGl內的點是齊次座標的四元組,缺省的z座標爲0.0f,w爲1.0f,所以該點爲(1, 2, 0, 1)
        glVertex2f(0.0f, 0.5f); //繪製的第二個點
        glVertex2f(0.5f, 0.25f); //繪製的第三個點
    }
    glEnd();

    glFlush();//glFlush,保證前面的OpenGL命令立即執行(而不是讓它們在緩衝區中等待)
}

需要注意的是:座標的值默認是1.0爲最大,即屏幕邊緣,所以如果大於1,則會超出屏幕,這時候除非改變觀察點,否則是看不到的。(0,0)表示在屏幕的中間,也就是座標系原點。

OpenGL中繪製幾何圖元,必須使用 glBegain() 和 glEnd() 這一對函數,glBegin() 和 glEnd() 需要成對使用,兩者之間是繪圖語句。

glBegin()的參數就是需要繪製的圖元類型,它決定了在glBegin()和glEnd()之間繪圖的點將如何組織成目標圖元,如參數爲“GL_POINTS”,表示每一個點都是獨立的,互不相連的,因此也就繪製出了一個個“點”。

2、線段

線段是由兩個頂點連接起來形成的圖元。線段間的連接方式有三種:

①獨立線段:圖元類型參數--GL_LINES

②線段間首尾相連但最終不閉合:折線,圖元類型參數--GL_LINE_STRIP

③線段間首尾相連最終封口閉合:圖形,圖元類型參數--GL_LINE_LOOP

對應的圖例:

 

線段代碼實例:

void display(void)
{
    /*同樣用5個點,畫出不同類型的線段組合*/
    //獨立線段,5個點能畫出2條線段
    glBegin(GL_LINES);
    {
        glVertex2f(-0.8f, -0.5f); 
        glVertex2f(-0.5f, -0.5f);

        glVertex2f(-0.8f, 0.0f); 
        glVertex2f(-0.5f, 0.0f); 

        glVertex2f(-0.8f, 0.5f); //最後的這個點沒有與之配對的點,無法連成線段,所以不會被畫出來,在獨立線段模式下被捨棄
    }
    glEnd();

    //連續不閉合折線,5個點能畫出4條線段
    glBegin(GL_LINE_STRIP);
    {
        glVertex2f(-0.3f, -0.5f); //起始點

        //後面的每一個點都會與前一個相連生成一條線段
        glVertex2f(-0.0f, -0.5f);
        glVertex2f(-0.3f, 0.0f); 
        glVertex2f(-0.0f, 0.0f); 
        glVertex2f(-0.3f, 0.5f);
    }
    glEnd();

    //連續閉合折線,5個點能畫出5條線段
    glBegin(GL_LINE_LOOP);
    {
        glVertex2f(0.2f, -0.5f); //起始點

        //後面的每一個點都會與前一個相連生成一條線段
        glVertex2f(0.5f, -0.5f);
        glVertex2f(0.2f, 0.0f); 
        glVertex2f(0.5f, 0.0f); 
        //最後一個點不僅與前一個點相連,還與起始點相連,形成閉合
        glVertex2f(0.2f, 0.5f);
    }
    glEnd();

    glFlush();//保證前面的OpenGL命令立即執行(而不是讓它們在緩衝區中等待)
}

程序運行示例圖:

同樣的,直線可以指定寬度:

void glLineWidth(GLfloat width); //width表示線寬,單位:像素

特殊的是線除了直線,還有虛線。可以用虛線連接兩個點。

在繪製虛線之前必須先啓動“虛線模式”:glEnable(GL_LINE_STIPPLE);

虛線有不同的類型,調節函數如下:

/*
        參數pattern是16位二進制數(0或1),如OxAAAA表示1010101010101010
        從低位開始,每一個二進制位代表一個像素, 1表示用當前顏色繪製一個像素,0表示當前不繪製,只移動一個像素位,中間留下一個像素的空白
        factor是用來調節二進制位0和1代表的像素個數,如果factor爲2,則表示遇到二進制1的時候用當前顏色繪製兩個像素,0移動兩個像素不繪製
*/ 
        void glLineStipple(GLint factor,GLushort pattern);

代碼示例:

void display(void)
{
    //開啓虛線模式
    glEnable(GL_LINE_STIPPLE);
    //調節虛線類型參數
    glLineStipple(2,0xAAAA);
    //調節線寬
    glLineWidth(3);
    //繪製一條虛線
    glBegin(GL_LINES);
    {
        glVertex2f(0,0);
        glVertex2f(0.5,0.5);
    }
    glEnd();

    glFlush();//保證前面的OpenGL命令立即執行(而不是讓它們在緩衝區中等待)
}

程序運行示例:

3、多邊形

類似於點組合線段的方式,OpenGL定義的多邊形是由多個點連接成線段再圍成封閉區域。

多邊形有兩種:凸多邊形(指多邊形任意非相鄰的兩點的連線位於多邊形的內部)和凹多邊形,但OpenGL中規定的多邊形必須是凸多邊形

但有時需要繪製一些凹多邊形,通常解決的辦法是對它們進行分割,用多個三角形來組合替代。顯然,繪製這些三角形時,有些邊不應該進行繪製,否則,多邊形內部就會出現多餘的線框。OpenGL提供的解決辦法是通過設置邊標誌命令glEdgeFlag()來控制某些邊產生繪製,而另外一些邊不產生繪製,這裏只需知道有這個工能,具體細節待遇到在研究,接下來看重點。

(1)連接方式

<1>按點的定義順序依次連接:圖元類型參數--GL_POLYGON

<2>從第1個點開始,每三個點一組畫一個三角形,三角形之間是獨立的:圖元類型參數--GL_TRIANGLES

<3>從第三個點開始,每點與前面的兩個點組合畫一個三角形,即線性連續三角形串:圖元類型參數--GL_TRIANGLE_STRIP

<4>從第三個點開始,每點與前一個點和第一個點組合畫一個三角形,即扇形連續三角形:圖元類型參數--GL_TRIANGLE_FAN

對應的圖例:

 

四邊形的繪製模式和三角形類似。

(2)多邊形的正反兩面

多邊形爲什麼會有正反面這一說法呢?舉個簡單的例子。

雖然多邊形是二維的,但是我們知道三維物體可以理解爲多邊形圍成的,也就是說在三維空間物體上有二維多邊形的存在。

一張“正方形”紙片,如果極限的薄,我們可以認爲是一個多邊形(正方形),那麼紙仍然會存在兩面,紙的正反面。更具體一點,如果我們用同大小6張正方形的紙片圍成一個正方體,那麼正方體的任何一個面都是一個多邊形,而且這個多邊形是有正反面,朝外的你能看到的部分是正面(假設),那麼朝內的看不到的那部分就是反面。同樣的道理,OpenGL要區分多邊形的正反面。那麼到底怎麼定義正面或者反面呢?

有一個函數來定義:

glFrontFace(GL_CCW);//設置點序列逆時針方向圍成的多邊形爲正面
glFrontFace(GL_CW); //設置點序列順時針方向圍成的多邊形爲正面

設置這個的原因是,默認情況下,OpenGL繪製三維物體時兩面都會繪製,而實際的時候很多面我們是看不到的,如物體朝內方向的多邊形,還有一些物體間遮擋的情況導致有些多邊形是不可見的,因此爲了提高性能,我們需要剔除這些不必要的繪製。

glEnable(GL_CULL_FACE); //來啓動剔除功能
glCullFace(); //參數可以是GL_FRONT、GL_BACK、GL_FRONT_AND_BACK,表示剔除多邊形的哪種面,設定後該類型的多邊形不繪製

(3)繪製模式

常用的多邊形繪製模式有:填充式(默認)輪廓線式頂點式鏤空圖案填充式

前三種都是使用glPolygonMode()函數來指定模式,最後一種比較特殊。

void glPolygonMode(GLenum face,GLenum mode);//該函數要求說明是對多邊形哪一個面是定face設置模式

畫一個多邊形,設置不同的繪製模式,看一下效果:

代碼:

void myDisplay(void)
{
    //設置點的大小,以便容易觀察
    glPointSize(5);

    //設置正面的繪製模式爲:填充式,反面不設定則默認爲填充式
    glPolygonMode(GL_FRONT,GL_FILL);
    glBegin(GL_POLYGON);
    {
        glVertex2f(0,0);
        glVertex2f(0,0.3);
        glVertex2f(-0.3,0.3);
        glVertex2f(-0.3,0);
    }
    glEnd();

    //設置正面的繪製模式爲:輪廓線式
    glPolygonMode(GL_FRONT,GL_LINE);
    glBegin(GL_POLYGON);
    {
        glVertex2f(0.5,0);
        glVertex2f(0.5,0.3);
        glVertex2f(0.2,0.3);
        glVertex2f(0.2,0);
    }
    glEnd();

    //設置正面的繪製模式爲:頂點式
    glPolygonMode(GL_FRONT,GL_POINT);
    glBegin(GL_POLYGON);
    {
        glVertex2f(0.9,0);
        glVertex2f(0.9,0.3);
        glVertex2f(0.6,0.3);
        glVertex2f(0.6,0);
    }
    glEnd();

    glFlush();
}

示例圖:

關於最後一種鏤空圖案樣式,有點類似於線段中的虛線,這裏只不過是針對多邊形內部區域進行像素點的繪製與否,來做鏤空效果。具體的細節還需查閱資料。

 


以上爲基本圖元的知識講解,並給出了針對性的代碼實例,在此基礎之上會進一步學習更加複雜的圖形繪製。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章