回顾Games101 chatper1 - 6

前言

本文只写回顾后重新加深认识的知识

透视除法的意义

经过MVP矩阵之后,将模型空间下某点的坐标,转换成了裁剪空间下的坐标,此时因为裁剪空间的范围是x∈[-W/2,W/2]和y∈[-H/2,H/2],所以经过以下两个变换,其中除以pz就是透视除法

一:

\[-1≤2·\frac{\left( \frac{p_x}{p_z}·near \right)}{w}≤1
\\
-1≤2·\frac{\left( \frac{p_y}{p_z}·near \right)}{h}≤1
\]

二:

\[\left[ \begin{matrix}
x& y& z& w\\
\end{matrix} \right] \left[ \begin{matrix}
1& 0& 0& 0\\
0& 1& 0& 0\\
0& 0& 1& 0\\
\varDelta x& \varDelta y& \varDelta z& 1\\
\end{matrix} \right] =\left[ \begin{matrix}
x+\varDelta x*w& y+\varDelta y*w& z+\varDelta z*w& w\\
\end{matrix} \right]
\]

只有当W=1,这个三维坐标转换是等价的,才能保证位移的量是正确的,W=0时,则没有位移

只有当W=1时,三维坐标点转换成四维齐次坐标点才是等价的

坐标系变换和矩阵推导

坐标系变换理解不直观,倾向于101中闫老师所说的理解坐标系的转换通过矩阵进行的线性变换,将A坐标系下的点P,乘上矩阵得出B坐标系下的点P',以下是抛开常见的变换(如透视投影变换、正交投影变换等)如何得出变换矩阵M,通过矩阵变换(下文着重说明)

已知坐标系A和坐标系B

\[坐标系B的x,y,z轴在坐标系A下可表示为(u_{\mathrm{x}},u_{\mathrm{y}},v_{\mathrm{z}},0)
\]
\[\left( \mathrm{v}_{\mathrm{x}},\mathrm{v}_{\mathrm{y}},\mathrm{v}_{\mathrm{z}},0 \right) \text{,}\left( \mathrm{w}_{\mathrm{x}},\mathrm{w}_{\mathrm{y}},\mathrm{w}_{\mathrm{z}},0 \right) \text{,坐标系B的原点在坐标系A下表示为(Q}_{\mathrm{x}},\mathrm{Q}_{\mathrm{y}},\mathrm{Q}_{\mathrm{z}},1\text{)}
\]

则将坐标系B中一点P从坐标系B变换到坐标系A的变换矩阵为:(注意此处的例子是将源坐标系A变换到目标坐标系B下)

\[\mathrm{M}=\left[ \begin{matrix}
u_{\mathrm{x}}& u_{\mathrm{y}}& u_{\mathrm{z}}& 0\\
v_{\mathrm{x}}& v_{\mathrm{y}}& v_{\mathrm{z}}& 0\\
w_{\mathrm{x}}& w_{\mathrm{y}}& w_{\mathrm{z}}& 0\\
Q_{\mathrm{x}}& Q_{\mathrm{y}}& Q_{\mathrm{z}}& 1\\
\end{matrix} \right]
\]

如之前所说,变换过程中点p在空间中的绝对位置没有发生改变,只是参考坐标系发生了改变,从B坐标系变到A坐标系。(缩放,旋转,平移变换只有在同一坐标系下才有意义)

矩阵变换是基于基向量组的结果

  • 矩阵变换之于同一个坐标系,可以理解为坐标系不变,点的位置改变
  • 矩阵变换之于不同坐标系,可以理解为点的绝对位置不变,坐标系改变
\[\left[ \begin{array}{c}
x^{'}\\
y^{'}\\
\end{array} \right] =B\left[ \begin{array}{c}
x\\
y\\
\end{array} \right] \Rightarrow \left[ \begin{array}{c}
x\\
y\\
\end{array} \right] =B^{-1}\left[ \begin{array}{c}
x^{'}\\
y^{'}\\
\end{array} \right] \text{,}B=\left[ \begin{matrix}
\overrightarrow{b_1}& \overrightarrow{b_2}\\
\end{matrix} \right] \text{,且}\overrightarrow{b_1}\text{,}\overrightarrow{b_2}\text{是坐标系}B\text{的基向量}
\]

其中,矩阵B的各个列向量分别对应B坐标系的各个基向量,\(
\left[ \begin{array}{c}
x\\
y\\
\end{array} \right]
\)是向量\(
\overrightarrow{OP}
\)或者说点P在B坐标系的表示,\(
\left[ \begin{array}{c}
x^{'}\\
y^{'}\\
\end{array} \right]
\)则是向量\(
\overrightarrow{OP}
\)或者点P在A坐标系中的表示

以图中的两个向量\(
\overrightarrow{b_1}
\),\(
\overrightarrow{b_2}
\)为基确定一个坐标系B,显然在B坐标系中\(
\overrightarrow{b_{1B}}=\left[ \begin{array}{c}
1\\
0\\
\end{array} \right]
\),\(
\overrightarrow{b_{2B}}=\left[ \begin{array}{c}
0\\
1\\
\end{array} \right]
\),接下来,将\(
\overrightarrow{b_1}
\),\(
\overrightarrow{b_2}
\)定位到A坐标系中,得到\(
\overrightarrow{b_{1A}}=\left[ \begin{array}{c}
2\\
1\\
\end{array} \right]
\),\(
\overrightarrow{b_{2A}}=\left[ \begin{array}{c}
-1\\
1\\
\end{array} \right]
\)

\(
\because \overrightarrow{OP}=2\overrightarrow{b_1}+2\overrightarrow{b_2}
\)

\(
\therefore \overrightarrow{OP}\)在B坐标系中的表示为\(
\left[ \begin{array}{c}
2\\
2\\
\end{array} \right]
\),现在,将\(
\overrightarrow{OP}
\)用A坐标系描叙:

\(
\overrightarrow{OP}=2\overrightarrow{b_1}+2\overrightarrow{b_2}=2\overrightarrow{b_{1A}}+2\overrightarrow{b_{2A}}=\left[ \begin{matrix}
\overrightarrow{b_{1A}}& \overrightarrow{b_{2A}}\\
\end{matrix} \right] \left[ \begin{array}{c}
2\\
2\\
\end{array} \right] =\left[ \begin{array}{c}
2\\
4\\
\end{array} \right]
\\
\)

现在,令矩阵B=\(
\left[ \begin{matrix}
\overrightarrow{b_{1A}}& \overrightarrow{b_{2A}}\\
\end{matrix} \right]
\),P点是用B坐标系表示的任意一点\((x,y)\)。

于是\(
\overrightarrow{OP}
\)在A坐标系中的表示\(
\left[ \begin{array}{c}
^{x^{'}}\\
y^{'}\\
\end{array} \right] =B\left[ \begin{array}{c}
x\\
y\\
\end{array} \right]
\),显然,B是可逆的,于是就有了之前的结论

那么在这个例子当中,当我们需要知道某点在转换坐标系后的新坐标时,通过该例子也可以加深印象,比如在B坐标系下有点\(Q(3,4)\),即\(\overrightarrow{OQ}=(3,4)\),跟据刚才的例子可以看出它转换在A坐标系下的点

\[\overrightarrow{OQ}=2\overrightarrow{b_1}+2\overrightarrow{b_2}=2\overrightarrow{b_{1A}}+2\overrightarrow{b_{2A}}=\left[ \begin{matrix}
\overrightarrow{b_{1A}}& \overrightarrow{b_{2A}}\\
\end{matrix} \right] \left[ \begin{array}{c}
3\\
4\\
\end{array} \right] =\left[ \begin{matrix}
2& -1\\
1& 1\\
\end{matrix} \right] \left[ \begin{array}{c}
5\\
4\\
\end{array} \right] =\left[ \begin{array}{c}
6\\
9\\
\end{array} \right]
\]

即转换到A坐标系下的点\(Q^{'}\)的坐标为\(Q^{'}(6,9)\)

虽然这里的讨论是基于二维的,但是,结论可以扩展到任意维度

阐述结论:

将B坐标系的基向量定位到A坐标系,然后将定位之后的基向量作为矩阵B的列向量,用矩阵B对B坐标系中的点P的坐标进行矩阵变换,将得到点P在A坐标系中的坐标。这个过程,就是从坐标系B到坐标系A的一个追溯过程

View/Camera Transformation

先将相机移到原点,然后进行分别对坐标轴进行旋转,用矩阵表示则是\(M_{view}=R_{view}T_{view}\)

  • 将相机移回原点
\[T_{view}=\left[ \begin{matrix}
1& 0& 0& -x_e\\
0& 1& 0& -y_e\\
0& 0& 1& -z_e\\
0& 0& 0& 1\\
\end{matrix} \right]
\]
  • \(Rotate\,\,g\,\,to\,\,-Z, t\,\,to\,\,Y, \left( g×t \right) \,\,To\,\,X\)

    g是相机看的方向(lookAt),t是相机向上的方向(Up),也就是相机的-Z轴和Y轴,两个向量叉积就是另一个坐标轴
\[R_{view}^{-1}=\left[ \begin{matrix}
x_{\widehat{g}×\widehat{t}}& x_t& x_{-g}& 0\\
y_{\widehat{g}×\widehat{t}}& y_t& y_{-g}& 0\\
z_{\widehat{g}×\widehat{t}}& z_t& z_{-g}& 0\\
0& 0& 0& 1\\
\end{matrix} \right]
\]

旋转矩阵是正交矩阵,所以旋转矩阵的逆就是旋转矩阵的转置

\[R_{view}^{}=\left[ \begin{matrix}
x_{\widehat{g}×\widehat{t}}& y_{\widehat{g}×\widehat{t}}& z_{\widehat{g}×\widehat{t}}& 0\\
x_t& y_t& y_t& 0\\
x_{-g}& y_{-g}& z_{-g}& 0\\
0& 0& 0& 1\\
\end{matrix} \right]
\]

正交投影矩阵

无论是正交投影还是透视投影,都是要将x、y、z移到-1到1的范围内,先将中心点移到原点,然后缩放

\[M_{ortho}=\left( \begin{matrix}
\frac{2}{r-l}& 0& 0& 0\\
0& \frac{2}{t-b}& 0& 0\\
0& 0& \frac{2}{n-f}& 0\\
0& 0& 0& 1\\
\end{matrix} \right) \left( \begin{matrix}
1& 0& 0& -\frac{r+l}{2}\\
0& 1& 0& -\frac{t+b}{2}\\
0& 0& 1& -\frac{n+f}{2}\\
0& 0& 0& 1\\
\end{matrix} \right)
\]

透视投影矩阵推导

首先先将frustum 转变为cuboid(n -> n,f -> f)(\(
M_{persp->ortho}
\)

)

然后再做正交投影

整个投影变换包括两部分

  • v = P(矩阵)*p
  • \(v=\frac{v}{v_w}=\frac{v}{pz}\)透视除法



以上大概推出等式这一步,接下来用公式展示更为直观

\[\left( \begin{matrix}
m00& m01& m02& m03\\
m10& m11& m12& m13\\
m20& m21& m22& m23\\
m30& m31& m32& m33\\
\end{matrix} \right) \left( \begin{array}{c}
x\\
y\\
z\\
1\\
\end{array} \right) =\left( \begin{array}{c}
\frac{x}{z*aspect*\tan \left( \frac{fov}{2} \right)}\\
\frac{y}{z*tan\left( \frac{fov}{2} \right)}\\
z^{‘’}\\
1\\
\end{array} \right)
\]
\[m00*x+m01*y+m02*z+m03=\frac{x}{z*aspect*\tan \left( \frac{fov}{2} \right)}
\]

将右边的四维列向量表示的坐标每一项乘以z,所以有

\[\left( \begin{matrix}
m00& m01& m02& m03\\
m10& m11& m12& m13\\
m20& m21& m22& m23\\
m30& m31& m32& m33\\
\end{matrix} \right) *\left( \begin{array}{c}
x\\
y\\
z\\
1\\
\end{array} \right) =\left( \begin{array}{c}
\frac{x}{aspect*\tan \left( \frac{fov}{2} \right)}\\
\frac{y}{\tan \left( \frac{fov}{2} \right)}\\
z*z^{{'}{'}}\\
z\\
\end{array} \right)
\]

所以求得矩阵为

\[\left( \begin{matrix}
\frac{1}{aspect*\tan \left( \frac{fov}{2} \right)}& 0& 0& 0\\
0& \frac{1}{\tan \left( \frac{fov}{2} \right)}& 0& 0\\
0& 0& m22& m23\\
0& 0& 1& 0\\
\end{matrix} \right)
\]
\[m22*z+m23 =\,\,z*z^{{'}{'}}
\\
\Rightarrow m22+\frac{m23}{z}=z^{{'}{'}}
\]

因为z=zNear时,z''=-1;z=zFar时,z''=1所以有以下等式

\[m22+\frac{m23}{zNear}=-1
\\
m22+\frac{m23}{zFar}=1
\]

联立求得:

\[m22=\frac{-zFar-zNear}{zNear-zFar}
\\
m23=\frac{2*zFar*zNear}{zNear-zFar}
\]

最后求得投影矩阵为

\[\left( \begin{matrix}
\frac{1}{aspect*\tan \left( \frac{fov}{2} \right)}& 0& 0& 0\\
0& \frac{1}{\tan \left( \frac{fov}{2} \right)}& 0& 0\\
0& 0& \frac{-zFar-zNear}{zNear-zFar}& \frac{2*zNear*zFar}{zNear-zFar}\\
0& 0& 1& 0\\
\end{matrix} \right)
\]

将这样得矩阵乘以视锥体内的一个顶点坐标,得到一个新的向量,再将这个向量的每个分量除以第四个分量(此步骤也被称为透视除法)(w),这样就可以得到顶点映射到规则立方观察体后的新的坐标

注意:z坐标的映射方式的获得,最后我们是为了方便矩阵乘法的操作方向求得了z坐标与cvv中的z坐标的映射方式:

\[m22+\frac{m23}{z}=z^{{'}{'}}
\]

此时的映射并不是线性的,当z越大时,z的变化对z''的扰动越小

Canonical Cube to Screen

  • Irrelevant to z
  • Transform in xy plane : [-1, 1] to [0, width] × [0, height]
  • Viewport transform matrix:

视口矩阵

\[M_{viewport}=\left[ \begin{matrix}
\frac{width}{2}& 0& 0& \frac{width}{2}\\
0& \frac{height}{2}& 0& \frac{height}{2}\\
0& 0& 1& 0\\
0& 0& 0& 1\\
\end{matrix} \right]
\]

深度z的计算

前言

3D光栅化发生在图元被变换到Screen space之后,因为这里的Screen space与2D的Screen Space完全一致,所以2D的光栅化算法在这里依然适用。

然而由于图元经过了投影变换,且投影变换为非线性变换,所以不能用简单的线性插值获取fragment的属性

投影变换不会保持相对距离不变性

如上图所示,view space中的线段v0v1上两点$
p0\left( p0_x,p0_y,p0_z,1 \right)
$,$
p1\left( p1_x,p1_y,p1_z,1 \right)
$在near plane上的投影为点$
s0\left( s0_x,s0_y \right)
$,$
s1\left( s1_x,s1_y \right)
$。$
p0
$,$p1$中间一点$v(v_x,v_y,v_z,1)$在near plane上的投影为点$q(q_x,q_y)$。从图中可以看出点v到p0,p1的距离比值与点q到s0,s1的距离比值完全不同,投影变换不保持距离不变。

为了执行z-buffer算法,需要通过点q获取到v的深度值(z)

点\(v\)的深度值可以通过如下方法插值得到:

\[v_z=\frac{1}{\frac{c}{p1_z}+\frac{\left( 1-c \right)}{p0_z}}
\]

以下是推导的过程:

手写版:



文字版:

由于点\(q\)为点\(v\)在near plane上的投影,因此点\(q\)与点\(v\)的关系为:

  • \(q_x=\frac{v_x·near}{v_z}\)

    且\(v\)位于\(p0p1\)之间,则
  • \(v_z=p0_{z}+t·(p1_z-p0_z)=\frac{v_x·near}{q_x}\)

    由点\(v\)在\(p0\),\(p1\)之间,点\(q\)在\(s0\),\(s1\)之间则有
  • \(v_x=p0_{x}·(1-t)+p1_{x}·t=p0_{x}+t·(p1_{x}-p0_{x})\)
  • \(q_x=s0_{x}·(1-c)+s1_{x}·c=s0_{x}+c·(s1_{x}-s0_{x})\)

    代入式(1)可得

    \(v_z=\frac{v_x·near}{q_x}=\frac{(p0_x+t·(p1_x-p0_x))·near}{s0_x+c·(s1_x-s0_x)}\)式(2)

    又s0和s1分别为p0和p1在near plane上的投影,则:
  • \(s0_x=\frac{p0_x·near}{p1_z}\)
  • \(s1_x=\frac{p1_x·near}{p1_z}\)

    代入式(2)可得:
\[v_z=\frac{\left( \frac{p0_x·s0_x}{near}+t·\left( \frac{p1_x·s1_x}{near}-\frac{p0_x·s0_x}{near} \right) \right) ·near}{s0_x+c·\left( s1_x-s0_x \right)}
\]
\[v_z=\frac{\left( \frac{p0_x·s0_x}{near}+t·\left( \frac{p1_x·s1_x}{near}-\frac{p0_x·s0_x}{near} \right) \right) ·near}{s0_x+c·\left( s1_x-s0_x \right)}
\\
v_z=\frac{\left( p0_x·s0_x+t·\left( p1_x·s1_x-p0_x·s0_x \right) \right)}{s0_x+c·\left( s1_x-s0_x \right)}
\\
p0_z+t·\left( p1_z-p0_z \right) =\frac{\left( p0_x·s0_x+t·\left( p1_x·s1_x-p0_x·s0_x \right) \right)}{s0_x+c·\left( s1_x-s0_x \right)}
\\
\left( p0_z+t·\left( p1_z-p0_z \right) \right) ·\left( s0_x+c·\left( s1_x-s0_x \right) \right) =p0_x·s0_x+t·\left( p1_x·s1_x-p0_x·s0_x \right)
\\
p0_z·s0_x+p0_z·c·\left( s1_x-s0_x \right) +t·\left( p1_z-p0_z \right) ·s0_x+t·c·\left( p1_z-p0_z \right) ·\left( s1_x-s0_x \right) =p0_x·s0_x+t·\left( p1_x·s1_x-p0_x·s0_x \right)
\]

化简得:

\[t·\left( p1_z-c·\left( p1_z-p0_z \right) \right) =c·p0_z
\]

则:

\[t=\frac{c·p0_z}{c·p0_z+(1-c)·p1_z}
\]

代入式(1)可得

\[v_z=p0_z+t·(p1_z-p0_z)
\]
\[v_z=p0_z+\frac{c·p0_z}{c·p0_z+(1-c)·p1_z}·(p1_z-p0_z)
\]
\[v_z=\frac{1}{\frac{c}{p1_z}+\frac{(1-c)}{p0_z}}
\]

若View Space中三角形\(v0v1v2\),变换到Screen Space后为三角形\(s0s1s2\),\(v0v1v2\)内一点v在Screen Space的投影点\(s0s1s2\)内的点\(q\),对三角形\(s0s1s2\)内的点(fragment)\(q\),可以通过如下方法取得fragment\(q\)在View Space中对应的深度值:

\[q.z=v.z=\frac{1}{\frac{\lambda0}{v0.z}+\frac{\lambda1}{v1.z}+\frac{\lambda2}{v2.z}}
\]

\(\lambda0,\lambda1,\lambda2\)为点p在三角形\(s0s1s2\)内的重心坐标

引入结论:

对Screen Space三角形\(s0,s1,s2\)内一点p的任意属性插值的公式为:

\[Atribute\left( p \right) =z·\left( \frac{\lambda 0·Atribute\left( v0 \right)}{z0}+\frac{\lambda 1·Atribute\left( v1 \right)}{z1}+\frac{\lambda 2·Atribute\left( v2 \right)}{z2} \right)
\]

\(\lambda0,\lambda1,\lambda2\)为点\(p\)的重心坐标,\(z0,z1,z2,z\)分别为\(s0,s1,s2,p\)在view space中对应点的深度值,可以用这个方法插值得到\(p\)在NDC Space内对应点的深度值

罗德里格斯旋转公式

字写得不好,在爬了...

手写版:

文字版:

首先先将\(\overrightarrow{k}\)处理成单位向量,这点很重要,关乎着下一步等式是否成立,有些博文写这里不需要处理单位向量,这是错的

\[\overrightarrow{v}·\overrightarrow{k}=|\overrightarrow{v}|·|\overrightarrow{k}|·\cos <\overrightarrow{v}\text{,}\overrightarrow{k}>=|\overrightarrow{v}|·\cos <\overrightarrow{v}\text{,}\overrightarrow{k}>
\]

可得

\[\overrightarrow{v_{||}}=|\overrightarrow{v}|·\cos <\overrightarrow{v},\overrightarrow{k}>·\overrightarrow{k}
\\
\overrightarrow{v}=\overrightarrow{v_{\bot}}+\overrightarrow{v_{||}}
\\
\overrightarrow{v_{\bot}}=\overrightarrow{v}-\overrightarrow{v_{||}}=\overrightarrow{v}-\left( \overrightarrow{v}·\overrightarrow{k} \right) \overrightarrow{k}
\]

绕\(\overrightarrow{k}\)做旋转时,向下做垂线,可看作底部经过了类似半圆的旋转

要求得\(\overrightarrow{v_{rot}}=\overrightarrow{v_{||}}+\overrightarrow{v_{rot\bot}}\),将\(\overrightarrow{v_{rot\bot}}\)作正交分解有\(
\overrightarrow{v_{rot\bot}}=\overrightarrow{a}+\overrightarrow{b}
\),易得\(
|\overrightarrow{w}|=|\overrightarrow{v_{\bot}}|
\),则有\(
\overrightarrow{w}=\overrightarrow{k}×\overrightarrow{v_{\bot}}=\overrightarrow{k}×\left[ \overrightarrow{v}-\overrightarrow{v_{||}} \right] =\overrightarrow{k}×\overrightarrow{v}-\overrightarrow{k}×\overrightarrow{v_{||}}=\overrightarrow{k}×\overrightarrow{v}-0=\overrightarrow{k}×\overrightarrow{v}
\)

接下来求\(
\overrightarrow{a}
\)和\(
\overrightarrow{b}
\)

\[|\overrightarrow{a}|=|\overrightarrow{v_{rot\bot}}|·\cos \left( \theta -90 \right) =|\overrightarrow{v_{rot\bot}}|·\sin \left( \theta \right)
\\
\overrightarrow{a}=\frac{\overrightarrow{w}}{|\overrightarrow{w}|}·|\overrightarrow{a}|=\frac{\overrightarrow{w}}{|\overrightarrow{v_{rot\bot}}|}·|\overrightarrow{v_{rot\bot}}|·\sin \left( \theta \right) =\overrightarrow{w}·\sin \left( \theta \right)
\]
\[|\overrightarrow{b}|=|\overrightarrow{v_{rot\bot}}|·\cos \left( 180-\theta \right) =|\overrightarrow{v_{rot\bot}}|·\cos \left( \theta \right)
\\
\overrightarrow{b}=\frac{\overrightarrow{v_{\bot}}}{|\overrightarrow{v_{\bot}}|}·|\overrightarrow{b}|=\frac{\overrightarrow{v_{\bot}}}{|\overrightarrow{v_{\bot}}|}·|\overrightarrow{v_{rot\bot}}|·\cos \left( \theta \right) =\overrightarrow{v_{\bot}}·\cos \left( \theta \right) \,\, \text{注意}|\overrightarrow{v_{\bot}}|=|\overrightarrow{v_{rot\bot}}|
\]
\[\overrightarrow{v_{rot\bot}}=\overrightarrow{a}+\overrightarrow{b}=\overrightarrow{w}·\sin \left( \theta \right) +\overrightarrow{v_{\bot}}·\cos \left( \theta \right) =\sin \left( \theta \right) ·\left( \overrightarrow{k}×\overrightarrow{v} \right) +\cos \left( \theta \right) \left( \overrightarrow{v}-\left( \overrightarrow{v}·\overrightarrow{k} \right) \overrightarrow{k} \right)
\\
\overrightarrow{v_{rot}}=\overrightarrow{v_{||}}+\overrightarrow{v_{rot\bot}}=\left( \overrightarrow{v}·\overrightarrow{k} \right) \overrightarrow{k}+\sin \left( \theta \right) ·\left( \overrightarrow{k}×\overrightarrow{v} \right) +\cos \left( \theta \right) \left( \overrightarrow{v}-\left( \overrightarrow{v}·\overrightarrow{k} \right) \overrightarrow{k} \right)
\\
=\cos \left( \theta \right) \overrightarrow{v}+\left( 1-\cos \left( \theta \right) \left( \overrightarrow{v}·\overrightarrow{k} \right) \overrightarrow{k} \right) +\sin \left( \theta \right) ·\left( \overrightarrow{k}×\overrightarrow{v} \right)
\]

把\(
\overrightarrow{k}
\)和\(
\overrightarrow{v}
\)分别写为列向量

\[\overrightarrow{k}=\left( \begin{array}{c}
k_x\\
k_y\\
k_z\\
\end{array} \right)
\]
\[\overrightarrow{v}=\left( \begin{array}{c}
v_x\\
v_y\\
v_z\\
\end{array} \right)
\]

令\(
\overrightarrow{v_{rot}}=R·\overrightarrow{v}
\)

两个式子

\[\left( \overrightarrow{v}·\overrightarrow{k} \right) \overrightarrow{k}=\overrightarrow{k}\left( \overrightarrow{v}·\overrightarrow{k} \right) =\overrightarrow{k}\left( \overrightarrow{k^T}·\overrightarrow{v} \right)
\]
\[\overrightarrow{k}×\overrightarrow{v}=\left[ \begin{array}{c}
k_yv_z-k_zv_y\\
k_zv_x-k_xv_z\\
k_xv_y-k_yv_x\\
\end{array} \right] =\left[ \begin{matrix}
0& -k_z& k_y\\
k_z& 0& -k_x\\
-k_y& k_x& 0\\
\end{matrix} \right] \left[ \begin{array}{c}
v_x\\
v_y\\
v_z\\
\end{array} \right]
\]

结合以上两个式子可得,其中\(I\)为3×3的单位矩阵

\[R=I\cos \left( \theta \right) +\left( 1-\cos \left( \theta \right) \right) \left( \begin{array}{c}
k_x\\
k_y\\
k_z\\
\end{array} \right) \left( \begin{matrix}
k_x& k_y& k_z\\
\end{matrix} \right) +\sin \left( \theta \right) \left( \begin{matrix}
0& -k_z& k_y\\
k_z& 0& -k_x\\
-k_y& k_x& 0\\
\end{matrix} \right) \,\,
\]

以下是比较通用的表示方式

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

部分引用的博文

https://blog.csdn.net/unclerunning/article/details/70948696#齐次坐标系与平移

https://zhuanlan.zhihu.com/p/45757899

回顾Games101图形学(一)几何变换中一些公式的推导的更多相关文章

  1. 《Shader入门精要》中MVP变换的Projection矩阵与《GAMES101图形学入门》中的区别

    game101的透视投影的投影矩阵是这样的 正交投影是这样的 而shader入门精要的透视投影矩阵是这样子 正交投影矩阵是这样子 game101的透视投影是这样得到的 而正交投影的时候并没有假设中心点 ...

  2. 回顾games101中的SSAA和MSAA

    回顾games101中的AA(抗锯齿) 前言 善于进行课后总结,可以更加巩固自己的知识和具体细节 锯齿(走样)产生的原因 本质上,在光栅化阶段中,用有限离散的数据想表示连续的(类似三角形的某一边),就 ...

  3. [word]2010中插入公式自动编号并且公式不自动缩小/变小

    要实现在word2010中插入公式自动编号,就要用到自动图文集功能,具体操作如下: 1.先制定制表位位置:单击一个空白段落,然后双击标尺线的底部:这会激活"制表位"对话框,如图所示 ...

  4. Microsoft Office Word 中的公式自动编号

    先插入公式,#,插入题注(交叉引用),生成了标号.此时整个公式是题注样式.在公式和标号之间插入一个样式分隔符. ____________________________________________ ...

  5. 不用MathType, 如何在Mac Word中插入公式

    不用MathType, 如何在Mac Word中插入公式 找了好久都找不到MathType的破解版,不得不使用免费清爽的MarkDown编辑工具Typora_for_Mac. 我是很喜欢Typora的 ...

  6. 在jupyter notebook 中编辑公式

    jupyter notebook是一个python的交互式开发环境,广泛应用于数据分析的场景下. 在jupyter notebook中,还可以很方便的编辑数学公式. 1.Markdown状态 编辑公式 ...

  7. Word 中实现公式居中编号右对齐 -- 含视频教程(9)

    1. 两种方法 不管你用「Word 自带公式」还是「Mathtype」,一般来说,Word 中实现公式居中编号右对齐的方法有两种.(1):表格法:(2):制表位. 2. 方法1:表格法 >> ...

  8. 在Markdown中写公式块

    Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式. Markdown中的公式语法是遵循LaTex语法的 $ sum = \sum_{i ...

  9. MathType的配置问题;将word中的公式转换为mathtype格式失败,缺少OMML2MML.XSL

    安装MathType后打开word报错 打开会出现以下问题: 首先,把startup添加到word的信任中心: 要确保路径被office信任.依次打开word->文件->选项->信任 ...

随机推荐

  1. 技术博客:Azure Functions + Azure Storage 开发

    Azure GitHub wiki 同步发布 传送门 Azure Functions 通过 Functions(一个事件驱动型无服务器计算平台,还可以解决复杂的业务流程问题)更加高效地进行开发.在本地 ...

  2. 调用免费API查询全年工作日、周末、法定节假日、节假日调休补班数据

    前言 日常开发中,难免会用到判断今天是工作日.周末.法定节假日.节假日调休补班做一些业务处理,例如:仅在上班时间给用户推送消息.本文记录调用免费API查询全年工作日.周末.法定节假日.节假日调休补班数 ...

  3. [bug] Unrecognized token 'code': was expecting (JSON String, Number, Array, Object,'true', 'false' or 'null')

    JSON格式有误,需用JSON.stringify()函数转换一下 参考 https://www.cnblogs.com/sunyanblog/p/13788740.html https://www. ...

  4. [Java] Solr & Elasticsearch

    背景 实现网站自带的搜索功能,如淘宝中的商品搜索 全文搜索 数据分类 结构化数据:固定格式或长度有限的数据,如数据库.元数据等 非结构化数据:不定长或无固定格式的数据,如邮件.word文档等 搜索分类 ...

  5. Docker——Registry搭建私有镜像仓库

    前言 在 Docker 中,当我们执行 docker pull xxx 的时候,它实际上是从 registry.hub.docker.com 这个地址去查找,这就是Docker公司为我们提供的公共仓库 ...

  6. elasticksearch分词,导致kibana的url出现问题

    在Kibana的展示页面中,我们点击Table的左侧栏,发现Elasticsearch中的数据在展示中是正确的数据,比如:agent中www.baidu.com/test,该界面中会正确的显示为www ...

  7. Ansible_管理playbook实现配置并行

    一.使用forks在Ansible中配置并行 1.Aniable运行play机制 1️⃣:当Ansible处理playbook时,会按顺序运行每个play.确定play的主机列表之后,Ansible将 ...

  8. Kubernetes 部署微服务电商平台(16)

    一.概念 微服务就是很小的服务,小到一个服务只对应一个单一的功能,只做一件事.这个服务可以单独部署运行,服务之间可以通过RPC来相互交互,每个微服务都是由独立的小团队开发,测试,部署,上线,负责它的整 ...

  9. 058.Python前端Django与Ajax

    一 Ajax简介 AJAX(Asynchronous Javascript And XML)翻译成中文就是"异步Javascript和XML".即使用Javascript语言与服务 ...

  10. python基础之错误、调试(异常处理)

    在程序运行过程中,总会遇到各种各样的错误. 有的错误是程序编写有问题造成的,比如本来应该输出整数结果输出了字符串,这种错误我们通常称之为bug,bug是必须修复的. 有的错误是用户输入造成的,比如让用 ...