Shader 入門:GLSL ES(數據類型)

前言

在上一篇文章中我們初步瞭解了 GLSL ES 的基本語法,那麼本篇文章就和大家一起學習 GLSL ES 的數據類型。

Let’s go!!!

上一篇:《Shader 入門:GLSL ES(簡介和基本語法)》

在本系列文章中主要針對 GLSL ES 3.0 進行講解


正文

數據類型

標量(Scalar)

標量表示只有大小沒有方向的量。

關鍵字

關鍵字 含義
int 有符號整型(Signed Integer)
uint 無符號整型(Unsigned Integer)
float 單精度浮點型(Single Floating-Point)
bool 布爾型(Boolean)

聲明並賦值:

int age = 18; // 整型
uint hello = 3u; // 無符號整型,在後面數字加 u
float pi = 3.14; // 浮點型
bool isMe = true; // 布爾型

類型轉換

標量類型之間可以互相轉換。

  • float類型的值轉換爲 intuint時小數點後面的值將會被忽略,要注意負的 float 類型的值不能轉換爲 uint 類型。

  • intuintfloat類型的值轉換爲 bool類型時,00.0將會被轉換爲 false,所有非零的值都會被轉換爲 true

  • bool類型的值轉換爲 intuintfloat類型時,false將會被轉換爲 00.0true會被轉換爲 11.0

我們可以使用標量類型的構造函數來進行類型轉換:

int a = 1;
float b = float(a); // 1.0
int c = int(b); // 1
uint d = uint(c); // 1u
bool e = bool(d); // true

當嘗試將非標量值轉換爲標量值時,實際處理的將會是非標量值的第一個元素:

vec3 a = vec3(0.1, 0.2, 0.3);
float b = float(a); // 0.1

向量(Vector)

在 GLSL 中向量一般用於儲存頂點座標、顏色或紋理座標數據。

一個向量可以包含 2 到 4 個分量(Component),分量的類型也可以是以上基礎類型中的任意一個,一般情況下我們使用浮點型 vecn就已經足夠了。

關鍵字

下面表格中的 n爲分量的個數

關鍵字 含義 舉例
vecn 包含 n 個 float類型分量的向量 vec2vec4
ivecn 包含 n 個 int類型分量的向量 ivec2ivec4
uvecn 包含 n 個 uint類型分量的向量 uvec2uvec4
bvecn 包含 n 個 bool類型分量的向量 bvec2bvec4

創建向量

我們可以使用不同的構造函數來創建相應的向量:

vec2 coord = vec2(0.5, 0.5); // 含有 2 個 float 類型分量的向量
ivec3 police = ivec3(1, 1, 0); // 含有 3 個 int 類型分量的向量
bvec4 hello = bvec4(true, false, true, false); // 含有 4 個 bool 類型分量的向量

只傳入一個參數的情況下會自動將其他值也設爲第一個參數:

vec3 three = vec3(0.1); // 等同於 vec3(0.1, 0.1, 0.1)

也可以使用一個向量作爲參數傳給另一個向量構造函數:

vec2 two = vec2(0.1, 0.2);
vec3 three = vec3(two, 0.3); // vec3(0.1, 0.2, 0.3)

而將“大”向量作爲參數來創建“小”向量(降維)會自動拋棄多餘的值:

vec4 four = vec4(0.1, 0.2, 0.3, 0.4);
vec3 three = vec3(four); // 等同於 vec3(0.1, 0.2, 0.3),拋棄了 0.4

獲取分量

通過分量名來獲取向量中的第 1 到第 4 個分量,包括:

實際上所有向量都可以使用 rgbargbastpq分量名,但是爲了代碼的嚴謹性和可讀性,建議使用相應的分量名

分量名(對應第 1 - 4 個分量) 使用場景
x, y, z, w 頂點座標向量
r, g, b, a 顏色向量
s, t, p, q 紋理座標向量

使用 .運算符加分量名來獲取向量的分量:

// 頂點座標
vec2 coord = vec2(1.0, 0.5);
float x = coord.x; // 1.0
float y = coord.y; // 0.5
float z = coord.z; // Error! 不存在

// 顏色
vec4 color = vec4(0.6, 0.8, 1,0, 0.5);
float r = color.r; // 0.6
float a = color.a; // 0.5
// 紋理座標
vec4 texCoord = vec4(0.2, 0.4, 0.6, 0.8);
float t = texCoord.t; // 0.4
float p = texCoord.p; // 0.6

重組(Swizzling)

另外,你還可以使用同一組分量名的任意組合來創建一個新的向量,這一行爲稱作重組:

vec4 coord = vec4(0.1, 0.2, 0.3, 0.4);
vec2 one = coord.xx; // vec2(0.1, 0.1)
vec2 two = coord.xy; // vec2(0.1, 0.2)
vec3 three = coord.xzw; // vec3(0.1, 0.3, 0.4)
vec4 four = coord.wzyx; // vec4(0.4, 0.3, 0.2, 0.1)
vec4 boom = coord.xyzw + coord.wzyx; // vec4(0.5, 0.5, 0.5, 0.5)
vec4 hello = vec4(coord.zyx, 0.0); // vec4(0.3, 0.2, 0.1, 0.0)

矩陣(Matrix)

一種類似於表格的複合數據類型,矩陣最多能夠支持 4 列 4 行的數據,且其元素只能夠爲 float類型。

關鍵字

下面表格中的 nm皆爲 2 到 4 的任意數字

關鍵字 含義 舉例
matnxn / matn(別名) 表示一個 n n 的浮點型矩陣 mat2mat3
mat3x3
matnxm 表示一個 n m 的浮點型矩陣 mat2x3mat4x3

創建矩陣

使用不同的構造函數來創建相應的矩陣:

// 創建一個 2x2 的矩陣
mat2 two = mat2(0.1, 0.2, // 第一列
                0.3, 0.4); // 第二列

[0.10.30.20.4](two) \left[ \begin{matrix} 0.1 & 0.3 \\ 0.2 & 0.4 \end{matrix} \right] \tag{two}

// 創建一個 3x3 的矩陣
mat3 three = mat3(0.1, 0.2, 0.3, // 第一列
                  0.4, 0.5, 0.6, // 第二列
                  0.7, 0.8, 0.9); // 第三列

[0.10.40.70.20.50.80.30.60.9](three) \left[ \begin{matrix} 0.1 & 0.4 & 0.7 \\ 0.2 & 0.5 & 0.8 \\ 0.3 & 0.6 & 0.9 \end{matrix} \right] \tag{three}

只傳入一個參數的情況下會自動補零:

mat2 two = mat2(1.0); // 等同於 mat2(1.0, 0.0, 0.0, 0.0)
mat3 three = mat3(1.0); // 等同於 mat3(1.0, 0.0, 0.0, 0.0, 0.0, 0.0)

我們也可以向構造函數傳入向量來創建矩陣:

vec2 a = vec2(1.0, 0.0);
vec2 b = vec2(0.5, 0.1);
mat2 four = mat2(a, b); // 等同於 mat2(1.0, 0.0, 0.5, 0.1)
// 創建一個 2x3 的矩陣
mat2x3 haha = mat2x3(a, 0.3,
                     b, 0.2); // 等同於 mat2x3(1.0, 0.0, 0.3, 0.5, 0.1, 0.2)

降維操作會自動拋棄多餘的元素,升維則會自動補零:

// 僞代碼
mat3x3(mat4x4); // 保留參數的前 3 列前 3 行的元素
mat2x3(mat4x2); // 保留參數的前 2 列前 2 行的元素,第 3 行補零

獲取元素

可以通過 []操作符來獲取矩陣的某個元素(下標從 0 開始):

mat3 three = mat3(0.1, 0.2, 0.3, // 第一列
                  0.4, 0.5, 0.6, // 第二列
                  0.7, 0.8, 0.9); // 第三列
float el = three[0][2]; // 獲取第一列第三行的元素:0.3

也可以通過分量名來獲取元素:

float el = three[0].z; // 同上,獲取第一列第三行的元素:0.3

採樣器(Sampler)

在 GLSL 中我們需要通過採樣器來獲取紋理的信息。

採樣器只能在 Shader 外部的宿主語言中通過 OpenGL 的 API 來進行賦值。

關鍵字

採樣器的類型較多,這裏只列出了常見的幾個

關鍵字 含義
sampler2D 用來訪問 2D 紋理的句柄
sampler3D 用來訪問 3D 紋理的句柄
samplerCube 用來訪問立方體映射紋理的句柄
sampler2DArray 用來訪問 2D 紋理數組的句柄

剩下不常用的還有 samplerCubeShadowsampler2DShadowsampler2DArrayShadowisampler2Disampler3DisamplerCubeisampler2DArrayusampler2Dusampler3DusamplerCubeusampler2DArray

採樣器必須使用 uniform關鍵字來修飾(關於 uniform我們後面會說到):

uniform sampler2D texture;

通過內置的 texture 函數獲取顏色:

uniform sampler2D myTexture;
// 通過內置的 texture 函數獲取 myTexture 紋理 uv_0 座標處的顏色
vec4 color = texture(myTexture, uv_0);

結構體(Structure)

GLSL 允許你使用 struct關鍵字來自定義一個新的類型,新的自定義類型可以包含其他已經定義的類型:

// 定義一個名爲 circle 的類型,包含一個浮點型成員和一個四維向量成員
struct circle {
    float radius;
    vec4 color;
};
// 創建一個 circle 類型的變量
circle myCircle;
// 單獨給 radius 賦值
myCircle.radius = 0.5;

定義新的結構體時可以包含已經定義的結構體,但是不能夠在結構體中定義新的結構體:

// 結構體 A
struct A {
    float f;
};
// 結構體 B
struct B {
    A a; // 可
    A; // Error! 禁止匿名成員
    struct { ... }; // Error! 不可
}

數組(Array)

GLSL 支持一維數組,只需要在變量名稱後面接上一對方括號[]

數組的長度必須大於 0,可以使用字面量或者整型常量:

// 字面量
float values[3];
// 整型常量
const int COUNT = 3;
float values2[COUNT];

作爲函數的返回值或參數的類型:

// 返回值類型
float[5] getValues() { ... }
// 參數類型
void setValues(float[2] values) { ... }

使用相應的構造函數初始化數組:

float a[2] = float[2](0.1, 0.2);
// 另外下面這 4 種方式是一樣的
float b[3] = float[3](0.1, 0.2, 0.3);
float b[] = float[3](0.1, 0.2, 0.3);
float b[3] = float[](0.1, 0.2, 0.3);
float b[] = float[](0.1, 0.2, 0.3);

同樣通過 []運算符來獲取數組中的元素(下標從0 開始):

float a[3] = float[3](0.1, 0.2, 0.3);
float b = a[1]; // 0.2

通過數組的 length函數可以獲取數組的長度(int類型):

int a[3] = int[3](1, 2, 3);
int b = a.length(); // 3

空(void)

void一般用於函數返回值或參數的聲明:

void main() {
    // ...
}

相關資料

OpenGL ES Registry(OpenGL ES 資料頁)
https://www.khronos.org/registry/OpenGL/index_es.php

OpenGL ES 3 Quick Reference Card(OpenGL ES 3 快速參考卡片)
https://www.khronos.org/files/opengles3-quick-reference-card.pdf

GLSL ES Specification 3.00(GLSL ES 規範 3.0)
https://www.khronos.org/registry/OpenGL/specs/es/3.0/GLSL_ES_Specification_3.00.pdf

OpenGL ES 3.0 Online Reference Pages(OpenGL ES 3.0 在線參考頁)
https://www.khronos.org/registry/OpenGL-Refpages/es3.0/


傳送門

微信推文版本

個人博客:菜鳥小棧

開源主頁:陳皮皮

Eazax-CCC 遊戲開發腳手架


更多分享

爲什麼選擇使用 TypeScript ?

高斯模糊 Shader

一文看懂 YAML


公衆號

菜鳥小棧

我是陳皮皮,這是我的個人公衆號,專注但不僅限於遊戲開發、前端和後端技術記錄與分享。

每一篇原創都非常用心,你的關注就是我原創的動力!

Input and output.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章