002-- 3D圖形 和 OpenGL 簡介 :http://www.reibang.com/p/ff26de4eee71
001--OpenGL在Mac 上的環(huán)境搭建:http://www.reibang.com/p/f3b21fe058e3
OpenGL 簡介
OpenGL發(fā)展至今筒狠,已經(jīng)20余年猪狈。作為一個成熟而久負盛名的跨平臺的計算機圖形應(yīng)用程序接口規(guī)范,它已經(jīng)被廣泛應(yīng)在游戲辩恼、影視雇庙、軍事、航空航天灶伊、地理疆前、醫(yī)學(xué)、機械設(shè)計聘萨,以及各類科學(xué)數(shù)據(jù)可視化的領(lǐng)域竹椒。
并且隨著網(wǎng)絡(luò)和移動平臺的飛速發(fā)展,異步突起的OpenGL ES 和 WebGL 標(biāo)準(zhǔn)也吸引了大批開發(fā)者的眼球米辐。而這兩者與OpenGL 本身同樣有千絲萬縷的聯(lián)系胸完。
OpenGL 幾乎支持所有現(xiàn)有的主流操作系統(tǒng)平臺,包括Windows翘贮、Mac OS X以及各種UNIX平臺赊窥。它同時也可以用于幾乎所有主流的編程語言環(huán)境中,例如C/C++择膝、Java誓琼、C#、Visual Basic肴捉、Python等腹侣。因此,OpenGL應(yīng)當(dāng)是全球最為廣泛學(xué)習(xí)和使用的圖形開發(fā)API接口齿穗。
Open GL 概述
什么是OpenGL
OpenGL 是一種應(yīng)用程序編程接口(Application Programming Interface,API),它是一種可以對圖形硬件設(shè)備特性進行訪問的軟件庫傲隶。包含了500個不同的命令,可以用于設(shè)置所需的對象窃页、圖像和操作跺株,以便開發(fā)交互式的3維計算機圖形應(yīng)用程序复濒。
OpenGL 被設(shè)計為一個現(xiàn)代化的,硬件無關(guān)的接口乒省。因此不需要考慮計算機操作系統(tǒng)和窗口系統(tǒng)的前提下巧颈,在多種不同的圖形硬件系統(tǒng)上,或者完全通過軟件的方式實現(xiàn)OpenGL 接口袖扛。
OpenGL 自身是不包含任何執(zhí)行的窗扣任何或者處理用戶輸入輸出的函數(shù)砸泛。事實上我們需要通過應(yīng)用程序所運行的窗口系統(tǒng)提供的接口來執(zhí)行這類操作。
OpenGL也沒有提供任何用戶表達3維物體模型蛆封,或者讀取圖像文件的操作唇礁。我們需要通過一系列幾何圖元(包括點、線惨篱、三角形以及patch)來創(chuàng)建三維空間的物體盏筐。
OpenGL 程序
- 渲染:表示計算機從模型創(chuàng)建最終圖像的過程。OpenGL 只是一種基于光柵化的系統(tǒng)砸讳。
- 模型(場景對象):通過幾何圖元(點琢融、線、三角形)來構(gòu)建的绣夺。
- 著色器吏奸,它是圖形硬件設(shè)計所執(zhí)行的一類特殊的函數(shù)√账#可以理解為圖像處理單元(GPU)編譯的一種小型程序。
- 四種不同的著色階段(shander stage)她混,其中最常用的包括頂點著色器(vertex shader)以及片元著色器烈钞,前者用于處理頂點數(shù)據(jù),后者用于處理光柵化后的片元數(shù)據(jù)坤按。所有OpenGL程序都需要用到這兩類著色器
- 幀緩存(framebuffer)毯欣,像素(pixel),是顯示器上最小的可見單元臭脓。計算機系統(tǒng)將所有的像素保存到幀緩存當(dāng)中酗钞,后者是有圖形硬件設(shè)備管理的一塊獨立內(nèi)存區(qū)域,可以直接映射到最終的顯示設(shè)備上
什么叫 光柵化来累?
將輸入圖元的數(shù)學(xué)描述轉(zhuǎn)為屏幕位置對應(yīng)的像素片元砚作,稱為關(guān)柵化
OpenGL 渲染圖像的OpenGL 程序需要執(zhí)行的操作:
- 從OpenGL的幾何圖元中設(shè)置數(shù)據(jù),用于構(gòu)建形狀嘹锁。
- 使用不同的著色器(shader)對輸入的圖元數(shù)據(jù)執(zhí)行計算操作葫录,判斷它們的位置、顏色领猾,以及其他渲染屬性米同。
- 將輸入圖元的數(shù)學(xué)描述轉(zhuǎn)化為與屏幕位置對應(yīng)的像素片元(fragment)骇扇。這一步也稱為光柵化(rasterization)。
- 最后面粮,針對光柵化過程產(chǎn)生的每個片元少孝,執(zhí)行片元著色器(fragment shader),從而決定這個片元的最終顏色和位置熬苍。
- 如果有必要韭山,還需要對每個片元執(zhí)行一些額外的操作,例如判斷片元對應(yīng)的對象是否可見冷溃,或者將片元的顏色與當(dāng)前屏幕位置的顏色進行融合钱磅。
案例1 繪制一個正方形
#include <iostream>
#include <GLUT/GLUT.h>
void draw() {
//設(shè)置清屏色
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
//設(shè)置顏色,紅色
glColor3f(1.0f, 0.0f, 0.0f);
//設(shè)置繪圖時的坐標(biāo)系統(tǒng)
glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
//開始渲染
glBegin(GL_POLYGON);
//設(shè)置多邊形的4個頂點
glVertex3f(0.25f, 0.25f, 0.0f);
glVertex3f(0.75f, 0.25f, 0.0f);
glVertex3f(0.75f, 0.75f, 0.0f);
glVertex3f(0.25f, 0.75f, 0.0f);
//結(jié)束渲染
glEnd();
//強制刷新緩沖區(qū)似枕,保證繪制命令被執(zhí)行
glFlush();
}
int main(int argc, const char* argv[]) {
//初始化GLUT庫
glutInit(&argc, (char**)argv);
//創(chuàng)建一個窗口并制定窗口名
glutCreateWindow("HelloWorld");
//注冊一個繪圖函數(shù)盖淡,操作系統(tǒng)在必要時刻就會對窗體進行重新繪制操作
glutDisplayFunc(draw);
//進入GLUT事件處理循環(huán),讓所有的與“事件”有關(guān)的函數(shù)調(diào)用無限循環(huán)(永生循環(huán))
glutMainLoop();
return 0;
}
OpenGL語法
使用GLUT這個作為函數(shù)名的都是使用了GLUT庫的
OpenGL 渲染管線
什么是渲染管線凿歼?
它是一系列數(shù)據(jù)處理過程褪迟,并且將應(yīng)用程序的數(shù)據(jù)轉(zhuǎn)換到最終的渲染圖像。
OpenGl 首先接收用戶提供的幾何數(shù)據(jù)(頂點和幾何圖元)答憔,并且將它輸入到一系列著色器階段中進行處理味赃,包括:頂點著色、細分著色虐拓、以及最后的幾何著色心俗,然后它將進入光刪化單元。光柵化單元負責(zé)對所有剪切區(qū)域內(nèi)的圖元生成片元數(shù)據(jù)蓉驹,然后對每個生成的片元都執(zhí)行一個片元著色器城榛。
事實上,只有頂點著色器 和 片元著色器是必須的态兴。細分和幾何著色器是可選的步驟狠持。
案例2 簡單繪制一個三角形
2.1要導(dǎo)入什么框架
-
#include<GLTools.h>
GLTool.h頭文件包含了大部分GLTool中類似C語言的獨立函數(shù) -
#include<GLShaderManager.h>
移入了GLTool 著色器管理器(shader Mananger)類。沒有著色器瞻润,我們就不能在OpenGL(核心框架)進行著色喘垂。著色器管理器不僅允許我們創(chuàng)建并管理著色器,還提供一組“存儲著色器”绍撞,他們能夠進行一些初步?基本的渲染操作正勒。 - 在Mac 系統(tǒng)下,
#include<glut/glut.h>
- 在Windows 和 Linux上楚午,我們使用freeglut的靜態(tài)庫版本并且需要添加一個宏昭齐。
#define FREEGLUT_STATIC
#include<GL/glut.h>
2.2 啟動GLUT
1.程序的總是“main”函數(shù)開始處理
GLTools
函數(shù)glSetWorkingDrectory
用來設(shè)置當(dāng)前工作目錄。實際上在Windows中是不必要的矾柜,因為工作目錄默認就是與程序可執(zhí)行執(zhí)行程序相同的目錄阱驾。但是在Mac OS X中就谜,這個程序?qū)?dāng)前工作文件夾改為應(yīng)用程序捆綁包中的/Resource
文件夾。GLUT
的優(yōu)先設(shè)定自動進行了這個中設(shè)置里覆,但是這樣中方法更加安全丧荐。
2.創(chuàng)建窗口并設(shè)置顯示模式
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
GLUT_DOUBLE
:雙緩存窗口,是指繪圖命令實際上是離屏緩存區(qū)執(zhí)行的喧枷,然后迅速轉(zhuǎn)換成窗口視圖虹统,這種方式,經(jīng)常用來生成動畫效果隧甚;
GLUT_DEPTH
:標(biāo)志將一個深度緩存區(qū)分配為顯示的一部分车荔,因此我們能夠執(zhí)行深度測試;
GLUT_STENCIL
:確保我們也會有一個可用的模板緩存區(qū)戚扳。
深度忧便、模板測試后面會細致講到。
3.初始化GLEW庫
重新調(diào)用GLEW庫初始化OpenGL 驅(qū)動程序中所有丟失的入口點帽借,以確保OpenGL API對開發(fā)者完全可用珠增。
調(diào)用glewInit()函數(shù)一次就能完成這一步。在試圖做任何渲染之前砍艾,還要檢查確定驅(qū)動程序的初始化過程中沒有出現(xiàn)任何問題蒂教。
4.SetupRC()
實際上這個函數(shù)對GLUT 沒有什么影響,但是在實際開始渲染之前脆荷,我們這里進行任何OpenGL 初始化都非常方便凝垛。這里的RC代表渲染環(huán)境,這是一個運行中的OpenGL狀態(tài)機的句柄简烘。在任何OpenGL 函數(shù)起作用之前必須創(chuàng)建一個渲染環(huán)境苔严。而GLUT在我們第一次創(chuàng)建窗口時就完成了這項工作。
5.初始化設(shè)置
void glClearColor(GLclampf red,GLclampf green,GLclampf blue,GLclampf alpha);
在windows 顏色成分取值范圍:0-255之間
在iOS孤澎、OS 顏色成分取值范圍:0-1之間浮點值

#include "GLShaderManager.h"
#include "GLTools.h"
#include <glut/glut.h>
//簡單的批次容器,是GLTools的一個簡單的容器類欠窒。
GLBatch triangleBatch;
GLShaderManager shaderManager;
//窗口大小改變時接受新的寬度和高度覆旭,其中0,0代表窗口中視口的左下角坐標(biāo),w岖妄,h代表像素
void ChangeSize(int w,int h)
{
glViewport(0,0, w, h);
}
//為程序作一次性的設(shè)置
void SetupRC()
{
//設(shè)置背影顏色
glClearColor(0.0f,0.0f,1.0f,1.0f);
//初始化著色管理器
shaderManager.InitializeStockShaders();
//設(shè)置三角形型将,其中數(shù)組vVert包含所有3個頂點的x,y,笛卡爾坐標(biāo)對。
GLfloat vVerts[] = {
-0.5f,0.0f,0.0f,
0.5f,0.0f,0.0f,
0.0f,0.5f,0.0f,
};
//批次處理
triangleBatch.Begin(GL_TRIANGLES,3);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
//開始渲染
void RenderScene(void)
{
//清除一個或一組特定的緩沖區(qū)
//緩沖區(qū)是一塊存在圖像信息的儲存空間荐虐,紅色七兜、綠色、藍色和alpha分量通常一起分量通常一起作為顏色緩存區(qū)或像素緩存區(qū)引用福扬。
//OpenGL 中不止一種緩沖區(qū)(顏色緩存區(qū)腕铸、深度緩存區(qū)和模板緩存區(qū))惜犀。
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
//設(shè)置一組浮點數(shù)來表示紅色
GLfloat vRed[] = {1.0f,0.0f,0.0f,1.0f};
//傳遞到存儲著色器,即GLT_SHADER_IDENTITY著色器狠裹,這個著色器只是使用指定顏色以默認笛卡爾坐標(biāo)第在屏幕上渲染幾何圖形
//沒有著色器虽界,在OpenGL 核心框架中就無法進行任何渲染。在后面的課程中我們講到不用固定渲染管線涛菠,當(dāng)然在前期會先學(xué)習(xí)如果使用存儲著色器莉御。
shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
//提交著色器
triangleBatch.Draw();
//將在后臺緩沖區(qū)進行渲染,然后在結(jié)束時交換到前臺
glutSwapBuffers();
}
int main(int argc,char* argv[])
{
//設(shè)置當(dāng)前工作目錄俗冻,針對MAC OS X
/*
`GLTools`函數(shù)`glSetWorkingDrectory`用來設(shè)置當(dāng)前工作目錄礁叔。實際上在Windows中是不必要的,因為工作目錄默認就是與程序可執(zhí)行執(zhí)行程序相同的目錄迄薄。但是在Mac OS X中琅关,這個程序?qū)?dāng)前工作文件夾改為應(yīng)用程序捆綁包中的`/Resource`文件夾。`GLUT`的優(yōu)先設(shè)定自動進行了這個中設(shè)置噪奄,但是這樣中方法更加安全死姚。
*/
gltSetWorkingDirectory(argv[0]);
//初始化GLUT庫
glutInit(&argc, argv);
/*初始化雙緩沖窗口,其中標(biāo)志GLUT_DOUBLE勤篮、GLUT_RGBA都毒、GLUT_DEPTH、GLUT_STENCIL分別指
雙緩沖窗口碰缔、RGBA顏色模式账劲、深度測試、模板緩沖區(qū)
2.創(chuàng)建窗口并設(shè)置顯示模式
`glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);`
`GLUT_DOUBLE`:雙緩存窗口金抡,是指繪圖命令實際上是離屏緩存區(qū)執(zhí)行的瀑焦,然后迅速轉(zhuǎn)換成窗口視圖,這種方式梗肝,經(jīng)常用來生成動畫效果榛瓮;
`GLUT_DEPTH`:標(biāo)志將一個深度緩存區(qū)分配為顯示的一部分,因此我們能夠執(zhí)行深度測試巫击;
`GLUT_STENCIL`:確保我們也會有一個可用的模板緩存區(qū)禀晓。
深度、模板測試后面會細致講到
*/
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
//GLUT窗口大小坝锰,標(biāo)題窗口
glutInitWindowSize(800,600);
glutCreateWindow("Triangle");
//注冊回調(diào)函數(shù)
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
//驅(qū)動程序的初始化中沒有出現(xiàn)任何問題粹懒。
GLenum err = glewInit();
if(GLEW_OK != err) {
fprintf(stderr,"glew error:%s\n",glewGetErrorString(err));
return 1;
}
//調(diào)用SetupRC
SetupRC();
glutMainLoop();
return 0;
}
OpenGL 常見流程
- 頂點著色器 和 片元著色器是必需的。細分和幾何著色器是可選的捕捉顷级。
- OpenGL 需要將所有的數(shù)據(jù)都保存到緩存對象中(buffer object)
將數(shù)據(jù)輸出到OpenGL
當(dāng)將緩存數(shù)據(jù)初始化完畢后凫乖,我們可以通過調(diào)用OpenGL 的一個繪制命令來請求渲染幾何圖元。使用的是glDrawArrays()就是一個常用的繪制命令
OpenGL 的繪制通常都是講頂點數(shù)據(jù)傳輸?shù)絆penGL 服務(wù)端。我們可以將一個頂點視為一個需要統(tǒng)一處理的數(shù)據(jù)包帽芽。這個包裝的數(shù)據(jù)可以是我們需要的任何數(shù)據(jù)(也就課)删掀,通常其中幾乎始終會包含位置數(shù)據(jù)。其他數(shù)據(jù)可能用來覺得一個像素的最終顏色嚣镜。
簡單介紹關(guān)鍵概念
- 頂點著色:對于繪制命令傳輸?shù)拿總€頂點爬迟,OpenGL都會調(diào)用一個頂點著色器來處理頂點相關(guān)的數(shù)據(jù)。只是將數(shù)據(jù)復(fù)制并傳遞到下一個著色階段菊匿,叫做傳遞著色器(pass-through shader)付呕。通常來說,一個復(fù)雜的應(yīng)用程序可能包含許多頂點著色器跌捆,但在同一時刻只能有一個頂點著色器起作用
-
細分著色:頂點著色器處理每個頂點的關(guān)聯(lián)數(shù)據(jù)之后徽职,如果同時激活了細分著色器,那么它將進一步處理這些數(shù)據(jù)佩厚。(第9章介紹)
細分著色器階段會用到兩個著色器來分別管理Patch數(shù)據(jù)并產(chǎn)生最終的形狀姆钉。 - 幾何著色:允許在光柵化之前對每一個幾何圖元做更進一步的處理,例如創(chuàng)建新的圖元抄瓦。這個著色階段是可選的潮瓶。我們在后面的課程詳解
- 圖元裝配:圖元裝配將頂點及相關(guān)的集合圖元之間組織起來枢纠,準(zhǔn)備下一步剪切和光柵化操作
- 剪切:頂點可能落在視口(viewport)之外哼鬓,此時與頂點相關(guān)的圖元會做出改動,以保證相關(guān)的像素不會在視口外繪制仔蝌。剪切(clipping)由OpenGL自動完成煞额。
- 光柵化:將更新后的圖元(primitive)數(shù)據(jù)傳遞到光柵化單元思恐,身材對應(yīng)的片元(fragment).我們將一個片元是為一個“候選的像素”。也就是可以放置在幀緩存(framebuffer)中的像素膊毁,但是它也可能被最終剔除胀莹,不再更新對應(yīng)的像素位置。之后兩個階段將會執(zhí)行片元的處理婚温。
- 片元著色:最后一個可以通過編程控制屏幕上顯示顏色的階段描焰。在Fragment Shader階段中,我們使用著色器計算片元的最終顏色和它的深度值栅螟。
頂點著色和片元著色器的之間的區(qū)別栈顷?
頂點著色器(包括細分和幾何著色)決定了一個圖元應(yīng)該位于屏幕的什么位置,而片元著色使用這些信息來決定某一個片元的顏色應(yīng)該是什么嵌巷?
- 逐步元的操作:這個階段里會使用深度測試(depth test )和模板測試(stencil test)的方式來決定一個片元是否可見的。
main函數(shù)里的常用函數(shù)
glutInit() 負責(zé)初始化GLUT庫室抽。它會處理向程序輸入的命令行參數(shù)搪哪,并且移除其中與控制GLUT如何操作相關(guān)的部分。它必須是應(yīng)用程序第一個GLUT函數(shù)坪圾,負責(zé)設(shè)置其他GLUT例程必需的數(shù)據(jù)結(jié)構(gòu)晓折。
glutInitDisplayMode() 設(shè)置了程序所使用的窗口類型惑朦。窗口設(shè)置更多的OpenGL 特性,例如RAGA顏色空間漓概,使用深度緩存或動畫效果漾月。
glutInitWindowsSize() 設(shè)置所需的窗口大小,如果不想在這個設(shè)置一個固定值胃珍,也可以先查詢顯示設(shè)備的尺寸梁肿,然后根據(jù)計算機的屏幕動態(tài)設(shè)置窗口的大小。
glutCreateWindow(),它的功能和它的名字一樣觅彰,如果當(dāng)前的系統(tǒng)環(huán)境可以滿足glutInitDisplayMode()的顯示模式要求吩蔑,這里就會創(chuàng)建一個窗口(此時會調(diào)用計算機窗口系統(tǒng)的接口)。只有GLUT創(chuàng)建了一個窗口之后(其中包含創(chuàng)建創(chuàng)建OpenGL環(huán)境的過程)填抬,我們才可以使用OpenGL相關(guān)的函數(shù)
glewInit()函數(shù)烛芬,屬于另一個輔助庫GLEW(OpenGL Extention Wrangler)。GLEW可以簡化獲取函數(shù)地址的過程飒责,并且包含了可以跨平臺使用的其他一些OpenGL編程方法赘娄。
glutDisplayFunc(),它設(shè)置了一個顯示回調(diào)(diplay callback)宏蛉,即GLUT在每次更新窗口內(nèi)容的時候回自動調(diào)用該例程
glutMainLoop()遣臼,這是一個無限執(zhí)行的循環(huán),它會負責(zé)一直處理窗口和操作系統(tǒng)的用戶輸入等操作檐晕。(注意:不會執(zhí)行在glutMainLoop()之后的所有命令暑诸。)
初始化頂點數(shù)組對象
void glGenVertexArray(GLsizei n ,GLUINT * arrays)
分配頂點Arr對象
返回n個未使用的對象名到數(shù)組arrays中,用作頂點數(shù)組對象辟灰。返回的名字可以用來分配的緩存對象个榕,并且它們已經(jīng)使用未初始化的頂點數(shù)組集合的默認狀態(tài)進行了數(shù)值的初始化。
void glBindVertexArray(GLuint array);
綁定激活對象數(shù)組
glBindVertexArray(),如果輸入的變量array非0芥喇,并且是glGenVertexArrays()所返回的西采,那么它將創(chuàng)建一個新的頂點數(shù)組對象并且與其名稱關(guān)聯(lián)起來。如果綁定到的是一個已經(jīng)創(chuàng)建的頂點數(shù)組對象中继控,那么會激活這個頂點數(shù)組對象械馆,并且直接影響對象找那個所保存的頂點數(shù)組對象,并且將渲染狀態(tài)重設(shè)為頂多數(shù)組的默認狀態(tài)武通。
如果array不是glGenVertexArrays(),所返回的數(shù)值霹崎,或者它已經(jīng)被glDeleteVertexArray()函數(shù)釋放,那么這里將產(chǎn)生一個GL_INVALID_OPERATION錯誤冶忱。
在2種情況下尾菇,我們需要綁定一個對象:
1.創(chuàng)建一個對象并初始化它所對應(yīng)的數(shù)據(jù)時;
2.每次準(zhǔn)備使用這個對象,而不是當(dāng)前綁定的對象時派诬。
當(dāng)我們完成對頂點數(shù)組對象的操作之后劳淆,是可以調(diào)用glDeleteVertexArrays()將它釋放的。
void glDeleteVertexArrays(GLsizei n,GLuint *arrays);
刪除n個在arrays中定義的頂點數(shù)組對象默赂,這樣所有的名稱可以再次用作頂點數(shù)據(jù)沛鸵。如果綁定頂點數(shù)組已經(jīng)被刪除,那么當(dāng)前綁定的頂點數(shù)組對象被重設(shè)為0(類似執(zhí)行了glBindBuffer()函數(shù)缆八,并且輸入?yún)?shù)為0)曲掰。默認的頂點數(shù)組會變成當(dāng)前對象。在arrays當(dāng)中未使用的名稱都會被釋放耀里,但是當(dāng)前頂點數(shù)組的狀態(tài)不會發(fā)生任何變化
為了保證程序的完整性蜈缤,可以調(diào)用gllsVertexArray()檢查某個名稱釋放已經(jīng)被保留為一個頂點數(shù)組對象了。
GLboolean gllsVertexArray(GLuint array);
如果array是一個已經(jīng)用GLgenVertexArrays()創(chuàng)建且沒有被刪除的頂點數(shù)組對象的名稱冯挎,那么返回GL_TRUE,如果array為0或者不是任何頂點數(shù)組對象的名稱底哥,那么返回GL_FALSE;
分配頂點緩存對象
頂點數(shù)組對象負責(zé)保存一系列的數(shù)據(jù),這些數(shù)據(jù)保存到緩沖對象中房官,并且由當(dāng)前綁定的頂點數(shù)組對象管理趾徽。緩存對象就是OpenGL 服務(wù)端分配和管理的一個塊內(nèi)存區(qū)域,并且?guī)缀跛袀魅氲腛penGL的數(shù)據(jù)都存儲在緩存對象當(dāng)中翰守。
頂點緩沖對象的初始化過程與頂點數(shù)組對象的創(chuàng)建過程類似孵奶,不過需要有向緩存添加數(shù)據(jù)的一個過程。
1.創(chuàng)建頂點緩存對象的名稱
void glGenBuffers(GLsizei n,GLuint *buffers);
返回n個當(dāng)前未使用的緩存對象名蜡峰,并保存到buffers數(shù)組中了袁。返回到buffers中的名稱不一定是連續(xù)的整型數(shù)據(jù)。
這里返回的名稱只用于分配其他緩存對象湿颅,它們在綁定之后只會記錄一個可用狀態(tài)载绿。
0是一個保留的緩存對象名稱,glGenBuffers()永遠都不會返回這個值的緩存對象油航。
2.綁定緩存對象
由于OpenGL 中有很多不同類型的緩存對象崭庸,因此綁定一個緩存時,需要指定對應(yīng)的類型谊囚。
1.指定當(dāng)前激活/綁定的對象
void glBindBuffer(GLenum target,GLunit buffer);
參數(shù)target的類型:GL_ARRAY_BUFFER怕享、GL_ELEMENT_ARRAY_BUFFER、GL_PIXEL_PACK_BUFFER镰踏、GL_PIXEL_UNPACK_BUFFER函筋、GL_COPY_READ_BUFFER、GL_COPY_WRITE_BUFFER奠伪、GL_TRANSFORM_FEEDBACK_BUFFER驻呐、GL_UNIFORM_BUFFER灌诅。
頂點數(shù)據(jù)緩存使用GL_ARRAY_BUFFER
參數(shù)buffer:綁定的緩存對象名稱
glBindBuffer完成3項工作:1.如果是第一次綁定buffer,且它是一個非零無符號整型,那么將創(chuàng)建一個與該名稱相對應(yīng)的新緩存對象含末。2.如果綁定到是一個已經(jīng)創(chuàng)建的緩存對象,那么它將成為當(dāng)前被激活的緩存對象即舌。3.如果綁定的buffer值為0佣盒,那么OpenGL將不在對當(dāng)前target應(yīng)用任何緩存對象。
2.釋放緩存
void glDeleteBuffers(GLSizei n,const GLuint *buffers);
刪除n個保存在buffer數(shù)組中的緩存對象顽聂。被釋放的緩存對象可以重用肥惭。
如果刪除的緩存已經(jīng)綁定,那么該對象所以綁定將會重置為默認緩存對象紊搪,即相當(dāng)于用0作為參數(shù)執(zhí)行g(shù)lBindBuffer()蜜葱,如果試圖刪除不存在的緩存對象,或者緩存對象為0耀石,那么將忽略該操作(不會產(chǎn)生錯誤)
3.判斷一個整數(shù)值是否是一個緩存對象的名稱牵囤。
GLboolean gllsBuffer(GLuint buffer);
如果buffer是一個已經(jīng)分配并且沒有釋放的緩存對象名稱,則返回GL_TRUE滞伟。如果buffer為0或者不是一個緩存對象的名稱揭鳞,則返回GL_FALSE。
將數(shù)據(jù)載入緩存對象
初始化頂點緩存對象之后梆奈,我們需要把頂點數(shù)據(jù)從對象傳輸?shù)骄彺鎸ο笾幸俺纭_@一步步是通過glBufferData()來實現(xiàn)的。它主要有2個任務(wù):分配頂點數(shù)據(jù)所需的存儲空間亩钟,然后將數(shù)據(jù)從應(yīng)用程序的數(shù)組拷貝到OpenGL 服務(wù)端的內(nèi)存中
glBufferData(GLenum target,GLsizeiptr size,const GLVoid *data,Glenum usage);
當(dāng)OpenGL 服務(wù)端內(nèi)存中分配size個存儲單元(通常都是byte)乓梨,用于存儲數(shù)據(jù)或者索引。如果當(dāng)前綁定的對象已經(jīng)存在了關(guān)聯(lián)數(shù)據(jù)清酥,那么首先會刪除這些數(shù)據(jù)扶镀。
參數(shù)target:
頂點屬性數(shù)據(jù),GL_ARRAY_BUFFER;
索引數(shù)據(jù)总处,索引數(shù)據(jù)狈惫,GL_ELEMENT_ARRAY_BUFFER;
從OpenGL 中獲取的像素數(shù)據(jù)鹦马,GL_PIXEL_PACK_BUFFER胧谈;
OpenGL 的像素數(shù)據(jù)GL_PIXEL_UNPACK_BUFFER;
對于緩存直接的復(fù)制數(shù)據(jù)荸频,GL_COPY_READ_BUFFER菱肖、GL_COPY_WRITE_BUFFER;
對于通過transform feedback 著色器獲得結(jié)果旭从,GL_TRANSFORM_FEEDBACK_BUFFER稳强、
一致變量场仲,GL_UNIFORM_BUFFER。
對于紋理緩存中存儲的紋理數(shù)據(jù)退疫,GL_TEXTURE_BUFFER
參數(shù)size:存儲數(shù)據(jù)的總數(shù)量渠缕,data存儲元素的總數(shù)*單位元素存儲空間
參數(shù)data: 客戶端內(nèi)存的指針,以便初始化緩存對象褒繁,要么是NULL,如果傳入的指針合法亦鳞,那么將會有size個大小的數(shù)據(jù)從客戶端拷貝到服務(wù)端。如果傳入的是NULL,那么將保留size大小的未初始化的數(shù)據(jù)棒坏,以備后用燕差。
如果所需的size大小超過了服務(wù)端能夠分配的額度,那么glBufferData()將產(chǎn)生一個GL_OUT_OF_MEMORY錯誤坝冕。如果usage設(shè)置的不是可用的模式值徒探,那么會產(chǎn)生GL_INVALID_VALUE錯誤。
一下子理解這么多內(nèi)容喂窟,可能會有些困難测暗。但是這些函數(shù)在后面的課程學(xué)習(xí)中會重復(fù)多次出現(xiàn)。
初始化頂點與片元著色器
對于每一個OpenGL 程序谎替,當(dāng)使用的OpenGL 版本高于或者等于3.1時偷溺,都需要指定至少2個著色器:頂點著色器 和 片元著色器。
對于OpenGL程序員而言钱贯,著色器使用OpenGL著色語言(OpenGL shading Language,GLSL)編寫的小型函數(shù)挫掏。GLSL是構(gòu)成所有OpenGL著色器的語言。它與C++語言非常類似秩命。用GLSL中的所有特性并不能用于OpenGL每一個著色階段尉共。當(dāng)我們可以以字符串的形式傳輸GLSL著色器到OpenGL。
為了讓學(xué)員更容易使用著色器開發(fā)弃锐,我們選擇將著色器字符串的內(nèi)存保存到文件袄友,并且使用LoadShaders()讀取文件和創(chuàng)建OpenGL著色程序。