JavaScript WebGL 基礎概念

XXHolic發表於2021-12-01

引子

看了一個庫的原始碼,裡面用到了 WebGL ,就開始找 WebGL 的資料。發現相關的知識點很多,按照自己的理解習慣進行了整理記錄。

簡介

WebGL 是一個跨平臺、免費的開放式 Web 標準,用於基於 OpenGL ES 的初級 3D 圖形 API 。可在任何相容的 Web 瀏覽器中渲染高效能的互動式 3D 和 2D 圖形,而無需使用外掛。在 JavaScript 中可以通過 HTML5 的 Canvas 元素使用。WebGL 1.0 基於 OpenGL ES 2.0,WebGL 2.0 基於 OpenGL ES 3.0 。目前瀏覽器支援情況見Can I use WebGL ?

WebGL 官方相關引導資源見這裡,感覺瀏覽載入有些慢,單獨下載了一份到 Github : WebGL 1.0WebGL 2.0

OpenGL ES 是一個跨平臺、免費的 API ,用於在嵌入式和移動系統(包括控制檯、手機、裝置和車輛)上渲染高階 2D 和 3D 圖形。它是 OpenGL 的子集。

OpenGL 是業界最廣泛採用的 2D 和 3D 圖形 API ,為各種計算機平臺帶來了數千種應用程式。它獨立於視窗系統和作業系統。OpenGL 公開了最新圖形硬體的所有功能。

OpenGL 規範嚴格規定了每個函式該如何執行,以及它們的輸出值。至於內部具體每個函式是如何實現的,將由 OpenGL 庫的開發者自行決定,因此在不同系統中相同的 API 可能會出現表現行為不一致的情況。

OpenGL ES 對應的可程式語言是 OpenGL ES Shading Language (GLSL ES),該語言基於 OpenGL Shading Language (GLSL) 制定。GLSL 是 OpenGL 的主要著色語言,其風格類似 C 語言,是為圖形計算量身定製的,它包含一些針對向量和矩陣操作的有用特性。

下面的概念大都是關於 OpenGL ,由於 WebGL 核心還是基於 OpenGL ,同樣有助於理解。

狀態機

狀態機(FSM)是一個計算數學模型,是一個抽象的機器,能在任何給定的時間處於有限狀態中的一個。FSM 可以根據一些輸入從一種狀態改變到另一種狀態。

OpenGL 自身就是一個巨大的狀態機:一系列的變數描述 OpenGL 此刻應當如何執行。在 OpenGL 相關程式中可以看到很多全域性的變數,其中一些是輸出變數,一些輸入變數。

圖形渲染管線

在 OpenGL 中,任何事物都在 3D 空間中,而螢幕和視窗卻是 2D 畫素,這導致 OpenGL 的大部分工作都是關於把 3D 座標轉變為適應螢幕的 2D 畫素。3D 座標轉為 2D 座標的處理過程是由 OpenGL 的圖形渲染管線(Graphics Pipeline)管理。

圖形渲染管線可以被劃分為幾個階段,每個階段將會把前一個階段的輸出作為輸入。所有這些階段都是高度專門化的,並且很容易並行執行。正是由於它們具有並行執行的特性,當今大多數顯示卡都有成千上萬的小處理核心,它們在 GPU 上為每一個(渲染管線)階段執行各自的小程式,從而在圖形渲染管線中快速處理資料。這些小程式叫做著色器(Shader)。

下面是一個圖形渲染管線的每個階段的抽象展示。注意藍色部分代表可以注入自定義著色器,也就是可程式設計。

91-pipeline

作為圖形渲染管線輸入的資料叫做頂點資料(Vertex Data)。頂點資料是一系列頂點的集合。一個頂點(Vertex)是一個 3D 座標資料的集合。而頂點資料是用頂點屬性(Vertex Attribute)表示的,它可以包含任何我們想用的資料。

輸入的資料會進入到圖形渲染管線的第一個處理階段:頂點著色器。

頂點著色器

頂點著色器(Vertex Shader)可程式設計,主要的目的是把 3D 座標轉為標準化裝置座標。還會在 GPU 上建立記憶體用於儲存頂點資料,還要配置 OpenGL 如何解釋這些記憶體,並且指定其如何傳送給顯示卡。頂點著色器允許我們對頂點屬性進行一些基本處理。

頂點相關的資訊都存放在頂點緩衝物件(Vertex Buffer Objects, VBO)中,它會在 GPU 記憶體(通常被稱為視訊記憶體)中儲存大量頂點。使用這些緩衝物件的好處是可以一次性傳送一大批資料到顯示卡上,而不是每個頂點傳送一次。當資料傳送至顯示卡的記憶體中後,頂點著色器幾乎能立即訪問頂點,這是個非常快的過程。

接著進入到圖元裝配階段。

圖元裝配

圖元裝配(Primitive Assembly)將頂點著色器輸出的所有頂點作為輸入,所有的點會裝配成指定圖元的形狀。圖元基本形狀有:

  • 三角形

圖元裝配階段的輸出會傳遞給幾何著色器階段。

幾何著色器

幾何著色器(Geometry Shader)可程式設計,把圖元形式的一系列頂點的集合作為輸入,它可以通過產生新頂點構造出新的(或是其它的)圖元來生成其它形狀。

幾何著色器的輸出會被傳入光柵化階段。

光柵化

光柵化(Rasterization)會把圖元對映為最終螢幕上相應的畫素,生成供片段著色器使用的片段(Fragment)。在片段著色器執行之前會執行裁切(Clipping)。裁切會丟棄超出檢視以外的所有畫素,用來提升執行效率。

片段著色器

片段著色器(Fragment Shader)可程式設計,主要目的是計算一個畫素的最終顏色,這也是所有 OpenGL 高階效果產生的地方。通常,片段著色器包含 3D 場景的資料(比如光照、陰影、光的顏色等等),這些資料可以被用來計算最終畫素的顏色。

在所有對應顏色值確定以後,最終的物件將會被傳到最後一個階段:測試混合。

測試混合

測試混合(Tests And Blending)階段檢測片段的對應深度(和模板(Stencil))值,用它們來判斷這個畫素是其它物體的前面還是後面,決定是否應該丟棄。這個階段也會檢查 alpha 值(alpha值定義了一個物體的透明度)並對物體進行混合(Blend)。所以,即使在片段著色器中計算出來了一個畫素輸出的顏色,最後渲染的畫素顏色也可能完全不同。

WebGL 中的著色器

WebGL 中主要編寫的著色器有頂點著色器和片段著色器。具體實現見 JavaScript WebGL 繪製一條直線

參考資料

相關文章