1 视图变换(Viewing Transformation)

1.1 罗德里格斯旋转公式

绕任意轴nn旋转α\alpha度(其中II为单位矩阵)

R(n,α)=cos(α)I+(1cos(α))nnT+sin(α)[0nznynz0nxnynx0]R(n,\alpha)=cos(\alpha)I+(1-cos(\alpha))nn^T+sin(\alpha) \begin{bmatrix} 0 & -n_z & n_y \\ n_z & 0 & -n_x \\ -n_y & n_x & 0 \end{bmatrix}

TODO:后面补3D数学基础时再来推导一遍吧

1.2 什么是视图变换

视图变换是想如何拍一张照片:

  • 找一个好的地方并安排拍照的人(Model Transformation 模型变换)
  • 找一个好的地方并且安放好相机(View Transformation 视图变换)
  • 拍照,将3D画面处理为2D画面(Projection Transformation 投影变换)

1.3 定义相机

相机有三个非常重要的属性:(此处的^代表一个单位向量)

  • Position e\vec{e}
  • Look-at/gaze direction g^\hat{g}
  • up direction t^\hat{t} (控制相机选择,固定相机)



如果相机和所有物件一起移动,这个"相片会是一样的",因此,将相机固定于(0,0,0)(0,0,0),向着z-z方向看

2 Model Transformation

e\vec{e} 移到原点,可得变换矩阵:

Tview=[100xe010ye001ze0001]T_{view}= \begin{bmatrix} 1 & 0 & 0 & -x_e \\ 0 & 1 & 0 & -y_e \\ 0 & 0 & 1 & -z_e \\ 0 & 0 & 0 & 1 \end{bmatrix}

3 View Transformation

将世界坐标系转换到摄像机坐标系,也就是Rotate gg to Z-Z, tt to YY, (g×tg \times t) to XX

直接变换我们可能想不出,为什么不考虑一下XX to (g×tg \times t), YY to tt, ZZ to g-g呢,因为旋转矩阵的逆矩阵就是其转置矩阵,因此我们写出了后者就得到了前者

Rview1=[xg^×t^xtxg0yg^×t^ytyg0zg^×t^ztzg00001]R^{-1}_{view}= \begin{bmatrix} x_{\hat{g}\times\hat{t}} & x_t & x_{-g} & 0 \\ y_{\hat{g}\times\hat{t}} & y_t & y_{-g} & 0 \\ z_{\hat{g}\times\hat{t}} & z_t & z_{-g} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}

可得到:

Rview[xg^×t^yg^×t^zg^×t^0xtytzt0xgygzg00001]R_{view} \begin{bmatrix} x_{\hat{g}\times\hat{t}} & y_{\hat{g}\times\hat{t}} & z_{\hat{g}\times\hat{t}} & 0 \\ x_t & y_t & z_t & 0 \\ x_{-g} & y_{-g} & z_{-g} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}

同时我们结合上一节也能得到Mview=RviewTviewM_{view}=R_{view}T_{view}

4 Projection transformation

4.1 正交投影 Orthographic

正交投影:

  1. 把相机放原点,看向Z-Z,头向着YY
  2. 扔掉ZZ
  3. 不管 xx, yy 范围有多大,都把它移到[1,1][1,1][-1,1]*[-1,1]



通常的做法是:记录一个长方体的 [l,r][b,t][f,n][l,r][b,t][f,n] (x, y, z轴范围),将其移动到原点,再缩放为[1,1]3[-1,1]^3

Mortho=[2/(rl)00002/(tb)00002/(nf)00001][100(r+l)/2010(b+t)/2001(n+r)/20001]M_{ortho}= \begin{bmatrix} 2/(r-l) & 0 & 0 & 0 \\ 0 & 2/(t-b) & 0 & 0 \\ 0 & 0 & 2/(n-f) & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & -(r+l)/2 \\ 0 & 1 & 0 & -(b+t)/2 \\ 0 & 0 & 1 & -(n+r)/2 \\ 0 & 0 & 0 & 1 \end{bmatrix}

ps:为什么此处是near - far(n - f),因为我们的camera是朝着Z-Z方向的,因此数值越小反而越远

4.2 透视投影 Perspective

做透视投影,要先投影再正交变换Mpersp>orthoM_{persp->ortho},将frustum(视椎)挤压为一个长方形


那如何来做这个"压扁"操作呢:


由上图可知,利用相似三角形的性质,可以得出x=(n/z)xx'=(n/z)x , y=(n/z)yy'=(n/z)y , 但是zz的变化是我们仍不知道的,例如:

[xyz1]=>[nx/zny/zunknown1]=>(multbyz)[nxnystillunknownz]\begin{bmatrix} x \\ y \\ z \\ 1 \end{bmatrix} => \begin{bmatrix} nx/z \\ ny/z \\ unknown \\ 1 \end{bmatrix} =>(mult \quad by \quad z) \begin{bmatrix} nx \\ ny \\ still \quad unknown \\ z \end{bmatrix}

同时又可以通过矩阵叉乘得到未知矩阵的一部分

Mpersp>ortho=[n0000n00????0010]M_{persp->ortho}= \begin{bmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ ? & ? & ? & ? \\ 0 & 0 & 1 & 0 \end{bmatrix}

但是ff,nn平面的zz在被挤压过后是不变的,只是中间的平面会变
由此我们可以得到

[00AB][xyn1]=n2>An+B=n2\begin{bmatrix} 0 & 0 & A & B \end{bmatrix} \begin{bmatrix} x \\ y \\ n \\ 1 \end{bmatrix} =n^2 \qquad->\qquad An+B=n^2

同理代入ff , 可以得到一个方程组:

{An+B=n2Af+B=f2=>{A=n+fB=nf\left\{ \begin{array}{c} An+B=n^2 \\ Af+B=f^2 \end{array} \right. => \left\{ \begin{array}{c} A=n+f \\ B=-nf \end{array} \right.

因此我们的矩阵最终写为

Mpersp>ortho=[n0000n0000n+fnf0010]M_{persp->ortho}= \begin{bmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 & n+f & -nf \\ 0 & 0 & 1 & 0 \end{bmatrix}

5 光栅化处理及视口变换

把东西画在屏幕上的过程就叫作光栅化

5.1 定义视椎体宽高比和垂直可视角度

  • fov:垂直可视角度
  • t:在y轴的高度
  • n:近平面上的z轴的点
  • r:中心点到右边的距离

宽高比(aspect)= r/tr/t

5.2 像素以及屏幕

pixel即picture element,pixel的范围:(0,0)(0,0) to (width1,height1)(width-1,height-1),中心:(x+0.5,y+0.5)(x+0.5,y+0.5)

屏幕覆盖范围:(0,0)(0,0) to (width,height)(width,height)

5.3 视口变换

x,yx,y转换:[1,1]2[-1,1]^2 to [0,width]×[0,height][0,width] \times [0,height]

Mviewport=[width/200width/20height/20height/200100001]M_{viewport}= \begin{bmatrix} width/2 & 0 & 0 & width/2 \\ 0 & height/2 & 0 & height/2 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}