# Viewing transformation

image-20210613235341120

视图变换包括了我们的模型变换,取景变换,投影变换,这是整个由 3 维转向 2 维的重要一步。我们可以类比我们日常生活中的拍摄的过程,首先我们需要找一个我们需要拍摄的对象,这部分叫做 model transformation (译:模型变换),这里完成的是将需要的模型构建出来,然后我们需要给相机找一个好的位置,好的角度,好的姿态,这部分叫做 view transformation(译:取景变换),这里完成的是取景器的设置工作,我们需要明确取景的位置,角度,姿态。最后我们需要按下我们的快门。这部分叫做 projection transformation(译:投影变换),这里完成将图像进行映射。这个过程简称为 MVP,因为模型变换部分需要建模部分,我们这里不讨论,只讨论图像部分的取景变换和投影变换。

# View transformation

# Basic Definition

View/Camera Transformation 取景变换,这里需要完成对取景点的设置,这是非常重要的一部,取景点的信息直接决定了投影变换的各种信息,也决定了最后成像的效果。决定取景点主要有以下几个信息:

  • Position:e\vec{e}.
  • Look-at / Gaze direction:g^\hat{g} .
  • Up direction:t^\hat{t} .

image-20210614001011956

现在我们考虑一个情景,相机和目标能够通过移动特殊的数值使得获取的信息和移动前一样。这就出现了一种麻烦的情况,我们需要进行两次计算,才能获取到一样的信息。所以为了简化相机与目标的相对关系,我们规定了相机的位置,我们称之为 Key observation,即相机的位置是在原地位置,以 -Z 为观察方向,Y 轴为水平偏差标准。这样所有的变换就成了目标的移动。

image-20210614002102132

有了这个规定以后,我们就能够将任意一个取景点进行变换,变到 Key observation,只需要:

  • Rotates g^\hat{g} to -Z
  • Rotates t^\hat{t} to Y
  • Rotates (g^×t^)(\hat{g} \times \hat{t}) To X

image-20210614002558978

# Math Conversion

在数学上,按照之前在目标转化分解一节中的描述,我们现进行平移变换使得位置到达原点,此时线性变换就能以原点为轴。

Mview=RviewTviewM_{view }= R_{view} T_{view}

平移变换TviewT_{view} 的部分

Tview=[100xe010ye001ze0001]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]

线性变换 $R_{view} $ 不好写,因为本身从特殊点进行的变换,但是我们可以通过到达目标位置进行逆变换来获取,然后利用其性质,其逆矩阵就是其转置矩阵:

Rview1=[xg^×t^xtxg0yg^×t^ytyg0zg^×t^ztzg00001]R_{view}^{-1} = \left[ \begin{matrix} 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{matrix}\right]

Rview=[xg^×t^yg^×t^yg^×t^0xtytzt0xgygzg00001]R_{view} = \left[ \begin{matrix} x_{\hat{g} \times \hat{t}} & y_{\hat{g} \times \hat{t}} &y_{\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{matrix}\right]

# Projection Transformation

# Basic Definition

投影变换是取景的最后一步,根据不同的场景设定有两种不同的投影类型,分别是:

  • Perspective projection:透视投影
  • Orthographic projection:正交投影

这两者最大的区别就是是否有近大远小的性质。

image-20210614005922421

# Orthographic Projection

正交投影作为最简单的投影方式,实际上假设取景点在无穷远的地方,这样就能让成像的画面和实际取景的每一个点都构成平行线。也正因取景点在无穷远的地方,使得目标物体间的具体可以忽略不记,这样物体的深度信息就丢失了,也就是 Z 的信息。

image-20210614010358393

对于一个已知的物体,我们需要 6 个信息来进行正交变换,分别是:

  • 左右信息:l r
  • 深度信息:n f
  • 高度信息:t b

image-20210614010659761

同理(目标转化分解),我们先进行平移变换,使各个维度的中点的投影在原点上,然后再进行线性变换:

Mortho=[2rl00002tb00002nf00001][100r+l2010t+b2001n+f20001]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]

Note: n > f

# Perspective Projection

透视投影是非常常见的投影方式,在 CG,艺术等领域都有广泛的应用,因为能够提供深度的信息,同时也符合人眼的成像习惯,因而能够给人带来真实感。透视投影的实质在特定的取景点下,成像画面会将取景画面进行 “挤压”,每个点到点之间构成的线不再能够平行。

image-20210614012101871

如果我们想要获取一个物体的透视投影,我们可以通过两步来实现:

  • 第一步:将物体图像挤压到和成像大小一样
  • 第二部:将挤压后的物体图像进行正交投影

image-20210614012252484

遵守几个规定:

  • 近平面的点永远不变
  • 远平面的点挤压后 Z 不会改变
  • 远平面的中心点在挤压中不会改变

有了这些基本的规定后,我们试着来推导一下整个过程。

首先看 “挤压” 的过程,我们以其中一个切面的角度看:

image-20210614124449790

因此我们能够获得:

y=nzyx=nzxy^{\prime} = \frac{n}{z} y \\ x^{\prime} = \frac{n}{z} x

image-20210614125553440

我们就能转换成

Mpresportho(xyz1)=(nxnyunknownz)M_{presp \to ortho } \left( \begin{matrix} x \\ y \\ z \\ 1 \end{matrix}\right) = \left( \begin{matrix} nx \\ ny \\ unknown \\ z \end{matrix}\right)

根据结果我们可以推算出

Mpresportho=(n0000n00????0010)M_{presp \to ortho } = \left( \begin{matrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ ? & ? & ? & ? \\ 0 & 0 & 1 & 0 \end{matrix}\right)

接着我们根据规定近平面的点永远不变远平面的点挤压后 Z 不会改变

近平面的点永远不变

image-20210614131418596

因此我们能够得出:

(00AB)(xyn1)=An+B=n2\left( \begin{matrix} 0 & 0 & A & B \end{matrix}\right) \left( \begin{matrix} x \\ y \\ n \\ 1 \end{matrix}\right) = An + B = n^2

远平面的点挤压后 Z 不会改变

image-20210614131855246

因此我们能够得出:

(00AB)(00f1)=Af+B=f2\left( \begin{matrix} 0 & 0 & A & B \end{matrix}\right) \left( \begin{matrix} 0 \\ 0 \\ f \\ 1 \end{matrix}\right) = Af + B = f^2

我们就获得一个方程组:

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

解的得:

{A=n+fB=nf\left\{ \begin{array}{c} A = n + f\\ B = -nf \end{array} \right.

因此 “挤压” 的转化矩阵为:

Mpresportho=(n0000n0000n+fnf0010)M_{presp \to ortho } = \left( \begin{matrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 & n + f & -nf \\ 0 & 0 & 1 & 0 \end{matrix}\right)

# Application

了解了两种核心的投影方式和相应的计算后,我们还需要知道一些常用的数据转化

  • fovYfov Y :vertical field-of-view 指的是相机的广角角度
  • aspectratio=widthheightaspect \space ratio = \frac{width}{height} : 显示的长宽比

image-20210615214050878

通过这两个常用的数据转为我们需要的数据(r, l, b, t)

这里我们一般假设: l = -r, b= -t

image-20210615214353135

这里我们可以获得

angle:fovY2tanfovY2=tnaspect=rtangle : \frac{fovY}{2} \\ \tan{\frac{fovY}{2}}= \frac{t}{|n|} \\ aspect = \frac{r}{t}

当我们在做透视投影或者正交投影时,都会最后转为规范立方矩阵,然后我们先需要通过 Viewport Transform 矩阵将图像转为显示器尺寸的矩阵:

Mpresportho=(width200width20height20height200100001)M_{presp \to ortho } = \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)

# Case One

问题:求出已知图像绕一个经过原点的任意轴旋转θ\theta 的转化矩阵

image-20210615220747011

分析:之前我们已经分析过绕 X,Y,Z 轴旋转的旋转矩阵了,现在我们需要的是任意过原点的旋转轴。我们可以通过把未知的旋转方式转为已知的进行旋转(Z,X,Y), 然后旋转完,再逆变换回去。

image-20210615221647796

如图所示,假设我们需要绕向量 V 为轴进行旋转θ\theta 角度,那么首先我们可以将向量进行旋转,使得 V 与已知的(X,Y,Z)其中一个重合,我这里演示的是与 Z 轴重合:分为两步法

  • 将向量绕 X 轴旋转到 ZOX 平面 获得V_
  • 然后将VZOXV_{ZOX} 绕 Y 轴旋转到和 Z 轴重合

第一步:将向量绕 X 轴旋转到 ZOX 平面 获得V_

image-20210615223353071

绕 X 轴旋转的角度αα 等于向量 V 在 ZOY 平面上的投影向量VZOYV_{ZOY} 与 Z 轴正向的夹角。其实就是VZOYV_{ZOY} 和 V 组成的面上的所有经过原点的向量要想通过 X 轴旋转到 ZOX 都是转的角度αα,由投影可知

VZOY(0,b,c)V_{ZOY} (0,b,c)

则夹角就可以通过简单的三角函数获得:

sinα=bb2+c2,cosα=1sin2α\sin{\alpha} = \frac{b}{\sqrt{b^2+c^2}}, \space \cos{\alpha} = 1 - \sin^2{\alpha}

获得到角度后,我们就能够列出绕 X 轴旋转的矩阵:

Vx(α)=(10000cosαsinα00sinαcosα00001)V_x(\alpha) = \left( \begin{matrix} 1 & 0 & 0 & 0 \\ 0 & \cos \alpha & -\sin \alpha & 0 \\ 0 & \sin \alpha & \cos \alpha & 0 \\ 0 & 0 & 0 & 1 \end{matrix}\right)

第二步:然后将VZOXV_{ZOX} 绕 Y 轴旋转到和 Z 轴重合

image-20210615225017184

绕 Y 轴旋转的角度β\beta 等于向量VZOXV_{ZOX} 与 Z 轴正向的夹角,这里我们可以知道VZOXV_{ZOX} 是由 V 绕 X 轴旋转而来,所以 X 轴的分量保持不变,Y 轴分量为 0,因为模长不变,所以可知

VZOX(a,0,b2+c2)V_{ZOX} (a,0,\sqrt{b^2+c^2})

同理,夹角就可以通过简单的三角函数获得:

sinβ=aa2+b2+c2,cosα=1sin2α\sin{\beta} = \frac{a}{\sqrt{a^2+b^2+c^2}}, \space \cos{\alpha} = 1 - \sin^2{\alpha}

获得到角度后,我们就能够列出绕 Y 轴旋转的矩阵:

Vy(β)=(cosβ0sinβ00100sinβ0cosβ00001)V_y(\beta) = \left( \begin{matrix} \cos \beta & 0 & \sin \beta & 0 \\ 0 & 1 & 0 & 0 \\ -\sin \beta & 0 & \cos \beta & 0 \\ 0 & 0 & 0 & 1 \end{matrix}\right)

完成这两步后我们就能对目标进行绕 Z 轴θ\theta 角度的旋转:

Vz(θ)=(cosθsinθ00sinθcosθ0000100001)V_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)

最后,将物体旋转回之前的位置。具体做法是乘以之前矩阵的逆矩阵。至此,我们得到物体旋转所需要的最终矩阵:

V(θ)=Vx(α)Vy(β)Vz(θ)Vy(β)Vx(α)V(\theta) = V_x(-\alpha)V_y(-\beta)V_z(\theta)V_y(\beta)V_x(\alpha)

而我们知道旋转矩阵的逆矩阵等于其转置矩阵,于是我们可以得到:

V(θ)=VxT(α)VyT(β)Vz(θ)Vy(β)Vx(α)V(\theta) = V^T_x(\alpha)V^T_y(\beta)V_z(\theta)V_y(\beta)V_x(\alpha)

# Case Two

问题:求出已知图像绕任意一个轴旋转θ\theta 的转化矩阵

分析:之前我们已经分析过绕过原点的任意轴旋转的旋转矩阵了,现在我们需要的是绕任意轴旋转。我们可以通过把未知的轴起点平移到原点,这样就能转为过原点的任意轴旋转的问题,然后旋转后,再把轴平移回去即可。

image-20210615232453557

如图所示,假设我们需要绕向量SP\vec{SP}为轴进行旋转θ\theta 角度,那么首先我们可以将向量进行平移,使得向量变成以原点为初始点的向量,这样就能用 Case One 的方法解答分:

  • 将向量SP\vec{SP}平移使得起点在原点
  • 解答绕过原点任意轴的问题

第一步:将向量SP\vec{SP}平移使得起点在原点

T(x,y,z)=(100a1a010b1b001c1c0001)T(x,y,z) = \left( \begin{matrix} 1 & 0 & 0 & a_1-a \\ 0 & 1 & 0 & b_1-b \\ 0 & 0 & 1 & c_1-c \\ 0 & 0 & 0 & 1 \end{matrix}\right)

第二步:使用 Case One 的方法

V(θ)=VxT(α)VyT(β)Vz(θ)Vy(β)Vx(α)V(\theta) = V^T_x(\alpha)V^T_y(\beta)V_z(\theta)V_y(\beta)V_x(\alpha)

最后,将物体平移回之前的位置。具体做法是乘以之前矩阵的反方向。至此,我们得到物体旋转所需要的最终矩阵:

V(θ)=T(x,y,z)VxT(α)VyT(β)Vz(θ)Vy(β)Vx(α)T(x,y,z)V(\theta) = T(-x,-y,-z)V^T_x(\alpha)V^T_y(\beta)V_z(\theta)V_y(\beta)V_x(\alpha)T(x,y,z)

更新于

请我喝[茶]~( ̄▽ ̄)~*

Junwide Xiao 微信支付

微信支付

Junwide Xiao 支付宝

支付宝