首頁/ 家居/ 正文

Cocos Shader 基礎入門(一):WebGL 著色器與 GLSL 著色器語言基礎

引言:

Shader(可程式設計著色器)是用來實現影象渲染的可編輯程式。它並不是簡單的計算機應用,要想真正地掌握 Shader,需要對圖形學、圖形 API、GPU、顯示卡等都有個宏觀概念。而對大多數遊戲開發者來說,“快速”入門又是當下的迫切需求。因此,Cocos 佈道師放空整理了一個

Cocos Shader 基礎系列教程(8期入門+2期擴充套件)

,介紹 Shader 的基礎知識以及在 Cocos Creator 裡的應用,帶一些小夥伴快速入門 Shader 編寫。

在 Cocos Shader 開始之前,我會先介紹一些 Shader 基礎知識,從最淺顯的部分開始,揭開 Shader 的神秘面紗。

本次講解採用的渲染引擎是 WebGL,首先來了解一些渲染管線知識。

CPU 與 GPU 的區別

在介紹 WebGL 之前先來了解一些前置知識,也就是 CPU 和 GPU。

CPU 和 GPU 都屬於處理單元,但是結構不同。形象來說,CPU 有點像大型的傳輸管道,等待處理的任務只能依次透過,所以 CPU 處理任務的速度取決於處理單個任務的時間。又由於 CPU 內部結構異常複雜,能夠處理大量的資料和邏輯判斷,所以處理一些大型任務是足夠的。但是處理影象卻不在行,因為處理影象的邏輯通常不復雜,但是由於一幅影象是有成千上萬的畫素點構成,每個畫素的處理都是一個任務,如果由 CPU 處理,那簡直就是大材小用。

因此就需要用到 GPU。

GPU 由大量的小型處理單元構成,處理能力沒 CPU 強大,但勝在數量多,並且能夠並行處理。

渲染管線

在渲染過程中需要 CPU 和 GPU 之間的通力合作。CPU 如同進貨的卡車不斷地將要處理的資料丟給 GPU,GPU 工廠調動一個個如工人一般的計算單元對這些資料進行簡單的處理,最後組裝出產品——影象。

什麼是 WebGL?

WebGL 是一種 3D 繪圖標準,

它的本質是 JavaScript 操作 OpenGL 介面,

所以 WebGL 是在 OpenGL 的基礎上做了一層封裝,底層本質還是 OpenGL。利用 WebGL 可以根據你的程式碼繪製出點、線和三角形。任何複雜的場景都可以組合使用點、線和三角形實現。WebGL 執行在 GPU 中,因此需要使用能夠在 GPU 上執行的程式。這樣的程式需要成對提供,每對方法中都包含一個頂點著色器和一個片斷著色器,並且使用 GLSL 語言(GL 著色語言)編寫。每對組合起來稱作一個program(著色程式)。

在 WebGL 中,任何事物都處於 3D 空間中,但最終輸出呈現給觀眾的往往是螢幕或者視窗這種 2D 畫素,因此,在渲染引擎底層大部分工作都是把 3D 座標轉變成適應螢幕的 2D 畫素。3D 座標轉 2D 的處理過程是由 WebGL 的

圖形渲染管線處理

,它的主要傳輸流程分為兩步:

將 3D 座標轉換成 2D 座標

把 2D 座標轉變成實際有顏色的畫素

這兩個流程又被劃分為幾個階段處理,每個階段都會把

前一個階段的輸出作為輸入。

Cocos Shader 基礎入門(一):WebGL 著色器與 GLSL 著色器語言基礎

如上圖所見,圖形渲染管線包含多個階段,在轉換頂點資料到最終畫素的這個過程中,每個階段都將處理各自的職責部分。

接下來,簡單介紹管線各個階段的功能:

頂點資料:

頂點資料用來為後面的頂點著色器等階段提供處理的資料,

是渲染管線的資料主要來源。

送入到渲染管線的資料包括頂點座標、紋理座標、頂點法線和頂點顏色等頂點屬性,WebGL 根據渲染指令傳遞對應的圖元資訊(常見圖元包括點、線和麵)。

頂點著色器:

頂點著色器的主要功能是座標轉換。把一個單獨的頂點作為輸入,並對頂點進行從區域性座標到裁剪座標的變換,其實就是將遊戲裡操作的 3D 座標轉換成另一種 3D 座標。

Cocos Shader 基礎入門(一):WebGL 著色器與 GLSL 著色器語言基礎

圖元裝配:

圖元裝配階段將頂點著色器輸出的

所有頂點

作為輸入,根據指定的指令(點、線或面)將所有的點裝配成指定圖元的形狀。例如:提供兩個頂點時,是否要將兩個頂點連線成一條線段,以及多條線段之間是否需要連線。

Cocos Shader 基礎入門(一):WebGL 著色器與 GLSL 著色器語言基礎

光柵化:

如何使用頂點和裝配的方式將矩形表示在螢幕上,就是

光柵化

的過程。遍歷所有的畫素為止,依次判斷它們是否落入了組裝的圖形內,如果在圖形內,則對該畫素進行下一步操作(著色)。還會對非頂點的位置進行插值處理,賦予每個畫素其他的資訊。

片段著色器:

片段著色器

主要是對圖形內的片元進行著色處理,這裡也是高階效果產生的階段。通常,片段著色器包含 3D 場景的資料(比如光照、陰影、光的顏色等等),這些資料可以被用來計算最終畫素的顏色。

測試與混合:

在所有對應顏色值確定以後,最終的物件將會被傳到最後一個階段,叫做

Alpha 測試與混合

階段。這個階段檢測片段的對應的深度,用以判斷這個畫素在其它物體的前面還是後面、決定是否應該丟棄。這個階段也會檢查透明度 alpha 值,並對物體進行混合。所以,即使在片段著色器中計算出了一個畫素輸出的顏色,在渲染多個三角形的時候最後的畫素顏色也可能完全不同。

可以看出,圖形渲染管線非常複雜,簡單總結一下:WebGL 在 GPU 上的工作基本上分為兩部分,

第一部分是將頂點資料轉換到裁剪空間座標, 第二部分是基於第一部分的結果繪製畫素點。

接下來,我們一步步實踐,加深對這塊的理解。

GLSL 語言基礎

GLSL 是為圖形計算量身定製的,它包含一些針對向量和矩陣操作的特性。一個著色器通常包含輸入輸出變數、uniform 和 main 函式。每個著色器的入口都是 main 函式,在 main 函式中處理所有輸入變數,並將結果輸出到輸出變數中。

一個常見頂點/片段著色器如下:

// 頂點著色器

// 輸入屬性 attribute 變數型別 vec4 變數名 a_position

attribute vec4 a_position;

attribute vec2 a_uv;

attribute vec4 a_color;

// 輸入輸出屬性

varying vec4 v_color;

varying vec2 v_uv;

// 每一個著色器都有 main 函式,這是與 WebGL 對接的介面

void main() {

// 基礎賦值語句

v_color = a_color;

v_uv = a_uv;

// 內建變數 gl_Position

gl_Position = a_position;

}

// 片段著色器

// lowp 精度

varying lowp vec4 v_color;

varying highp vec2 v_uv;

uniform sampler2D mainTexture;

void main(void) {

vec4 o = texture2D(mainTexture, v_uv);

o *= v_color

gl_FragColor = o;

}

此處會列舉一些變數、修飾符和常見用法,更多使用方式可以參考下方的 GLSL 詳解(基礎篇),裡面的內容寫的還是很詳細的,當然,有條件的同學可以直接上 GLSL 官網文件檢視。

1

變數和變數型別

Cocos Shader 基礎入門(一):WebGL 著色器與 GLSL 著色器語言基礎

常用的幾種使用方式如下:

// 標量

float myFloat = 1。0;

bool myBool = bool(myFloat); // float -> bool

// 向量

vec4 myVec4 = vec4(1。0); // myVec4 =

vec2 myVec2 = vec2(1。0, 0。5);  // myVec2 =

vec2 temp = vec2(myVec2); // temp =

myVec4 = vec4(myVec2, temp, 0。0);

// 向量和矩陣的計算是逐分量進行的,因此,也可以採用下面這兩個個方法

vec3 myVec3a = myVec2。xyx; // 透過分量訪問符 myVec3a =

vec3 myVec3b = vec3(myVec2[0], myVec2[1], myVec2[0]); // 透過陣列 myVec3b =

// 矩陣

mat3 myMat3 = mat3(1。0, 0。0, 0。0,  // 第一列

0。0, 1。0, 0。0,  // 第二列

0。0, 1。0, 1。0); // 第三列

mat4 myMat4 = mat4(1。0) // myMat4 =

// 向量、標量和矩陣的互動使用

vec3 v, u;

float f;

v = u + f;

// 等價於 v。x = u。x + f;

// v。y = u。y + f;

// v。z = u。z + f;

mat3 m;

u = v * m;

// 等價於 u。x = m[0]。x * v。x + m[1]。x * v。y + m[2]。x * v。z;

// u。y = m[0]。y * v。x + m[1]。y * v。y + m[2]。y * v。z;

// u。z = m[0]。z * v。x + m[1]。z * v。y + m[2]。z * v。z;

2

限定符

2.1  儲存限定符

Cocos Shader 基礎入門(一):WebGL 著色器與 GLSL 著色器語言基礎

使用方法:

attribute vec4 a_position;

varying vec4 v_color;

2.2  引數限定符

Cocos Shader 基礎入門(一):WebGL 著色器與 GLSL 著色器語言基礎

vec4 myFunc(inout float myFloat, // 輸入輸出引數

out vec4 myVec4,   // 輸出

mat4 myMat4);    // 輸入引數

2.3  精度限定符

Cocos Shader 基礎入門(一):WebGL 著色器與 GLSL 著色器語言基礎

使用方法:

// 預先宣告

precision highp float;

precision mediump int;

// 指定變數宣告

varying lowp vec4 v_color;

狀態機

在 WebGL 上,大多數元素都可以用狀態來描述,比如:是否啟用了光照、是否啟用了紋理、是否啟用了混合、是否啟用了深度測試等。通常 WebGL 會執行預設狀態,除非我們呼叫相關介面改變它,比如:gl。Enablexxx 或者 gl。Disablexxx。

上下文(Context)

WebGL 需要依賴 canvas 這個載體獲取對應的繪圖上下文,透過繪圖上下文呼叫相對應的繪圖 API,包括上面提到的各種狀態切換。每一個物件的繪製,都需要先設定一系列狀態值,然後透過呼叫 “gl。drawArrays” 或 “gl。drawElements” 執行一個著色方法對,使得你的著色器對能夠在 GPU 上執行。WebGL 渲染上下文建立如下:

// 定義一個 canvas 元素

var gl = canvas。getContext(“webgl”);

if(!gl){

// 你不能使用 WebGL

}

本章到此主要介紹一些 WebGL 的基礎知識,包括渲染管線流程、渲染使用語言等。下一章開始介紹

繪製流程

,重點內容包括

頂點著色器和片元著色器的作用

內容參考:

1。 WebGL 基礎:

https://webglfundamentals。org/webgl/lessons/zh_cn/webgl-fundamentals。html

2。 WebGL API 對照表:

https://www。khronos。org/files/webgl/webgl-reference-card-1_0。pdf

3。 OpenGL 中文文件:

https://learnopengl-cn。github。io/01%20Getting%20started/04%20Hello%20Triangle/

4。 GLSL 詳解:

https://colin1994。github。io/2017/11/11/OpenGLES-Lesson04/

5。 細說圖形渲染管線:

https://zhuanlan。zhihu。com/p/79183044

相關文章

頂部