【前端視覺化】 OpenGL / WebGL 入門和實踐

文章推薦指數: 80 %
投票人數:10人

OpenGL ES 是OpenGL 的子集,專門針對手機/PDA(掌上電腦,如: 條形掃碼器,POS機等)/遊戲主機等嵌入式裝置設計的。

OpenGL ES 主要直接提供C api,各自平臺 ... MdEditor 【前端視覺化】OpenGL/WebGL入門和實踐 語言:CN/TW/HK 時間 2019-10-2108:58:27 code祕密花園 主題: OpenGL WebGL 作者:竇金蘭  —位元組跳動IES前端工程師   希望通過這篇文章,大家能夠對OpenGL/WebGL有一個基礎的認識~~ OpenGL 定義 OpenGL是一套規範,不是介面,學習這套規範,就可以在支援OpenGL的機器上正常使用這些規範,在顯示器上看到繪製的結果。

這套介面是Khronos這個組織在維護。

怎麼維護呢?就是寫一個說明書,指導各個GPU廠家,如果他們要支援OpenGL的話,要怎麼實現一個具體的OpenGL庫。

比如Khronos說要實現glDrawArray這個介面,那麼硬體廠家就得在它的庫裡實現這個介面。

如果不實現,那麼就不算支援OpenGL。

當然也有一些介面不一定要實現。

廠家實現的OpenGL庫的內容,其實就是廠家自己的團隊整合自己的圖形知識以及GPU硬體的指令,這些OpenGL的實現通常被稱為“驅動”,它們負責將OpenGL定義的API命令翻譯為GPU指令。

因此使用時只需要安裝顯示卡的驅動。

既然是在GPU上執行的OpenGL,那麼接下來我們來了解一下GPU~ GPU 概念 顯示卡處理器稱為圖形處理器(即GPU),它是顯示卡的“心臟”,與CPU類似,只不過GPU是專為執行復雜的數學和幾何計算而設計的,這些計算是圖形渲染所必需的。

一些最快速的GPU整合的電晶體數甚至超過了普通CPU。

GPU的工作 現代的GPU功能涵蓋了圖形顯示的方方面面,這裡只取一個簡單的方向作為例子。

這個立方體渲染的例子,會有助於理解接下來會講到的GLSL(OpenGL著色器)語言。

大家可能都見過上面這張圖,這是老版本DirectX(是由微軟公司建立的一系列專為多媒體以及遊戲開發的應用程式介面)的一項測試,就是一個旋轉的立方體。

顯示出一個這樣的立方體要經過很多步驟,我們先考慮簡單一點的,想象一下他只是一個線框,沒有側面的“X”影象。

再簡化一點,連線都沒有,就是八個點(立方體有八個頂點的)。

那麼問題就簡化成如何讓這八個點轉起來。

首先,在創造這個立方體的時候,肯定有八個頂點的座標,座標都是用向量表示的,因而至少也是個三維向量。

然後“旋轉”這個變換,線上性代數裡面是用一個矩陣來表示的。

向量旋轉,是用向量乘以這個矩陣。

把這八個點轉一下,就是進行八次向量與矩陣的乘法而已。

這種計算並不複雜,拆開來看無非就是幾次乘積加一起,就是計算量比較大。

八個點就要算八次,2000個點就要算2000次。

這就是GPU工作的一部分,頂點變換,這也是最簡單的一部分。

通過這個例子可以先思考一下,想要渲染出一個圖形,就需要告訴GPU圖形的頂點(即座標向量),如果需要變化(如:平移、旋轉、縮放等),就需要告之對應的矩陣,這也就是文章後面要說的GLSL語言核心需要做的事情~ CPU與GPU區別大揭祕 CPU和GPU因為最初用來處理的任務就不同,所以設計上有很大的區別。

它們分別針對了兩種不同的應用場景。

CPU需要很強的通用性來處理各種不同的資料型別,同時又要邏輯判斷又會引入大量的分支跳轉和中斷的處理。

這些都使得CPU的內部結構異常複雜。

而GPU面對的則是型別高度統一的、相互無依賴的大規模資料和不需要被打斷的純淨的計算環境。

於是CPU和GPU就呈現出非常不同的架構(示意圖): 其中綠色的是計算單元,橙紅色的是儲存單元,橙黃色的是控制單元。

GPU採用了數量眾多的計算單元和超長的流水線,但只有非常簡單的控制邏輯並省去了Cache。

而CPU不僅被Cache佔據了大量空間,而且還有有複雜的控制邏輯和諸多優化電路,相比之下計算能力只是CPU很小的一部分。

而GPU的工作大部分就是這樣,計算量大,但沒什麼技術含量,而且需要重複很多次。

就像你有個工作需要算幾億次一百以內加減乘除一樣,最好的辦法就是僱上幾十個小學生一起算,一人算一部分,反正這些計算也沒什麼技術含量,純粹體力活,人海戰術而已。

而CPU則像老教授,積分微分都會算,一個老教授資頂二十個小學生。

GPU就是這樣,用很多簡單的計算單元去完成大量的計算任務。

不過這種策略基於一個前提,就是每個小學生工作沒有什麼依賴性,是互相獨立的,即GPU的計算單元所做的事情是互相獨立的。

還有一些任務涉及到步驟的問題,不能把執行順序顛倒了。

這種比較複雜的問題都是CPU來做的。

GPU的運算速度取決於僱了多少小學生,CPU的運算速度取決於請了多厲害的教授。

教授處理複雜任務的能力是碾壓小學生的,但是對於沒那麼複雜的任務,還是人多力量大。

不過現在的GPU也能做一些稍微複雜的工作,但還是需要CPU把資料給GPU才能開始幹活,因此還是靠CPU來管的。

至此為止,GPU的內容先了解到這裡,接下來我們繼續回到OpenGL。

OpenGLES OpenGLES與WebGL有關,WebGL是基於OpenGLES2.0的JavascriptAPI,因此我們在這裡先來了解一下OpenGLES。

OpenGLES是OpenGL的子集,專門針對手機/PDA(掌上電腦,如:條形掃碼器,POS機等)/遊戲主機等嵌入式裝置設計的。

OpenGLES主要直接提供Capi,各自平臺根據習慣提供一層包裝(比如Android提供了Java的包裝,iOS提供了obj-c的包裝)。

雖然OpenGLES是OpenGL的子集,但是OpenGL與OpenGLES還是有一點區別,比如他們的資料型別會存在一些不一樣: OpenGLES沒有double型(浮點)資料型別,而是加入了高效能的定點小數資料型別; OpenGLES沒有glBegin/glEnd/glVertex,只能用glDrawArrays/glDraw......; 沒有實時將非壓縮圖片資料轉成壓縮貼圖的功能,程式必須直接提供壓縮好的貼圖; ... 可實現濾鏡效果:chestnut: 這裡可以簡單看一些直接使用OpenGL實現的濾鏡效果 縮放、出竅、抖動、閃白、毛刺 灰度、旋渦、馬賽克 分屏 注意:這些直接使用OpenGL實現濾鏡效果的例子可以瞭解一下,但是團隊專案中使用到的濾鏡效果是通過effectsdk統一支援(Windows/Mac/Android/iOS),因此如果需要實現effectcreatorforweb,則需要在瀏覽器支援effectsdk的使用,以保證多端統一,且支援現有功能效果。

至此,除了GLSL語言以及具體API,OpenGL的基礎知識就這麼多了。

OpenGL是在移動端/桌面端使用,那麼在Web端呢?就是大家熟悉的WebGL了,我們一起來看一下~ WebGL 一些WebGL應用場景:chestnut: 3D的資料視覺化 kaspersky 3D遊戲開發 WebCamMesh webglgames CubeSlam 打造炫酷的互動 WebGLbookcase H5宣傳頁面&廣告 淘寶雙11VR邀請函H5頁面 進行3D產品/物體展示 WebGLreflection ... 概念 WebGL是一種3D繪圖標準,這種繪圖技術標準把JavaScript和OpenGLES2.0結合在一起,通過HTML5的Canvas來和DOM打交道,為HTML5Canvas提供硬體3D加速渲染。

WebGL技術標準免去了開發網頁專用渲染外掛的麻煩,可被用於建立具有複雜3D結構的網站頁面,甚至可以用來設計3D網頁遊戲等。

與OpenGL的關係 通過上述概念可以看出,WebGL將JavaScript和OpenGLES2.0結合在一起,因此也會使用GLSL(OpenGLShaderLanguage)作為ShadingLanguage(一種頂點計算和著色的語言,快取編譯到GPU,由GPU來執行)。

說白了,就是通過瀏覽器提供的介面,我們能夠直接和底層的OpenGL庫打交道。

由於能直接呼叫底層介面,並且有硬體加速,因此WebGL要比普通的Canvas2DApi效能要高出不少。

這裡有一個WebGL和Canvas2DApi效能的對比實驗結果,橫座標是繪製任務數量,縱座標是頁面的FPS(畫面每秒傳輸幀數)。

從結果中可見,當需要執行大量繪製任務時,WebGL的效能遠遠超越了Canvas2DApi,達到了後者的3~5倍。

Three.js 為什麼會介紹一下這個庫,是因為在學習WebGL知識時總會看到一個庫:Three.js,那我們這裡也來簡單的瞭解一下。

Three.js是一個用於在瀏覽器中繪製3D圖形的JS庫,其底層實際是對瀏覽器提供的WebGLApi進行了封裝,類似於JS與JQuery的關係,甚至不需要WebGL基礎就能夠上手使用,但是由於是以WebGL為基礎,所以遇到問題還得回來檢視WebGL,而WebGL的基礎又是OpenGLES,因此OpenGL就顯得至關重要了。

OpenGL很重要,而OpenGL還有一個重要部分就是前面多次提到的GLSL(OpenGL著色器語言),接下來我們就來看看這個著色器語言究竟是什麼吧~~ GLSL著色器語言 首先要明白,著色器(Shader)是執行在GPU上的小程式。

這些小程式為圖形渲染管線的某個特定部分而執行。

從基本意義上來說,著色器只是一種把輸入轉化為輸出的程式,比如我們要畫一個三角形,著色器只是通過讀取我們傳給它的頂點,顏色,變化等輸入,然後經過一系列計算,最終輸出圖形。

著色器主要分為頂點著色器和片段(畫素)著色器,這也是主要的兩種著色器,還有一種是幾何著色器。

每個著色器是非常獨立的程式,它們之間不能相互通訊,唯一的溝通只能通過輸入和輸出。

通常一個WebGL應用會有多個著色程式。

我們可以根據著色起的名字來思考一下他們的作用。

頂點著色器,顧名思義就是為了渲染圖形的頂點所使用的,回想一下我們剛才講的GPU的工作,一個立方體的渲染,肯定是先要找到立方體的頂點,這個就是頂點著色器的作用了。

頂點找到後,就會連線成線,以及形成平面,那麼線段/平面的顏色等就是片段著色器的工作了。

著色器是使用一種叫GLSL的類C語言寫成的。

GLSL是為圖形計算量身定製的,它包含一些針對向量和矩陣操作的有用特性。

資料型別: 修飾符: 這裡只是簡單介紹了一下常用概念,關於GLSL概念的詳解,可以看一下這裡 我們在GPU的工作一節提到過,座標都是向量表示,變化(比如:旋轉/平移/縮放等)都是通過矩陣表示,回到大學線性代數知識,向量(a1=[x1,y1,z1])與矩陣相乘,就會得到另一個向量(a2=[x2,y2,z2]),a1通過矩陣運算,得到了a2,這樣就改變了座標的位置。

看到這裡就明白了,如何通過計算得出我們想要的結果,就需要線性代數的知識了。

(PS:矩陣真的很神奇,幾乎一切變化都從這裡來,在最後的例子中帶大家來看看矩陣帶來的魔法吧) 看完著色器的基本知識後,我們就可以看一下渲染的過程了。

WebGL渲染過程 WebGLAPI 在瞭解一門新技術前,我們都會先看看它的開發文件或者API。

於是,我們檢視WebGL繪圖API,發現: 是的,它只能畫點、線、三角形。

就算是像下面這樣的複雜模型,也是一個個三角形畫出來的。

簡單繪製流程 簡單說來,WebGL繪製過程包括以下三步: 獲取頂點座標(使用頂點著色器) 圖元裝配(這裡畫出一個個三角形,gl.TRIANGLES) 光柵化(生成片元/片段,即一個個畫素點,使用片段/畫素著色器) 接下來,我們分步講解每個步驟。

頂點座標 頂點座標從何而來呢?一個立方體還好說,但如果是像上邊複雜的茶壺呢?想一下,每個三角形都有三個頂點,而一個茶壺就會有成千上萬個頂點,而且還需要精密的計算,顯然人的肉眼以及精力是不允許一個一個寫這些座標的。

往往它使用三維軟體(C4D、MAYA、3DSmax等)匯出,或者是框架生成。

獲取頂點座標過程圖: 前面兩個步驟都很好理解,但是第三部寫入快取區是什麼意思呢?由於頂點資料往往成千上萬,在獲取到頂點座標後,我們通常會將它儲存在快取區內,方便GPU更快的讀取。

圖元裝配 我們已經知道,圖元裝配就是由頂點生成一個個圖元(即點/線/三角形)。

那這個過程是自動完成的嗎?答案是並非完全如此。

WebGL需要我們先處理頂點,那怎麼處理呢?我們先看下圖: 第一步就是將上面快取中的頂點座標傳入了頂點著色器,頂點著色器根據傳入的gl.POINTS/gl.LINES/gl.TRIANGLES引數,進行圖元裝配(通俗一點講,就是要畫點,還是線,還是三角形) 下面是一段頂點著色器程式碼: 這裡具體解釋一下:attribute修飾符,是由瀏覽器(javascript)傳輸給頂點著色器的變數值修飾符;vec4就是包含4個元素的浮點型向量(座標);position即我們定義的頂點座標,傳入到著色器的;gl_Position是一個內建的傳出變數。

這段程式碼其實就是GPU通過傳入的資料找頂點的過程。

光柵化 和圖元裝配類似,光柵化也是可控的。

在圖元生成完畢之後,我們需要給模型“上色”,模型看起來是什麼質地(顏色、漫反射、貼圖等)、燈光等,而完成這部分工作的,則是執行在GPU的“片元著色器”來完成。

如下是一段簡單的片元著色器程式碼: precision是指向一個整數的指標,返回的該整數是對應格式的精度的位數,用log2取對數的值,暫不做深究。

gl_FragColor是一個內建的傳出變數,即輸出的顏色值,這段程式碼就是紫粉色。

片元著色器處理流程 片元著色器具體是如何控制顏色生成的呢? 如上圖,頂點著色器是有多少頂點,運行了多少次,而片元著色器則是,有多少片元(畫素),執行多少次。

整體詳細繪製流程 至此,實質上,WebGL經歷瞭如下處理流程(這裡我們涉及到的前面沒講到的名詞稍微多一點,但是大概涵蓋了所有涉及到的內容): 準備資料階段在這個階段,我們需要提供頂點座標、索引(三角形繪製順序)、uv(決定貼圖座標)、法線(決定光照效果),以及各種矩陣(比如投影矩陣)。

如何傳入? 頂點資料儲存在快取區(因為數量巨大),以修飾符attribute傳遞給頂點著色器; 矩陣則以修飾符uniform傳遞給頂點著色器。

生成頂點著色器根據我們需要,由Javascript定義一段頂點著色器程式的字串,生成並且編譯成一段著色器程式傳遞給GPU。

傳入的頂點著色器程式,是一個字串,這是WebGLAPI所要求的,會進行編譯成著色器語言。

我們來大致看一下看一下。

圖元裝配GPU根據頂點數量,挨個執行頂點著色器程式,生成頂點最終的座標,完成座標轉換。

生成片元著色器這一步則是解決我們最終繪製出來的效果,它的模型是什麼顏色,看起來是什麼質地,光照效果,陰影(流程較複雜,需要先渲染到紋理,可以先不關注),都在這個階段處理。

光柵化通過第4步生成了片元著色器,因此GPU內部已經確定好了每個片元的顏色,然後根據深度快取區判斷哪些片元被擋住了,不需要渲染,最終將片元資訊儲存到顏色快取區,最終完成整個渲染。

WebGL入門例項 通過一些小例子,學會使用WebGL基礎知識 例1:簡單的畫一個三角形,學會從WebGL到著色器的全過程 [可參看這裡] 步驟: 獲取canvas,以及webglcontext 編寫著色器(字串形式) 建立頂點/片段著色器 將頂點/片段著色器連結在一起 將位置的座標放入buffer中,因為著色器從buffer讀取資料 傳入繪製需要的資料(比如2D/3D緩衝位置等) 開始繪製 例2:通過例1進行簡單的修改,一個變色三角形 [可參看這裡https://webglfundamentals.org/webgl/lessons/zhcn/webgl-how-it-works.html] 例3:只能畫點/線/三角形的WebGL如何畫一個矩形呢?[可參看這裡https://webglfundamentals.org/webgl/lessons/zh cn/webgl-fundamentals.html] 例4:繪製一張圖片呀,再加一點魔法 [可參看這裡https://webglfundamentals.org/webgl/lessons/zhcn/webgl-image-processing.html] 例5:給圖片施更多的魔法(矩陣的神奇力量) [可參看這裡https://webglfundamentals.org/webgl/lessons/zh cn/webgl-image-processing-continued.html] 例6:二維平移/旋轉/縮放(二維矩陣的由來看這裡https://webglfundamentals.org/webgl/lessons/zh_cn/webgl-2d-matrices.html) 其實最重要的就是頂點座標,因為片段著色器只是將頂點按照所需圖元連線,因此平移/旋轉/縮放只需計算出變化後的頂點座標即可 WebGL入門篇大概就講到這裡,相信大家對基礎已經有了一定的瞭解,但是WebGL還有很多知識,比如投影/光源/相機/三維呈現等,有興趣的可以接下來了解。

相關資料 OpenGL中文教程OpenGLESOpenGL書籍: 紅寶書 OpenGLProgrammingGuide,出到第八版 藍寶書 OpenGLSuperBible,出到第六版 橙寶書 OpenGLShadingLanguage,出到第三版 更多 一個易懂的WebGL教程:WebGLFundamentalsWebGLMDN 相關文章圖解WebGL與Threejs工作原理與CPU的區別是什麼,渲染是否是平行計算的? 「其他文章」 React的一些最佳安全實踐 有哪些值得學習的大型React開源專案? Get一種可以用來裝逼的JavaScript編碼風格 rollup最佳實踐!可除錯、編譯的小型開源專案思路 HTTP新增的103狀態碼,這次終於派上用場了! 如何做一個壞面試官? WWDC2022:哪些是前端開發者要關注的資訊? 一行Object.keys()引發的思考 從零到一建立一套完整的前端規範 Web應用開發進化論 助你成為CSS大師的18個GitHub倉庫 2022年的前端行業,咋樣啦? 邊緣渲染是如何前端效能的? 前端歷史專案的Vite遷移實踐總結 如何逼瘋專案經理,照著這10條做就成了 fencedframe可以替代iframe嗎? JavaScript陣列新增4個非破壞性方法! 比eval和iframe更強的新一代JavaScript沙箱! 2022年的React生態 前端架構設計中如何做好技術決策? 「OpenGL」 IOSOpenGLESGPUImage影象透明混合GPUImageAlphaBlendFilter IOSOpenGLESGPUImage影象混合GPUImageNormalBlendFilter IOSOpenGLESGPUImage影象陰影和深度效果GPUImageMultiplyBlendFilter 輕鬆入門OpenGLES——這或許是你遇過最難畫的三角形(一) AMD新驅動優化OpenGL,R76800U跑分提升12% AMDAdrenalin22.7.1驅動更新:OpenGL效能翻倍,支援微軟Win1122H2系統 輕鬆入門OpenGLES——再談OpenGL工作機制 OpenGLES設計指南(上) AndroidOpenGL開發——EGL詳解 OpenGLES程式設計指南(下) 「WebGL」 WebGL第二十課:位移很奇怪及其矩陣表達(涉及數學推導)|8月更文挑戰 【零基礎】充分理解WebGL(七) 【零基礎】充分理解WebGL(六) 【零基礎】充分理解WebGL(五) 單向資料流的真正甜蜜 【零基礎】充分理解WebGL(四) 【零基礎】充分理解WebGL(三) 【零基礎】充分理解WebGL(二) 【零基礎】充分理解WebGL(一) CesiumDrawCommand[1]不談地球畫個三角形



請為這篇文章評分?