在先前文件中,我們自行推導出各種矩陣,並實作為各個函式,有能力或有時間的話,這是值得推薦的過程,不但可以理解各種轉換背後的原理,在呼叫各個函式時,對於每個參數的作用也會更加明瞭,知道在什麼情況下該採用什麼呼叫。
當然,每個矩陣或函式都要推導與實作,也是蠻累人的一件事,有沒有程式庫來幫忙做這件事呢?可以使用 glMatrix,實際上先前在實作各個矩陣相關函式時,我也是參考 glMatrix 的原始碼,以避免實作上一些失誤或沒有注意到的地方。
因為是參考 glMatrix 實作的,如果你也跟隨著先前文件的內容,在接觸 glMatrix 時應該是沒太大問題,在撰寫本文時,glMatrix 版本是 2.0,src 目錄中的原始碼是基於 ES6 實作,使用 ES6 模組功能來管理不同的模組原始碼,如果偏好使用 ES6 模組,可以直接使用這些模組,例如,先前文件在實作時,主要是參考 src/mat4.js 的內容。
如果在意相容性,可以在 dist 中找到 gl-matrix.js,這是透過建構工具建構後,不使用 ES6 相關語法的版本,全域變數基本上就是 src 中看到的各個模組名稱,這在 gl-matrix.js 原始碼最下方中可以看到:
exports.glMatrix = common;
exports.mat2 = mat2;
exports.mat2d = mat2d;
exports.mat3 = mat3;
exports.mat4 = mat4;
exports.quat = quat;
exports.quat2 = quat2;
exports.vec2 = vec2;
exports.vec3 = vec3;
exports.vec4 = vec4;
gl-matrix-min.js 是 gl-matrix.js 的壓縮版本,實際上線後的頁面可以使用這個版本。
如果你想要自行建構 gl-matrix.js、gl-matrix-min.js,可以安裝 Node.js,將 glMatrix 用 git clone
後,進入目錄並執行:
npm install
npm run build
建構完成之後,同樣是在 dist 目錄中會出現 gl-matrix.js、gl-matrix-min.js。
如果要查詢 API 文件,可以查看 Documentation,基本上就是將原始碼中註解文件的部份用 JSDoc 網頁化,我是都直接看原始碼中的註解。
glMatrix 採用 OpenGL/WebGL 的慣例,以線性陣列來實作矩陣時,都是採取行為主(column-major),也就是對於矩陣:
1 0 0 x
0 1 0 y
0 0 1 z
0 0 0 0
使用陣列實作時要寫成:
[
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
x, y, z, 0
]
glMatrix 可用來建立新矩陣的相關函式,傳回值大多是 Float32Array
而不是 Array
,至於與矩陣運算相關的函式,參數部份可以接受 Array
、Float32Array
或 Array-like 實例,因為原始碼實作中都是基於索引來取元素值。
不過建議還是使用 Float32Array
,這是因為與矩陣運算相關的函式,矩陣運算的結果慣例上,會儲存在第一個參數傳入的矩陣,這個矩陣也會被當成傳回值,如果第一個參數使用 Array
,傳回值也會是 Array
型態,這也許不會是你想要的結果。
例如網頁中如果撰寫:
<script type="module">
import * as mat4 from './mat4.js';
const m = mat4.create();
console.log(m);
mat4.translate(m, m, [10, 10, 10]);
console.log(m); // 可以看到 m 內容改變了
</script>
mat4.create()
會建立 4x4 單位矩陣,也就是傳回:
[
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
]
mat4.translate(m, m, [10, 10, 10])
的第一個參數會用來儲存位移操作後的結果,第二個參數是要參與位移運算的矩陣,就上例來說,m
的內容會被改變,也就是 m
結果會是:
[
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
10, 10, 10, 1
]
如果不想改變 m
,就是在第一個參數指定另一個矩陣,例如:
<script type="module">
import * as mat4 from './mat4.js';
const m = mat4.create();
console.log(m);
const r = mat4.translate(mat4.create(), m, [10, 10, 10]);
console.log(m); // 可以看到 m 內容沒有改變
console.log(r); // 矩陣運算後的結果
</script>