图形学 旋转与投影矩阵-3

game101 第二次作业； webgl 实现

1. 正确构建模型矩阵
2. 正确构建透视投影矩阵
3. 看到变换后的三角形
4. 按 A 和 D 三角形能够进行旋转
5. 按 Q 和 E 三角形能够绕任意过原点的向量进行旋转

构建透视投影矩阵

1. 将透视投影转换为正交投影，得到转换矩阵
2. 将正交投影转换为标准相机，得到正交相机矩阵

$M_{persp} =M_{ortho} \times M_{persp \rightarrow ortho}$

// 构建一个透视投影矩阵，
function perspMatrix(fov, aspect, near, far){
fov = Math.PI*fov/180;
const top = Math.tan(fov/2) * Math.abs(near);
const right = aspect * top;
const bottom = -top;
const left = -right;

const ortho = new THREE.Matrix4()
.scale(new THREE.Vector3(2/(right-left), 2/(top-bottom), 2/(near-far)))
.multiply(new THREE.Matrix4().setPosition(-(right+left)/2, -(top+bottom)/2, -(near+far)/2));

const perseToOrtho = new THREE.Matrix4().set(
near, 0, 0, 0,
0, near, 0, 0,
0, 0, near+far, -1*near*far,
0, 0,1, 0
)
return ortho.clone().multiply(perseToOrtho);
}


const per = perspMatrix(90, 1, -3, -9);


$M_{persp}= \left[ \begin{matrix} -1 & 0 & 0 & 0 \\ 0 & -1 & 0 & 0 \\ 0 & 0 & -2 & -9 \\ 0 & 0 & 1 & 0 \end{matrix} \right]$

绕任意向量的旋转变换矩阵

$R(n, \theta) = \cos(\theta) \times I + (1-\cos(\theta)) \times n \times n^T + \sin(\theta) \times \left[ \begin{matrix} 0 & -n_z & n_y \\ n_z & 0 & -n_x \\ -n_y & n_x & 0 \end{matrix} \right] \\ n_x, n_y, n_z \: 分别是向量\: \overrightarrow{n} \: 的x,y,z值$

// 绕任意过原点的轴的旋转变换矩阵
function getAnyRotation(axis, angle){
const cosTheta = Math.cos(angle);
const matrix1 = new THREE.Matrix3().multiplyScalar(cosTheta);
const matrix2 = getSelfMul(axis).multiplyScalar(1-cosTheta);
const matrix3 = new THREE.Matrix3();
matrix3.set(
0, -axis.z, axis.y,
axis.z, 0, -axis.x,
-axis.y, axis.x, 0
);
matrix3.multiplyScalar(Math.sin(angle));

return new THREE.Matrix4().setFromMatrix3(result);
}


设置模型矩阵

$R_x(\theta)= \left[ \begin{matrix} 1 & 0 & 0 & 0 \\ 0 & \cos(\theta) & -\sin(\theta) & 0 \\ 0 & \sin(\theta) & \cos(\theta) & 0 \\ 0 & 0 & 0 & 1 \end{matrix} \right] \\ \\ R_z(\theta)= \left[ \begin{matrix} \cos(\theta) & -\sin(\theta) & 0 & 0 \\ \sin(\theta) & \cos(\theta) & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{matrix} \right] \\ \\ R_y(\theta)= \left[ \begin{matrix} \cos(\theta) & 0 & \sin(\theta) & 0 \\ 0 & 1 & 0 & 0 \\ -\sin(\theta) & 0 & \cos(\theta) & 0 \\ 0 & 0 & 0 & 1 \end{matrix} \right]$

// 等价于 makeRotationZ  model.makeRotationZ(rotation);
function rotateZ(model, rotate){
model.set(
Math.cos(rotate), -Math.sin(rotate), 0, 0,
Math.sin(rotate), Math.cos(rotate), 0, 0,
0, 0,1, 0,
0, 0, 0, 1
)
}


添加交互事件

window.addEventListener('keydown', ev => {
if(ev.key === "a" ){
rotation += 0.2;
rotateZ(model, rotation)
return;
}
if ( ev.key === 'd'){
rotation -= 0.2;
rotateZ(model, rotation);
return;
}
if ( ev.key === 'q'){
angle -= 0.2;
uniforms.anyRotate.value = getAnyRotation(vec, angle);
return;
}
if ( ev.key === 'e'){
angle += 0.2;
uniforms.anyRotate.value = getAnyRotation(vec, angle);
}
})


总结

posted @ 2021-12-28 16:33  随遇丿而安  阅读(229)  评论(0编辑  收藏  举报