实时渲染 -- 变换(Transformation)

模型变换(Model Transformation)

模型变换:模型空间坐标可经过模型变换得到世界空间坐标。模型变换可理解为设置场景中模型的位置(包括角度、大小)。在进行模型变换时,大多数应用(符合人的直觉)都会按照以下顺序进行变换:伸缩、旋转、位移

M_{model} = T_{model}R_{model}S_{model}

为什么需要按照伸缩、旋转、位移的顺序进行变换?
比方说,通过变换希望获得的结果可能是:将一个放在原点的可乐罐移动到(30,50),让它自身倾斜45度,再放大2倍。 而不希望的结果是:

  • 当缩放在旋转之后时,会发生和本地坐标轴成角度的缩放(会导致扭曲,像踩扁的可乐罐)。
  • 当缩放和旋转在位移之后时,会发生进行绕自己几何中心以外位置的原点的旋转(地球公转式)和缩放。

变换常用有三种:伸缩【线性变换】、旋转【线性变换】、位移【位移变换】。

而我们常听到的仿射(affline)变换,实际上就是线性变换与位移变换相乘后的变换结果。

伸缩(Scale)

S(s_x,s_y,s_z) = \begin{pmatrix} s_x & 0 & 0 & 0 \\ 0 & s_y & 0 & 0 \\ 0 & 0 & s_z & 0\\ 0 & 0 & 0 & 1 \end{pmatrix}

旋转(Rotation)

xy平面绕z轴旋转\phi度(俯仰角-Pitch)的旋转矩阵:

R_{xy}(\phi ) = \begin{bmatrix} cos\phi & -sin\phi & 0 \\ sin\phi & cos\phi & 0 \\ 0 & 0 & 1 \end{bmatrix}

yz平面绕x轴旋转\psi度(滚动角 - Roll)的旋转矩阵:

R_{yz}(\psi ) = \begin{bmatrix}1 & 0 & 0 \\ 0 & cos\psi & -sin\psi \\ 0 & sin\psi & cos\psi \end{bmatrix}

xz平面绕y轴旋转\theta度 (偏航角- Yaw) 的旋转矩阵:

R_{xz}(\theta ) = \begin{bmatrix} cos\theta & 0 & sin\theta \\ 0 & 1 & 0 \\ -sin\theta & 0 & cos\theta \end{bmatrix}

 

 这三种旋转运动是独立的,也就是说,你可以实施任意一种旋转而不考虑其他的旋转,当然,也可依次实施这三种旋转。

M = \begin{bmatrix}1 & 0 & 0 \\ 0 & cos\psi & -sin\psi \\ 0 & sin\psi & cos\psi \end{bmatrix} \begin{bmatrix} cos\theta & 0 & sin\theta \\ 0 & 1 & 0 \\ -sin\theta & 0 & cos\theta \end{bmatrix} \begin{bmatrix} cos\phi & -sin\phi & 0 \\ sin\phi & cos\phi & 0 \\ 0 & 0 & 1 \end{bmatrix} = \begin{bmatrix} cos\theta cos\phi & -cos\theta sin\phi & sin\theta \\ \ast & \ast & -sin\psi cos\theta \\ \ast & \ast & cos\psi cos\theta \end{bmatrix}

通过选择合适的\theta, \phi , \psi的值,该乘积能表示所有可能的旋转。但是当cos\theta = 0 时的情形有点复杂,例如当 \theta = \pi / 2,可以发现多个(\phi ,\psi ) 对应同一个结果;改变他们并不会导致物体姿态的变化,这种现象被称作“万向节锁”  解决这个问题可以利用四元数,这里不在详述

可以证明3D空间中的每个旋转都是围绕某一轴旋转某个角度,于是有绕向量n旋转α弧度角,最后得到3X3矩阵还要扩展成4X4矩阵

R(n,\alpha ) = cos(\alpha ) E + (1-cos(\alpha ))nn^T + sin(\alpha )\begin{pmatrix} 0 & -n_z & n_y \\ n_z & 0 & -n_x\\ -n_y & n_x & 0 \end{pmatrix}

任何旋转必定是正交变换(理由可以自己去查),而正交矩阵的好处就是它的逆矩阵必定是转置矩阵,这样求逆的时候就不必通过复杂的求逆方法(例如用克莱姆法则)

 位移(Translation)

T(t_x,t_y,t_z) = \begin{pmatrix} 1 & 0 & 0 & t_x\\ 0 & 1 & 0 & t_y\\ 0 & 0 & 1 & t_z\\ 0 & 0 & 0 & 1 \end{pmatrix}

齐次坐标表示法 

齐次坐标系是与笛卡尔坐标不同的坐标表示法,相当于笛卡尔坐标再增广一个w维度,如笛卡尔坐标(3,4,0)可扩展成齐次坐标(3,4,0,1)。

  • 3Dpoint=(x,y,z,1)^T:齐次坐标的w分量为1时,该向量视为点(x,y,z)
  • 3Dvector= (x,y,z,0)^T :齐次坐标的w分量为0时,该向量视为向量(x,y,z)
  • 3Dpoint= (x,y,z,w)^T :齐次坐标的w分量不为0时,该向量视为齐次坐标(\frac{x}{w},\frac{y}{w},\frac{z}{w},1)
    ,即对应笛卡尔点(\frac{x}{w},\frac{y}{w},\frac{z}{w})

图形学常用齐次坐标,是因为三维空间下的位移只可用三维矩阵加法,而线性变换却都是用三维矩阵乘法。为了统一这些变换的表示,引入了齐次坐标,通过增加一个维度便可以让矩阵乘法完美支持三维空间下的位移。 

这样一来,我们不仅可以统一所有变换都使用乘法,还可以用4X4矩阵表示一个将若干个变换(无论是线性还是位移)压缩后的变换,从而节省内存:

A_{compose} = A_1A_2A_3....

此,三维空间下的变换往往用4X4矩阵表示,而点/向量则用4个分量的向量表示。

视图变换/观察变换(View/Camera Transformation)

首先,在产生视图之前,我们需要定义摄像机(位置、朝前方向、朝上方向),也就是我们人眼在哪个地方朝某个方向看。同时我们还注意到,摄像机在不同的位置朝不同的方向看,在有些情况下应该看到的画面是等价的:

因此为了方便计算,我们可以以摄像机的位置视为原点,以朝前方向为Z轴、朝上方向为Y坐标轴建立一个坐标系(摄像机坐标系)

视图变换/观察变换:世界空间坐标可经过视图变换得到观察空间坐标。视图变换可理解为将物体的世界坐标系位置(包括角度)转换成在摄像机坐标系的位置(包括角度),换句话说就是求物体相对于摄像机的位置(包括角度)。

摄像机的世界坐标是 M_{modelC} = T_{modelC}R_{modelC}

但想象一下,现在我们要将摄像机的世界坐标经过一定变换,变换成在原点的位置且轴向与朝向一致,这样的话求物体相对于摄像机的位置实际上就是让物体也经过相同的变换后得到的位置,因此有了下面视图变换的公式:

M_{view} = R_{view}T_{view}

其中R_{view},T_{view}分别为R_{modelC},T_{modelC}的逆矩阵

正好由于旋转矩阵R是正交矩阵,其求逆只需直接转置矩阵,然后位移矩阵T求逆也只需将简单的将t_{x},t_{y},t_{z}都变一下正负号。

投影变换(Projection Transformation)

投影变换:观察空间的坐标通过投影变换得到裁剪空间(Clip Space)的坐标。投影变化则可理解成将3D空间中的坐标转换成在投影面上的坐标,即将三维空间上的东西投影在我们最终呈现画面的投影面。

为此我们需要先定义视景体:

  • 剪裁面(Near Clip Plane):最终投影呈现的面
  • 远剪裁面(Far Clip Plane):视景体可见的最远面

这样,我们认为摄像机可见范围便是这两个面之间的空间范围,不过投影又分为透视投影正交投影两种投影方式,因此前者的空间是一个截锥体(Frustum)而后者则是一个长方体(Cuboid):

为了方便计算成像,我们规定将可视的范围空间映射成 规范立方体(canoical cube),这个立方体实际上就是所谓的裁剪空间,且立方体长宽高范围均设定为[-1,1]

这个投影出来的空间之所以叫裁剪空间,是因为通过规范范围,可将[-1,1]以外的坐标(这意味着不在可视范围内)很方便地裁剪掉。

正交投影(Orthographic Projection)

可以理解成行投射(例如太阳照射,可以看成无数条行线投射过来)。物体无论放多远,最终在投影面看到的大小都不会变,常用于2D游戏的投影方式。

坐标映射成规范立方体里的坐标很简单,只需要先位移至规范立方体的中心点,后伸缩成[-1,1]的范围即可,因此正交投影变换的公式为:

M_{ortho} = \begin{pmatrix} \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{pmatrix} \begin{pmatrix} 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{pmatrix}

其中l、r为视景体在x轴上的最大值、最小值,t、b为在y轴上的最大值、最小值,f、n为在z轴上的最大最小值。

透视投影(Perspective Projection)

符合现实人眼的投影方式,典型特征就是近大远小,大部分3D游戏使用的都是透视投影方式。

将截锥体映射成规范立方体的方式则可以先把截锥体映射成长方体,再沿用正交投影变换映射成规范立方体。

我们可以根据近裁面离视点的距离(z轴值)和近裁面的高度(y轴值)或宽度(x轴值),利用相似三角形计算出对应物体映射在长方体的新x值和y值: 

x' = \frac{n}{z}x

y' = \frac{n}{z}y

不过在齐次坐标表示中,如果w不为0,实际等价于表示(\frac{x}{w},\frac{y}{w},\frac{z}{w},1)

\begin{pmatrix} n & 0 & 0 & 0\\ 0 & n & 0 & 0\\ 0 & 0 & A & B\\ 0 & 0 & 1 & 0 \end{pmatrix}\begin{pmatrix} x\\ y\\ z\\ 1 \end{pmatrix} = \begin{pmatrix} nx\\ ny\\ zz'\\ z \end{pmatrix} = \begin{pmatrix} nx/z\\ ny/z\\ z'\\ 1 \end{pmatrix}

此时A、B仍然未知(因为挤压后的z′是不确定的,但是近裁面的z和远裁面的z必须和原来一致),我们可以通过解方程求得A、B,假设一个点(x1,y1,n)在近裁面,另一个点(x2,y2,f)在远裁面,我们期望最终经过映射后的z轴维度分别为n^2,f^2,则有:An+B = n^2, Af+B=f^2

从而解得:A= n+f, B = -nf

裁剪(Clipping)

当摄像机视野范围覆盖不了所有场景物体的时候,可以用对摄像机视野范围外的物体裁剪掉,从而减少不必要的进一步计算。

由于通过MVP变换,我们得到的顶点坐标各分量均是[-1,1]范围(即视野范围内),那么只要简单的把这个范围外的顶点剔除即可。但是仍有一些图元的部分顶点在视野范围内,另一些则在视野范围内,则需要“裁剪”掉视野外的部分,并在视野边界生成新的顶点。

与视锥体剔除不同,视锥体剔除往往是在CPU判断整个物体对象是否在摄像机视野内,要不剔除整个对象,要不什么也不剔除。而裁剪则是在GPU判断顶点是否在摄像机视野内,对某个图元允许仅裁剪一部分。

虽然有l,r,b,t表示面的左右上下最大值,但是在通常的应用中会使用更加直观的两个参数:
fovY(vertical field-of-view) 和 Aspect Ratio,可理解为仰角范围和宽高比

  • 21
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想做后端的前端

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值