OpenGL/OpenGL ES 初探

佐籩發表於2019-05-13

OpenGL/OpenGL ES 初探(一)

當初接觸OpenGL的時候,也關注到了蘋果爸爸棄用的問題,心裡想著,蘋果爸爸都棄用了OpenGL/Open LG ES,那麼學這東西還有什麼用呢?

Apple宣佈iOS12.0棄用OpenGL/CL

值得注意的是: 1、蘋果自身的系統遷移到Metal是花費了4年時間 2、在沒有推出Metal時,蘋果對於OpenGL ES是高度整合且配合相應圖層和GLKit來輔助開發者能快速使用OpenGL ES 3、OpenGL ES的棄用,只是針對蘋果內部系統底層API依賴而言,並不是想讓iOS開發者從此不使用OpenGL ES。只是角色變成了第三方,畢竟它的跨平臺以及穩定是很難讓現有的開發放棄,而這幾點Metal目前很難做到 4、目前大多數類似百度地圖、高德地圖和音視訊處理的專案組已經很龐大了,暫時不會遷移到Metal,所以只學習Metal是不夠用的 5、所以學習需要一步一步的走OpenGL -> OpenGL ES -> Metal,這個也是親身體會,之前嘗試過上來就學GPUImage或者是OpenGL ES,但是僅僅停留在會用,但是不知道原理,所以先要打好基礎

本篇文章的目的

  • 快速瞭解圖形API
  • 快速瞭解OpenGL下專業名詞

圖形API

圖形API簡介

  • OpenGL(Open Graphics Library):是一個跨程式語言、跨平臺的程式設計圖形程式介面,它將計算機的資源抽象稱為一個個OpenGL的物件,對這些資源的操作抽象為一個個的OpenGL指令。

  • OpenGL ES(OpenGL for Embedded Systems):是OpenGL三維圖形API的子集,針對手機、PDA和遊戲主機等嵌入式裝置而設計的,去除了許多不必要和效能較低的API介面。

  • DirectX:是由很多API組成的,DirectX並不是一個單純的圖形API。最重要的是DirectX是屬於Windows上一個多媒體處理API。並不支援Windows以外的平臺,所以不是跨平臺框架。按照性質分類,可分為四大部分,顯示部分、聲音部分、輸入部分和網路部分。

  • Metal:Apple為遊戲開發者推出了新的平臺技術,該技術能夠為3D影像提高10倍的渲染效能。Metal是Apple為解決3D渲染而推出的框架

圖形API的目的是解決什麼問題

簡單的說就是實現圖形的底層渲染

  • 比如在遊戲開發中,對遊戲場景/遊戲任務的渲染
  • 比如在音視訊開發中,對於視訊解碼後的資料渲染
  • 比如在地圖引擎,對於地圖上的資料渲染
  • 比如在動畫中,實現動畫的繪製
  • 比如在視訊處理中,對於視訊加上濾鏡效果

本質:就是利用GPU晶片來高效渲染圖形影像 圖形API是iOS開發者唯一接近GPU的方式

OpenGL下專業名詞解析

OpenGL上下文 context

  • 在應用程式呼叫任何OpenGL的指令之前,需要先建立一個OpenGL的上下文context。這個上下文是一個非常龐大的狀態機,儲存了OpenGL中的各種狀態,這也是OpenGL指令執行的基礎

  • OpenGL的函式不管在哪個語言中,都是類似C語言一樣的程式導向的函式,本質上都是對OpenGL上下文這個龐大的狀態機中的某個狀態或者物件進行操作,當然你得首先把這個物件設定為當前物件。因此,通過對OpenGL指令的封裝,是可以將OpenGL的相關呼叫封裝成為一個物件導向的圖形API

  • 由於OpenGL上下文是一個巨大的狀態機,切換上下文往往會產生較大的開銷,但是不同的繪製模組,可能需要使用完全獨立的狀態管理。因此,可以在應用程式中分別建立多個不同的上下文,在不同執行緒中使用不同的上下文,上下文之間共享紋理、緩衝區等資源。這樣的方案,會比反覆切換上下文,或者大量修改渲染狀態更加合理高效

OpenGL 狀態機

  • 狀態機理論上是一種機器,它描述了一個物件在其生命週期內所經歷的各種狀態,狀態間的轉變、傳送轉變的動因、條件以及轉變中所執行的活動。或者說,狀態機是一種行為,即物件在其生命週期中響應事件所經歷的狀態序列以及對那些狀態事件的響應。具有一下特點:

    • 有記憶功能,能夠記住當前的狀態
    • 可以接收輸入,根據輸入的內容和自己的原先狀態,修改自己當前狀態,並且可以有對應輸出
    • 當進入特殊狀態(停機狀態)的時候,便不再接收輸入,即停止工作
  • 電腦可以說就是典型的狀態機

    • 電腦的儲存器(記憶體、硬碟等),可以記住電腦自己當前的狀態(當前暗轉在電腦中的軟體、儲存在電腦中的資料、電腦當前的設定等,其實都是二進位制的值,都屬於當前的狀態)
    • 電腦的輸入裝置接收輸入(鍵盤、滑鼠、檔案輸入),根據輸入的內容和自己的狀態(主要指可以執行的程式程式碼),修改自己的狀態(修改記憶體中的值),並且可以得到輸出(將結果顯示到螢幕)
    • 當它進入到特殊狀態(關機狀態)的時候,便不再接收輸入,停止工作
  • 類推到OpenGL中,可以這麼理解

    • OpenGL可以記錄自己的狀態(如當前所使用的顏色、是否開啟了混合功能等)
    • OpenGL可以接收輸入(呼叫OpenGL函式時,可以理解成OpenGL在接收輸入),如呼叫glColor3f,即OpenGL接收到這個輸入後,會修改自己的“當前顏色”這個狀態
    • OpenGL可以進入停止狀態,不再接收輸入。在程式退出前,OpenGL總會先停止工作

OpenGL是一個狀態機,它保持自身的狀態,除非使用者輸入一條命令讓它改變狀態

渲染

將圖形/影像資料轉換成3D空間影像操作叫做渲染Rendering

頂點陣列VertexArray和頂點緩衝區VertexBuffer

  • 頂點: 指的是在繪製一個圖形時,它的頂點位置資料,而這個資料可以直接存粗在陣列中或者將其快取到GPU記憶體中

  • OpenGL中的影像都是由圖元組成,在OpenGL ES中,有3種型別的圖元:點、線、三角形。開發者可以選擇設定函式指標,在呼叫繪製方法的時候,直接由記憶體傳入頂點資料,也就是說這部分資料之前是儲存在記憶體當中的,被稱為頂點陣列。而效能更高的做法是提前分配一塊視訊記憶體,將頂點資料預先傳入到視訊記憶體當中,這部分的視訊記憶體,就被稱為頂點緩衝區

管線

  • 管線:可以理解為渲染流水線。實際上指一堆原始圖形資料途徑一個輸送管道,期間經過各種變化處理最終出現在螢幕的過程。

  • 在OpenGL下渲染圖形,就會經歷一個一個節點。而這樣的操作可以理解為管線。可以想象成流水線,每個任務類似流水線一樣執行,任務之間有先後順序。之所以稱之為管線是因為顯示卡在處理資料的時候是按照一個固定的順序來的,而且嚴格按照這個順序。就像水從一根管子的一端留到另一端,這個順序不能打破。

  • 固定管線:簡單理解為渲染影像這個過程,我們只能通過呼叫GLShaderManager類的固定管線效果實現一系列的著色器處理。

  • 可程式設計管線:簡單理解為在處理圖形的過程,我們能夠使用自定義頂點著色器和片元著色器的過程。由於OpenGL的使用場景非常豐富,固定管線或者儲存著色器無法完成每一個任務,這時將相關部分開放成可程式設計

著色器程式Shader

  • 將固定渲染管線架構變成為可程式設計渲染管線。因此,OpenGL在實際呼叫繪製函式之前,還需要指定一個由shader編譯成的著色器程式。常見的著色器主要有頂點著色器(VertexShader)、片段/片元著色器(FragmentShader)/畫素著色器(PixelShader)、幾何著色器(GeometryShader)、曲面細分著色器(TessellationShader)。知道OpenGL ES3.0,依然只支援了頂點著色器和片段著色器這兩個最基礎的著色器

  • OpenGL在處理shader時,和其他編譯器一樣。通過編譯、連結等步驟,生成了著色器程式(glProgram),著色器程式同時包含了頂點著色器和片元著色器的運算邏輯。在OpenGL進行繪製的時候,首先由頂點著色器對傳入的頂點資料進行運算。在通過圖元裝配,將頂點轉換為圖元。然後進行光柵化,將圖元這種向量圖形,轉換為柵格化資料。最後,將柵格化資料傳入片元著色器中進行運算。片元著色器會對柵格化資料中的每一個畫素進行運算,並決定畫素的顏色。

頂點著色器VertexShader

  • 一般用來處理圖形每個頂點變換(旋轉/平移/投影等)

  • 頂點著色器時OpenGL中用於計算頂點屬性的程式。頂點著色器是逐頂點運算的程式,也就是說每個頂點資料都會執行一次。當然這是並行,並且頂點著色器運算過程中無法訪問其他頂點資料

  • 一般來說典型的需要計算的頂點屬性主要包括頂點座標變換、逐頂點光照運算等等。頂點座標由自身座標系轉換到規範化座標系的運算,就是在這裡發生的

片元著色器FragmentShader

  • 一般用來處理圖形中每個畫素點顏色計算和填充

  • 片元著色器是OpenGL中用於計算片段(畫素)顏色的程式,片元著色器是逐畫素運算的程式,也就說每個畫素都會執行一次片元著色器,當然也是並行的

GLSL (OpenGL Shading Language)

OpenGL著色語言是用來在OpenGL中著色編碼的語言,也就是開發人員寫的短小的自定義程式,他們是在GPU(Graphic Processor Unit圖形處理單元)上執行的,代替了固定的渲染管線的一部分,使渲染管線中不同層次具有可程式設計性。
GLSL的著色器程式碼分成2個部分: VertexShader(頂點著色器) 和 Fragment Shader(片元著色器)

光柵化 Rasterization

  • 光柵化就是把頂點資料轉換為片元的過程。具有將圖轉化為一個個柵格組成的影像的作用。片元中的每一個元素對應於幀緩衝區的一個畫素

  • 光柵化其實是一種將幾何圖元變為二維影像的過程。該過程包含了兩部分的工作。第一部分工作:決定視窗座標中的哪些整型柵格區域被基本圖元佔用;第二部分工作:分配一個顏色值和一個深度值到各個區域。光柵化過程產生的是片元

  • 把物體的數學描述以及與物體相關的顏色資訊轉換為螢幕上用於對應位置的畫素以及用於填充畫素的顏色,這個過程稱為光柵化,這是一個將模擬訊號轉化為離散訊號的過程

紋理

紋理可以理解為圖片。在渲染圖形時需要在其編碼填充圖片,為了使得場景更加逼真,而這裡使用的圖片,就是常說的紋理。在OpenGL中,更加習慣叫紋理,而不是圖片。

混合 Blending

  • 在測試階段之後,如果畫素依然沒有被剔除,那麼畫素的顏色將會和幀緩衝區中顏色附著上的顏色進行混合。混合的演算法可以通過OpenGL的函式進行指定。但是OpenGL提供的混合演算法有限的,如果需要更加複雜的混合演算法,一般可以通過畫素著色器進行實現,當然效能會比原聲的混合演算法差一些

  • 混合就是把兩種顏色混在一起。具體一點,就是把某一畫素位置原來的顏色和將要畫上去的顏色,通過某種方式混在一起,從而達到特殊的效果

變換矩陣 Transformation

圖形想發生平移、縮放、旋轉變換,就需要使用變換矩陣

投影矩陣 Projection

用於將3D座標轉換為二維螢幕座標,實際線條也將在二維座標下進行繪製

渲染上屏/交換緩衝區 SwapBuffer

渲染緩衝區一般對映的是系統的資源,比如視窗。如果將影像直接渲染到視窗對應的緩衝區,則可以將影像顯示到螢幕上。但是,值得注意的是,如果每個視窗只有一個緩衝區,那麼在繪製過程中,螢幕進行了重新整理,視窗可能顯示出不完整的影像。

常規的OpenGL程式至少都會有兩個緩衝區。顯示在螢幕上的稱為螢幕緩衝區,沒有顯示的稱為離屏緩衝區。在一個緩衝區渲染完成之後,通過將螢幕緩衝區和離屏緩衝區交換,實現影像在螢幕上顯示。

因為顯示器的重新整理一般是逐行進行的,因此為了防止交換緩衝區的時候,螢幕上下區域的影像分屬於兩個不同的幀,因此交換一般會等待顯示器重新整理完成的訊號,在顯示器兩次重新整理的間隔中進行交換,這個訊號就被稱為垂直同步訊號,這個技術被稱為垂直同步

使用了雙緩衝區和垂直同步技術之後,由於總是要等待緩衝區交換之後再進行下一幀的渲染,使得幀率無法完全達到硬體允許的最高水平,為了解決這個問題,引入了三緩衝區技術,在等待垂直同步時,來回交替渲染兩個離屏的緩衝區,而垂直同步發生時,螢幕緩衝區和最近渲染完成的離屏緩衝區交換,實現充分利用硬體效能的目的

相關文章