為了在各平臺(tái)實(shí)現(xiàn)圖形圖像的高效渲染,減少開發(fā)者的重復(fù)工作,出現(xiàn)了一批優(yōu)秀的API,如下簡單的介紹一下這些API。
1. OpenGL
- OpenGL(Open Graphics Library泊窘,開放圖形庫)是用于渲染2D、3D矢量圖形的跨語言、跨平臺(tái)的應(yīng)用程序編程接口(API)谭羔。它將計(jì)算機(jī)的資源抽象成為一個(gè)個(gè)OpenGL對(duì)象干厚,對(duì)這些資源的操作抽象為一個(gè)個(gè)的OpenGL指令莉撇。
2.OpenGL ES
- OpenGL ES(OpenGL for Embedded Systems)是OpenGL三維圖形API的子集鳖眼,針對(duì)手機(jī)、PDA和游戲主機(jī)等嵌入式設(shè)備而設(shè)計(jì)祭衩,去除了許多不必要和性能較低的API接口灶体。
- OpenGL ES是從OpenGL裁剪的定制而來的,去除了glBegin/glEnd掐暮,四邊形(GL_QUADS)蝎抽、多邊形(GL_POLYGONS)等復(fù)雜圖元等許多非絕對(duì)必要的特性。
3.DirectX
- DirectX(Direct eXtension路克,簡稱DX)是由微軟公司創(chuàng)建的多媒體編程接口樟结。由C++編程語言實(shí)現(xiàn)养交,遵循COM。不支持Windows以外的平臺(tái)瓢宦,所以不是跨平臺(tái)框架碎连。
- 他們旨在使基于Windows的計(jì)算機(jī)成為運(yùn)行和顯示具有豐富多媒體元素(例如全色圖形、視頻驮履、3D動(dòng)畫和豐富音頻)的應(yīng)用程序的理想平臺(tái)鱼辙。
- DirectX是由很多API組成的,不是一個(gè)單純的圖形API玫镐。按照性質(zhì)分類座每,可以分為四大部分,顯示部分摘悴、聲音部分、輸入部分和網(wǎng)絡(luò)部分舰绘。
4.Metal
- Apple為游戲開發(fā)者推出了了新的平臺(tái)技術(shù) Metal蹂喻,該技術(shù)能夠?yàn)?3D 圖像提高10倍的渲染性能。
- Metal 是Apple為了解決3D渲染?推出的框架捂寿。在2014年以前蘋果一直沿用OpenGL ES 來解決底層渲染口四,而后開始慢慢將自身底層框架的依賴從OpenGL ES遷移到Metal,但其核心的處理思想還是源于OpenGL ES秦陋。對(duì)于適應(yīng)于OpenGL ES的開發(fā)者而言并沒有太大的改變蔓彩。
OpenGL 專業(yè)名詞解析
1. OpenGL狀態(tài)機(jī)
狀態(tài)機(jī)是理論上的一種機(jī)器。狀態(tài)機(jī)描述了一個(gè)對(duì)象在其生命周期內(nèi)所經(jīng)歷的各種狀態(tài)驳概,狀態(tài)間的轉(zhuǎn)變赤嚼,發(fā)生轉(zhuǎn)變的動(dòng)因,條件及轉(zhuǎn)變中所執(zhí)行的活動(dòng)顺又。或者說更卒,狀態(tài)機(jī)是一種行為。說明對(duì)象在其生命周期中響應(yīng)事件所經(jīng)歷的狀態(tài)序列以及對(duì)那些狀態(tài)的響應(yīng)稚照。因此具有以下特點(diǎn):
- 有記憶功能蹂空,能記住其當(dāng)前的狀態(tài)。
- 可以接收輸入果录,根據(jù)輸入的內(nèi)容和自己的原先狀態(tài)上枕,修改自己當(dāng)前狀態(tài),并且可以有對(duì)應(yīng)輸出弱恒。
- 當(dāng)進(jìn)入特殊狀態(tài)(停機(jī)狀態(tài))的時(shí)候辨萍,便不再接收輸入,停止工作斤彼。
類推到OpenGL 中來,可以這么理解:
- OpenGL可以記錄自己的狀態(tài)(如當(dāng)前所使用的顏色分瘦、是否開啟了混合功能等)蘸泻;
- OpenGL可以接收輸入(當(dāng)調(diào)用OpenGL函數(shù)的時(shí)候,實(shí)際上可以看成OpenGL在接收我們的輸入)嘲玫,如我們調(diào)用glColor3f悦施,則OpenGL接收到這個(gè)輸入后會(huì)修改自己的“當(dāng)前顏色”這個(gè)狀態(tài);
- OpenGL可以進(jìn)入停止?fàn)顟B(tài)去团,不再接收輸入抡诞。在程序退出前,OpenGL總會(huì)先停止工作的土陪。
可以使用glColor * 函數(shù)來選擇一種顏色昼汗,以后繪制的所有物體都是這種顏色,除非再次使用glColor * 函數(shù)重新設(shè)定鬼雀。
可以使用glTexCoord * 函數(shù)來設(shè)置一個(gè)紋理坐標(biāo)顷窒,以后繪制的所有物體都是采用這種紋理坐標(biāo),除非再次使用glTexCoord * 函數(shù)重新設(shè)置源哩。
可以使用glBlendFunc函數(shù)來指定混合功能的源因子和目標(biāo)因子鞋吉,以后繪制的所有物體都是采用這個(gè)源因子和目標(biāo)因子,除非再次使用glBlendFunc函數(shù)重新指定励烦。
可以使用glLight*函數(shù)來指定光源的位置谓着、顏色,以后繪制的所有物體都是采用這個(gè)光源的位置坛掠、顏色赊锚,除非再次使用glBlendFunc函數(shù)重新指定。
OpenGL是一個(gè)狀態(tài)機(jī)屉栓,它保持自身的狀態(tài)舷蒲,除非用戶輸入一條命令讓它改變狀態(tài)。
2. OpenGL上下文(context)
在應(yīng)?程序調(diào)?任何OpenGL的指令之前友多,首先需要?jiǎng)?chuàng)建?個(gè)OpenGL的上下?阿纤。這個(gè)上下?是?個(gè)?常龐?的狀態(tài)機(jī),保存了OpenGL中的各種狀態(tài)夷陋,這也是OpenGL指令執(zhí)?的基礎(chǔ)欠拾。
OpenGL的函數(shù)不管在哪個(gè)語?中,都是類似C語?一樣的面向過程的函數(shù)骗绕。本質(zhì)上都是對(duì)OpenGL上下?這個(gè)龐?的狀態(tài)機(jī)中的某個(gè)狀態(tài)或者對(duì)象進(jìn)行操作藐窄。通過對(duì) OpenGL指令的封裝,可以將OpenGL的相關(guān)調(diào)?封裝成為?個(gè)?向?qū)ο蟮膱D形API酬土。
由于OpenGL上下?是?個(gè)巨大的狀態(tài)機(jī)荆忍,切換上下文往往會(huì)產(chǎn)生較?的開銷,但是不同的繪制模塊,可能需要使?完全獨(dú)立的狀態(tài)管理刹枉。因此叽唱,可以在應(yīng)?程序中分別創(chuàng)建多個(gè)不同的上下文,在不同線程中使?不同的上下文微宝,上下?之間共享紋理棺亭、緩沖區(qū)等資源。這樣的方案蟋软,會(huì)比反復(fù)切換上下?镶摘,或者?量修改渲染狀態(tài),更加合理高效岳守。
OpenGL指令執(zhí)?的基礎(chǔ)凄敢,是?個(gè)?常龐?的狀態(tài)機(jī)。
OpenGL上下文切換開銷大湿痢。雖然可能使用多個(gè)上下文涝缝,但上下文之間會(huì)共享紋理、緩沖區(qū)等資源譬重。
OpenGL的函數(shù)雖然是面向過程的俊卤,但可以把相關(guān)的調(diào)用封裝為面向過程的圖形API。
3. 渲染
將圖形/圖像數(shù)據(jù)轉(zhuǎn)換成3D空間圖像操作叫做渲染(Rendering)害幅。
4. 頂點(diǎn)數(shù)組(VertexArray)和頂點(diǎn)緩沖區(qū)(VertexBuffer)
頂點(diǎn)數(shù)據(jù)就是圖像的輪廓。OpenGL中的圖像都是由圖元組成岂昭。在OpenGL ES中以现,有3種類型的圖元:點(diǎn)、線约啊、三?形邑遏。
在調(diào)?繪制?法的時(shí)候,直接由內(nèi)存?zhèn)魅腠旤c(diǎn)數(shù)據(jù)恰矩,也就是說這部分?jǐn)?shù)據(jù)之前是存儲(chǔ)在內(nèi)存當(dāng)中的记盒,被稱為頂點(diǎn)數(shù)組(VertexArray)。
?性能更高的做法是外傅,提前分配?塊顯存纪吮,將頂點(diǎn)數(shù)據(jù)預(yù)先傳?到顯存當(dāng)中。這部分的顯存萎胰,就被稱為頂點(diǎn)緩沖區(qū)(VertexBuffer)碾盟。
5. 管線
在OpenGL下渲染圖形,就會(huì)經(jīng)歷?個(gè)?個(gè)的節(jié)點(diǎn)技竟。而這樣的操作可以理解為管線冰肴。就像一個(gè)流?線,任務(wù)按照先后順序依次執(zhí)行。管線是?個(gè)抽象的概念熙尉,之所以稱之為管線是因?yàn)轱@卡在處理數(shù)據(jù)的時(shí)候是按照一個(gè)固定的順序來的联逻,而且嚴(yán)格按照這個(gè)順序。
6. 固定管線/存儲(chǔ)著色器
在早期的OpenGL版本检痰,封裝了多種著色器程序塊包归,內(nèi)置了一段包含了光照、坐標(biāo)變換攀细、裁剪等諸多功能的固定shader程序來完成箫踩。來幫助開發(fā)者來完成圖形的渲染。開發(fā)者只需要傳入相應(yīng)的參數(shù)谭贪,就能快速完成圖形的渲染境钟。類似于iOS開發(fā)會(huì)封裝很多API,而我們只需要調(diào)?俭识,就可以實(shí)現(xiàn)功能慨削,不需要關(guān)注底層實(shí)現(xiàn)原理。
但是由于OpenGL的使?場景?常豐富套媚,固定管線或存儲(chǔ)著?器?法完成每一 個(gè)業(yè)務(wù)缚态,這時(shí)將相關(guān)部分開放成可編程。
7. 著?器程序(Shader)
著色器程序塊開放編程后就全面的將固定渲染管線架構(gòu)變?yōu)榱丝删幊啼秩竟芫€堤瘤。因此玫芦,OpenGL在實(shí)際調(diào)用繪制函數(shù)之前,還需要指定一個(gè)由shader編譯成的著色器程序本辐。常見的著色器主要有頂點(diǎn)著色器(VertexShader)桥帆,片段著色器(FragmentShader)/像素著色器(PixelShader),幾何著色器(GeometryShader)慎皱,曲面細(xì)分著色器(TessellationShader)老虫。片段著色器和像素著色器只是在OpenGL和DX中的不同叫法而已∶6啵可惜的是祈匙,直到OpenGLES 3.0,依然只支持了頂點(diǎn)著色器和片段著色器這兩個(gè)最基礎(chǔ)的著色器天揖。
OpenGL在處理shader時(shí)夺欲,和其他編譯器一樣。通過編譯今膊、鏈接等步驟洁闰,生成了著色器程序(glProgram),著色器程序同時(shí)包含了頂點(diǎn)著色器和片段著色器的運(yùn)算邏輯万细。在OpenGL進(jìn)行繪制的時(shí)候扑眉,首先由頂點(diǎn)著色器對(duì)傳入的頂點(diǎn)數(shù)據(jù)進(jìn)行運(yùn)算纸泄。再通過圖元裝配,將頂點(diǎn)轉(zhuǎn)換為圖元腰素。然后進(jìn)行光柵化聘裁,將圖元這種矢量圖形,轉(zhuǎn)換為柵格化數(shù)據(jù)弓千。最后衡便,將柵格化數(shù)據(jù)傳入片段著色器中進(jìn)行運(yùn)算。片段著色器會(huì)對(duì)柵格化數(shù)據(jù)中的每一個(gè)像素進(jìn)行運(yùn)算洋访,并決定像素的顏色
8. 頂點(diǎn)著?器(VertexShader)
一般用來處理圖形每個(gè)頂點(diǎn)變換(旋轉(zhuǎn)/平移/投影等)
頂點(diǎn)著色器是OpenGL中用于計(jì)算頂點(diǎn)屬性的程序镣陕。頂點(diǎn)著色器是逐頂點(diǎn)運(yùn)算的程序,也就是說每個(gè)頂點(diǎn)數(shù)據(jù)都會(huì)執(zhí)行一次頂點(diǎn)著色器姻政,當(dāng)然這是并行的呆抑,并且頂點(diǎn)著色器運(yùn)算過程中無法訪問其他頂點(diǎn)的數(shù)據(jù)。
一般來說典型的需要計(jì)算的頂點(diǎn)屬性主要包括頂點(diǎn)坐標(biāo)變換汁展、逐頂點(diǎn)光照運(yùn)算等鹊碍。頂點(diǎn)坐標(biāo)由自身坐標(biāo)系轉(zhuǎn)換到歸一化坐標(biāo)系的運(yùn)算,就是在這里發(fā)生的食绿。
9. 片元著?器(FragmentShader)
一般用來處理圖形中每個(gè)像素點(diǎn)顏色計(jì)算和填充
片元著色器是OpenGL中用于計(jì)算片段(像素)顏色的程序侈咕。片元著色器是逐像素運(yùn)算的程序,也就是說每個(gè)像素都會(huì)執(zhí)行一次片元著色器器紧,當(dāng)然也是并行的耀销。
10. GLSL(OpenGL Shading Language)
GLSL著色語?是?來在OpenGL中著?編程的語?,是在圖形卡的GPU上執(zhí)?的铲汪。代替了固定的渲染管線的?部分熊尉,使渲染管線中不同層次具有可編程性。?如:視圖轉(zhuǎn)換桥状、投影轉(zhuǎn)換等。GLSL(GL Shading Language)的著?器代碼分成2個(gè)部分: Vertex Shader(頂點(diǎn)著?器)和Fragment(?斷著?器)硝清。
11. 光柵化(Rasterization)
光柵化就是把頂點(diǎn)數(shù)據(jù)轉(zhuǎn)換為片元的過程辅斟。具有將圖轉(zhuǎn)化為?個(gè)個(gè)柵格組成的圖象的作?,特點(diǎn)是每個(gè)元素對(duì)應(yīng)幀緩沖區(qū)中的?像素芦拿。
光柵化其實(shí)是?種將?何圖元變?yōu)槎S圖像的過程士飒。該過程包含了兩部分的?作。第?部分工作:決定窗?坐標(biāo)中的哪些整型柵格區(qū)域被基本圖元占?蔗崎;第?部分?作:分配一個(gè)顏?值和?個(gè)深度值到各個(gè)區(qū)域酵幕。
把物體的數(shù)學(xué)描述以及與物體相關(guān)的顏色信息轉(zhuǎn)換為屏幕上用于對(duì)應(yīng)位置的像素及?于填充像素的顏?,這個(gè)過程稱為光柵化缓苛。這是?個(gè)將模擬信號(hào)轉(zhuǎn)化為離散信號(hào)的過程芳撒。
12. 紋理(Texture)
紋理可以理解為圖?。 在渲染圖形時(shí)需要在頂點(diǎn)圍成的區(qū)域中填充圖?,使得場景更加逼真笔刹。?這?使?的圖?芥备,就是常說的紋理。只是在OpenGL舌菜,我們更加習(xí)慣叫紋理萌壳,?不是圖?。
13. 混合(Blending)
在測試階段之后日月,如果像素依然沒有被剔除袱瓮,那么像素的顏?將會(huì)和幀緩沖區(qū)中顏?附著上的顏色進(jìn)?混合,混合的算法可以通過OpenGL的函數(shù)進(jìn)行指定爱咬。但是OpenGL提供的混合算法有限尺借,如果需要更加復(fù)雜的混合算法,一般可以通過片段著?器進(jìn)?實(shí)現(xiàn)台颠,當(dāng)然性能會(huì)?原?的混合算法差?些褐望。
14. 矩陣
- 變換矩陣(Transformation)
例如圖形想發(fā)?平移、縮放串前、旋轉(zhuǎn)等變換瘫里,就需要使用變換矩陣。
- 投影矩陣(Projection)
?于將3D坐標(biāo)轉(zhuǎn)換為?維屏幕坐標(biāo)荡碾,實(shí)際線條也將在二維坐標(biāo)下進(jìn)行繪制谨读。
15. 渲染上屏/交換緩沖區(qū)(SwapBuffer)
渲染緩沖區(qū)?般映射的是系統(tǒng)的資源?如窗?。如果將圖像直接渲染到窗口對(duì)應(yīng)的渲染緩沖區(qū)坛吁,則可以將圖像顯示到屏幕上劳殖。
值得注意的是,如果每個(gè)窗?只有?個(gè)緩沖區(qū)拨脉,那么在繪制過程中屏幕進(jìn)?了刷新哆姻,窗?可能顯示出不完整的圖像。
為了解決這個(gè)問題玫膀,常規(guī)的OpenGL程序?少都會(huì)有兩個(gè)緩沖區(qū)矛缨。顯示在屏幕上的稱為屏幕緩沖區(qū),沒有顯示的稱為離屏緩沖區(qū)帖旨。在一個(gè)緩沖區(qū)渲染完成之后箕昭,通過將屏幕緩沖區(qū)和離屏緩沖區(qū)交換,實(shí)現(xiàn)圖像在屏幕上顯示解阅。
由于顯示器的刷新?般是逐?進(jìn)?的落竹,為了防?交換緩沖區(qū)的時(shí)候屏幕上下區(qū)域的圖像分屬于兩個(gè)不同的幀,因此交換一般會(huì)等待顯示器刷新完成的信號(hào)货抄,在顯示器兩次刷新的間隔中進(jìn)?交換述召,這個(gè)信號(hào)就被稱為垂直同步信號(hào)朱转,這個(gè)技術(shù)被稱為垂直同步。
使用了雙緩沖區(qū)和垂直同步技術(shù)之后桨武,由于總是要等待緩沖區(qū)交換之后再進(jìn)?下?幀的渲染肋拔,使得幀率無法完全達(dá)到硬件允許的最??平。為了解決這個(gè)問題呀酸,引?了三緩沖區(qū)技術(shù)凉蜂。在等待垂直同步時(shí),來回交替渲染兩個(gè)離屏的緩沖區(qū)性誉,?垂直同步發(fā)生時(shí)窿吩,屏幕緩沖區(qū)和最近渲染完成的離屏緩沖區(qū)交換,實(shí)現(xiàn)充分利?硬件性能的?的错览。