本文轉載自文章: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();
}
示例圖:
關於最後一種鏤空圖案樣式,有點類似於線段中的虛線,這裏只不過是針對多邊形內部區域進行像素點的繪製與否,來做鏤空效果。具體的細節還需查閱資料。
以上爲基本圖元的知識講解,並給出了針對性的代碼實例,在此基礎之上會進一步學習更加複雜的圖形繪製。