Html CSS transform matrix3d 3D轉場特效
透視矩陣
2n/(r-l) 0 (r+l)/(r-l) 0
0 2n/(t-b) (t+b)/(t-b) 0
0 0 (n+f)/(n-f) 2fn/(n-f)
0 0 -1 0
t、b、l、r 分別代表camera投影面的上下左右,camera指向-z方向(指向屏幕內),n為近景距離,f為遠景距離。
Y軸旋轉矩陣
cos(θ) 0 sin(θ) 0
0 1 0 0
-sin(θ) 0 cos(θ) 0
0 0 0 1
轉場效果
主要步驟:
let w = 1024;
let h = 576;
// 1/2寬作為近景在 X-O-Z 平面上,可以剛好使圖像左右兩邊到camera的夾角為直角,
// 且3個點組成的三角形為等腰直角三角形,便於后面計算。
let n = -w / 2;
let f = -w * 1000;
let r = 1;
let l = -1;
let t = 1;
let b = -1;
let m00 = 2 * n / (r - l);
let m02 = (r + l) / (r - l); //0
let m11 = 2 * n / (t - b);
let m12 = (t + b) / (t - b); //0
let m22 = (n + f) / (n - f);
let m23 = 2 * f * n / (n - f);
let m32 = -1;
const aperspect = math.matrix([
[m00, 0, m02, 0],
[0, m11, m12, 0],
[0, 0, m22, m23],
[0, 0, m32, 0]
])
const aperspectT = math.transpose(aperspect);
var change3d = (rfactor, dfactor, mSlide) => {
//thet θ,圖像距離近景越近,圖像完全移出畫布的角度越逼近於90度,越遠越接近45度。
let thet = 1 / 2 * rfactor * Math.PI;
const rotationYT = math.matrix([
[Math.cos(thet), 0, -Math.sin(thet), 0],
[0, 1, 0, 0],
[Math.sin(thet), 0, Math.cos(thet), 0],
[0, 0, 0, 1]
])
let result = math.identity(4);
//把圖像移動至原點(0, 0),方便計算繞Y軸旋轉
//若拉遠至近景距離的2倍,視覺上為圖像縮小1倍
const transOT = math.matrix([
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[-w / 2, -h / 2, -w / 2 * dfactor, 1]
]);
result = transOT;
//y旋轉
result = math.multiply(result, rotationYT);
//透視
result = math.multiply(result, aperspectT);
//還原至畫布中央
const transCenterT = math.matrix([
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[w / 2, h / 2, 0, 1]
]);
result = math.multiply(result, transCenterT);
let mStr = math.flatten(result)._data.join(',');
mSlide.style.transform = `matrix3d(${mStr})`
}
另外 CSS transform matrix3d 的值為列向量計算矩陣的轉置,上面全部使用轉置矩陣來計算。
matrix3d(
a1, b1, c1, d1,
a2, b2, c2, d2,
a3, b3, c3, d3,
a4, b4, c4, d4)
還需要引入math.js文件。
參考文獻: