OpenGL入門學習 ?
說起編程作圖,大概還有很多人想起TC的#include
但是各位是否想過,那些畫面絢麗的PC游戲是如何編寫出來的?就靠TC那可憐的640*480分辨率、16色來做嗎?顯然是不行的。
本帖的目的是讓大家放棄TC的老舊圖形接口,讓大家接觸一些新事物。
OpenGL作為當前主流的圖形API之一,它在一些場合具有比DirectX更優(yōu)越的特性。
1、與C語言緊密結合。
OpenGL命令最初就是用C語言函數來進行描述的,對于學習過C語言的人來講,OpenGL是容易理解和學習的。如果你曾經接觸過TC的graphics.h,你會發(fā)現(xiàn),使用OpenGL作圖甚至比TC更加簡單。
2、強大的可移植性。
微軟的Direct3D雖然也是十分優(yōu)秀的圖形API,但它只用于Windows系統(tǒng)(現(xiàn)在還要加上一個XBOX游戲機)。而OpenGL不僅用于 Windows,還可以用于Unix/Linux等其它系統(tǒng),它甚至在大型計算機、各種專業(yè)計算機(如:醫(yī)療用顯示設備)上都有應用。并且,OpenGL 的基本命令都做到了硬件無關,甚至是平臺無關。
3、高性能的圖形渲染。
OpenGL是一個工業(yè)標準,它的技術緊跟時代,現(xiàn)今各個顯卡廠家無一不對OpenGL提供強力支持,激烈的競爭中使得OpenGL性能一直領先。
總之,OpenGL是一個很NB的圖形軟件接口。至于究竟有多NB,去看看DOOM3和QUAKE4等專業(yè)游戲就知道了。
OpenGL官方網站(英文)
http://www.opengl.org
下面將對Windows下的OpenGL編程進行簡單介紹。
學習OpenGL前的準備工作
第一步,選擇一個編譯環(huán)境
現(xiàn)在Windows系統(tǒng)的主流編譯環(huán)境有Visual Studio,Broland C++ Builder,Dev-C++等,它們都是支持OpenGL的。但這里我們選擇Visual Studio 2005作為學習OpenGL的環(huán)境。
第二步,安裝GLUT工具包
GLUT不是OpenGL所必須的,但它會給我們的學習帶來一定的方便,推薦安裝。
Windows環(huán)境下的GLUT下載地址:(大小約為150k)
http://www.opengl.org/resources/libraries/glut/glutdlls37beta.zip
無法從以上地址下載的話請使用下面的連接:
http://upload.programfan.com/upfile/200607311626279.zip
Windows環(huán)境下安裝GLUT的步驟:
1、將下載的壓縮包解開,將得到5個文件
2、在“我的電腦”中搜索“gl.h”,并找到其所在文件夾(如果是VisualStudio2005,則應該是其安裝目錄下面的“VCPlatformSDKincludegl文件夾”)。把解壓得到的glut.h放到這個文件夾。
3、把解壓得到的glut.lib和glut32.lib放到靜態(tài)函數庫所在文件夾(如果是VisualStudio2005,則應該是其安裝目錄下面的“VClib”文件夾)。
4、把解壓得到的glut.dll和glut32.dll放到操作系統(tǒng)目錄下面的system32文件夾內。(典型的位置為:C:WindowsSystem32)
第三步,建立一個OpenGL工程
這里以VisualStudio2005為例。
選擇File->New->Project,然后選擇Win32 Console Application,選擇一個名字,然后按OK。
在談出的對話框左邊點Application Settings,找到Empty project并勾上,選擇Finish。
然后向該工程添加一個代碼文件,取名為“OpenGL.c”,注意用.c來作為文件結尾。
搞定了,就跟平時的工程沒什么兩樣的。
第一個OpenGL程序
一個簡單的OpenGL程序如下:(注意,如果需要編譯并運行,需要正確安裝GLUT,安裝方法如上所述)
#include
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glRectf(-0.5f, -0.5f, 0.5f, 0.5f);
glFlush();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(100, 100);
glutInitWindowSize(400, 400);
glutCreateWindow("第一個OpenGL程序");
glutDisplayFunc(&myDisplay);
glutMainLoop();
return 0;
}
該程序的作用是在一個黑色的窗口中央畫一個白色的矩形。下面對各行語句進行說明。
首先,需要包含頭文件#include
本來OpenGL程序一般還要包含
然后看main函數。
int main(int argc, char *argv[]),這個是帶命令行參數的main函數,各位應該見過吧?沒見過的同志們請多翻翻書,等弄明白了再往下看。
注意main函數中的各語句,除了最后的return之外,其余全部以glut開頭。這種以glut開頭的函數都是GLUT工具包所提供的函數,下面對用到的幾個函數進行介紹。
1、glutInit,對GLUT進行初始化,這個函數必須在其它的GLUT使用之前調用一次。其格式比較死板,一般照抄這句glutInit(&argc, argv)就可以了。
2、 glutInitDisplayMode,設置顯示方式,其中GLUT_RGB表示使用RGB顏色,與之對應的還有GLUT_INDEX(表示使用索引顏色)。GLUT_SINGLE表示使用單緩沖,與之對應的還有GLUT_DOUBLE(使用雙緩沖)。更多信息,請自己Google。當然以后的教程也會有一些講解。
3、glutInitWindowPosition,這個簡單,設置窗口在屏幕中的位置。
4、glutInitWindowSize,這個也簡單,設置窗口的大小。
5、glutCreateWindow,根據前面設置的信息創(chuàng)建窗口。參數將被作為窗口的標題。注意:窗口被創(chuàng)建后,并不立即顯示到屏幕上。需要調用glutMainLoop才能看到窗口。
6、glutDisplayFunc,設置一個函數,當需要進行畫圖時,這個函數就會被調用。(這個說法不夠準確,但準確的說法可能初學者不太好理解,暫時這樣說吧)。
7、glutMainLoop,進行一個消息循環(huán)。(這個可能初學者也不太明白,現(xiàn)在只需要知道這個函數可以顯示窗口,并且等待窗口關閉后才會返回,這就足夠了。)
在glutDisplayFunc函數中,我們設置了“當需要畫圖時,請調用myDisplay函數”。于是myDisplay函數就用來畫圖。觀察myDisplay中的三個函數調用,發(fā)現(xiàn)它們都以gl開頭。這種以gl開頭的函數都是OpenGL的標準函數,下面對用到的函數進行介紹。
1、glClear,清除。GL_COLOR_BUFFER_BIT表示清除顏色,glClear函數還可以清除其它的東西,但這里不作介紹。
2、glRectf,畫一個矩形。四個參數分別表示了位于對角線上的兩個點的橫、縱坐標。
3、glFlush,保證前面的OpenGL命令立即執(zhí)行(而不是讓它們在緩沖區(qū)中等待)。其作用跟fflush(stdout)類似。
OpenGL入門學習[二]
本次課程所要講的是繪制簡單的幾何圖形,在實際繪制之前,讓我們先熟悉一些概念。
一、點、直線和多邊形
我們知道數學(具體的說,是幾何學)中有點、直線和多邊形的概念,但這些概念在計算機中會有所不同。
數學上的點,只有位置,沒有大小。但在計算機中,無論計算精度如何提高,始終不能表示一個無窮小的點。另一方面,無論圖形輸出設備(例如,顯示器)如何精確,始終不能輸出一個無窮小的點。一般情況下,OpenGL中的點將被畫成單個的像素(像素的概念,請自己搜索之~),雖然它可能足夠小,但并不會是無窮小。同一像素上,OpenGL可以繪制許多坐標只有稍微不同的點,但該像素的具體顏色將取決于OpenGL的實現(xiàn)。當然,過度的注意細節(jié)就是鉆牛角尖,我們大可不必花費過多的精力去研究“多個點如何畫到同一像素上”。
同樣的,數學上的直線沒有寬度,但OpenGL的直線則是有寬度的。同時,OpenGL的直線必須是有限長度,而不是像數學概念那樣是無限的??梢哉J為,OpenGL的“直線”概念與數學上的“線段”接近,它可以由兩個端點來確定。
多邊形是由多條線段首尾相連而形成的閉合區(qū)域。OpenGL規(guī)定,一個多邊形必須是一個“凸多邊形”(其定義為:多邊形內任意兩點所確定的線段都在多邊形內,由此也可以推導出,凸多邊形不能是空心的)。多邊形可以由其邊的端點(這里可稱為頂點)來確定。(注意:如果使用的多邊形不是凸多邊形,則最后輸出的效果是未定義的——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的很多函數都是采用這樣的形式,一個相同的前綴再加上參數說明標記,這一點會隨著學習的深入而有更多的體會。
三、開始繪制
假設現(xiàn)在我已經指定了若干頂點,那么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等,每種方式的大致效果見下圖:
聲明:該圖片來自www.opengl.org,該圖片是《OpenGL編程指南》一書的附圖,由于該書的舊版(第一版,1994年)已經流傳于網絡,我希望沒有觸及到版權問題。
我并不準備在glBegin的各種方式上大作文章。大家可以自己嘗試改變glBegin的方式和頂點的位置,生成一些有趣的圖案。
程序代碼:
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glBegin(/* 在這里填上你所希望的模式 */);
/* 在這里使用glVertex*系列函數 */
/* 指定你所希望的頂點位置 */
glEnd();
glFlush();
}
把這段代碼改成你喜歡的樣子,然后用它替換第一課中的myDisplay函數,編譯后即可運行。
兩個例子
例一、畫一個圓
/*
正四邊形,正五邊形,正六邊形,……,直到正n邊形,當n越大時,這個圖形就越接近圓
當n大到一定程度后,人眼將無法把它跟真正的圓相區(qū)別
這時我們已經成功的畫出了一個“圓”
(注:畫圓的方法很多,這里使用的是比較簡單,但效率較低的一種)
試修改下面的const int n的值,觀察當n=3,4,5,8,10,15,20,30,50等不同數值時輸出的變化情況
將GL_POLYGON改為GL_LINE_LOOP、GL_POINTS等其它方式,觀察輸出的變化情況
*/
#include
在第二課中,我們學習了如何繪制幾何圖形,但大家如果多寫幾個程序,就會發(fā)現(xiàn)其實還是有些郁悶之處。例如:點太小,難以看清楚;直線也太細,不舒服;或者想畫虛線,但不知道方法只能用許多短直線,甚至用點組合而成。
這些問題將在本課中被解決。
下面就點、直線、多邊形分別討論。
1、關于點
點的大小默認為1個像素,但也可以改變之。改變的命令為glPointSize,其函數原型如下:
void glPointSize(GLfloat size);
size必須大于0.0f,默認值為1.0f,單位為“像素”。
注意:對于具體的OpenGL實現(xiàn),點的大小都有個限度的,如果設置的size超過最大值,則設置可能會有問題。
例子:
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glPointSize(5.0f);
glBegin(GL_POINTS);
glVertex2f(0.0f, 0.0f);
glVertex2f(0.5f, 0.5f);
glEnd();
glFlush();
}
2、關于直線
(1)直線可以指定寬度:
void glLineWidth(GLfloat width);
其用法跟glPointSize類似。
(2)畫虛線。
首先,使用glEnable(GL_LINE_STIPPLE);來啟動虛線模式(使用glDisable(GL_LINE_STIPPLE)可以關閉之)。
然后,使用glLineStipple來設置虛線的樣式。
void glLineStipple(GLint factor, GLushort pattern);
pattern是由1和0組成的長度為16的序列,從最低位開始看,如果為1,則直線上接下來應該畫的factor個點將被畫為實的;如果為0,則直線上接下來應該畫的factor個點將被畫為虛的。
以下是一些例子:
聲明:該圖片來自www.opengl.org,該圖片是《OpenGL編程指南》一書的附圖,由于該書的舊版(第一版,1994年)已經流傳于網絡,我希望沒有觸及到版權問題。
示例代碼:
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_LINE_STIPPLE);
glLineStipple(2, 0x0F0F);
glLineWidth(10.0f);
glBegin(GL_LINES);
glVertex2f(0.0f, 0.0f);
glVertex2f(0.5f, 0.5f);
glEnd();
glFlush();
}
3、關于多邊形
多邊形的內容較多,我們將講述以下四個方面。
(1)多邊形的兩面以及繪制方式。
雖然我們目前還沒有真正的使用三維坐標來畫圖,但是建立一些三維的概念還是必要的。
從三維的角度來看,一個多邊形具有兩個面。每一個面都可以設置不同的繪制方式:填充、只繪制邊緣輪廓線、只繪制頂點,其中“填充”是默認的方式??梢詾閮蓚€面分別設置不同的方式。
glPolygonMode(GL_FRONT, GL_FILL); // 設置正面為填充方式
glPolygonMode(GL_BACK, GL_LINE); // 設置反面為邊緣繪制方式
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); // 設置兩面均為頂點繪制方式
(2)反轉
一般約定為“頂點以逆時針順序出現(xiàn)在屏幕上的面”為“正面”,另一個面即成為“反面”。生活中常見的物體表面,通常都可以用這樣的“正面”和“反面”,“合理的”被表現(xiàn)出來(請找一個比較透明的礦泉水瓶子,在正對你的一面沿逆時針畫一個圓,并標明畫的方向,然后將背面轉為正面,畫一個類似的圓,體會一下“正面”和“反面”。你會發(fā)現(xiàn)正對你的方向,瓶的外側是正面,而背對你的方向,瓶的內側才是正面。正對你的內側和背對你的外側則是反面。這樣一來,同樣屬于“瓶的外側”這個表面,但某些地方算是正面,某些地方卻算是反面了)。
但也有一些表面比較特殊。例如“麥比烏斯帶”(請自己Google一下),可以全部使用“正面”或全部使用“背面”來表示。
可以通過glFrontFace函數來交換“正面”和“反面”的概念。
glFrontFace(GL_CCW); // 設置CCW方向為“正面”,CCW即CounterClockWise,逆時針
glFrontFace(GL_CW); // 設置CW方向為“正面”,CW即ClockWise,順時針
下面是一個示例程序,請用它替換第一課中的myDisplay函數,并將glFrontFace(GL_CCW)修改為glFrontFace(GL_CW),并觀察結果的變化。
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glPolygonMode(GL_FRONT, GL_FILL); // 設置正面為填充模式
glPolygonMode(GL_BACK, GL_LINE); // 設置反面為線形模式
glFrontFace(GL_CCW); // 設置逆時針方向為正面
glBegin(GL_POLYGON); // 按逆時針繪制一個正方形,在左下方
glVertex2f(-0.5f, -0.5f);
glVertex2f(0.0f, -0.5f);
glVertex2f(0.0f, 0.0f);
glVertex2f(-0.5f, 0.0f);
glEnd();
glBegin(GL_POLYGON); // 按順時針繪制一個正方形,在右上方
glVertex2f(0.0f, 0.0f);
glVertex2f(0.0f, 0.5f);
glVertex2f(0.5f, 0.5f);
glVertex2f(0.5f, 0.0f);
glEnd();
glFlush();
}
(3)剔除多邊形表面
在三維空間中,一個多邊形雖然有兩個面,但我們無法看見背面的那些多邊形,而一些多邊形雖然是正面的,但被其他多邊形所遮擋。如果將無法看見的多邊形和可見的多邊形同等對待,無疑會降低我們處理圖形的效率。在這種時候,可以將不必要的面剔除。
首先,使用glEnable(GL_CULL_FACE);來啟動剔除功能(使用glDisable(GL_CULL_FACE)可以關閉之)
然后,使用glCullFace來進行剔除。
glCullFace的參數可以是GL_FRONT,GL_BACK或者GL_FRONT_AND_BACK,分別表示剔除正面、剔除反面、剔除正反兩面的多邊形。
注意:剔除功能只影響多邊形,而對點和直線無影響。例如,使用glCullFace(GL_FRONT_AND_BACK)后,所有的多邊形都將被剔除,所以看見的就只有點和直線。
(4)鏤空多邊形
直線可以被畫成虛線,而多邊形則可以進行鏤空。
首先,使用glEnable(GL_POLYGON_STIPPLE);來啟動鏤空模式(使用glDisable(GL_POLYGON_STIPPLE)可以關閉之)。
然后,使用glPolygonStipple來設置鏤空的樣式。
void glPolygonStipple(const GLubyte *mask);
其中的參數mask指向一個長度為128字節(jié)的空間,它表示了一個32*32的矩形應該如何鏤空。其中:第一個字節(jié)表示了最左下方的從左到右(也可以是從右到左,這個可以修改)8個像素是否鏤空(1表示不鏤空,顯示該像素;0表示鏤空,顯示其后面的顏色),最后一個字節(jié)表示了最右上方的8個像素是否鏤空。
但是,如果我們直接定義這個mask數組,像這樣:
static GLubyte Mask[128] =
{
0x00, 0x00, 0x00, 0x00, // 這是最下面的一行
0x00, 0x00, 0x00, 0x00,
0x03, 0x80, 0x01, 0xC0, // 麻
0x06, 0xC0, 0x03, 0x60, // 煩
0x04, 0x60, 0x06, 0x20, // 的
0x04, 0x30, 0x0C, 0x20, // 初
0x04, 0x18, 0x18, 0x20, // 始
0x04, 0x0C, 0x30, 0x20, // 化
0x04, 0x06, 0x60, 0x20, // ,
0x44, 0x03, 0xC0, 0x22, // 不
0x44, 0x01, 0x80, 0x22, // 建
0x44, 0x01, 0x80, 0x22, // 議
0x44, 0x01, 0x80, 0x22, // 使
0x44, 0x01, 0x80, 0x22, // 用
0x44, 0x01, 0x80, 0x22,
0x44, 0x01, 0x80, 0x22,
0x66, 0x01, 0x80, 0x66,
0x33, 0x01, 0x80, 0xCC,
0x19, 0x81, 0x81, 0x98,
0x0C, 0xC1, 0x83, 0x30,
0x07, 0xE1, 0x87, 0xE0,
0x03, 0x3F, 0xFC, 0xC0,
0x03, 0x31, 0x8C, 0xC0,
0x03, 0x3F, 0xFC, 0xC0,
0x06, 0x64, 0x26, 0x60,
0x0C, 0xCC, 0x33, 0x30,
0x18, 0xCC, 0x33, 0x18,
0x10, 0xC4, 0x23, 0x08,
0x10, 0x63, 0xC6, 0x08,
0x10, 0x30, 0x0C, 0x08,
0x10, 0x18, 0x18, 0x08,
0x10, 0x00, 0x00, 0x08 // 這是最上面的一行
};
這樣一堆數據非常缺乏直觀性,我們需要很費勁的去分析,才會發(fā)現(xiàn)它表示的竟然是一只蒼蠅。
如果將這樣的數據保存成圖片,并用專門的工具進行編輯,顯然會方便很多。下面介紹如何做到這一點。
首先,用Windows自帶的畫筆程序新建一副圖片,取名為mask.bmp,注意保存時,應該選擇“單色位圖”。在“圖象”->“屬性”對話框中,設置圖片的高度和寬度均為32。
用放大鏡觀察圖片,并編輯之。黑色對應二進制零(鏤空),白色對應二進制一(不鏤空),編輯完畢后保存。
然后,就可以使用以下代碼來獲得這個Mask數組了。
static GLubyte Mask[128];
FILE *fp;
fp = fopen("mask.bmp", "rb");
if( !fp )
exit(0);
// 移動文件指針到這個位置,使得再讀sizeof(Mask)個字節(jié)就會遇到文件結束
// 注意-(int)sizeof(Mask)雖然不是什么好的寫法,但這里它確實是正確有效的
// 如果直接寫-sizeof(Mask)的話,因為sizeof取得的是一個無符號數,取負號會有問題
if( fseek(fp, -(int)sizeof(Mask), SEEK_END) )
exit(0);
// 讀取sizeof(Mask)個字節(jié)到Mask
if( !fread(Mask, sizeof(Mask), 1, fp) )
exit(0);
fclose(fp);
好的,現(xiàn)在請自己編輯一個圖片作為mask,并用上述方法取得Mask數組,運行后觀察效果。
說明:繪制虛線時可以設置factor因子,但多邊形的鏤空無法設置factor因子。請用鼠標改變窗口的大小,觀察鏤空效果的變化情況。
#include
#include
void myDisplay(void)
{
static GLubyte Mask[128];
FILE *fp;
fp = fopen("mask.bmp", "rb");
if( !fp )
exit(0);
if( fseek(fp, -(int)sizeof(Mask), SEEK_END) )
exit(0);
if( !fread(Mask, sizeof(Mask), 1, fp) )
exit(0);
fclose(fp);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_POLYGON_STIPPLE);
glPolygonStipple(Mask);
glRectf(-0.5f, -0.5f, 0.0f, 0.0f); // 在左下方繪制一個有鏤空效果的正方形
glDisable(GL_POLYGON_STIPPLE);
glRectf(0.0f, 0.0f, 0.5f, 0.5f); // 在右上方繪制一個無鏤空效果的正方形
glFlush();
}
小結
本課學習了繪制幾何圖形的一些細節(jié)。
點可以設置大小。
直線可以設置寬度;可以將直線畫成虛線。
多邊形的兩個面的繪制方法可以分別設置;在三維空間中,不可見的多邊形可以被剔除;可以將填充多邊形繪制成鏤空的樣式。
了解這些細節(jié)會使我們在一些圖象繪制中更加得心應手。
另外,把一些數據寫到程序之外的文件中,并用專門的工具編輯之,有時可以顯得更方便。
===================== 第三課 完 =====================
=====================TO BE CONTINUED=====================
OpenGL入門學習[四]
2008-10-06 21:26
本次學習的是顏色的選擇。終于要走出黑白的世界了~~
OpenGL支持兩種顏色模式:一種是RGBA,一種是顏色索引模式。
無論哪種顏色模式,計算機都必須為每一個像素保存一些數據。不同的是,RGBA模式中,數據直接就代表了顏色;而顏色索引模式中,數據代表的是一個索引,要得到真正的顏色,還必須去查索引表。
1. RGBA顏色
RGBA模式中,每一個像素會保存以下數據:R值(紅色分量)、G值(綠色分量)、B值(藍色分量)和A值(alpha分量)。其中紅、綠、藍三種顏色相組合,就可以得到我們所需要的各種顏色,而alpha不直接影響顏色,它將留待以后介紹。
在RGBA模式下選擇顏色是十分簡單的事情,只需要一個函數就可以搞定。
glColor*系列函數可以用于設置顏色,其中三個參數的版本可以指定R、G、B的值,而A值采用默認;四個參數的版本可以分別指定R、G、B、A的值。例如:
void glColor3f(GLfloat red, GLfloat green, GLfloat blue);
void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
(還記得嗎?3f表示有三個浮點參數~請看第二課中關于glVertex*函數的敘述。)
將浮點數作為參數,其中0.0表示不使用該種顏色,而1.0表示將該種顏色用到最多。例如:
glColor3f(1.0f, 0.0f, 0.0f); 表示不使用綠、藍色,而將紅色使用最多,于是得到最純凈的紅色。
glColor3f(0.0f, 1.0f, 1.0f); 表示使用綠、藍色到最多,而不使用紅色?;旌系男Ч褪菧\藍色。
glColor3f(0.5f, 0.5f, 0.5f); 表示各種顏色使用一半,效果為灰色。
注意:浮點數可以精確到小數點后若干位,這并不表示計算機就可以顯示如此多種顏色。實際上,計算機可以顯示的顏色種數將由硬件決定。如果OpenGL找不到精確的顏色,會進行類似“四舍五入”的處理。
大家可以通過改變下面代碼中glColor3f的參數值,繪制不同顏色的矩形。
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0f, 1.0f, 1.0f);
glRectf(-0.5f, -0.5f, 0.5f, 0.5f);
glFlush();
}
注意:glColor系列函數,在參數類型不同時,表示“最大”顏色的值也不同。
采用f和d做后綴的函數,以1.0表示最大的使用。
采用b做后綴的函數,以127表示最大的使用。
采用ub做后綴的函數,以255表示最大的使用。
采用s做后綴的函數,以32767表示最大的使用。
采用us做后綴的函數,以65535表示最大的使用。
這些規(guī)則看似麻煩,但熟悉后實際使用中不會有什么障礙。
2、索引顏色
在索引顏色模式中,OpenGL需要一個顏色表。這個表就相當于畫家的調色板:雖然可以調出很多種顏色,但同時存在于調色板上的顏色種數將不會超過調色板的格數。試將顏色表的每一項想象成調色板上的一個格子:它保存了一種顏色。
在使用索引顏色模式畫圖時,我說“我把第i種顏色設置為某某”,其實就相當于將調色板的第i格調為某某顏色?!拔倚枰趉種顏色來畫圖”,那么就用畫筆去蘸一下第k格調色板。
顏色表的大小是很有限的,一般在256~4096之間,且總是2的整數次冪。在使用索引顏色方式進行繪圖時,總是先設置顏色表,然后選擇顏色。
2.1、選擇顏色
使用glIndex*系列函數可以在顏色表中選擇顏色。其中最常用的可能是glIndexi,它的參數是一個整形。
void glIndexi(GLint c);
是的,這的確很簡單。
2.2、設置顏色表
OpenGL 并直接沒有提供設置顏色表的方法,因此設置顏色表需要使用操作系統(tǒng)的支持。我們所用的Windows和其他大多數圖形操作系統(tǒng)都具有這個功能,但所使用的函數卻不相同。正如我沒有講述如何自己寫代碼在Windows下建立一個窗口,這里我也不會講述如何在Windows下設置顏色表。
GLUT工具包提供了設置顏色表的函數glutSetColor,但我測試始終有問題?,F(xiàn)在為了讓大家體驗一下索引顏色,我向大家介紹另一個OpenGL工具包: aux。這個工具包是VisualStudio自帶的,不必另外安裝,但它已經過時,這里僅僅是體驗一下,大家不必深入。
#include