openGL ES 教程(一):基本概念和發(fā)展歷史

1. khronos 簡介

image.png

khronos 是由 170 家企業(yè)組成的開源、非盈利的成員驅(qū)動型組織,主要負責(zé)開發(fā)、發(fā)布和維護免稅版權(quán)標(biāo)準,其范圍涉及到 3D圖像學(xué)、虛擬現(xiàn)實、增強現(xiàn)實、并行計算、視覺加速和機器學(xué)習(xí)。該組織制定的標(biāo)準及其相關(guān)的適應(yīng)性測試提高了軟件和中間軟件的創(chuàng)作,而且加速了動態(tài)多媒體的在跨平臺設(shè)備上的回放。

khronos 是 OpenGL ES 標(biāo)準的制定者、維護者,有什么疑問直接去官方找資料即可:

https://www.khronos.org/registry/OpenGL/specs

2. OpenGL 和 OpenGL ES

OpenGL ES 是 OpenGL 的子集,專門為嵌入式設(shè)備而設(shè)計,如手機端,另外 Play Station 也有使用;

嵌入式設(shè)備的因為諸多限制,比如能耗,所以 GPU 和 CPU 性能一般不如 PC 端,所以 OpenGL ES 的設(shè)計相對 OpenGL 就很精簡、高效,比較典型的區(qū)別如下:

  1. 在OpenGL ES的世界里,沒有四邊形、多邊形,無論多復(fù)雜的圖形都是由點、線和三角形組成的;
  2. 沒有g(shù)lBegin/glEnd/glVertex,只能用glDrawArrays/glDraw;
  3. 沒有double型數(shù)據(jù)類型,但加入了高性能的定點小數(shù)數(shù)據(jù)類型;
  4. 沒有實時將非壓縮圖片數(shù)據(jù)轉(zhuǎn)成壓縮貼圖(紋理)的功能,程序必須直接提供壓縮好的貼圖;
  5. 刪除了很多功能:顯示列表、求值器、索引色模式等等;
  6. glDrawArrays等函數(shù)中數(shù)據(jù)必須緊密排列,即間隔為 0;
    7.各種數(shù)據(jù)的堆棧深度較低;

3. iOS 中 OpenGL ES 的版本

在學(xué)習(xí)時,一般參考 OpenGL 的官方教程:

https://learnopengl-cn.github.io/

但是需要注意的是,OpenGL 和 OpenGL ES 還是有很大的不同,比如 #version 的聲明,所以一些圖形學(xué)的概念可以參考 openGL 中的教程,但是涉及到具體的 Api 差異或者版本問題,最好直接看 OpenGL ES 的官方文檔;

這里是 openGL 和 openGL ES 相關(guān)文檔的歸檔:
https://www.khronos.org/registry/OpenGL/specs/es/

image.png

3. version

按照 LearnOpenGL 中的示例代碼,編譯著色器時如果使用到了#version 330 core,跑在 iOS 設(shè)備上,必定是會報錯的,報錯信息大概如下:

ERROR: 0:1: '' : version '330' is not supported
ERROR: 0:1: '' : syntax error: #version

那為什么會報錯呢?原因是因為 OpenGL ES 中的 GLSL 最高版本為 320,且使用 GLSL ES 時,需要這樣:

#version number es

而 OpenGL 中,3.3 版本發(fā)生了重大更新,所以一般使用 OpenGL 3.3 版本,對應(yīng)的 GLSL 為 330,具體可以上官網(wǎng)查詢。而 OpenGL 中版本聲明一般這么寫:

#version number core

關(guān)鍵就在于版本號和 es 、core 的區(qū)別;

來看看官方文檔中的描述吧~~~

這里是 3.1.0 的版本:GLSL_ES_3.1.0

最新版本為 3.2.0,iOS 中支持的 GLSL ES 最高版本為 3.0.0,但是 version 部分基本沒什么變化,所以直接那 3.1.0 中的文檔來看了;

關(guān)于 #version 的描述如下:

image.png

比較重要的幾個結(jié)論:

  1. 必須聲明在第一行,且必須在所有預(yù)處理命令之前,且必須在注釋之前;
  2. 如果沒有聲明 version,則默認為 1.0.0 版本;
  3. 和 OpenGL 中的 GLSL 不同, #version number 后面必須加 es,以此來表明該 GLSL 為 ES 版本;

再來看看 iOS 中的 OpenGL ES,iOS 支持 openGL ES 3.0,相關(guān)文檔如下:

image.png

這里其實有待商榷,Apple 官方文檔中沒有找到 OpenGL ES 的具體版本,只知道是 OpenGL ES 3.0 以上的??梢宰鱿聹y試,如果著色器代碼中聲明 #version 320 es 被支持,也就是最新版本的 GLSL ES,是不是可以理解為:iOS 的 OpenGL ES 雖然被遺棄了,但是仍然是最新的?

測試 #version 320 es#version 310 es結(jié)果如下:

image.png

測試 #version 300 es,結(jié)果如下:

image.png

也就是說,iOS 中的 GLSL ES 版本為 3.0.0。所以,iOS 對應(yīng)的 OpenGL ES 也為 3.0.0,并不是 2019 年修訂的 3.2 版本。

4. Apple 拋棄 OpenGL

iOS 從 iphone7 + iOS12 開始就已經(jīng)拋棄了 OpenGL ES,開始主推自研的 Metal:

image.png

這里有個疑問:

已經(jīng)有現(xiàn)成的 openGL ES 了,得罪開發(fā)者,而且自己也需要額外的工作量來開發(fā)新的 Metal 框架,同時還需要底層 GPU 支持自己的 Metal 框架,這么吃力不討好的事情, Apple 為什么這么做?

其實這里可以拆解成幾個問題:

  1. OpenGL ES 是否已經(jīng)不能滿足 Apple 的需求了?
  2. 是否真的得罪開發(fā)者?
  3. Apple 是否在為自己的獨立 GPU 步道?

首先第一個問題,查閱資料之后可以確定,openGL ES 已經(jīng)無法滿足 Apple 了。因為:

  1. OpenGL ES 由 khronos 制定、發(fā)布、更新,但是該組織由很多公司組成,各公司為了自己的利益在 openGL/openGL ES 中增加擴展,需要得到的部分公司同意之后才能發(fā)布到 release 版本,所以效率極慢;
  2. openGL 和 openGL ES 已經(jīng)很久沒有更新了,而且官方已經(jīng)使用 Vulken 來替代 openGL 了。嵌入式設(shè)備端, Vulken 已經(jīng)支持嵌入式設(shè)備,并在安卓和 Flutter 上應(yīng)用,只是 Apple 有了 Metal,所以官方并沒有對其進行支持。如果想在 MacOS/iOS 上使用 Vulken,只能使用 khronos 開發(fā)的擴展來進行支持,本質(zhì)上是對 Metal 的封裝;
  3. OpenGL 擁有很多歷史包袱且支持跨平臺,那么性能必定上無法滿足 Apple 對高性能的追求。加上更新緩慢,Apple 研發(fā)自己的圖形 Api 勢在必行;

所以,對于第一個問題可以做出解答:

OpenGL/OpenGL ES 已經(jīng)有點更不上現(xiàn)在 GPU 的發(fā)展,在性能和、更新周期、Api 設(shè)計上皆無法滿足 Apple 的需求了,所以 Metal 勢在必行;

第二個問題,Apple 是否對開發(fā)者不友好?這個要從幾點來說明:

  1. Apple 從來都是以自身的發(fā)展方向作為技術(shù)選型的主要考慮,包括后面的自研芯片,因特爾的芯片因為無法跟上自己的需求被 Apple 拋棄轉(zhuǎn)向自研 M1 芯片,Metal 同樣如此;
  2. DirectX 和 Metal 一樣都是屬于面向 GPU 的圖形 Api,windows 早就這么做了,為什么現(xiàn)在 Apple 這么做就不行?
  3. OpenGL/OpenGL ES 官方都已經(jīng)拋棄并轉(zhuǎn)向 Vulken 了,這個時候怪 Apple 對開發(fā)者不友好?誰讓你在 Metal 都已經(jīng)武裝完成之后才出來 Vulken,難不成 Apple 還要一直等你或者受制于 khronos?

第三個問題,其實已經(jīng)不用回答了,從 M1 芯片的推出,Apple 幾乎已經(jīng)大通了硬件+軟件的全鏈路,自成一派了,自身的發(fā)展完全由自己掌握,包括后續(xù)的電車、增強現(xiàn)實、虛擬現(xiàn)實、機器學(xué)習(xí)、Aiot 框架等等,都可以由自己來支持。

5. 圖形學(xué)框架常見名詞和分層

常見的名詞有:

  1. Unity 3D、Cocos3D 、UE4;
  2. sika;
  3. Core Animation、Core Graphics
  4. FlutterUI、MaterialUI、UIKit;

這里以 Flutter 的圖形架構(gòu)圖來展開:

image.png

從上圖可以看出,基本上可以這樣分層:

  1. 圖形 Api

該層是面向 GPU 的圖形 Api,也就是我們上文說到的 Vulken 、DirectX 、Metal、 OpenGL/OpenGL ES。OpenGL 已經(jīng)被拋棄,所以主流的圖形 Api 也就剩下三個了。

從上文可以看到,F(xiàn)lutter 使用 OpenGL ES 對低端機器進行支持,使用 Metal 支持 iOS 平臺,使用 Vulken 支持 Android 平臺。因為 DirectX 主要用于 PC 端,自然不在其框架內(nèi)。

  1. 中間層

為什么需要中間層?

封裝的主要原因是滿足不同級別的抽象。面向 GPU 的圖形學(xué) Api 不可能直接提供給所有的開發(fā)者,所以系統(tǒng)需要為開發(fā)者提供 UI 框架。但是在開發(fā)這個框架時,也不太可能直接使用圖形 Api,因為這樣會有大量重復(fù)工作。

另外,有很多業(yè)務(wù)是不需要所有的上層開發(fā)者知道的,學(xué)習(xí)成本越低,那么框架的普及就越高效,所以就需要封裝很多流程,比如渲染機制的封裝。

所以中間層誕生了,這個主要供系統(tǒng)開發(fā)人員使用,同時也會部分提供給業(yè)務(wù)開發(fā)者;

如上圖,Core Animation 主要是封裝了渲染管線、CPU 和 GPU 的交互。蘋果的員工在開發(fā) UIKit 時,不需要自己去生成和計算頂點數(shù)據(jù)、著色器代碼,也不需要去調(diào)用很多 openGLES/Metal 的接口就可以完成渲染操作。

skia 作為 Flutter 的核心渲染框架,也是同理。因為 Flutter 是跨平臺的,所以 Skia 內(nèi)部相對于 Core Animation,必定會多出很多跨平臺判斷、兼容的代碼;

  1. UI 層

這一層就是系統(tǒng) UI 框架的最上層,面向普通的開發(fā)者。比如 iOS 中的 UIKit,MacOS 中的 AppKit,Android 中的 View、Group 等,還有 Flutter 的 Flutter UI;

開發(fā)者可以使用該層架構(gòu)提供的 Api 來快速完成 UI 相關(guān)的業(yè)務(wù),就算是新手也可以使用幾行代碼就可以展示一個 Label、Button 或者是列表;

Unity 3D 沒有使用過,個人理解,Unity 3D 類似于 UIKit 和 AppKit 框架,或者說是介于 UIKit 和 OpenGL/Metal 中間的一個框架。開發(fā)者可以使用 Unity 3D 提供的 Api 做出很多酷炫的動畫和圖形,從而簡化游戲開發(fā)或者是重度繪制 App 的開發(fā)流程。

image.png

個人更偏向于把 Unity3D 放在和 Core Animation/Skia 平級,也就是直接操作圖形 Api。Unity3D 作為跨平臺游戲引擎,自然也是完成了對 OpenGL、Metal、Vulken 的封裝。

上文中寫道,不可能面向所有的開發(fā)者提供圖形 Api,關(guān)鍵在于這個所有人的區(qū)分。工具人還是工程師,取決于你對原理了解的多少,對本質(zhì)觸及的多少,這些才最終決定了你是哪一類人。

6. Tips

image.png

總結(jié):

  1. 圖形 Api(graphics Api)是針對 GPU 的,由 GPU 廠商進行支持;GPU 廠商支持的越多,你的標(biāo)準就更容易流行并被開發(fā)者接納,亦或是像蘋果一樣,依靠自身的生態(tài)鏈自成一派;
  2. 現(xiàn)在的圖形 Api 只有三種:Metal、OpenGL、Vulken;
  3. 圖形 Api 之上還有中間層,也就是對圖形 Api 的封裝和渲染流程的封裝,有:skia(flutter)、Core Animation/Core Graphic、Canvans??類似的,游戲開發(fā)中的游戲引擎也是處于這一部分,比如 Unity3D、UE4 或 cocos2dx 都是給予對圖形 Api 的封裝而實現(xiàn)的;
  4. 在中間層之上,還有 UI Framework ,比如 UIKit 就是使用 Core Animation 或者 Core Graphic 實現(xiàn)了一套 UI。類似的還有 Android 和 Flutter 上層的 UI Framework;
  5. openGL 是最初的圖形 Api,在最早也是所有圖形繪制框架的基礎(chǔ)架構(gòu),跨平臺支持很好。但是隨著嵌入式設(shè)備的普及而嵌入式的 GPU 又沒有 PC 端那么強悍,所以只能在 openGL 上拉出一個子集來支持,也就是 openGL ES;
  6. openGL 雖然歷史悠久,跨平臺支持很好,但是存在著很多歷史包袱,另外因為跨平臺,if else 自然就會消耗性能,最后,因為 khronos 是有很多公司組成的一個組織,大家都會為了子集的利益各自為戰(zhàn),這就導(dǎo)致 openGL 更新緩慢,適應(yīng)不了一些公司的發(fā)展,所以就出現(xiàn)了 DirectX 和 Metal;
  7. Vulken 本質(zhì)上是為了 替換 openGL,所以一開始就是跨平臺的。但是 Apple 已經(jīng)有了自己的 Metal 框架,所以暫時沒有對 Vulken 進行支持,這也就讓 Vulken 的跨平臺意義大打折扣,也就讓 Vulken 和 DirectX 成為了競爭對手。
  8. 當(dāng)前除了 Apple 在 iOS/MacOS 上已經(jīng)完全拋棄了 openGL,其他平臺暫時還處于一種比較糾結(jié)和共存的狀態(tài),但是大部分 GPU 廠商已經(jīng)支持 Vulken 了,這算是一個比較好的地基;
  9. Windows PC 端,大部分游戲應(yīng)用都是給予 DirectX 開發(fā),少部分已經(jīng)支持 Valken,比如 Dota2;
  10. 安卓端,仍然是 openGL ES 為主,F(xiàn)lutter 已經(jīng)是 Vulken 和 Metal 為主了?openGL 用于支持低端機型?
  11. vulkan 相對于 openGL,Api 上更偏向于底層,這意味著可以使用 vulkan 更加自由的操作 GPU 以此來為上層提供更豐富和搞笑的功能。于此同時,開發(fā)者也需要做更多的工作,所以也就出現(xiàn)了圖形 Api 入門程序中,繪制三角形時,vulkan 的代碼遠超過 openGL/openGL ES;

7. iOS 和 OpenGL ES

幾個結(jié)論:

  1. iOS 上仍然可以使用 OpenGL ES 進行開發(fā),只不過版本最高只能使用 OpenGL ES 3.0;
  2. iOS 上如果實在對圖形 Api 有需求,趁早轉(zhuǎn) Metal;
  3. iOS 中做一些渲染優(yōu)化時,最好直接參考 Apple 的官方文檔。因為 Metal 和 OpenGL ES 的流程、設(shè)計思路都不一樣了;
  4. 要深刻認識封裝、封裝顆粒、Api 通用性設(shè)計的重要性;

比如如果 App 中有圖形 Api 的需求,就應(yīng)該基于 OpenGL ES 進行封裝,產(chǎn)生一套自有的中間框架,而且 Api 應(yīng)當(dāng)盡量屏蔽硬件層的邏輯。如果這樣做了,除非 Metal 不支持,后續(xù)更換 Metal,只需要將 OpenGL ES 的調(diào)用替換成 Metal 即可,相對而言會輕松一些;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容