當(dāng)前位置:首頁(yè) > 芯聞號(hào) > 充電吧
[導(dǎo)讀]OpenGL入門學(xué)習(xí) ?說(shuō)起編程作圖,大概還有很多人想起TC的#include但是各位是否想過(guò),那些畫面絢麗的PC游戲是如何編寫出來(lái)的?就靠TC那可憐的640*480分辨率、16色來(lái)做嗎?顯然

OpenGL入門學(xué)習(xí) ?

說(shuō)起編程作圖,大概還有很多人想起TC的#include

但是各位是否想過(guò),那些畫面絢麗的PC游戲是如何編寫出來(lái)的?就靠TC那可憐的640*480分辨率、16色來(lái)做嗎?顯然是不行的。

本帖的目的是讓大家放棄TC的老舊圖形接口,讓大家接觸一些新事物。

OpenGL作為當(dāng)前主流的圖形API之一,它在一些場(chǎng)合具有比DirectX更優(yōu)越的特性。

1、與C語(yǔ)言緊密結(jié)合。

OpenGL命令最初就是用C語(yǔ)言函數(shù)來(lái)進(jìn)行描述的,對(duì)于學(xué)習(xí)過(guò)C語(yǔ)言的人來(lái)講,OpenGL是容易理解和學(xué)習(xí)的。如果你曾經(jīng)接觸過(guò)TC的graphics.h,你會(huì)發(fā)現(xiàn),使用OpenGL作圖甚至比TC更加簡(jiǎn)單。

2、強(qiáng)大的可移植性。

微軟的Direct3D雖然也是十分優(yōu)秀的圖形API,但它只用于Windows系統(tǒng)(現(xiàn)在還要加上一個(gè)XBOX游戲機(jī))。而OpenGL不僅用于 Windows,還可以用于Unix/Linux等其它系統(tǒng),它甚至在大型計(jì)算機(jī)、各種專業(yè)計(jì)算機(jī)(如:醫(yī)療用顯示設(shè)備)上都有應(yīng)用。并且,OpenGL 的基本命令都做到了硬件無(wú)關(guān),甚至是平臺(tái)無(wú)關(guān)。

3、高性能的圖形渲染。

OpenGL是一個(gè)工業(yè)標(biāo)準(zhǔn),它的技術(shù)緊跟時(shí)代,現(xiàn)今各個(gè)顯卡廠家無(wú)一不對(duì)OpenGL提供強(qiáng)力支持,激烈的競(jìng)爭(zhēng)中使得OpenGL性能一直領(lǐng)先。

總之,OpenGL是一個(gè)很NB的圖形軟件接口。至于究竟有多NB,去看看DOOM3和QUAKE4等專業(yè)游戲就知道了。

OpenGL官方網(wǎng)站(英文)

http://www.opengl.org

下面將對(duì)Windows下的OpenGL編程進(jìn)行簡(jiǎn)單介紹。

學(xué)習(xí)OpenGL前的準(zhǔn)備工作

第一步,選擇一個(gè)編譯環(huán)境

現(xiàn)在Windows系統(tǒng)的主流編譯環(huán)境有Visual Studio,Broland C++ Builder,Dev-C++等,它們都是支持OpenGL的。但這里我們選擇Visual Studio 2005作為學(xué)習(xí)OpenGL的環(huán)境。

第二步,安裝GLUT工具包

GLUT不是OpenGL所必須的,但它會(huì)給我們的學(xué)習(xí)帶來(lái)一定的方便,推薦安裝。

Windows環(huán)境下的GLUT下載地址:(大小約為150k)

http://www.opengl.org/resources/libraries/glut/glutdlls37beta.zip

無(wú)法從以上地址下載的話請(qǐng)使用下面的連接:

http://upload.programfan.com/upfile/200607311626279.zip

Windows環(huán)境下安裝GLUT的步驟:

1、將下載的壓縮包解開(kāi),將得到5個(gè)文件

2、在“我的電腦”中搜索“gl.h”,并找到其所在文件夾(如果是VisualStudio2005,則應(yīng)該是其安裝目錄下面的“VCPlatformSDKincludegl文件夾”)。把解壓得到的glut.h放到這個(gè)文件夾。

3、把解壓得到的glut.lib和glut32.lib放到靜態(tài)函數(shù)庫(kù)所在文件夾(如果是VisualStudio2005,則應(yīng)該是其安裝目錄下面的“VClib”文件夾)。

4、把解壓得到的glut.dll和glut32.dll放到操作系統(tǒng)目錄下面的system32文件夾內(nèi)。(典型的位置為:C:WindowsSystem32)

第三步,建立一個(gè)OpenGL工程

這里以VisualStudio2005為例。

選擇File->New->Project,然后選擇Win32 Console Application,選擇一個(gè)名字,然后按OK。

在談出的對(duì)話框左邊點(diǎn)Application Settings,找到Empty project并勾上,選擇Finish。

然后向該工程添加一個(gè)代碼文件,取名為“OpenGL.c”,注意用.c來(lái)作為文件結(jié)尾。

搞定了,就跟平時(shí)的工程沒(méi)什么兩樣的。


第一個(gè)OpenGL程序

一個(gè)簡(jiǎn)單的OpenGL程序如下:(注意,如果需要編譯并運(yùn)行,需要正確安裝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("第一個(gè)OpenGL程序");

glutDisplayFunc(&myDisplay);

glutMainLoop();

return 0;

}

該程序的作用是在一個(gè)黑色的窗口中央畫一個(gè)白色的矩形。下面對(duì)各行語(yǔ)句進(jìn)行說(shuō)明。

首先,需要包含頭文件#include

本來(lái)OpenGL程序一般還要包含

然后看main函數(shù)。

int main(int argc, char *argv[]),這個(gè)是帶命令行參數(shù)的main函數(shù),各位應(yīng)該見(jiàn)過(guò)吧?沒(méi)見(jiàn)過(guò)的同志們請(qǐng)多翻翻書,等弄明白了再往下看。

注意main函數(shù)中的各語(yǔ)句,除了最后的return之外,其余全部以glut開(kāi)頭。這種以glut開(kāi)頭的函數(shù)都是GLUT工具包所提供的函數(shù),下面對(duì)用到的幾個(gè)函數(shù)進(jìn)行介紹。

1、glutInit,對(duì)GLUT進(jìn)行初始化,這個(gè)函數(shù)必須在其它的GLUT使用之前調(diào)用一次。其格式比較死板,一般照抄這句glutInit(&argc, argv)就可以了。

2、 glutInitDisplayMode,設(shè)置顯示方式,其中GLUT_RGB表示使用RGB顏色,與之對(duì)應(yīng)的還有GLUT_INDEX(表示使用索引顏色)。GLUT_SINGLE表示使用單緩沖,與之對(duì)應(yīng)的還有GLUT_DOUBLE(使用雙緩沖)。更多信息,請(qǐng)自己Google。當(dāng)然以后的教程也會(huì)有一些講解。

3、glutInitWindowPosition,這個(gè)簡(jiǎn)單,設(shè)置窗口在屏幕中的位置。

4、glutInitWindowSize,這個(gè)也簡(jiǎn)單,設(shè)置窗口的大小。

5、glutCreateWindow,根據(jù)前面設(shè)置的信息創(chuàng)建窗口。參數(shù)將被作為窗口的標(biāo)題。注意:窗口被創(chuàng)建后,并不立即顯示到屏幕上。需要調(diào)用glutMainLoop才能看到窗口。

6、glutDisplayFunc,設(shè)置一個(gè)函數(shù),當(dāng)需要進(jìn)行畫圖時(shí),這個(gè)函數(shù)就會(huì)被調(diào)用。(這個(gè)說(shuō)法不夠準(zhǔn)確,但準(zhǔn)確的說(shuō)法可能初學(xué)者不太好理解,暫時(shí)這樣說(shuō)吧)。

7、glutMainLoop,進(jìn)行一個(gè)消息循環(huán)。(這個(gè)可能初學(xué)者也不太明白,現(xiàn)在只需要知道這個(gè)函數(shù)可以顯示窗口,并且等待窗口關(guān)閉后才會(huì)返回,這就足夠了。)

在glutDisplayFunc函數(shù)中,我們?cè)O(shè)置了“當(dāng)需要畫圖時(shí),請(qǐng)調(diào)用myDisplay函數(shù)”。于是myDisplay函數(shù)就用來(lái)畫圖。觀察myDisplay中的三個(gè)函數(shù)調(diào)用,發(fā)現(xiàn)它們都以gl開(kāi)頭。這種以gl開(kāi)頭的函數(shù)都是OpenGL的標(biāo)準(zhǔn)函數(shù),下面對(duì)用到的函數(shù)進(jìn)行介紹。

1、glClear,清除。GL_COLOR_BUFFER_BIT表示清除顏色,glClear函數(shù)還可以清除其它的東西,但這里不作介紹。

2、glRectf,畫一個(gè)矩形。四個(gè)參數(shù)分別表示了位于對(duì)角線上的兩個(gè)點(diǎn)的橫、縱坐標(biāo)。

3、glFlush,保證前面的OpenGL命令立即執(zhí)行(而不是讓它們?cè)诰彌_區(qū)中等待)。其作用跟fflush(stdout)類似。

OpenGL入門學(xué)習(xí)[二]

本次課程所要講的是繪制簡(jiǎn)單的幾何圖形,在實(shí)際繪制之前,讓我們先熟悉一些概念。

一、點(diǎn)、直線和多邊形
我們知道數(shù)學(xué)(具體的說(shuō),是幾何學(xué))中有點(diǎn)、直線和多邊形的概念,但這些概念在計(jì)算機(jī)中會(huì)有所不同。
數(shù)學(xué)上的點(diǎn),只有位置,沒(méi)有大小。但在計(jì)算機(jī)中,無(wú)論計(jì)算精度如何提高,始終不能表示一個(gè)無(wú)窮小的點(diǎn)。另一方面,無(wú)論圖形輸出設(shè)備(例如,顯示器)如何精確,始終不能輸出一個(gè)無(wú)窮小的點(diǎn)。一般情況下,OpenGL中的點(diǎn)將被畫成單個(gè)的像素(像素的概念,請(qǐng)自己搜索之~),雖然它可能足夠小,但并不會(huì)是無(wú)窮小。同一像素上,OpenGL可以繪制許多坐標(biāo)只有稍微不同的點(diǎn),但該像素的具體顏色將取決于OpenGL的實(shí)現(xiàn)。當(dāng)然,過(guò)度的注意細(xì)節(jié)就是鉆牛角尖,我們大可不必花費(fèi)過(guò)多的精力去研究“多個(gè)點(diǎn)如何畫到同一像素上”。
同樣的,數(shù)學(xué)上的直線沒(méi)有寬度,但OpenGL的直線則是有寬度的。同時(shí),OpenGL的直線必須是有限長(zhǎng)度,而不是像數(shù)學(xué)概念那樣是無(wú)限的。可以認(rèn)為,OpenGL的“直線”概念與數(shù)學(xué)上的“線段”接近,它可以由兩個(gè)端點(diǎn)來(lái)確定。
多邊形是由多條線段首尾相連而形成的閉合區(qū)域。OpenGL規(guī)定,一個(gè)多邊形必須是一個(gè)“凸多邊形”(其定義為:多邊形內(nèi)任意兩點(diǎn)所確定的線段都在多邊形內(nèi),由此也可以推導(dǎo)出,凸多邊形不能是空心的)。多邊形可以由其邊的端點(diǎn)(這里可稱為頂點(diǎn))來(lái)確定。(注意:如果使用的多邊形不是凸多邊形,則最后輸出的效果是未定義的——OpenGL為了效率,放寬了檢查,這可能導(dǎo)致顯示錯(cuò)誤。要避免這個(gè)錯(cuò)誤,盡量使用三角形,因?yàn)槿切味际峭苟噙呅危?br />
可以想象,通過(guò)點(diǎn)、直線和多邊形,就可以組合成各種幾何圖形。甚至于,你可以把一段弧看成是很多短的直線段相連,這些直線段足夠短,以至于其長(zhǎng)度小于一個(gè)像素的寬度。這樣一來(lái)弧和圓也可以表示出來(lái)了。通過(guò)位于不同平面的相連的小多邊形,我們還可以組成一個(gè)“曲面”。

二、在OpenGL中指定頂點(diǎn)
由以上的討論可以知道,“點(diǎn)”是一切的基礎(chǔ)。
如何指定一個(gè)點(diǎn)呢?OpenGL提供了一系列函數(shù)。它們都以glVertex開(kāi)頭,后面跟一個(gè)數(shù)字和1~2個(gè)字母。例如:
glVertex2d
glVertex2f
glVertex3f
glVertex3fv
等等。
數(shù)字表示參數(shù)的個(gè)數(shù),2表示有兩個(gè)參數(shù),3表示三個(gè),4表示四個(gè)(我知道有點(diǎn)羅嗦~)。
字母表示參數(shù)的類型,s表示16位整數(shù)(OpenGL中將這個(gè)類型定義為GLshort),
i表示32位整數(shù)(OpenGL中將這個(gè)類型定義為GLint和GLsizei),
f表示32位浮點(diǎn)數(shù)(OpenGL中將這個(gè)類型定義為GLfloat和GLclampf),
d表示64位浮點(diǎn)數(shù)(OpenGL中將這個(gè)類型定義為GLdouble和GLclampd)。
v表示傳遞的幾個(gè)參數(shù)將使用指針的方式,見(jiàn)下面的例子。
這些函數(shù)除了參數(shù)的類型和個(gè)數(shù)不同以外,功能是相同的。例如,以下五個(gè)代碼段的功能是等效的:
(一)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*來(lái)表示這一系列函數(shù)。
注意:OpenGL的很多函數(shù)都是采用這樣的形式,一個(gè)相同的前綴再加上參數(shù)說(shuō)明標(biāo)記,這一點(diǎn)會(huì)隨著學(xué)習(xí)的深入而有更多的體會(huì)。


三、開(kāi)始繪制
假設(shè)現(xiàn)在我已經(jīng)指定了若干頂點(diǎn),那么OpenGL是如何知道我想拿這些頂點(diǎn)來(lái)干什么呢?是一個(gè)一個(gè)的畫出來(lái),還是連成線?或者構(gòu)成一個(gè)多邊形?或者做其它什么事情?
為了解決這一問(wèn)題,OpenGL要求:指定頂點(diǎn)的命令必須包含在glBegin函數(shù)之后,glEnd函數(shù)之前(否則指定的頂點(diǎn)將被忽略)。并由glBegin來(lái)指明如何使用這些點(diǎn)。
例如我寫:
glBegin(GL_POINTS);
glVertex2f(0.0f, 0.0f);
glVertex2f(0.5f, 0.0f);
glEnd();
則這兩個(gè)點(diǎn)將分別被畫出來(lái)。如果將GL_POINTS替換成GL_LINES,則兩個(gè)點(diǎn)將被認(rèn)為是直線的兩個(gè)端點(diǎn),OpenGL將會(huì)畫出一條直線。
我們還可以指定更多的頂點(diǎn),然后畫出更復(fù)雜的圖形。
另一方面,glBegin支持的方式除了GL_POINTS和GL_LINES,還有GL_LINE_STRIP,GL_LINE_LOOP,GL_TRIANGLES,GL_TRIANGLE_STRIP,GL_TRIANGLE_FAN等,每種方式的大致效果見(jiàn)下圖:

聲明:該圖片來(lái)自www.opengl.org,該圖片是《OpenGL編程指南》一書的附圖,由于該書的舊版(第一版,1994年)已經(jīng)流傳于網(wǎng)絡(luò),我希望沒(méi)有觸及到版權(quán)問(wèn)題。

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

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



兩個(gè)例子
例一、畫一個(gè)圓
/*
正四邊形,正五邊形,正六邊形,……,直到正n邊形,當(dāng)n越大時(shí),這個(gè)圖形就越接近圓
當(dāng)n大到一定程度后,人眼將無(wú)法把它跟真正的圓相區(qū)別
這時(shí)我們已經(jīng)成功的畫出了一個(gè)“圓”
(注:畫圓的方法很多,這里使用的是比較簡(jiǎn)單,但效率較低的一種)
試修改下面的const int n的值,觀察當(dāng)n=3,4,5,8,10,15,20,30,50等不同數(shù)值時(shí)輸出的變化情況
將GL_POLYGON改為GL_LINE_LOOP、GL_POINTS等其它方式,觀察輸出的變化情況
*/
#include

在第二課中,我們學(xué)習(xí)了如何繪制幾何圖形,但大家如果多寫幾個(gè)程序,就會(huì)發(fā)現(xiàn)其實(shí)還是有些郁悶之處。例如:點(diǎn)太小,難以看清楚;直線也太細(xì),不舒服;或者想畫虛線,但不知道方法只能用許多短直線,甚至用點(diǎn)組合而成。

這些問(wèn)題將在本課中被解決。

下面就點(diǎn)、直線、多邊形分別討論。

1、關(guān)于點(diǎn)

點(diǎn)的大小默認(rèn)為1個(gè)像素,但也可以改變之。改變的命令為glPointSize,其函數(shù)原型如下:

void glPointSize(GLfloat size);

size必須大于0.0f,默認(rèn)值為1.0f,單位為“像素”。

注意:對(duì)于具體的OpenGL實(shí)現(xiàn),點(diǎn)的大小都有個(gè)限度的,如果設(shè)置的size超過(guò)最大值,則設(shè)置可能會(huì)有問(wèn)題。

例子:

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、關(guān)于直線

(1)直線可以指定寬度:

void glLineWidth(GLfloat width);

其用法跟glPointSize類似。

(2)畫虛線。

首先,使用glEnable(GL_LINE_STIPPLE);來(lái)啟動(dòng)虛線模式(使用glDisable(GL_LINE_STIPPLE)可以關(guān)閉之)。

然后,使用glLineStipple來(lái)設(shè)置虛線的樣式。

void glLineStipple(GLint factor, GLushort pattern);

pattern是由1和0組成的長(zhǎng)度為16的序列,從最低位開(kāi)始看,如果為1,則直線上接下來(lái)應(yīng)該畫的factor個(gè)點(diǎn)將被畫為實(shí)的;如果為0,則直線上接下來(lái)應(yīng)該畫的factor個(gè)點(diǎn)將被畫為虛的。

以下是一些例子:

聲明:該圖片來(lái)自www.opengl.org,該圖片是《OpenGL編程指南》一書的附圖,由于該書的舊版(第一版,1994年)已經(jīng)流傳于網(wǎng)絡(luò),我希望沒(méi)有觸及到版權(quán)問(wèn)題。

示例代碼:

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、關(guān)于多邊形

多邊形的內(nèi)容較多,我們將講述以下四個(gè)方面。

(1)多邊形的兩面以及繪制方式。

雖然我們目前還沒(méi)有真正的使用三維坐標(biāo)來(lái)畫圖,但是建立一些三維的概念還是必要的。

從三維的角度來(lái)看,一個(gè)多邊形具有兩個(gè)面。每一個(gè)面都可以設(shè)置不同的繪制方式:填充、只繪制邊緣輪廓線、只繪制頂點(diǎn),其中“填充”是默認(rèn)的方式??梢詾閮蓚€(gè)面分別設(shè)置不同的方式。

glPolygonMode(GL_FRONT, GL_FILL); // 設(shè)置正面為填充方式

glPolygonMode(GL_BACK, GL_LINE); // 設(shè)置反面為邊緣繪制方式

glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); // 設(shè)置兩面均為頂點(diǎn)繪制方式

(2)反轉(zhuǎn)

一般約定為“頂點(diǎn)以逆時(shí)針順序出現(xiàn)在屏幕上的面”為“正面”,另一個(gè)面即成為“反面”。生活中常見(jiàn)的物體表面,通常都可以用這樣的“正面”和“反面”,“合理的”被表現(xiàn)出來(lái)(請(qǐng)找一個(gè)比較透明的礦泉水瓶子,在正對(duì)你的一面沿逆時(shí)針畫一個(gè)圓,并標(biāo)明畫的方向,然后將背面轉(zhuǎn)為正面,畫一個(gè)類似的圓,體會(huì)一下“正面”和“反面”。你會(huì)發(fā)現(xiàn)正對(duì)你的方向,瓶的外側(cè)是正面,而背對(duì)你的方向,瓶的內(nèi)側(cè)才是正面。正對(duì)你的內(nèi)側(cè)和背對(duì)你的外側(cè)則是反面。這樣一來(lái),同樣屬于“瓶的外側(cè)”這個(gè)表面,但某些地方算是正面,某些地方卻算是反面了)。

但也有一些表面比較特殊。例如“麥比烏斯帶”(請(qǐng)自己Google一下),可以全部使用“正面”或全部使用“背面”來(lái)表示。

可以通過(guò)glFrontFace函數(shù)來(lái)交換“正面”和“反面”的概念。

glFrontFace(GL_CCW); // 設(shè)置CCW方向?yàn)椤罢妗?,CCW即CounterClockWise,逆時(shí)針

glFrontFace(GL_CW); // 設(shè)置CW方向?yàn)椤罢妗?,CW即ClockWise,順時(shí)針

下面是一個(gè)示例程序,請(qǐng)用它替換第一課中的myDisplay函數(shù),并將glFrontFace(GL_CCW)修改為glFrontFace(GL_CW),并觀察結(jié)果的變化。

void myDisplay(void)

{

glClear(GL_COLOR_BUFFER_BIT);

glPolygonMode(GL_FRONT, GL_FILL); // 設(shè)置正面為填充模式

glPolygonMode(GL_BACK, GL_LINE); // 設(shè)置反面為線形模式

glFrontFace(GL_CCW); // 設(shè)置逆時(shí)針?lè)较驗(yàn)檎?/p>

glBegin(GL_POLYGON); // 按逆時(shí)針繪制一個(gè)正方形,在左下方

glVertex2f(-0.5f, -0.5f);

glVertex2f(0.0f, -0.5f);

glVertex2f(0.0f, 0.0f);

glVertex2f(-0.5f, 0.0f);

glEnd();

glBegin(GL_POLYGON); // 按順時(shí)針繪制一個(gè)正方形,在右上方

glVertex2f(0.0f, 0.0f);

glVertex2f(0.0f, 0.5f);

glVertex2f(0.5f, 0.5f);

glVertex2f(0.5f, 0.0f);

glEnd();

glFlush();

}

(3)剔除多邊形表面

在三維空間中,一個(gè)多邊形雖然有兩個(gè)面,但我們無(wú)法看見(jiàn)背面的那些多邊形,而一些多邊形雖然是正面的,但被其他多邊形所遮擋。如果將無(wú)法看見(jiàn)的多邊形和可見(jiàn)的多邊形同等對(duì)待,無(wú)疑會(huì)降低我們處理圖形的效率。在這種時(shí)候,可以將不必要的面剔除。

首先,使用glEnable(GL_CULL_FACE);來(lái)啟動(dòng)剔除功能(使用glDisable(GL_CULL_FACE)可以關(guān)閉之)

然后,使用glCullFace來(lái)進(jìn)行剔除。

glCullFace的參數(shù)可以是GL_FRONT,GL_BACK或者GL_FRONT_AND_BACK,分別表示剔除正面、剔除反面、剔除正反兩面的多邊形。

注意:剔除功能只影響多邊形,而對(duì)點(diǎn)和直線無(wú)影響。例如,使用glCullFace(GL_FRONT_AND_BACK)后,所有的多邊形都將被剔除,所以看見(jiàn)的就只有點(diǎn)和直線。

(4)鏤空多邊形

直線可以被畫成虛線,而多邊形則可以進(jìn)行鏤空。

首先,使用glEnable(GL_POLYGON_STIPPLE);來(lái)啟動(dòng)鏤空模式(使用glDisable(GL_POLYGON_STIPPLE)可以關(guān)閉之)。

然后,使用glPolygonStipple來(lái)設(shè)置鏤空的樣式。

void glPolygonStipple(const GLubyte *mask);

其中的參數(shù)mask指向一個(gè)長(zhǎng)度為128字節(jié)的空間,它表示了一個(gè)32*32的矩形應(yīng)該如何鏤空。其中:第一個(gè)字節(jié)表示了最左下方的從左到右(也可以是從右到左,這個(gè)可以修改)8個(gè)像素是否鏤空(1表示不鏤空,顯示該像素;0表示鏤空,顯示其后面的顏色),最后一個(gè)字節(jié)表示了最右上方的8個(gè)像素是否鏤空。

但是,如果我們直接定義這個(gè)mask數(shù)組,像這樣:

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 // 這是最上面的一行

};

這樣一堆數(shù)據(jù)非常缺乏直觀性,我們需要很費(fèi)勁的去分析,才會(huì)發(fā)現(xiàn)它表示的竟然是一只蒼蠅。

如果將這樣的數(shù)據(jù)保存成圖片,并用專門的工具進(jìn)行編輯,顯然會(huì)方便很多。下面介紹如何做到這一點(diǎn)。

首先,用Windows自帶的畫筆程序新建一副圖片,取名為mask.bmp,注意保存時(shí),應(yīng)該選擇“單色位圖”。在“圖象”->“屬性”對(duì)話框中,設(shè)置圖片的高度和寬度均為32。

用放大鏡觀察圖片,并編輯之。黑色對(duì)應(yīng)二進(jìn)制零(鏤空),白色對(duì)應(yīng)二進(jìn)制一(不鏤空),編輯完畢后保存。

然后,就可以使用以下代碼來(lái)獲得這個(gè)Mask數(shù)組了。

static GLubyte Mask[128];

FILE *fp;

fp = fopen("mask.bmp", "rb");

if( !fp )

exit(0);

// 移動(dòng)文件指針到這個(gè)位置,使得再讀sizeof(Mask)個(gè)字節(jié)就會(huì)遇到文件結(jié)束

// 注意-(int)sizeof(Mask)雖然不是什么好的寫法,但這里它確實(shí)是正確有效的

// 如果直接寫-sizeof(Mask)的話,因?yàn)閟izeof取得的是一個(gè)無(wú)符號(hào)數(shù),取負(fù)號(hào)會(huì)有問(wèn)題

if( fseek(fp, -(int)sizeof(Mask), SEEK_END) )

exit(0);

// 讀取sizeof(Mask)個(gè)字節(jié)到Mask

if( !fread(Mask, sizeof(Mask), 1, fp) )

exit(0);

fclose(fp);

好的,現(xiàn)在請(qǐng)自己編輯一個(gè)圖片作為mask,并用上述方法取得Mask數(shù)組,運(yùn)行后觀察效果。

說(shuō)明:繪制虛線時(shí)可以設(shè)置factor因子,但多邊形的鏤空無(wú)法設(shè)置factor因子。請(qǐng)用鼠標(biāo)改變窗口的大小,觀察鏤空效果的變化情況。

#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); // 在左下方繪制一個(gè)有鏤空效果的正方形

glDisable(GL_POLYGON_STIPPLE);

glRectf(0.0f, 0.0f, 0.5f, 0.5f); // 在右上方繪制一個(gè)無(wú)鏤空效果的正方形

glFlush();

}

小結(jié)

本課學(xué)習(xí)了繪制幾何圖形的一些細(xì)節(jié)。

點(diǎn)可以設(shè)置大小。

直線可以設(shè)置寬度;可以將直線畫成虛線。

多邊形的兩個(gè)面的繪制方法可以分別設(shè)置;在三維空間中,不可見(jiàn)的多邊形可以被剔除;可以將填充多邊形繪制成鏤空的樣式。

了解這些細(xì)節(jié)會(huì)使我們?cè)谝恍﹫D象繪制中更加得心應(yīng)手。

另外,把一些數(shù)據(jù)寫到程序之外的文件中,并用專門的工具編輯之,有時(shí)可以顯得更方便。

===================== 第三課 完 =====================

=====================TO BE CONTINUED=====================






OpenGL入門學(xué)習(xí)[四] 2008-10-06 21:26 本次學(xué)習(xí)的是顏色的選擇。終于要走出黑白的世界了~~


OpenGL支持兩種顏色模式:一種是RGBA,一種是顏色索引模式。
無(wú)論哪種顏色模式,計(jì)算機(jī)都必須為每一個(gè)像素保存一些數(shù)據(jù)。不同的是,RGBA模式中,數(shù)據(jù)直接就代表了顏色;而顏色索引模式中,數(shù)據(jù)代表的是一個(gè)索引,要得到真正的顏色,還必須去查索引表。

1. RGBA顏色
RGBA模式中,每一個(gè)像素會(huì)保存以下數(shù)據(jù):R值(紅色分量)、G值(綠色分量)、B值(藍(lán)色分量)和A值(alpha分量)。其中紅、綠、藍(lán)三種顏色相組合,就可以得到我們所需要的各種顏色,而alpha不直接影響顏色,它將留待以后介紹。
在RGBA模式下選擇顏色是十分簡(jiǎn)單的事情,只需要一個(gè)函數(shù)就可以搞定。
glColor*系列函數(shù)可以用于設(shè)置顏色,其中三個(gè)參數(shù)的版本可以指定R、G、B的值,而A值采用默認(rèn);四個(gè)參數(shù)的版本可以分別指定R、G、B、A的值。例如:
void glColor3f(GLfloat red, GLfloat green, GLfloat blue);
void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
(還記得嗎?3f表示有三個(gè)浮點(diǎn)參數(shù)~請(qǐng)看第二課中關(guān)于glVertex*函數(shù)的敘述。)
將浮點(diǎn)數(shù)作為參數(shù),其中0.0表示不使用該種顏色,而1.0表示將該種顏色用到最多。例如:
glColor3f(1.0f, 0.0f, 0.0f); 表示不使用綠、藍(lán)色,而將紅色使用最多,于是得到最純凈的紅色。
glColor3f(0.0f, 1.0f, 1.0f); 表示使用綠、藍(lán)色到最多,而不使用紅色?;旌系男Ч褪菧\藍(lán)色。
glColor3f(0.5f, 0.5f, 0.5f); 表示各種顏色使用一半,效果為灰色。
注意:浮點(diǎn)數(shù)可以精確到小數(shù)點(diǎn)后若干位,這并不表示計(jì)算機(jī)就可以顯示如此多種顏色。實(shí)際上,計(jì)算機(jī)可以顯示的顏色種數(shù)將由硬件決定。如果OpenGL找不到精確的顏色,會(huì)進(jìn)行類似“四舍五入”的處理。

大家可以通過(guò)改變下面代碼中g(shù)lColor3f的參數(shù)值,繪制不同顏色的矩形。
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系列函數(shù),在參數(shù)類型不同時(shí),表示“最大”顏色的值也不同。
采用f和d做后綴的函數(shù),以1.0表示最大的使用。
采用b做后綴的函數(shù),以127表示最大的使用。
采用ub做后綴的函數(shù),以255表示最大的使用。
采用s做后綴的函數(shù),以32767表示最大的使用。
采用us做后綴的函數(shù),以65535表示最大的使用。
這些規(guī)則看似麻煩,但熟悉后實(shí)際使用中不會(huì)有什么障礙。

2、索引顏色
在索引顏色模式中,OpenGL需要一個(gè)顏色表。這個(gè)表就相當(dāng)于畫家的調(diào)色板:雖然可以調(diào)出很多種顏色,但同時(shí)存在于調(diào)色板上的顏色種數(shù)將不會(huì)超過(guò)調(diào)色板的格數(shù)。試將顏色表的每一項(xiàng)想象成調(diào)色板上的一個(gè)格子:它保存了一種顏色。
在使用索引顏色模式畫圖時(shí),我說(shuō)“我把第i種顏色設(shè)置為某某”,其實(shí)就相當(dāng)于將調(diào)色板的第i格調(diào)為某某顏色?!拔倚枰趉種顏色來(lái)畫圖”,那么就用畫筆去蘸一下第k格調(diào)色板。
顏色表的大小是很有限的,一般在256~4096之間,且總是2的整數(shù)次冪。在使用索引顏色方式進(jìn)行繪圖時(shí),總是先設(shè)置顏色表,然后選擇顏色。

2.1、選擇顏色
使用glIndex*系列函數(shù)可以在顏色表中選擇顏色。其中最常用的可能是glIndexi,它的參數(shù)是一個(gè)整形。
void glIndexi(GLint c);
是的,這的確很簡(jiǎn)單。

2.2、設(shè)置顏色表
OpenGL 并直接沒(méi)有提供設(shè)置顏色表的方法,因此設(shè)置顏色表需要使用操作系統(tǒng)的支持。我們所用的Windows和其他大多數(shù)圖形操作系統(tǒng)都具有這個(gè)功能,但所使用的函數(shù)卻不相同。正如我沒(méi)有講述如何自己寫代碼在Windows下建立一個(gè)窗口,這里我也不會(huì)講述如何在Windows下設(shè)置顏色表。
GLUT工具包提供了設(shè)置顏色表的函數(shù)glutSetColor,但我測(cè)試始終有問(wèn)題?,F(xiàn)在為了讓大家體驗(yàn)一下索引顏色,我向大家介紹另一個(gè)OpenGL工具包: aux。這個(gè)工具包是VisualStudio自帶的,不必另外安裝,但它已經(jīng)過(guò)時(shí),這里僅僅是體驗(yàn)一下,大家不必深入。
#include

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉