WebGL - 著色器



著色器是在GPU上執行的程式。著色器是用OpenGL ES著色器語言(稱為ES SL)編寫的。ES SL有自己的變數、資料型別、限定符、內建輸入和輸出。

資料型別

下表列出了OpenGL ES SL提供的基本資料型別。

序號 型別和描述
1

void

表示空值。

2

bool

接受真或假。

3

int

這是一個有符號整數資料型別。

4

float

這是一個浮點標量資料型別。

5

vec2, vec3, vec4

n分量浮點向量

6

bvec2, bvec3, bvec4

布林向量

7

ivec2, ivec3, ivec4

有符號整數向量

8

mat2, mat3, mat4

2x2、3x3、4x4浮點矩陣

9

sampler2D

訪問二維紋理

10

samplerCube

訪問立方體貼圖紋理

限定符

OpenGL ES SL中有三個主要的限定符:

序號 限定符和描述
1

attribute

此限定符充當頂點著色器和OpenGL ES之間每個頂點資料的連結。此屬性的值在每次執行頂點著色器時都會更改。

2

uniform

此限定符連結著色器程式和WebGL應用程式。與attribute限定符不同,uniform的值不會改變。Uniforms是隻讀的;您可以將它們與任何基本資料型別一起使用來宣告變數。

示例 − uniform vec4 lightPosition;

3

varying

此限定符在頂點著色器和片段著色器之間形成插值資料的連結。它可以與以下資料型別一起使用:float、vec2、vec3、vec4、mat2、mat3、mat4或陣列。

示例 − varying vec3 normal;

頂點著色器

頂點著色器是一個程式程式碼,它在每個頂點上都被呼叫。它轉換(移動)幾何體(例如:三角形)從一個位置到另一個位置。它處理每個頂點的資料(每個頂點資料),例如頂點座標、法線、顏色和紋理座標。

在頂點著色器的ES GL程式碼中,程式設計師必須定義屬性來處理資料。這些屬性指向用JavaScript編寫的頂點緩衝區物件。可以使用頂點著色器以及頂點變換執行以下任務:

  • 頂點變換
  • 法線變換和歸一化
  • 紋理座標生成
  • 紋理座標變換
  • 光照
  • 顏色材質應用

預定義變數

OpenGL ES SL為頂點著色器提供以下預定義變數:

序號 變數和描述
1

highp vec4 gl_Position;

儲存頂點的位置。

2

mediump float gl_PointSize;

儲存變換後的點大小。此變數的單位為畫素。

示例程式碼

看一下以下頂點著色器的示例程式碼。它處理三角形的頂點。

attribute vec2 coordinates;

void main(void) {
   gl_Position = vec4(coordinates, 0.0, 1.0);
};

如果你仔細觀察上面的程式碼,我們會宣告一個名為coordinates的屬性變數。(此變數將使用getAttribLocation()方法與頂點緩衝區物件關聯。屬性coordinates作為引數傳遞給此方法以及著色器程式物件。)

在給定頂點著色器程式的第二步中,定義了gl_position變數。

gl_Position

gl_Position是僅在頂點著色器程式中可用的預定義變數。它包含頂點位置。在上面的程式碼中,coordinates屬性以向量的形式傳遞。由於頂點著色器是每個頂點的操作,因此為每個頂點計算gl_position值。

稍後,gl_position值將由圖元裝配、裁剪、剔除以及其他在頂點處理完成後對圖元進行操作的固定功能操作使用。

我們可以為頂點著色器的所有可能操作編寫頂點著色器程式,我們將在本教程中分別討論這些操作。

片段著色器

一個網格由多個三角形組成,每個三角形的表面稱為一個片段。片段著色器是在每個片段的每個畫素上執行的程式碼。它是用來計算和填充單個畫素的顏色。可以使用片段著色器執行以下任務:

  • 對插值值進行操作
  • 紋理訪問
  • 紋理應用
  • 顏色相加

預定義變數

OpenGL ES SL為片段著色器提供以下預定義變數:

序號 變數和描述
1

mediump vec4 gl_FragCoord;

儲存幀緩衝區內的片段位置。

2

bool gl_FrontFacing;

儲存屬於正面圖元的片段。

3

mediump vec2 gl_PointCoord;

儲存點內的片段位置(僅限點光柵化)。

4

mediump vec4 gl_FragColor;

儲存著色器的輸出片段顏色值

5

mediump vec4 gl_FragData[n]

儲存顏色附件n的片段顏色。

示例程式碼

以下片段著色器的示例程式碼演示如何將顏色應用於三角形中的每個畫素。

void main(void) {
   gl_FragColor = vec4(0, 0.8, 0, 1);
}

在上面的程式碼中,color值儲存在變數gl.FragColor中。片段著色器程式使用固定函式變數將輸出傳遞給流水線;FragColor是其中之一。此變數儲存模型畫素的顏色值。

儲存和編譯著色器程式

由於著色器是獨立的程式,我們可以將其編寫為單獨的指令碼並在應用程式中使用。或者,您可以像下面那樣直接以字串格式儲存它們。

var vertCode =
   'attribute vec2 coordinates;' +
	
   'void main(void) {' +
      ' gl_Position = vec4(coordinates, 0.0, 1.0);' +
   '}';

編譯著色器

編譯包括以下三個步驟:

  • 建立著色器物件
  • 將原始碼附加到已建立的著色器物件
  • 編譯程式

建立頂點著色器

要建立一個空著色器,WebGL提供了一個名為createShader()的方法。它建立並返回著色器物件。其語法如下:

Object createShader (enum type)

正如語法中觀察到的那樣,此方法接受一個預定義的列舉值作為引數。我們有兩個選擇:

  • gl.VERTEX_SHADER 用於建立頂點著色器

  • gl.FRAGMENT_SHADER 用於建立片段著色器。

將原始碼附加到著色器

您可以使用shaderSource()方法將原始碼附加到已建立的著色器物件。其語法如下:

void shaderSource(Object shader, string source)

此方法接受兩個引數:

  • shader − 您必須將建立的著色器物件作為引數傳遞。

  • Source − 您必須以字串格式傳遞著色器程式程式碼。

編譯程式

要編譯程式,您必須使用compileShader()方法。其語法如下:

compileShader(Object shader)

此方法接受著色器程式物件作為引數。建立著色器程式物件後,將原始碼附加到它並將該物件傳遞給此方法。

以下程式碼片段演示如何建立和編譯頂點著色器以及片段著色器來建立三角形。

// Vertex Shader
var vertCode =
   'attribute vec3 coordinates;' +
	
   'void main(void) {' +
      ' gl_Position = vec4(coordinates, 1.0);' +
   '}';

var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
 
// Fragment Shader
var fragCode =
   'void main(void) {' +
      ' gl_FragColor = vec4(0, 0.8, 0, 1);' +
   '}';

var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);

組合程式

建立和編譯這兩個著色器程式後,您需要建立一個包含這兩個著色器(頂點和片段)的組合程式。需要遵循以下步驟:

  • 建立程式物件
  • 附加兩個著色器
  • 連結兩個著色器
  • 使用程式

建立程式物件

使用createProgram()方法建立一個程式物件。它將返回一個空程式物件。以下是其語法:

createProgram();

附加著色器

使用attachShader()方法將著色器附加到已建立的程式物件。其語法如下:

attachShader(Object program, Object shader);

此方法接受兩個引數:

  • Program − 將建立的空程式物件作為引數傳遞。

  • Shader − 傳遞已編譯的著色器程式之一(頂點著色器、片段著色器)

注意 − 您需要使用此方法附加兩個著色器。

連結著色器

使用linkProgram()方法連結著色器,方法是將程式物件傳遞給已附加著色器的程式物件。其語法如下:

linkProgram(shaderProgram);

使用程式

WebGL提供了一個名為useProgram()的方法。您需要將連結的程式傳遞給它。其語法如下:

useProgram(shaderProgram);

以下程式碼片段演示如何建立、連結和使用組合著色器程式。

var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram); 
廣告