OpenGL初識
圖形API簡介
- OpenGL(Open Graphics Library):一個跨編程語言、跨平臺的圖形程序接口,它將計算機(jī)的資源抽象稱為一個個OpenGL的對象,對這些資源的操作抽象為?個個的OpenGL指令。
-
OpenGL ES (OpenGL for Embedded Systems):是
OpenGL三維圖形API的子集,針對?手機(jī)、PDA和游戲主機(jī)等嵌?式設(shè)備而設(shè)計,OpenGL ES為了支持新改進(jìn)的方法拋棄了對于舊式的低效的內(nèi)存復(fù)制操作的支持。 -
DirectX:是由很多API組成的,
DirectX并不是一個單純的圖形API。最重要的是DirectX是屬于Windows上?個多媒體處理API。并不支持Windows以外的平臺,所以不是跨平臺框架。按照性質(zhì)分類,可以分為四?大部分,顯示部分、聲?部分、輸入部分和網(wǎng)絡(luò)部分。 -
Metal:Apple為游戲開發(fā)者推出了了新的平臺技術(shù)
Metal,該技術(shù)能夠?yàn)?D圖像提高10倍的渲染性能。Metal是Apple為了解決3D渲染?而推出的框架。
圖形API的功能:實(shí)現(xiàn)圖形的底層渲染
- 在游戲開發(fā)中,對于游戲場景/游戲?物的渲染
- 在?音視頻開發(fā)中,對于視頻解碼后的數(shù)據(jù)渲染
- 在地圖引擎,對于地圖上的數(shù)據(jù)渲染
- 在動畫中,實(shí)現(xiàn)動畫的繪制
- 在視頻處理理中,對于視頻加上濾鏡效果
OpenGL名詞注解
GPU:圖形處理單元,圖形卡上的可編程芯片,它是高度并行的,并且具有非常快的速度。能夠結(jié)合幾何、顏色、燈光和其他數(shù)據(jù)而產(chǎn)生一個屏幕圖像的硬件組件。
渲染:屏幕只有2維,因此顯示3D數(shù)據(jù)的技巧就在于產(chǎn)生能夠迷惑眼睛使其看到丟失的第3維的一個圖像。將數(shù)學(xué)和圖形數(shù)據(jù)轉(zhuǎn)換成3D空間圖像的操作叫做渲染。
像素:在計算機(jī)上顯示的圖片是由矩形的顏色點(diǎn)組成的,這些矩形的顏色點(diǎn)叫做像素。單獨(dú)的像素,如果通過放大鏡仔細(xì)觀察顯示器,你會看到每個像素都是由3個顏色元素組成的,即一個紅點(diǎn)、一個綠點(diǎn)和一個藍(lán)點(diǎn)。
緩存:
OpenGL ES為兩個內(nèi)存區(qū)域間的數(shù)據(jù)交換定義了緩存(buffers)的概念。緩存是指 圖形處理器能夠控制和管理的連續(xù)RAM。
程序從 CPU 的內(nèi)存復(fù)制數(shù)據(jù)到 OpenGL ES 的緩存。在 GPU 取得一個緩存的所有權(quán)以后,運(yùn)行在 CPU 中的程序理想情況下將不 再接觸這個緩存。通過控制獨(dú)占的緩存,GPU 就能夠盡可能以最有效的方式讀寫內(nèi)存。 圖形處理器把它處理大量數(shù)據(jù)的能力異步同時地應(yīng)用到緩存上,這意味著在 GPU 使用 緩存中的數(shù)據(jù)工作的同時,運(yùn)行在 CPU 中的程序可以繼續(xù)執(zhí)行。
OpenGL上下文(context):用于配置OpenGL的保存在特定平臺的軟件數(shù)據(jù)結(jié)構(gòu)中的信息會被封裝到一個OpenGL上下文(context)中。OpenGL是一個狀態(tài)機(jī)器,這意味著在一個程序中設(shè)置了一個配置值后,這個值會一直保持,直到程序修改了這個值。切換上下文往往會產(chǎn)生較大的開銷,但是不同的繪制模塊,可能需要使用完全獨(dú)立的狀態(tài)管理。因此,可以在應(yīng)用程序中分別創(chuàng)建多個不同的上下?,在不同線程中使用不同的上下文,上下文之間共享紋理、緩沖區(qū)等資源。這樣的方案,會?反復(fù)切換上下文,或者大量修改渲染狀態(tài),更加合理高效的。
-
OpenGL狀態(tài)機(jī)
- 狀態(tài)機(jī)是一個抽象的模型,表示一組狀態(tài)變量的集合。每個狀態(tài)變量可以有各種不同的值,或者只能可以打開或關(guān)閉等。當(dāng)我們在OpenGL中進(jìn)行繪圖時,如果每次都要指定所有這些變量顯然有點(diǎn)不切實(shí)際。反之,OpenGL使用了一種狀態(tài)模型(或稱狀態(tài)機(jī))來追蹤所有的OpenGL狀態(tài)變量。當(dāng)一個狀態(tài)值被設(shè)置之后,它就一直保持這個狀態(tài),直到其他函數(shù)對它進(jìn)行修改為止。許多狀態(tài)只能簡單地打開或關(guān)閉。例如,深度測試就是要么打開、要么關(guān)閉。
- OpenGL可以記錄自己的狀態(tài)(比如:當(dāng)前所使用的顏色、是否開啟了混合功能,等等,這些都是要記錄的)
- OpenGL可以接收輸入(當(dāng)我們調(diào)用OpenGL函數(shù)的時候,實(shí)際上可以看成OpenGL在接收我們的輸入),根據(jù)輸入的內(nèi)容和自己的狀態(tài),修改自己的狀態(tài),并且可以得到輸出(比如我們調(diào)用glColor3f,則OpenGL接收到這個輸入后會修改自己的“當(dāng)前顏色”這個狀態(tài);我們調(diào)用glRectf,則OpenGL會輸出一個矩形)
- OpenGL可以進(jìn)入停止?fàn)顟B(tài),不再接收輸入。這個可能在我們的程序中表現(xiàn)得不太明顯,不過在程序退出前,OpenGL總會先停止工作的。
頂點(diǎn)(空間中的一個位置):在2D和3D中,當(dāng)我們繪制一個物體時,實(shí)際上是用一些更小的稱為圖元(Primitives)的形狀來組成這個物體。圖元是一維或者二維的實(shí)體或表面,如點(diǎn)、直線和多邊形(平面多邊的形狀)。在3D空間中,我們把圖元組合在一起創(chuàng)建3D物體。例如一個三維立方體是由6個正方形組成,每個正方形代表一個獨(dú)立的面。正方形(其他任何圖元)的每個角稱為頂點(diǎn)(Vertex)。這些頂點(diǎn)就在3D空間中指定了一個特定的坐標(biāo)。頂點(diǎn)其實(shí)就是2D或3D空間中的一個坐標(biāo)。
頂點(diǎn)數(shù)組:一個頂點(diǎn)(vertex)就是一個坐標(biāo)空間的點(diǎn)。頂點(diǎn)數(shù)組就是存儲這一個圖形的所有頂點(diǎn)數(shù)據(jù)的一段緩存。
-
管線:
- OpenGL的模型就好比一條生產(chǎn)線或者管線。數(shù)據(jù)流在這個模型中通常是單一路經(jīng)的,數(shù)據(jù)通過我們的程式調(diào)用的命令進(jìn)入管線的開端,然后流過一個一個階段直到管線的末端。
- OpenGL通過連接多個叫做著色器的小程序并佐以固定功能函數(shù)作為"膠水"來工作。當(dāng)我們繪圖時,圖形處理器執(zhí)行我們的著色器并將它們的輸入輸出在管線中串聯(lián)起來,直到像素完成于管線末端。
-
固定管線/存儲著色器
- 在早期的OpenGL版本,它封裝了很多種著色器程序塊內(nèi)置的一段包含了光照、坐標(biāo)變換、裁剪等等諸多功能的固定shader程序來完成,來幫助開發(fā)者來完成圖形的渲染而開發(fā)者只需要傳入相應(yīng)的參數(shù),就能快速完成圖形的渲染。
- 但是由于OpenGL的使用場景非常豐富,固定管線或存儲著色器無法完成每一個業(yè)務(wù)。這時將相關(guān)部分開放成可編程。
-
著色器程序shader
- 就全面的將固定渲染管線架構(gòu)變?yōu)榱丝删幊啼秩竟芫€。因此,OpenGL在實(shí)際調(diào)用繪制函數(shù)之前,還需要指定一個由shader編譯成的著色器程序。常見的著色器主要有頂點(diǎn)著色器(VertexShader),片段著色器(FragmentShader)/像素著色器(PixelShader) ,幾何著色器(GeometryShader)曲面細(xì)分著色器(TessellationShader)。片段著色器和像素著色器只是在OpenGL和DX中的不同叫法而已??上У氖?,直到OpenGL ES 3.0,依然只支持了頂點(diǎn)著色器和片段著色器這兩個最基礎(chǔ)的著色器。
- OpenGl在處理Shader時,和其他編譯器一樣。通過編譯、鏈接等步驟,生成了著色器程序(glProgram),著色器程序同時包含了頂點(diǎn)著色器和片段著色器的運(yùn)算邏輯。在0penGL進(jìn)行繪制的時候,首先由頂點(diǎn)著色器對傳入的頂點(diǎn)數(shù)據(jù)進(jìn)行運(yùn)算。再通過圖元裝配,將頂點(diǎn)轉(zhuǎn)換為圖元。然后進(jìn)行光柵化,將圖元這種矢量圖形,轉(zhuǎn)換為柵格化數(shù)據(jù)。最后,將柵格化數(shù)據(jù)傳入片段著色器中進(jìn)行運(yùn)算。片段著色器會對柵格化數(shù)據(jù)中的每一個像素進(jìn)行運(yùn)算,并決定像素的顏色。
-
頂點(diǎn)著色器VertexShader
- 用來處理圖形每個頂點(diǎn)變換(旋轉(zhuǎn)/平移/投影等)。
- 頂點(diǎn)著色器是逐頂點(diǎn)運(yùn)算的程序,也就是說每個頂點(diǎn)數(shù)據(jù)都會執(zhí)行一次頂點(diǎn)著色器,當(dāng)然這是并行的,并且頂點(diǎn)著色器運(yùn)算過程中無法訪問其他頂點(diǎn)的數(shù)據(jù)。
- 典型的需要計算的頂點(diǎn)屬性主要包括頂點(diǎn)坐標(biāo)變換、逐頂點(diǎn)光照運(yùn)算等等。頂點(diǎn)坐標(biāo)由自身坐標(biāo)系轉(zhuǎn)換到歸一化坐標(biāo)系的運(yùn)算,就是在這里發(fā)生的。
-
片元著色器程序FragmentShader
- 用來處理圖形中每個像素點(diǎn)顏色的計算和填充的程序。
- 它是逐像素運(yùn)算的程序,也就是說每個像素都會執(zhí)行一次片段著色器,當(dāng)然也是并行的。
GLSL(OpenGL Shadding Language):OpenGL著色器使用一種叫做OpenGL著色語言(OpenGL Shading Language)的語言進(jìn)行編寫,或者叫做GLSL。這個語言的編譯器內(nèi)置在OpenGl中。
光柵化Rasterization:實(shí)際繪制或填充每個頂點(diǎn)之間的像素形成線段就叫做光柵化。
紋理:一個用來保存圖像的顏色元素值的 OpenGL ES 緩存。
混合Blending:像素的顏色將會和幀緩沖區(qū)中顏色附著上的顏色進(jìn)行混合,混合的算法可以通過0penGL的函數(shù)進(jìn)
行指定。變幻矩陣:計算圖形發(fā)生變化的矩陣。
投影矩陣:用于將3D坐標(biāo)轉(zhuǎn)換為2D坐標(biāo),并在2D下繪制。
-
渲染上屏/交換緩沖區(qū):
- 一般窗口上顯示的是某個渲染緩沖區(qū)的資源,如果直接在這個緩沖區(qū)中進(jìn)行渲染,在渲染過程中,窗口會顯示不完整的圖像。
- 所以O(shè)penGL程序都至少使用兩個緩沖區(qū),在窗口中看到的是屏幕緩沖區(qū),還有一個不顯示的離屏幕緩沖區(qū)。在離屏緩沖區(qū)渲染完成后,通過離屏緩沖區(qū)和屏幕緩沖區(qū)進(jìn)行數(shù)據(jù)交換實(shí)現(xiàn)屏幕顯示。
- 屏幕的刷新一般是逐行進(jìn)行的。如果一次刷新未結(jié)束時進(jìn)行了兩個緩沖區(qū)交換,圖像就會錯亂,一部分是舊圖的內(nèi)容,一部分是新圖的內(nèi)容。因此,交換需要等到屏幕發(fā)出刷新完成的信號,這個信號叫垂直同步信號,這個技術(shù)就是垂直同步技術(shù)。
- 在使用雙緩沖區(qū)和垂直同步技術(shù)的情況下,離屏渲染完成后收到垂直同步信號并交換緩沖區(qū)后才能進(jìn)行下一幀的渲染。這樣無法達(dá)到最高的幀率,硬件性能產(chǎn)生了浪費(fèi)。因此,引入了三緩沖區(qū)技術(shù)。等待垂直同步信號時,交替渲染兩個離屏緩沖區(qū),屏幕刷新完成后,屏幕渲染區(qū)和最近完成渲染的離屏緩沖區(qū)交換。
OpenGL坐標(biāo)系解析
在一個簡單的平面計算機(jī)屏幕上繪制點(diǎn)和線時,我們根據(jù)行和列指定位置。
在OpenGL或幾乎所有的3D PAI中創(chuàng)建一個用于繪制的窗口時,必須指定希望使用的坐標(biāo)系統(tǒng)以及指定的坐標(biāo)如何映射到實(shí)際的屏幕像素。
2D笛卡爾坐標(biāo)系
在二維繪圖中,最常用的是笛卡爾坐標(biāo)系統(tǒng)。笛卡爾坐標(biāo)由一個x坐標(biāo)和y坐標(biāo)構(gòu)成。x坐標(biāo)測量水平方向的位置,y坐標(biāo)測量垂直方向的位置。x軸和y軸垂直相交定義了一個平面。
3D笛卡爾坐標(biāo)系
2D笛卡爾坐標(biāo)新增一個表示深度分量的z軸就是3D笛卡爾坐標(biāo)。
視口
視口就是窗口內(nèi)部用于繪制裁剪區(qū)域的客戶區(qū)域。視口簡單的把裁剪區(qū)域映射到窗口中的一個區(qū)域。通常,視口被定義為整個窗口,但這并非嚴(yán)格必須的。
有時我們只想在窗口的一部分部分進(jìn)行繪圖。我們可以使用視口來縮小和放大窗口中的圖像,也可以通過把視口設(shè)置大于窗口的用戶區(qū)域,從而只顯示裁剪區(qū)域的一部分。
投影方式
首先需要理解投影:把3D幾何圖形的坐標(biāo)數(shù)據(jù)投影在一個2D的平面。就像用筆在玻璃上描摹出玻璃后面的物體的外形。而平面上的投影就是視景體。通過指定投影,我們可以指定在窗口中顯示的視景體。
正投影
正投影又叫平行投影。使用這種投影時,需要指定一個正方形或長方形的視景體。視景體之外的任何物體都不會被繪制。而且,所有實(shí)際大小相同的物體在屏幕上都具有相同的大小,不管它們是遠(yuǎn)是近。
我們還可以在正投影中通過指定遠(yuǎn)、近、左、右、頂和底裁剪平面來指定視景體。在這個視景體中出現(xiàn)的物體和圖形將被投影( 考慮它們的方向)到一個在屏幕上出現(xiàn)的2D圖像。
透視投影
在透視投影中,遠(yuǎn)處的物體看上去比近處的物體更小一些。它的視景體看上去有點(diǎn)像一個頂部被削平的金字塔。剩下來的這個形狀稱為平截頭體( Frustum)??拷暰绑w前面的物體看上去比較接近它們的原始大小。但是,當(dāng)靠近視景體后部的物體被投影到視景體的前部時,它們看上去就顯得比較小。在模擬和3D動畫中,這種投影能夠獲得最大程度的逼真感。