本篇同時也寫在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創造形狀。