Win32 OpenGL 編程 ( 3 ) 基本圖元(點,直線,多邊形)的繪制
write by 九天雁翎 (JTianLing) -- blog.csdn.net/vagrxie
一、 提要
在前面兩篇相關文章
《 Win32 OpenGL 編程(1)Win32下的OpenGL編程必須步驟 》
《 Win32 OpenGL編程(2) 尋找缺失的OpenGL函數 》
中,我們已經建立了一個較為全面的 Win32 OpenGL 編程環境及一個簡單的框架,并且,實際上掌握了 OpenGL 在 Windows 下與 Win32 窗口交互的方法,在此基礎上,總算是可以正式進行一些 OpenGL 相關知識的學習,前面的那些也就算是熱身。本文的目的是將 OpenGL 中基本圖元(點,線,多邊形)的繪制大概的講解一遍,最后可以組合的使用這些技術用 OpenGL 完成較為復雜的 2D 圖形。
二、 基本圖元相關概念
首先講講相關的概念,在 OpenGL 中,即使是復雜的圖形,實際上也是由一些非常基本的圖元組成,即點,直線,多邊形,多邊形中用的較多的又是三角形和矩形。在數學中,兩點確定一條直線,三點確定一個三角形和一個面,同一個面上的四個點確定一個四邊形。。。。。。在 OpenGL 中也大致的利用此方式來確定直線和多邊形,也就是說,當你想畫一個直線或者一個多邊形的時候,只需要告訴 OpenGL 能確定此直線或者多邊形的點即可。用參考 2 中的描述是:“在 OpenGL 中,所有的幾何物體最終都描述成一組有序的頂點”。有此基本的概念后就可以看下面的例子了。
三、 OpenGL 的 Hello World 示例分析
這里的 Hello World 程序指的是一個利用 OpenGL 完成的矩形繪制程序,相對于在系列文章 1 中的 Win32 OpenGL 編程框架,簡化了很多東西,只剩下最最基本的 OpenGL 元素,但也是一個完善的 OpenGL 示例了。此示例顯示的是一個白色的矩形,運行效果如附圖 1 ,完整代碼見我博客代碼的 2009-10-12/SimpleRectangle 工程,具體下載及查看方法見本文最后的說明。
此示例 OpenGL 相關的主要就是兩部分。
//OpenGL 初始化開始
void SceneInit ( int w , int h )
{
}
// 這里進行所有的繪圖工作
void SceneShow ( GLvoid )
{
glClear ( GL_COLOR_BUFFER_BIT );
glBegin ( GL_QUADS );
glVertex3f (-0.5, -0.5, 0.0);
glVertex3f (0.5, -0.5, 0.0);
glVertex3f (0.5, 0.5, 0.0);
glVertex3f (-0.5, 0.5, 0.0);
glEnd ();
glFlush ();
}
我們下面從 OpenGL 的角度來分析此程序。作為 HelloWorld 級的程序,我簡化了很多東西,首先 OpenGL 的初始化省略了,用的都是 OpenGL 的默認值,具體有哪些,后面一步一步說。以下是按步驟說明每個 OpenGL 函數。
1. glClear
OpenGL 參考手冊 :
glClear takes a single argument that is the bitwise OR of several values indicating which buffer is to be cleared.
GL_COLOR_BUFFER_BIT Indicates the buffers currently enabled for color writing.
作用是清除顏色緩沖區。類似于我們使用一塊新申請的內存時先用 memset/ZeroMemory 去清零一下,用這樣的 Clear 操作為我們需要使用的顏色緩沖區 (Color Buffer) 清零一下。假如沒有這樣的操作,以前留在顯存 / 內存 ( 不確定 ) 中的值會影響我們的操作,并且,這樣的問題往往是非常難以調試和發現的,這一點大家可以嘗試一下。
2. glBegin , glEnd
OpenGL 參考手冊 :
glBegin, glEnd - delimit the vertices of a primitive or a group of like primitives
OpenGL 代碼的主體部分是:
glBegin ( GL_QUADS );
glVertex3f (-0.5, -0.5, 0.0);
glVertex3f (0.5, -0.5, 0.0);
glVertex3f (0.5, 0.5, 0.0);
glVertex3f (-0.5, 0.5, 0.0);
glEnd ();
glBegin 與 glEnd 很明顯是一對, 標志著一組 OpenGL 操作的開始和結束。 并且在參數中告訴了 OpenGL 下面的操作是針對什么圖形進行的,此例中 GL_QUADS 是表示四邊形。事實上還有很多其他的參數來表示各類圖形,在《 OpenGL Programming Guide 》的 此頁 中 Figure 2-7 : Geometric Primitive Types 一圖形象的說明了各個參數的作用。
3. glVertex *
glVertex3f 就是在 基本圖元相關概念 一節提到的 OpenGL 中確定頂點的函數。簡而言之,上面的 4 句 glVertex3f 確定了矩形的 4 個頂點。(注意順序)然后, OpenGL 就會自動根據 glBegin 指定的參數去完成相關的繪制任務了, 此例中 GL_QUADS 是表示四邊形,所以最后的效果是一個矩形,實際的其他參數讀者可以自己嘗試一下。
4. OpenGL 默認坐標系
我們再看一下 glVertex* 指定頂點的代碼:
glVertex3f (-0.5, -0.5, 0.0);
glVertex3f (0.5, -0.5, 0.0);
glVertex3f (0.5, 0.5, 0.0);
glVertex3f (-0.5, 0.5, 0.0);
為什么上述就指定了一個矩形的四個頂點呢?需要說明的是,在 OpenGL 中默認坐標體系與 Windows 中常用的不同, Windows 中常用的坐標體系(僅 2D )是用戶區的左上角為坐標原點,即 (0.0,0.0) 點,右為坐標軸的 X 軸正方向,下為 Y 軸正方向, OpenGL 中的坐標軸( 3D )默認以客戶區中心點為坐標原點( 0.0,0.0,0.0 ),右為坐標軸的 X 軸正方向,上為 Y 軸正方向,垂直指出屏幕的方向為 Z 軸正方向。長度定義是將客戶區范圍為按單位長度定義,即整個客戶區恰好是 (-1,-1) (左下)到 (1,1) (右上)。附圖 2 是一個上述示例程序附上 OpenGL 的平面坐標系的圖,也可以作為 OpenGL 默認坐標系的參考圖。
5. OpenGL 函數命名
這里順面介紹一下 OpenGL 函數的命名規范,因為 C 語言天生的弱點及豐富的數據類型,在 OpenGL 中凡是牽涉到與參數數量和數據類型相關的函數,一般的命名方式都是 xxxx[n][t] 。
xxxx 表示函數的意義, [t] 用于表示此函數對應的類型。一般用單個的字母表示參數的類型, s 表示 16 位整數( OpenGL 中將這個類型定義為 GLshort ), i 表示 32 位整數( OpenGL 中將這個類型定義為 GLint 和 GLsizei ), f 表示 32 位浮點數( OpenGL 中將這個類型定義為 GLfloat ), d 表示 64 位浮點數( OpenGL 中將這個類型定義為 GLdouble )。此例中使用的是 32 位浮點數,所以是 f 。這是 C 語言沒有函數重載機制的天生弱點導致的扭曲應對方案。(用 C++ 就不需要這么麻煩了)
然后是數字,因為同樣的原因,在 C 語言中一個同樣意義的函數不能同時有不同個數的參數,所以 OpenGL 用一個數字來表示參數的個數,此例中是 3 ,表示以 3 個參數(即點的 X,Y,Z 坐標)來表示頂點。(事實上還有 glVertex2* , glVertex4* )
比如此例中,用如下代碼效果是一樣的:
glVertex2f (-0.5, -0.5);
glVertex2f (0.5, -0.5);
glVertex2f (0.5, 0.5) ;
glVertex2f (-0.5, 0.5);
在 glVertex2f 中, Z 軸默認為 0.
這里我依照參考 2 的用法,以 * 作為通配符來表示一組函數, * 既可以表示代表參數數量的數字也可以表示代表類型的字母。
6. glFlush
OpenGL 參考手冊 :
glFlush - force execution of GL commands in finite time
說白了就是強制執行已經指定的 OpenGL 命令,與 fflush 命名類似作用也類似。
7. 小結
以上的 5 個 OpenGL 函數就構成了一個基本的 OpenGL 程序(不包括模板中使用的那些),由 glClear 清空顏色緩沖區獲得干凈的環境,由 glBegin 指定開始一組頂點操作的開始,并確認繪制圖形,由 glVertex* 指定頂點,由 glEnd 表示操作結束,由 glFlush 強制開始繪圖。運行效果如附圖 1 。
四、 基本圖元
事實上,上一節已經包含了所有的知識,各個圖元在 OpenGL 中繪制方式的不同僅僅在于 glBegin 的參數不同而已,這里將基本圖元簡單介紹一下。
1. 點
點是最常用的圖元之一了,而且所有的圖像都可以看做是由點構成的,事實上屏幕也就是由一個一個像素點構成了圖像:)
畫點的方式是使用 GL_POINTS 為參數調用 glBegin 。那么,每一個 glVertex* 指定頂點就會繪制成一個單獨的點。點的默認大小為 1 個像素,可以通過 glPointSize 函數來改變點的大小,在點比較大并且沒有開啟抗鋸齒時,是按照一個正方形來繪制的。比如上例中,僅僅將 GL_QUADS 換成 GL_POINTS ,將是繪制上述矩形的 4 個頂點,為了截圖效果顯著,調用 glPointSize 將點的大小改為 20 。如下代碼:
// 這里進行所有的繪圖工作
void SceneShow ( GLvoid )
{
glClear ( GL_COLOR_BUFFER_BIT );
glPointSize (20);
glBegin ( GL_POINTS );
glVertex3f (-0.5, -0.5, 0.0);
glVertex3f (0.5, -0.5, 0.0);
glVertex3f (0.5, 0.5, 0.0);
glVertex3f (-0.5, 0.5, 0.0);
glEnd ();
glFlush ();
}
效果如附圖 3 所示。
光是點也可以做很多有趣的應用, Windows 的屏保模擬星空即是其一,事實上,在原來學習簡單的圖形編程時,我用多種語言嘗試了用點做一些有意思的東西。見簡單圖形編程學習系列:
《 簡單圖形編程的學習( 2 ) --- 點 (Qt 實現 ) 》
《 簡單圖形編程的學習( 2 ) --- 點 (Windows GDI 實現 ) 》
《 簡單圖形編程的學習( 2 ) --- 點 (small basic 實現 ) 》
其中點與文字結合形成的那個星空文字效果我是印象深刻,我一直將其作為“簡單的編程技術 + 創意”也能很強大的例子。
2. 直線
直線也是很基礎的東西了,但是 OpenGL 中的直線與數學概念上有些區別,不知道外國的那些專家在命名時為啥亂了,其實 OpenGL 中的直線與數學中的線段概念一致,有兩個端點確認長度。事實上,在 OpenGL 繪制中,指定的也就是線段的兩個端點。用 GL_LINES 調用 glBegin 時,表示繪制的是直線。默認情況下寬度為一個像素,同樣, OpenGL 也提供了函數 glLineWidth 用以改變直線的寬度。比如上例中,僅僅將 GL_QUADS 換成 GL_LINES 將是兩條平行的直線,并用 glLineWidth 將直線寬度改為 5 ,如下代碼:
// 這里進行所有的繪圖工作
void SceneShow ( GLvoid )
{
glClear ( GL_COLOR_BUFFER_BIT );
glLineWidth (5);
glBegin ( GL_LINES );
glVertex3f (-0.5, -0.5, 0.0);
glVertex3f (0.5, -0.5, 0.0);
glVertex3f (0.5, 0.5, 0.0);
glVertex3f (-0.5, 0.5, 0.0);
glEnd ();
glFlush ();
}
運行效果如附圖 4 所示。
直線的應用也是非常廣泛的,還記得 Windows 的屏保中的變幻線嗎?千變萬變,無論多么絢爛的效果,其實也僅僅是一條條變化的線段而已。
3. 多邊形
其實可以將多邊形看成是從點到線到面的一種擴展,這里的面自然也是有范圍的,那么就成了多邊形了,在繪制圖形中用的最多的是三角形,因為三角形肯定在同一個面上,這樣可以簡化很多計算的處理。 GL_TRIANGLES 調用 glBegin 表示開始繪制三角形。然后還有 GL_QUADS 表示四邊形(上例中的用法), GL_POLYGON 表示多邊形(必須是凸的)。
4. 小結
其實除了上面講到的那些參數,還有一些額外的參數,比如 GL_LINE_STRIP,GL_TRIANGLES_STRIP 等,表示繪制的時候繪制一些列連續的圖形,這些參數用文字解釋起來不夠形象,還是推薦參考 《 OpenGL Programming Guide 》的 此頁 中 Figure 2-7 : Geometric Primitive Types 一圖,此圖形象的展示了各個參數時對點的解釋方式和順序。在此圖的下面,還有個表總結了一下各個參數的作用。
在一個 glBegin 和 glEnd 對中可以連續的制定多個頂點,甚至超出你指定的圖形的數目,比如繪制三角形時可以指定 6 個點,那么此時,將會繪制兩個三角形而不是一個,這樣而當指定 4 , 5 個點時用 GL_TRIANGLES 參數時將會丟棄,用 GL_TRIANGLE_STRIP 參數時將會連續繪制兩個三角形,具體的解釋方法也是要看 glBegin 參數的,建議還是參考上述圖片。
五、 參考資料
1. 《 OpenGL Reference Manual 》, OpenGL 參考手冊
2. 《 OpenGL 編程指南》(《 OpenGL Programming Guide 》), Dave Shreiner , Mason Woo , Jackie Neider , Tom Davis 著,徐波譯,機械工業出版社
3. 《 Nehe OpenGL Tutorials 》, Nehe 著,在 http://nehe.gamedev.net/ 上可以找到教程及相關的代碼下載,(有 PDF 版本教程下載) Nehe 自己還做了一個面向對象的框架,作為演示程序來說,這樣的框架非常合適。也有 中文版 ,各取所需吧。
4. 《 OpenGL 入門學習》 , eastcowboy 著,這是我在網上找到的一個比較好的教程,較為完善,而且非常通俗。這是第一篇的地址: http://bbs.pfan.cn/post-184355.html
六、 系列其他文章
1. 《 Win32 OpenGL 編程(1)Win32下的OpenGL編程必須步驟 》
2. 《 Win32 OpenGL編程(2) 尋找缺失的OpenGL函數 》
七、 最后說明
本文中所有代碼(如果有的話)都能用 Mercurial 在 Google Code 中下載。
文章以博文發表的日期分目錄存放,下載地址見:
http://code.google.com/p/jtianling/source/checkout?repo=blog-sample-code
或者直接使用 Mercurial 克隆下列庫:
https://blog-sample-code.jtianling.googlecode.com/hg/
Mercurial 使用方法見《 分布式的,新一代 版本控制系統 Mercurial 的介紹及簡要入門 》
八、 附圖
1. 圖 1 SimpleRectangle
圖2 SimpleRectangle with coordinate
圖3 SimplePoints
圖4 SimpleLines
write by 九天雁翎 (JTianLing) -- blog.csdn.net/vagrxie
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
