新聞中心
大家好,我是前端西瓜哥。之前講了平移矩陣、旋轉(zhuǎn)矩陣以及縮放矩陣,以及演示了在 WebGL 中的單獨(dú)應(yīng)用的效果。

創(chuàng)新互聯(lián)建站專(zhuān)注為客戶(hù)提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、宣恩網(wǎng)絡(luò)推廣、小程序定制開(kāi)發(fā)、宣恩網(wǎng)絡(luò)營(yíng)銷(xiāo)、宣恩企業(yè)策劃、宣恩品牌公關(guān)、搜索引擎seo、人物專(zhuān)訪(fǎng)、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);創(chuàng)新互聯(lián)建站為所有大學(xué)生創(chuàng)業(yè)者提供宣恩建站搭建服務(wù),24小時(shí)服務(wù)熱線(xiàn):13518219792,官方網(wǎng)址:www.cdcxhl.com
這次我們看看同時(shí)進(jìn)行多次矩陣變換的組合寫(xiě)法。
我們將會(huì)對(duì)一個(gè)三角形先平移,然后旋轉(zhuǎn)。
矩陣乘法
一個(gè)坐標(biāo)(矢量),先進(jìn)行矩陣變形 1,然后再做矩陣變換 2,它的寫(xiě)法是:
m2 * m1 * vec第一個(gè)矩陣 A 的列數(shù)如果等于第二個(gè)矩陣 B 的行數(shù),那這兩個(gè)矩陣可以做乘法。
矩陣乘法不滿(mǎn)足交換律,即 AxB 通常不等于 BxA。
矩陣乘法,一種理解方式是:A 的第 i 行的每個(gè)元素,依次乘以 B 的第 j 列的對(duì)應(yīng)元素,然后加起來(lái),作為新矩陣的第 [i][j] 個(gè)元素。
矩陣乘法的計(jì)算順序?yàn)閺淖笸摇?/p>
以一個(gè)比較低維度的 2x2 矩陣為例:
矩陣乘法滿(mǎn)足交換律。
m2 * m1 * vec
= m2 * (m1 * vec)
= (m2 * m1) * vec所以,一個(gè)頂點(diǎn)要做多次矩陣變換,我們可以先計(jì)算這些矩陣的結(jié)果,得到一個(gè)復(fù)合矩陣,然后再乘以頂點(diǎn)。
當(dāng)多個(gè)頂點(diǎn)做的矩陣變換是一樣的時(shí)候,我們就能減少計(jì)算量,一些線(xiàn)性計(jì)算就得到結(jié)果。
這種將一個(gè)模型丟到世界坐標(biāo)系中進(jìn)行各種變換,我們也稱(chēng)為 模型變換(model transform)。
頂點(diǎn)著色器中運(yùn)算
頂點(diǎn)著色器代碼:
const vertexShaderSrc = `
attribute vec4 a_Position;
uniform mat4 u_translateMatrix;
uniform mat4 u_rotateMatrix;
mat4 compoundMatrix = u_rotateMatrix * u_translateMatrix;
void main() {
gl_Position = compoundMatrix * a_Position;
}
`;聲明了兩個(gè) uniform 類(lèi)型的矩陣 u_translateMatrix 和 u_rotateMatrix,分別保存平移矩陣和旋轉(zhuǎn)矩陣,然后將它們相乘。
compoundMatrix 因?yàn)椴恍枰獠總魅胫担圆恍枰?uniform 聲明。
因?yàn)槭窍绕揭圃傩D(zhuǎn),所以平移矩陣在右,旋轉(zhuǎn)矩陣在左。
平移矩陣的構(gòu)造:
/****** (1) 平移矩陣 ****/
const dx = 0.5; // 向右移動(dòng)
const dy = 0; // 向下移動(dòng)
// z 先不管,沒(méi)用到透視矩陣,設(shè)置值也看不到效果
const translateMatrix = new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
dx, dy, 0, 1
]);
// 傳入頂點(diǎn)著色器
const u_translateMatrix = gl.getUniformLocation(
gl.program,
"u_translateMatrix"
);
gl.uniformMatrix4fv(u_translateMatrix, false, translateMatrix);旋轉(zhuǎn)矩陣的構(gòu)造:
/****** (2) 旋轉(zhuǎn)矩陣 ****/
const angle = 60;
const radian = (angle * Math.PI) / 180;
const cos = Math.cos(radian);
const sin = Math.sin(radian);
// prettier-ignore
const rotateMatrix = new Float32Array([
cos, sin, 0, 0,
-sin, cos, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
]);
const u_rotateMatrix = gl.getUniformLocation(gl.program, "u_rotateMatrix");
gl.uniformMatrix4fv(u_rotateMatrix, false, rotateMatrix);demo 地址:
渲染結(jié)果:
使用 JavaScript 運(yùn)算
換成用 JavaScript 來(lái)做矩陣乘法,將計(jì)算好的矩陣傳入到著色器中。
頂點(diǎn)著色器只要聲明一個(gè) uniform 類(lèi)型的 u_compoundMatrix 就好。
uniform 是一個(gè)不變的類(lèi)型,使用下一頂點(diǎn)時(shí)還會(huì)使用原來(lái)的值。如果頂點(diǎn)更換時(shí),值會(huì)變,你應(yīng)該使用的是 attribute 類(lèi)型。
const vertexShaderSrc = `
attribute vec4 a_Position;
uniform mat4 u_compoundMatrix;
void main() {
gl_Position = u_compoundMatrix * a_Position;
}
`;創(chuàng)建完兩個(gè) Float32Array 的數(shù)組后,我們用自己實(shí)現(xiàn)的 JavaScript 將它們相乘。
/*************** 計(jì)算復(fù)合矩陣 *************/
// 兩個(gè) 4x4 矩陣相乘的方法。m1 x m2
function multiply(m1, m2) {
const size = 4;
const m = new Float32Array(size * size);
for (let i = 0; i < size; i++) {
for (let j = 0; j < size; j++) {
let sum = 0;
for (let k = 0; k < size; k++) {
sum += m2[i * size + k] * m1[k * size + j];
}
m[i * size + j] = sum;
}
}
return m;
}
// 這里創(chuàng)建了倆 Float32Array 數(shù)組
// ...
// 兩個(gè)矩陣相乘,得到復(fù)合變換矩陣
const xformMatrix = multiply(rotateMatrix, translateMatrix);
// 將計(jì)算出來(lái)的矩陣傳給著色器
const u_compoundMatrix = gl.getUniformLocation(gl.program, "u_compoundMatrix");
gl.uniformMatrix4fv(u_compoundMatrix, false, xformMatrix);在實(shí)現(xiàn) multiply 方法過(guò)程中,有一個(gè)容易踩的坑,就是 WebGL 中的矩陣是 按列主序 的,即 m[0] 到 m[1] 對(duì)應(yīng)的是第一列,而不是第一行,我們實(shí)現(xiàn) JavaScript 矩陣乘法的時(shí)候要注意,否則就會(huì)從 AxB 變成了 BxA。
西瓜哥我就踩了這個(gè)坑,發(fā)現(xiàn) JavaScript 實(shí)現(xiàn)和預(yù)期不符,居然是先旋轉(zhuǎn)再移動(dòng),大眼瞪了半天才發(fā)現(xiàn)自己把左邊矩陣的列當(dāng)成行去運(yùn)算了。
demo 地址:
渲染效果和在頂點(diǎn)著色器計(jì)算的一樣:
如果我們將兩個(gè)變換矩陣的順序交換一下,就會(huì)得到一個(gè)先旋轉(zhuǎn)再移動(dòng)的效果。感興趣的朋友可以去線(xiàn)上 demo 修改試試。
結(jié)尾
我是前端西瓜哥,歡迎關(guān)注我,學(xué)習(xí)更多前端知識(shí)。
頂點(diǎn)的變換可以用矩陣乘法來(lái)表示,乘以一個(gè)矩陣就是一個(gè)變形(比如平移、旋轉(zhuǎn)、縮放)。如果應(yīng)用了多個(gè)矩陣,我們可以利用矩陣乘法的結(jié)合律將這幾個(gè)矩陣先預(yù)先計(jì)算好。
另外一個(gè)坑,就是矩陣是用一維數(shù)組表示的,且為比較別扭的按列主序,聲明的數(shù)組在形式上和矩形真正的樣子有一點(diǎn)不同,需要沿著從左上到右下的軸線(xiàn)進(jìn)行一個(gè)翻轉(zhuǎn)才行。
網(wǎng)站題目:一起學(xué)WebGL:復(fù)合矩陣
瀏覽路徑:http://m.fisionsoft.com.cn/article/dpejssi.html


咨詢(xún)
建站咨詢(xún)
