openGL初學函數解釋匯總
1.GLUT工具包提供的函數
//GLUT工具包所提供的函數 glutInit(&argc, argv);//對GLUT進行初始化,這個函數必須在其它的GLUT使用之前調用一次。 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);//初始化顯示模式,(顏色使用RGB,單緩沖GLUT_SINGLE\GLUT_DOUBLE雙緩沖)
glutSwapBuffers();//交換緩沖區 glutInitWindowPosition(100, 100);//初始化窗口位置 glutInitWindowSize(400, 400);//初始化窗口大小 glutCreateWindow("OpenGL程序窗口");//創建窗口 glutDisplayFunc(&myDisplay);//作圖時一定要調用的函數 glutIdleFunc(&myIdle);//只要CPU空閑就可以運行該參數當中的函數 glutMainLoop();//進行一個消息循環,顯示圖像,窗口關閉則返回
2.OpenGL的標准函數
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清空顏色緩存以及深度緩存 glRectf(-0.5f, -0.5f, 0.5f, 0.5f);//畫一個矩形。四個參數分別表示了位於對角線上的兩個點的橫、縱坐標 glFlush();//保證前面的OpenGL命令立即執行(而不是讓它們在緩沖區中等待)。其作用跟fflush(stdout)類似
頂點的使用
glVertex3f(1.0f, 3.0f, 0.0f);//其中前綴glVertex不變,后面的3代表點的維度,f是浮點型(也可為i,d等等)
glBegin(GL_POINTS);//指定頂點的命令必須包含在glBegin函數之后,glEnd函數之前(否則指定的頂點將被忽略),括號中的參數指的是利用頂點需要的繪制的圖像的類型,下面會有幾種參數的介紹
......//輸入頂點,要按一定順序輸入(程序會按順序處理輸入的頂點,glbegin()中的參數會告訴我們如何處理頂點)
glEnd();
//glBegin()當中的幾種參數類型的介紹
GL_POINTS:按順序在圖中畫出頂點
GL_LINES:將輸入的頂點兩兩組合,繪制成線段
GL_TRIANGLE_FAN:輸入的第一個點作為中心點,其余的點,按輸入順序,每兩個點就可以和中心點組合成為一個三角形
GL_POLYGON,GL_LINE_LOOP:輸入頂點繪制成凸多邊形
頂點,直線,多邊形的修整函數
//關於定點
glPointSize(5.0f);//定義頂點的大小
//關於直線
glLineWidth(5.0f);//定義直線的寬度
glEnable(GL_LINE_STIPPLE);//啟用虛線模式,glDisable(GL_LINE_STIPPLE)可以關閉之
glLineStipple(1, 0x5555);//前一個參數是連續線段最大長度,后一個參數的二進制是16位,每一位如果是1那么畫出點,否則不畫
//關於多邊形
//(1)多邊形兩面的繪制方式
glPolygonMode(GL_FRONT,GL_FILL);//凸多邊形模式(正面or反面,填充方式[繪制邊界或填充圖案等等])
glPolygonMode(GL_BACK, GL_LINE);//同上介紹
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); // 同上介紹,設置兩面均為頂點繪制方式
//(2)多邊形正反面的概念
glFrontFace(GL_CCW);//定義凸包點列逆時針分布的面為正面,其中參數GL_CCW即為逆時針旋轉,改為GL_CW則效果相反
//(3)剔除多邊形表面
glEnable(GL_CULL_FACE);//來啟動剔除功能(使用glDisable(GL_CULL_FACE)可以關閉之)
glCullFace(GL_BACK);//剔除多邊形的反面,參數還可以是:GL_FRONT,GL_FRONT_AND_BACK
//(4)鏤空的多邊形,類似虛直線,多邊形也可以鏤空
glEnable(GL_POLYGON_STIPPLE);//來啟動鏤空模式(使用glDisable(GL_POLYGON_STIPPLE)可以關閉之)
glPolygonStipple(Mask);//其中Mask數組定義為static GLubyte Mask[128];自定義一幅圖畫,如何調取出圖畫的Mask數組?以下為調用方法
/////////////////////////////////////////////
static GLubyte Mask[128];
FILE *fp;
fp = fopen("mask.bmp", "rb");//打開保存的bmp文件
if( !fp )
exit(0);
if( fseek(fp, -(int)sizeof(Mask), SEEK_END) )//移動文件指針,使得再讀sizeof(Mask)個字節就會到達文件末尾
exit(0);
if( !fread(Mask, sizeof(Mask), 1, fp) )//讀取文件sizeof(Mask)個字節到Mask數組中
exit(0);
fclose(fp);
glEnable(GL_POLYGON_STIPPLE);
glPolygonStipple(Mask);
glRectf(-0.5f, -0.5f, 0.0f, 0.0f); // 在左下方繪制一個有鏤空效果的正方形
/////////////////////////////////////////////
glutSolidSphere(r,20,20);//參數r代表球體的半徑,后兩個參數代表繪制球體的精確程度,數值越大,繪制越精確
顏色的使用
glColor3f(0.0f, 1.0f, 1.0f);//前綴glColor不變,后綴3f代表有3個浮點型參數作為點的三維坐標
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);//定義“空”的顏色類型(也可以認為是最初的背景色)
glShadeModel(GL_SMOOTH); // 點與點連成直線時,若兩個頂點顏色不一,openGL默認會以漸變的顏色填充這條線段,修改該設定可采用這個函數,當前方式為平滑方式,這也是默認方式
glShadeModel(GL_FLAT); // 介紹同上,單色方式,即以線段某一端的端點的顏色作為線段的顏色
模型變換和視圖變換
glMatrixMode(GL_MODELVIEW);//設置當前操作的矩陣為“模型視圖矩陣”,及可以利用矩陣進行旋轉等變換
glLoadIdentity();//將當前矩陣設置為單位矩陣(還未進行任何旋轉操作)
glRotatef(30.0, 0.0f, 0.0f, -1.0f);//glRotate前綴不變,后綴f代表參數是浮點型,第一個參數是旋轉角度,后三個參數代表按照向量n=(0,0,-1)為軸進行旋轉
glTranslatef(1.0f, 2.0f, 3.0f);//函數形式和旋轉函數類似,3個參數的含義分別是沿着X,Y,Z軸正方向平移的距離
glScalef(1.0f,2.0f,3.0f);//函數形式同上,3個參數的含義:調用該函數以后,所有函數點的X,Y,Z坐標會乘上3個參數當中相應位置的參數數值,譬如參數為(1,2,3),則(x,y,z)變換后為(x,2y,3z)
gluLookAt(0, -20, 20, 0, 0, 0, 0, 0, 1);//(前三個參數為觀察點位置坐標,中間三個參數為觀察目標的位置坐標,后三個參數為觀察者認為的上方的方向向量)
投影變換
投影變換就是定義一個可視空間,可視空間以外的物體不會被繪制到屏幕上,OpenGL支持兩種類型的投影變換,即透視投影和正投影。
以下為投影函數
glMatrixMode(GL_PROJECTION);//投影也是使用矩陣來實現的。如果需要操作投影矩陣,需要以GL_PROJECTION為參數調用glMatrixMode函數
glLoadIdentity();//同模型和視圖變換,在進行變換前要將矩陣設置為單位矩陣
//將可視空間設置為透視投影空間的函數:
glFrustum (left, right, bottom, top, near, far);//(left,bottom),(right,top)是被投影的裁剪平面左下角和右上角點的坐標,near是被投影的裁剪平面到視點(即觀察點)的距離,far是通過投影產生的平面到視點的距離,near,far參數必須為正值
gluPerspective(fovy,aspect,Near,Far);//參數fovy為視角的大小(可以理解為視野的大小,視角越大,說明眼睛睜開的角度越大,視野就越開廣,能看到東西越多,但是看到的物體會比較小,不清晰,視角越小,說明正眯着眼,只能看到局部的視野,但是看到的東西更清晰,如同放大鏡的效果),aspect為實際窗口的寬高比,參數near,far含義同函數glFrustum
以下為正投影函數
glOrtho(left, right, bottom, top, near, far);//參數含義同glFrustum,作用是平行投影(即物體不會因為屏幕的遠近而改變大小),可以當作是一個裁剪函數,從原圖當中摳出一部分來作為原圖的裁剪面。
視口變換
//視口變換,可以把上面透視、正投影處理后的投影面輸出到顯示器的窗口上指定的位置
glViewport(0, 0, (GLsizei)width, (GLsizei)height);//將裁剪窗口輸出到屏幕,寬為width,高為height,注意如果裁剪面的長寬比例和輸出比例(即width/height)不一樣的話,輸出時圖像會被拉伸或收縮,要讓裁剪面輸出到屏幕后圖形比例和原來一樣的話,需要讓裁剪面的長寬比和輸出比例一致。
變換矩陣的存儲及恢復功能
操作矩陣的堆棧,需要注意:模型視圖變換和投影變換兩者都有相應的堆棧,使用glMatrixMode來轉換這兩種變換類型
glPushMatrix();//把當前變換矩陣壓入到堆棧
glPoatrix();//從堆棧中pop出一個矩陣,即恢復上一次存儲的變換矩陣
glEnable(GL_DEPTH_TEST);//啟用深度測試,防止后繪制的物體遮住先繪制的物體
雙緩沖技術
在glutInitDisplayMode這個工具包函數里面啟動雙緩沖功能(可以理解為其中一個緩沖用於給計算機畫圖像,還有一個緩沖用於顯示圖像,當計算機畫完,交換指着對應緩沖的指針,就實現了兩個緩沖的交換,此時屏幕就顯示計算機剛畫完的圖像了。)
glutSwapBuffers();//參考glut工具包函數
glutIdleFunc(&myIdle);//參考glut工具包函數
關於垂直同步的簡單介紹(一個簡單的例子)
設顯示器的刷新頻率為60HZ,意義為1秒鍾刷新60次屏幕,現在電腦如果需要繪制圖像,繪制一張的時間為1/50s,那么如果沒有設置垂直同步,那么FPS(幀數)就是50了,1s顯示50張畫面。若設置了垂直同步,即每次刷新最多顯示一張圖片,那么顯示器第一次刷新的時候(也就是1/60時),電腦還沒有將圖像繪制好,那么只能等到第二次刷新的時候才能輸出一張圖片,幀數就變成了30.可以看到幀數急劇下降了,如果計算機性能太好,1秒能畫上百上千的圖,這樣顯示器根本沒法全部輸出畫好的圖像,垂直同步也可以很好的防止資源過度浪費。
光照的基本處理
openGL把光照分解為光源、材質、光照模式三個部分,根據這三部分信息,以及物體表面的法線向量,可以確定最終的光照效果,接下來對每一部分函數逐一介紹
1:法線向量
glNormal*();//
2:控制光源
。。。
未完待續
顯示列表
在編寫OpenGL程序時,遇到重復的工作,可以創建一個顯示列表,把重復的工作裝入其中,並在需要的地方調用這個顯示列表
使用顯示列表一般有四個步驟:分配顯示列表編號、創建顯示列表、調用顯示列表、銷毀顯示列表
1:分配顯示列表
glGenLists(x);//自動分配x個沒有使用的並且連續的顯示列表編號,譬如x=3,函數返回20,則分配到的顯示列表編號為20,21,22
glIsList(x);//判斷編號為x的顯示列表是否存在
2:創建顯示列表
glNewList(list, GL_COMPILE);//開始裝入編號為list的顯示列表,第二個參數GL_COMPILE表示內容只是裝入顯示列表,但暫時不執行,如果需要馬上執行,參數改為GL_COMPILE_AND_EXECUTE
glEndList();//結束顯示列表的裝入
3:調用顯示列表
glCallList(10);//調用編號為10的顯示列表
glCallLists(4,GL_UNSIGNED_INT,lists);//第一個參數表示調用的列表的數量,第二個參數表示列表編號的存儲格式,第三個參數表示編號所在地的指針
glListBase(k);//表示一個偏移量,偏移k個位置
//////////////////////
舉個小例子
GLuint lists[] = {1, 3, 4, 8};
glListBase(10);
glCallLists(4, GL_UNSIGNED_INT, lists);
最終調用編號為11,13,14,18的顯示列表
//////////////////////
4:銷毀列表
glDeleteLists(10,4);//最終銷毀編號為10,11,12,13的四個列表
混合
glEnable(GL_BLEND);//使用opengl混合功能,相應的,關閉該功能即為glDisable(GL_BLEND);
源顏色和目標顏色:源顏色即為當前需要畫上去的顏色,目標顏色是原本存在於畫板的顏色,采用RGBA,源顏色和目標顏色均有四個分量:(紅色,綠色,藍色,alpha值(亮度))
源因子和目標因子:源因子和目標因子是對應於源顏色和目標顏色的4維向量,即源顏色和目標顏色最后混合產生的顏色值為----(源因子·源顏色+目標因子·目標顏色),其中·為向量作點乘
glBlendFunc(GL_ONE, GL_ZERO);//源因子和目標因子可以通過該函數進行設置,,函數前一個參數設置源因子,后一個參數設置目標因子。當中參數有好幾種類型,以下分別進行介紹:
GL_ZERO: // 表示使用0.0作為因子,實際上相當於不使用這種顏色參與混合運算。
GL_ONE: // 表示使用1.0作為因子,實際上相當於完全的使用了這種顏色參與混合運算。
GL_SRC_ALPHA://表示使用源顏色的alpha值來作為因子。
GL_DST_ALPHA://表示使用目標顏色的alpha值來作為因子。
GL_ONE_MINUS_SRC_ALPHA://表示用1.0減去源顏色的alpha值來作為因子。
GL_ONE_MINUS_DST_ALPHA://表示用1.0減去目標顏色的alpha值來作為因子。
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//比較常用,相當於源顏色乘上它的alpha值,目標顏色乘上(1-源顏色alpha),這樣源顏色alpha越大,源顏色混合占比越大。、
三維混合
三維混合要注意深度緩沖,深度緩沖記錄了每一個像素點距離觀察點又多近,如果將要繪制的像素比原來的像素更近,像素會被繪制,否則就會被忽略掉。所以一旦我們在近處繪制了半透明的圖形,在緩沖區留下了信息,遠處的圖形將無法再繪制出來。這時可以這樣解決問題:先繪制不透明的物體,因為不透明誰先誰后都不影響。之后將深度緩沖區設置為可讀不可寫,再接着畫半透明的物體即可。繪制完畢后將深度緩沖區設置為可讀可寫。
glDepthMask(GL_FALSE);//將深度緩存區設置為只讀形式。glDepthMask(GL_TRUE);將深度緩存區設置為可讀可寫形式
BMP文件格式
BMP是像素文件,可以保存單色位圖,16色或256色索引模式像素圖,24位真彩色圖。以上每種格式每一個像素的大小是1、4、8、24位,也就分別是1\8、1\2、1、3字節,BMP格式的文件在開始處有一個大小為54字節的文件頭,文件頭中包含了文件格式標識、顏色數、圖象大小、壓縮方式等信息,其中圖像大小的信息比較有用,圖像的高度和寬度都是32位的整數在文件中的地址是0x0012、0x0016d.
以下做法可以提取BMP格式文件的信息:
GLint width,height;
File *file;
fseek(file,0x0012,SEEK_SET);
fread(&width,sizeof(width),1,file);
//fseek(file,0x0016,SEEK_SET);可以省略這一步,因為提取完width指針已經轉移到0x0012的4個字節之后了,也就是轉到了0x0016
fread(&height,sizeof(height),1,file);
需要注意的一些地方:1:opengl通常使用RGB表示顏色,但BMP采用BGR,也就是反過來了。2:BMP文件格式采用“對齊”的機制,也就是每一行的所使用的位數一定要是4的整數倍,若不是,要一直補到4的整數倍才可以,所以不能簡單的使用圖像的高度乘上圖片的寬度再乘上每一個像素的位數作為文件總的像素個數,要注意。
opengl的像素操作
glReadPixels(0,0,width,height,GL_BGR_EXT,GL_UNSIGNED_BYTE,pixelData);//該函數可以把顯存中已經繪制好的圖像信息保存在最后一個參數(是1個指針)所指的地方。該函數一共7個參數,其兩個參數是選取圖像的左下角頂點坐標(窗口最左下角為(0,0)),width,height是選取的區域的寬和高(像素數量),第五個參數表示讀取像素的數據內容,譬如設置參數是GL_RED,則只讀取圖像的紅色數據。因為bmp格式文件采用BGR,所以讀取時可以采用GL_BGR_EXT,若使用GL_RBG參數來讀數據,還要手動將每個像素的第一個字節和第三個字節交換。第6個參數讀取的數據內容保存到內存時采用的存儲格式,例如GL_UNSIGNED_BYTE可以把數據保存為GLubyte。第7個參數則是指針,這些數據會保存到指針指向的地點。
int alignment = 4;
glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);//若要將圖像數據保存在BMP格式文件中,那么在采用glReadPixels函數保存圖像數據前,要使用glPixelStorei函數將需要保存的圖像的每一行像素數據的字節補齊為4的倍數。其中第一個參數GL_UNPACK_ALIGNMENT表示“設置像素的對齊值”,第二個參數為具體按多少字節的整數倍對其。可以是1,2,4,8等等,即分別按照1,2,4,8字節的整數倍對其。
glDrawPixels(width,height,GL_BGR_EXT,GL_UNSIGNED_BYTE,pixelData);//該函數用於將保存在內存中的圖像數據繪制出來。第一、二個參數為圖像數據的高度和寬度(像素數量),第三個參數是讀取像素的格式信息,第4個參數是圖像存儲在內存中的存儲格式,最后一個是指針,指向內存中保存的圖像信息的數據位置。
glRasterPosf();//注意glDrawPixels函數沒有指定繪制位置,繪制位置可以由該函數設置。通過指定一個二維/三維/四維坐標,OpenGL將自動計算出該坐標對應的屏幕位置,並把該位置作為繪制像素的起始位置。
glPixelZoom(0.5f, 0.8f);//在繪制像素前,可以對對圖像進行一些處理,譬如用該函數進行放大縮小,當設置參數為(0.5f,0.8f)則圖像水平方向變為原來的50%,垂直方向變為原來的80%,默認從左下角開始往右上方繪制,若參數為負數,則繪制方向相反
glCopyPixels(0,0,width,height,GL_COLOR);//復制像素並進行繪制的操作,前兩個參數代表被復制的圖的左下角坐標,width,height是復制原來矩形的寬度和高度。最后一個參數代表復制原本像素的顏色。
紋理操作
glEnable(GL_TEXTURE_2D); // 啟用二維紋理
glDisable(GL_TEXTURE_2D); // 禁用二維紋理
在使用紋理前,必須載入紋理,利用以下函數可以載入一個紋理:
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,width,height,0,GL_BGR_EXT,GL_UNSIGNED_BYTE,PixelsData);//一共9個參數,第一個為GL_TEXTURE_2D,為2維紋理。第二個參數為“多重細節層次”,暫且將這個參數設置為零。第三個參數為采用顏色的分量數,可以調用參數GL_RGB,GL_RGBA。第4,5個參數是調用2維紋理的寬度和高度,很多版本的openGL可能需要寬高為2的整數倍,當這個要求無法滿足時,使用gluScaleImage函數把圖象縮放至所指定的大小,可以調用函數glGetIntegerv來獲取最大紋理大小。第6個參數是紋理邊框的大小,可以設置為0。最后三個參數與glDraoPixels的后三個參數一致。
GLint max;
glGetIntegerv(GL_MAX_TEXTURE_SIZE,&max);//將紋理最大調用值保存在max變量中。
紋理坐標的設置:
glBegin( /* ... */ );
glTexCoord2f( /* ... */ ); glVertex3f( /* ... */ );//利用glTexCoord2f指定紋理圖案的某個位置點(規定紋理坐標左下角坐標為(0,0),右上角坐標為(1,1)),這個點將變換到我需要繪制的三維空間上的某一個點,這個點的坐標由glVertex3f定義,這樣就有一一對應的關系了
glTexCoord2f( /* ... */ ); glVertex3f( /* ... */ );
/* ... */
glEnd();
當然紋理也可以進行旋轉平移等變換,這需要利用glMatrixMode(GL_TEXTURE)將變換矩陣切換到紋理矩陣,接着即可使用glRotatef(),glScalef(),glTranslate*()等函數進行變換了。
紋理參數:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//當一個紋理圖像被應用到一個大小小於本身的空間時(即紋理圖像中的多個像素被繪制到一個像素點上,譬如256*256的紋理應用到128*128的圖像上)的處理方式,GL_LINEAR可以設置當前像素顏色是若干相鄰像素顏色的加權平均。
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//當紋理圖像被應用到一個比它本身大的空間上的處理方式,同上。
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//紋理第一維坐標在0到1之間,若坐標超過這個或者小於這個范圍的處理方式。GL_REPEAT表示重復循環(0,0)至(1,1)上的圖畫
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);//設置紋理第二維坐標,設置方式同上
紋理對象:
載入一幅紋理需要比較長的時間,所以要盡量減少紋理的載入次數,利用紋理對象,可以在第一次繪制之前就載入它,以后就不需要載入了。我們可以把每一副紋理(包括紋理的像素數據,大小信息,參數設置等等)放到紋理對象當中,這樣創建多個紋理對象來保存多副紋理。這樣,繪制時只需指明究竟在使用哪一個紋理對象即可。
紋理對象和顯示列表的相似之處在於:使用一個正整數來代表紋理對象的編號,並且可以調用glGenTextures()來分配紋理對象,以下是該函數的用法:
GLuint texture_id;
glGenTextures(1,&texture_id);//分配一個紋理對象的編號,該編號保存於texture_id中
GLuint texture_id[5];
glGenTexture(5,texture_id);//分配五個紋理對象的編號,保存於texture_id數組
對應於glGenTexture函數,glDeleteTextures用於銷毀一個紋理對象。
分配了紋理對象的編號后,使用glBindTexture函數來指定“當前所使用的紋理對象”。之后就可以調用glTexImage函數指定紋理像素、glTexParameter指定紋理參數、glTexCoord*函數指定紋理坐標。若不用glBindTexture,后三個函數默認使用編號為0的紋理對象進行操作。
glBindTexture(GL_TEXTURE_2D,id);//第一個參數是需要使用紋理的目標,用二維紋理,指定為GL_TEXTURE_2D,第二個參數是需要調用的紋理編號。
GLuint texture_id[2];
glGenTextures(2,texture_id);
glBindTexture(GL_TEXTURE_2D,texture_id[0]);
//載入第一幅紋理
glBindTexture(GL_TEXTURE_2D,texture_id[1]);
//載入第二幅紋理
........
//在繪制時,切換到想要使用的紋理坐標即可
glBindTexture(GL_TEXTURE_2D,texture_id[0]);//指定為第一幅紋理
//使用該紋理
glBindTexture(GL_TEXTURE_2D,texture_id[1]);//指定為第二幅紋理
//使用該紋理
片段測試
片段測試用於測試每一個像素,只有像素通過所有測試才會被繪制。openGL測試的順序是:裁剪測試->Alpha測試->模板測試->深度測試
1:裁剪測試,只有在窗口內的像素才會被繪制
glEnable(GL_SCISSOR_TEST);//啟用裁剪測試。glDisable(GL_SCISSOR_TEST);禁用裁剪測試
glScissor(x,y,width,height);//指定一個位置在(x,y),寬度為width,高度為height的裁剪窗口(注意:opengl窗口坐標左下角(0,0),右上角(width,height))。這里注意這個函數和視口變換函數glViewport的區別,視口變換函數只是將畫面所有內容縮放到一個規定大小的矩形區域內,而裁剪測試不會縮放,超出矩形范圍的像素直接忽略。
2:Alpha測試,用於檢查每個像素點的Alpha值,只有Alpha值滿足條件的像素才會通過測試。
glEnable(GL_ALPHA_TEST);//開啟Alpha測試 glDisable(GL_ALPHA_TEST);關閉Alpha測試
glAlphaFunc(GL_GREATER,0,5f);//該函數用於設置Alpha測試條件,參數GL_GREATER和0,5f代表大於Alpha值大於0.5則通過。參數還可以選取以下各值:
GL_ALWAYS(始終通過) GL_NEVER(始終不通過) GL_LESS(小於則通過) GL_LEQUAL(小於等於就通過) GL_EQUAL(等於則通過) GL_GEQUAL(大於等於則通過) GL_NOTEQUAL(不等於則通過)
3:模板測試,檢查每個像素點的模板值,模板值滿足一定條件才繪制像素。
首先,模板測試需要一個模板緩沖區,這個緩沖區是在初始化OPENGL時指定的。調用glutInitDisplayMode(GLUT_STENCIL);即可
glEnable(GL_STENCIL_TEST);//啟用模板測試。glDisable(GL_STENCIL_TEST);禁用模板測試
glStencilFunc(GL_LESS,3,mark);//該函數用於設置模板測試條件,注意模板值只能為整數,函數前兩個參數和glAlphaFunc參數一樣,第三個參數mask表示只比較mask二進位制為1的位,設當前像素模板值為b,那么最終比較的是(b&mask)的值和模板測試值得關系。
glClear(GL_STENCIL_BUFFER_BIT);//可以復位所有像素得模板值,那么復位到那個值呢?可以調用下面得函數設置模板初始值。
glClearStencil(0);//設置0為模板初始值,該函數類似於glClearColor
glStencilOp(fail,zfail,zpass);//每個像素得“模板值”會根據模板測試和深度測試的結果進行改變。該函數三個參數,第一個參數代表模板測試失敗后該像素模板值如何變化,第二個參數代表像素通過模板測試但沒通過深度測試后值如何變化,最后一個參數代表通過了深度測試后值該如何變化。
上述函數三個參數可以有如下的幾種選擇:
GL_KEEP(不改變值,也是默認值) GL_ZERO(回零) GL_REPLACE(使用測試條件設定的模板值來替換當前像素的模板值) GL_INCR(增加1,如果達到最大值,則不變) GL_INCR_WRAR(增加1,如果達到最大值,則從0開始) GL_DECR(減少1,已經是0則不變) GL_DECR_WRAR(減少1,已經是0,則設置為最大值) GL_INVERT(按位取反)。
在多邊形中,允許多邊形正面和背面使用不同的模板測試條件和模板值改變方式。可以利用以下函數:
glStencilFuncSeparate(GL_FRONT,GL_LESS,3,mark);//第一個參數代表這是對多邊形正面的測試條件,后三個參數與glStencilFunc類似
glStencilOpSeperate(GL_FRONT,fail,zfail,zpass);//介紹同上。
4:深度測試
glutInitDisplayMode(GLUT_DEPTH);//明確指定要求使用深度緩沖區
glEnable(GL_DEPTH_TEST);//啟用深度測試。glDisable(GL_DEPTH_TEST);//禁用深度測試
glDepthFunc(GL_LESS);//判定像素的深度值是否符合要求就調用該函數,參數為設置條件,參數類型與Alpha測試當中的8種一樣。
glDepthMask(GL_FALSE);//設置深度測試狀態為可讀不可寫狀態。可以再調用參數GL_TRUE恢復可寫狀態。
openGL工作流程:輸入像素數據以及頂點數據,兩種數據進行操作后,進行光柵化,得到片段fragment,經過片段處理,繪制到幀緩沖區。整個繪制的過程也可以逆向傳送,轉化為像素數據。
利用頂點數組減少繪制工作
在繪制立體圖像的時候,如果直接利用vertex*類函數的話比較麻煩且容易繪制失誤,盡量使用頂點數組。舉個例子,以下要繪制一個正方體的做法:可以先把正方體的6個頂點的3維數據保存在頂點數組當中,現在還要繪制6個面,每個面都需要正方體其中4個頂點,故還可以建立一個序號數組,把繪制每一個面需要的頂點序號保存於序號數組當中:
static const GLfloat vertex_list[][3]={
-0.5f,-0.5f,-0.5f,//寫下每一個頂點的3維坐標位置
0.5f,-0.5f,-0.5f,
.......
}
static const GLint index_list[][4]={
0,2,3,1,//每一個面需要四個頂點,寫下四個頂點在頂點數組中的序號位置即可
0,4,6,2,//注意編號順序,正面逆時針,反面順時針
......
}
glBegin(GL_QUADS);
for(int i=0;i<6;i++)
for(int j=0;j<4;j++)
glVertex3fv(vectex_list[index_list[i][j]]);
glEnd();
因為我們定義了正面逆時針順序,反面順時針順序,繪制前調用以下代碼:
glFrontFace(GL_CCW);//逆時針代表正面
glEnable(GL_CULL_FACE);//開啟剔除功能
glCullFace(GL_BACK);//剔除多邊形反面,即不繪制多邊形反面,提高運行效率
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);//只顯示線條,不進行填充
上面關於頂點數組的操作還可以更加簡便的調用函數:
glEnableClientState(GL_VERTEX_ARRAY);//啟用頂點數組
glVertexPointer(3,GL_FLOAT,0,vertex_list);//指定了頂點數組的位置。其中第一個參數3代表維度,GL_FLOAT代表每一維度的數據類型,0是"stride"參數,表示從一個數據的開始到下一個數據的開始,所間隔的數字。第四個參數指明了數組實際位置。
glDrawElements(GL_QUADS,24,GL_UNSIGNED_INT,index_list);//根據序號數組index_list中的序號,查找相應的頂點並完成繪制。GL_QUADS代表繪制四邊形,24代表要繪制的頂點個數,GL_UNSIGNED_INT代表序號的數據類型,第四個即序號列表存儲位置。
頂點數組實際可以是多個數組,頂點坐標,紋理坐標,法線向量,頂點顏色等等,每一個屬性可以指定一個數組來存儲,之后用統一的序號來進行訪問,代表同一個頂點的元素信息。
利用glEnableClientState();單獨開啟並關閉每一個數組的使用,每一個數組的參數類型有:
GL_VERTEX_ARRAY(頂點位置數組) GL_COLOR_ARRAY(頂點顏色數組) GL_NORMAL_ARRAY(頂點法線向量數組) GL_TEXTURE_COORD_ARRAY(頂點紋理坐標數組)
開啟相應的數組以后,以下函數可以用來指定數組所在位置:
glVertexPointer();glColorPointer(); glNormalPointer(); glTexCoordPointer();
混合數組:如果同時需要使用顏色數組,頂點坐標數組,紋理數組等等,可以把它們混合到一個數組當中,這個數組稱為混合數組。
GLfloat arr_c3f_v3f[] = {
1,0,0,0,1,0,
0,1,0,1,0,0,
0,0,1,-1,0,0,
};
GLuint index_list[] = { 0,1,2 };
glInterleavedArrays(GL_C3F_V3F, 0, arr_c3f_v3f);//該函數用於指定混合數組,
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, index_list);//根據序號數組的序列,查找相應頂點並繪制
頂點數組和顯示列表的區別:顯示列表的數據已經全部存放於服務器端,也就是說每次調用顯示列表,數據直接從服務器端拿,而不需要再從內存取出,速度比較快,但是又比較死板,數據不能隨意進行修改。而每次調用頂點數組,每次都需要把數據從內存里面取出,比較花時間,但是由於內存中的數據可以隨意進行修改,所以頂點數組比較靈活,但速度較慢。