一次搞懂應用Shader(著色器)時所需知道的GLSL基本知識

蘇桓晨
Jun 3, 2021

--

本篇同時也寫在ithome30天鐵人賽其中一篇「Day24: WebGL Shader — — 透過自製環境光實作shader傳值」裡面,如果有興趣可以從那邊看到更多應用介紹。鐵人賽的作者也是我本人喔!

前一篇提到如何實作Shader,但光看步驟流程很難很透徹的理解。

GLSL跟C語言相近,若你熟悉C語言,那你能很快上手。若沒接觸C語言就涉獵Shader,你會需要搞懂GLSL,本篇介紹GLSL中所需理解的基本知識。包含變數、函式以及Variable Qualifiers。

1. 變數

GLSL的變數相當多種,舉凡int, float, bool, vec2, vec3, vec4等。前三個你應該可以猜的出來,就是整數、浮點數、布林值,但後面三個是什麼?它們即是Vector的縮寫,它可以一個數組,可以是二維、三為、四維,依照你的需求而定。

vec2可以裝兩個,vec3可以裝三個,以此類推。如果想像成陣列存取這些可能比較好理解。

這些數組的提取、給定都跟JS不太一樣。下面介紹幾個面相。

A. 存取這些數值的方式

透過以下方式宣告一個vec3:

vec3 color = vec3(0.0, 0.5, 1.0);

你可以透過你宣告的vac3給定一個數值

float redComponent = color.r;

透過這個方式,你可以獲得這個vec3的第一個數值。當你使用color.r時,你在抽取的是第一個數值。

為什麼呢?

B. 如何稱呼向量中不同的數值

是這樣的,vec3可以依照r,g,b三個關鍵字提取三個不同位置的數值,也可以依照x,y,z三個關鍵字提取三個不同位置的數值。無論是透過r,g,b還是透過x,y,z,本質都是一樣的,並沒有變。

你可以透過這方式依序提取三個數值

vec3 colorCopy1 = color.rgb;         // R = 0, G = 0.5, B = 1.0

你也可以透過x, y, z 提取三個數值,這跟前者沒差別。

vec3 colorCopy2 = color.xyz;         // R = 0, G = 0.5, B = 1.0

2. 著色器的函式

函式跟JS的函式很像,但還是有差異,估計你可以直接透過用看的就能看出兩者差異:

vec3 rgb(float r, float g, float b){
return vec3(r / 255.0, g / 255.0, b / 255.0);
}

3. Variable Qualifiers

GLSL的變數有多種不同的Variable Qualifiers,下面介紹幾個常見的幾個:

A. Const or #define @

Const就很像Js ES6的Const。至於Define,則是用來取代文件中提及的所有關鍵字,主要是替換文字,基本上並沒有因此多儲存資料在記憶體,所以會比較有效率。

B. Attributes

  • 依據不同的vertex變化的變數
  • 可用來從外戶獲取資料,例如從js取得資料到着色器中
  • 可轉成其他變數如vec3

C.Uniforms

  • 可以從JS傳值到著色器中。
  • 由於GPU在渲染畫面時,一個螢幕會有很多平行的thread一起渲染,但無論是哪一個thread在渲染,這個數值固定一致,這也是被稱作uniforms的原因。
  • 透過其他套件例如p5.js,我們能夠從js傳值到着色器,如下:
theShader.setUniform("u_resolution", [width, height]); 
// 傳螢幕大小給shader
theShader.setUniform("u_time", millis() / 1000.0);
// 傳時間給shader (millis()是p5的函式)
theShader.setUniform("u_mouse", [mouseX, mouseY]);
// 傳滑鼠的位置給shader

接著在Fragment宣告同名的名稱,即可從Js接收資料並且加以應用。

uniform vec2 u_resolution; 
uniform float u_time;
uniform vec2 u_mouse;

D. Varying

  • 跟uniform不同,uniform在每個像素渲染時保持不變,但在varying則各不相同。
  • 通常用來傳遞texture coordinates通常用來傳遞texture coordinates

理解這些基本常識之後,我們可以開始用shader創造一點不一樣的,下篇將整合前兩篇的知識,操控Shader創造形狀。

--

--