Assignment 1

环境配置

依旧超绝环境配置。在 lab0 的锤炼下,现在已经知道外部包怎么顺利引入了。

这次除了 Eigen3 之外,还需要一个 OpenCV。在 Mac 上没装过,brew install 了一下发现要安装 62 个 dependencies,哈不出来了。

OpenCV 依赖安装提示

3维旋转矩阵

这个 lab 里面涉及到的仅仅是绕 z 轴旋转,所以只需要考虑类似简单的二维旋转矩阵。

[ABCD][10]=[cos(θ)sin(θ)]\begin{bmatrix} A & B \\ C & D \end{bmatrix} \cdot \begin{bmatrix} 1 \\ 0 \end{bmatrix} =\begin{bmatrix} \cos(\theta) \\ \sin(\theta) \end{bmatrix} [ABCD][01]=[sin(θ)cos(θ)]\begin{bmatrix} A & B \\ C & D \end{bmatrix} \cdot \begin{bmatrix} 0 \\ 1 \end{bmatrix} =\begin{bmatrix} -\sin(\theta) \\ \cos(\theta) \end{bmatrix}

得到旋转矩阵:

[cos(θ)sin(θ)sin(θ)cos(θ)]\begin{bmatrix} \cos(\theta) & -\sin(\theta) \\ \sin(\theta) & \cos(\theta) \end{bmatrix}

所以三维的就是把前两行换成这个就行了,齐次式再带上一个第四维。

[cos(θ)sin(θ)00sin(θ)cos(θ)0000100001]\begin{bmatrix} \cos(\theta) & -\sin(\theta) & 0 & 0\\ \sin(\theta) & \cos(\theta) & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}

注意:这里的角度都是弧度制。代码里面通过 float 格式传递的角度,需要转换。

radian = rational_angle * MY_PI / 180.0f;

投影矩阵

涉及以下几个参数:

r:半宽r:半宽,

t:半高t:半高,

n:近平面与原点距离n:近平面与原点距离,

f:远平面与原点距离f:远平面与原点距离,

ratio=rtratio=\frac{r}{t}

eye_fov:视野角eye\_fov:视野角

GAMES101 规定:相机位置为 (0,0,0)(0, 0, 0),朝 z-z 的方向看。

其中,视锥拉正矩阵 M1M_1 表示为:

[n0000n0000(n+f)nf0010]\begin{bmatrix} -n & 0 & 0 & 0 \\ 0 & -n & 0 & 0 \\ 0 & 0 & -(n+f) & -nf \\ 0 & 0 & 1 & 0 \end{bmatrix}

经历这个矩阵变换后:

  • 近平面表现为不变
  • 远平面被缩放为与近平面大小相同;
  • 只有这两个平面的 z 轴位置保持不变;
  • 两者之间的所有点,呈现z-z 端移动的趋势。

形状上,这一步把视锥变成了一个盒子:

x[r,r],y[t,t],z[f,n]x \in [-r, r], \quad y \in [-t, t], \quad z \in [-f, -n]

之后,需要把矩阵再处理一步,使得这个盒子映射到 [1,+1][-1, +1] 上成为正方体。可以看成第二次变换,其中 x,yx, y 方向都只需要简单地除以 r,tr, t

zz 方向上,需要把近平面映射到 11,远平面映射到 1-1,所以可以列出方程:

Af+B=1An+B=1\begin{aligned} -Af + B &= -1 \\ -An + B &= 1 \end{aligned}

得到变换矩阵 M2M_2

[1r00001t00002fnf+nfn0001]\begin{bmatrix} \frac{1}{r} & 0 & 0 & 0 \\ 0 & \frac{1}{t} & 0 & 0 \\ 0 & 0 & \frac{2}{f-n} & \frac{f+n}{f-n} \\ 0 & 0 & 0 & 1 \end{bmatrix}

然后:

M2M1=[nr0000nt0000f+nfn2nffn0010]M_2 \cdot M_1 = \begin{bmatrix} -\frac{n}{r} & 0 & 0 & 0 \\ 0 & -\frac{n}{t} & 0 & 0 \\ 0 & 0 & -\frac{f+n}{f-n} & -\frac{2nf}{f-n} \\ 0 & 0 & 1 & 0 \end{bmatrix}

提高项

最后还提供了一个提高项:在 main.cpp 里面实现一个能返回绕任意轴旋转的旋转矩阵。

线性代数学得很糟糕,但是想了一下也觉得这个应该不能通过三维旋转的简单线性组合来得到。这里查到一个 Rodrigues 旋转公式,矩阵十分丑陋,也没有可视化的展示,就懒得写了。

R=[c+x2(1c)xy(1c)zsxz(1c)+ysyx(1c)+zsc+y2(1c)yz(1c)xszx(1c)yszy(1c)+xsc+z2(1c)]R= \begin{bmatrix} c+x^2(1-c) & xy(1-c)-zs & xz(1-c)+ys \\ yx(1-c)+zs & c+y^2(1-c) & yz(1-c)-xs \\ zx(1-c)-ys & zy(1-c)+xs & c+z^2(1-c) \end{bmatrix}

其中,(x,y,z)(x, y, z) 是转轴单位向量,s=sin(θ)s = \sin(\theta)c=cos(θ)c = \cos(\theta)

运行结果和实验总结

Lab1 运行结果

可以按 ad,就会绕中心点旋转。

本来这个实验是光栅化章节的实验,但是光栅化的代码都给我们了,只需要实现两个矩阵部分