原文:计算机图形学(四)-MVP变换之视图(View)变换 - 2021.08.07
作者:点燃火柴 - CSDN
1. 视口变换
视口变换(Viewport Transform)
当我们要把物体投影到屏幕上,首先经过MVP变换以标准立方体绘制到屏幕上,在绘制前要把这个标准立方体变换到屏幕空间上,这个变换过程称之为视口变换。
假设屏幕大小为width×height,暂时不考虑z轴变换,变换分为两步:
- 缩放,将标准立方体x轴和y轴长度分别缩放为width和height
- 平移,将标准立方体的中点从原点平移到屏幕中心(width/2,height/2)
根据平移变换和缩放变换矩阵结构,推算出 视口变换矩阵
2. 光栅化(Rasterization)
2.1. 屏幕空间、像素
学习光栅化前,先要了解两个概念,屏幕空间和像素,具体如下
屏幕空间
如上图,将电脑屏幕理解为一个二维坐标,屏幕上左下角为坐标原点,水平向右为x轴方向,垂直向上为y轴方向
像素(Pixel)
在屏幕上排列的最小单位,上图中每一个方块理解为一个像素,假设屏幕大小为w×h,那么在屏幕中一共有w×h个像素,这些像素像二维数组一样在屏幕中排列,左下角像素的坐标是(0,0),右上角像素的坐标为(w-1,h-1)。每个方块的中点(方块中的小圆圈)称为像素的中点,像素(x, y)的中点为 (x+0.5, y+0.5),现实中,屏幕的大小用分辨率表示,例如一个屏幕的分辨率为19201080,那么它就有19201080个像素排列在屏幕上
2.2. 什么是光栅化
光栅化其实就是将物体投影在屏幕上的图形,依据像素打散,每一个像素中填充不同的颜色,如下图中的老虎,老虎投影到屏幕上后,会被打散成一个一个的小方块,即会被拆分成一个一个的像素,把投影在屏幕上的图形,打散成一个个像素的过程就是光栅化
在图形学中,我们会把物体表面分解成无数个三角形(Triangle),之所以使用三角形作为基本单元,是因为有诸多优点:
- 任何多边形都可以用三角形拼装而成
- 可以通过向量叉乘来判断一个点是不是在三角形内部
- 可以使用三角形的顶点进行线性插值,实现颜色的平滑过渡
也可以说一切物体都是由三角形组合而成,这样一来,光栅化本质就是把无数个三角形进行光栅化,每个三角形的光栅化过程都是一样的,所以只要拿出一个三角形说清楚,其他都一样.
3. 采样
采样实际就是通过一个连续的函数f(x) 在x等于不同的值拿到的结果。在图形学中,我们使用屏幕中的像素中心进行采样,也就是获取不同的像素中心对应的值,可以采样的内容包括时间、位置、法线,反射光等
3.1. 三角形采样基本过程
如下图,假设我们要对屏幕中的一个三角形进行采样
我们需要做什么呢,要获取一个结果,就是屏幕中每个像素的像素中心是否在三角形内部,如下图可以一目了然看到,实际需要通过一个函数处理
这个函数要做的事情就是给定屏幕空间中任意一点Point(x,y) 判断这个点是否在三角形内,在三角形内返回1,否则返回0
接下来使用这个函数对屏幕上所有点进行计算,下面给出参考伪代码:
通过这个函数可以让这个像素要么等于0要么等于1,然后给着色不同的颜色,这里其实就是通过采样的方法进行光栅化的过程
说明:当某个像素的像素中心在三角形边上,如何处理,–有规范参照规范,没有规范自己决定,也就是你可以认为它在三角形内也可以认为它不在三角形内部
3.2. 三角形光栅化加速(采样过程优化)
上面提到的判定一个像素中心是否在三角形内是遍历整个屏幕,但如果三角形只在屏幕较小的区域中时会造成极大的浪费,这时就需要进行优化处理
3.2.1. AABB包围盒
如下图,采样过程中最左侧一列肯定不会在三角形内部,而右侧部分是三角形在屏幕中所覆盖的最大区域,我们把这个区域(下图蓝色部分)称为包围盒 ,图中指的是轴向包围盒,英文名 Axis-Aligned Bounding Box 缩写AABB
顺便说说包围盒的分类:
[1] - AABB包围盒(Axis-aligned bounding box),确定AABB包围盒只需要六个标量,分别是X轴、Y轴、Z轴上的最大值和最小值
[2] - 包围球(Sphere),确定包围球,先通过所有顶点的x,y,z坐标的均值以确定包围球的球心,再由球心与三个最大值坐标所确定半径
[3] - OBB方向包围盒(Oriented bounding box),OBB包围盒比AABB包围盒和包围球更加逼近物体本身的形状
[4] - FDH固定方向凸包(Fixed directions hulls或k-DOP),FDH比其他包围体更紧贴原物体,做相交检测时会减少更多的冗余计算,但相互间的求交运算较为复杂
3.2.2. 逐行检测
当一个三角形不大,但AABB包围盒又覆盖了很大的面积时用AABB检测方式有些浪费,这时可以从三角形的左下角开始以行为单位从左到右检测,检测完接着检测上一行,这样可以极大的降低无用检测,但实现难度和计算开销比较大
3.3. 采样分类
3.3.1. 在位置上的采样
图像信息到达感光元件时,把他们离散为屏幕上一个一个的像素,这个过程中的采样发生在不同的位置,就是在位置上的采样,也称为在空间中的采样,例如上图中的照片放大后其实是一个个的像素点,就是在屏幕上不同位置对照片进行采样获取不同像素上的颜色值
3.3.2. 在时间上的采样
如上图,在动画中的以不同时段进行的采样就是在时间上的采样,其实在时间上的采样采的就是动画中的每一帧图片
4. 走样
在采样工程中经常会发生一些预想不到和不想看到的现象称为走样,走样的的英文名Aliasing,常见的走样有锯齿(Jaggies)、摩尔纹(Moire)、车轮效应(Wagon wheel effect)
4.1. 锯齿(Jaggies)
使用屏幕中像素中心采样三角形,有些点在三角形内着红色,有些在三角形外,着白色,就会得到像上图一样的在三角形内的像素的中心点的集合,我们知道在屏幕中一个像素是一个方格,如果给对应的像素着上红色就得到向下面这张图一样的效果
上图中可以看到有三角形的轮廓,但并不是我们想要的三角形的样子,可以明显看出这个三角形的边缘并不是一条平滑直线,而是一个一个正方体的棱角,像这样的走样效果称为锯齿
如下图中右侧图片,可以明显看到最外层的三角形产生了锯齿
4.2. 摩尔纹(Moire)
如上图,由于采样不全导致得到的图像出现了向布料被抽调其中一些线一样的效果,称为摩尔纹
4.3. 车轮效应(Wagon wheel effect)
有时候看走的比较快的车的车轮时,会感觉车轮好像在倒着走,这个现象就是车轮效应,是因为我们的眼睛在做采样时,采样的频率低于实际车轮运动的频率而产生的一种错觉
5. 抗锯齿(反走样)
如上图在采样前先进行模糊操作(滤波),经过模糊操作后三角形的边缘颜色变化有了一定的过渡,再进行采样时,靠近三角形边缘的地方可以采到一部分过渡色的像素,采样结果不在是要么红色要么白色,就可以达到抗锯齿的目的
下面两张图分别是使用模糊操作抗锯齿前和抗锯齿后的效果图,通过对比你会发现效果还是挺不错的,即使放大有一点锯齿但是变的平滑一些
再来看另外一组通过滤波处理再采样的效果
6. 频域(Frequency Domain)
上面提到通过先进行滤波操作,在采样来达到抗锯齿的效果,那么先进行采样在进行滤波操作能不能同样达到抗锯齿的效果呢,答案是不行的,看下面两张图对比一下,第一张是先进行滤波操作在进行采样,第二张是先进行采样在进行滤波操作,可以发现第二种操作是行不通的
那么为什么不能达到预想的效果呢,先介绍两个概念,频域和时域,之后在慢慢说明
频域用来表示不同频率下信号的变化,用横轴表示频率,纵轴是该频率信号的幅度,也就是通常说的频谱图。
时域用来表示不同时间下信号的变化,用横轴表示时间,纵轴是当前时间信号的幅度
6.1. 周期与频率
下图是周期性变换的波形函数正弦和余弦函数,它们之间的不同点在于它们的相位不同
如上图以余弦函数来说一下,一个余弦函数为 cos2πfx,这里的f表示频率,你会发现频率越高函数变化的越快,周期越短,所以频率 f 也可以通过周期求倒数获得即 f = 1 / T
对于图像信号而言,我们认为两个像素间的颜色变化大则代表频率高,反之则是频率低
6.2. 频率与采样
如上图,函数 f1(x) 、f2(x) 、f3(x) 、f4(x) 、f5(x) 的频率不断增加,我们对每个函数都使用相同的采样频率,对函数 f1(x) 采样出来的点做函数恢复(采样点相连接),基本可以恢复原本函数的样子
函数f2(x),恢复有一定的偏差,f3(x) 开始基本就不是原有的样子了,f4(x) 、f5(x)越到最后,离原本函数的样子差的越来越远,由此可以发现采样要想得到函数原本的样子,和采样的频率有很大的关系
也就是说当采样的频率跟不上函数本身变化的频率时,采样结果就会出现偏差,就会产生走样现象
上图是另一个采样走样的例子,如图,黑色线和蓝色线明显不是同一个函数,但采样结果却是一样的。换种说法就是,同样一种采样方法,采样不同频率的函数,得出的结果一样的,无法区分来自哪个函数,就会出现走样现象
6.3. 傅里叶变换(Fourier Transform)
6.3.1. 傅里叶级数展开
任何周期函数都可以用一系列正弦、余弦函数构成的线性组合以及一个常数项来表示,这种展开方式我们称为傅里叶级数展开
如果需要获取一个函数得到向下面这样周期变换的方波函数:
可以首先将余弦函数振幅增加并向上移动,得到近似的周期变换函数
接着加入一些函数,会更加接近这个周期函数
继续加入
还不够接着加入,直到周期波无限接近这个周期函数
最后,通过傅里叶级数展开,将一个目标函数展开成了多个不同频率的正弦或余弦函数
6.3.2. 傅里叶变换
如上图,我们可以把一个时域上的函数 f(x) 变换成频域上的函数 F(w)。称为傅里叶变换。同时我们也可以把频域上的函数 F(w) 变换回时域上的函数 f(x) ,这个过程称为逆傅里叶变换。
6.4. 图像与频域
我们已经知道通过傅里叶变换可以把图像信号从时域变换到频域,上图中左侧是原本的图片,也就是图像的时域信号,经过傅里叶变换变换到频域,得到上图中右侧的图片,右侧中的图片的中心表示低频区域,以这点为中心向周围扩散,越往外频率越高,在不同频率的位置上有多少信息用亮度来表示,以右侧图来说明,中心比较亮,说明图片上大多是低频信息,也有部分高频信息,但相对于低频信息特别少,如果感兴趣可以试一下,比如一张图片经过傅里叶变换,你会发现基本就是右侧图片的样子,也就是说,自然这种拍摄的图片基本都是低频信息会占据相当大的比例,而高频信息只是占了很小一部分,如果你发现右侧图中有一个条水平的直线和竖直一条竖直的直线比较亮,是怎么回事呢,简单说一下
图形学中分析信号的时候会认为它通常是周期性重复的,对于不周期性重复(例如一张图片)就认为到了右边界之后重复左边界,左边界和右边界通常通常内容相差较大,就会产生剧烈的信号变化,也就会产生极其高的高频信号,上边界和下边界同理,所以在经过傅里叶变换的图片中会看到两条水平和垂直的比较亮的线
傅里叶变换可以看到一张图片中的信号在不同频率长什么样,通用的说法就是任何信号在不同频率长什么样,也称为频谱
6.4.1. 滤波
6.4.1.1. 高通滤波(High-Pass Filter)
高通滤波的意思就是高频信号可以通过,把低频信号过滤掉。如下图中的右侧,我们去掉低频信号,然后在通过逆傅里叶变换,得到下图中左侧的图片,可以发现高频信号其实表示的是图像中物体的边界,这里拓展一下,为什么高频信号表示的是图像中物体的边界,在傅里叶变换前图像中物体的边界,颜色变化比较剧烈,颜色变化剧烈就会产生剧烈变化的信号,剧烈变化就会产生高频信号,所以经过傅里叶变换高频信号表示的是原图形中物体的边界
6.4.1.2. 低通滤波(Low-Pass Filter)
低通滤波的意思就是低频信号可以通过,把高频信号过滤掉,如下图右侧,把经过傅里叶变换的图像中所有的高频信号都去掉,只留下部分低频信号,在经过逆傅里叶变换就会得到下图左侧中的图像,你会发现图像变模糊了,是因为滤掉了表示图像边界的高频信号
6.4.1.3. 带通滤波(Band-Pass Filter)
带通滤波,允许限定频段的波通过,通常是将一张图片经过傅里叶变换得到频域,然后去掉高于限定的最高频和低于限定的最低频信号,如下图中右侧,像一个圈圈一样,经过逆傅里叶变换就可以得到左侧的图像
6.4.2. 卷积(Convolution)
卷积实际上就是定义一个滤波器(滤波器也被称之为卷积核),这个滤波器可以是一维数组也可以是二维数组,使用这个滤波器对原来的信号挨个进行处理,然后把处理好的结果写进一个与原数据相同大小的容器中,滤波的本质是将信号与滤波器在时域上进行卷积的操作。
举一个简单卷积计算的例子,下图中的卷积核是一个1x3的一维数组,这个数组中的权重值从左到右依次是1/4、1/2、1/4,使用这个卷积核与原信号中卷积核覆盖的值做叉乘,将结果写入到原信号对应的位置,具体如下图:
接着处理下一个信号,原信号的第三个元素
依次处理完每一个信号得到的结果就是经过该卷积核卷积操作的结果,第一个信号和最后一个信号要特殊处理一下,第一个信号,最左边并没有信号对应卷积核的第一个值。对于缺省的信号需要自动补零。第一个信号取得的31的信号值分别为0,1,3,然后进行卷积操作,得到的结果为 (0 x 1/4) + (1 x 1/2) + (3 x1/4) = 1.25
卷积定律:
上图中上半部分表示,一张图片进行使用3x3的一个卷积核进行卷积操作,得到的结果一张模糊的图片,
同时如果对原始图片进行傅里叶变换,把图片从时域转换到频域,卷积核也经过傅里叶变换从时域转换到频域,这时把转换到频域的图片与转换到频域的卷积核相乘,使用相乘的结果进行逆傅里叶变换得到的结果与在时域上进行卷积操作的结果一样,这其实就是卷积定律的一部分内容:时域上的卷积相当于频域上的乘积
可能也注意到了,卷积核(滤波器)在使用的时候乘以1/9,它是一个3x3的二维数组,之所以乘以1/9 是为了图像中整体的颜色值与原本的颜色不发生变化,在做卷积操作时会取原图像中的9个像素与卷积核中的元素分别相乘再相加,如果不乘以1/9,得到的结果是原来的9倍,会导致图像异常明亮,乘以1/9其实是对处理结果进行了一个归一化的操作
卷积核经过傅里叶变换后,可以发现它大都是低频信号,所以卷积核可以认为是一个低通滤波器
通过上面的图片发现,卷积核在时域上变大,它在频域上反而变小了,也就是使用越大的卷积核经过卷积处理得到的图像会越模糊
6.5. 采样与频域
如上图,假设a是一个连续的函数(信号),b是该函数经过傅里叶变换后再频域上的体现
c函数是采样函数,也称冲击函数,d是冲击函数在频域上的体现
使用a函数与c函数相乘,乘出来的结构就是e函数,其实就是采样的信号
卷积定律中的另一部分内容是:时域上的乘积相当于频域上的卷积
依据上面的定律可以得到 a乘以c = e 等价于 b卷积d = f
通过上面的几幅图片可以发现,取样结果在频域上的体现就是把原本频域的信号进行重复,也可以认为采样就是在重复原始信号的频谱。
7. 反走样方法
7.1. 走样的本质
我们已经知道采样是根据冲击函数的间隔(频率)在重复信号的频谱,如上图中下半部分,当冲击函数的间隔(取样频率)小于频谱的大小时,就会出现部分频谱混叠的现象,这就是发生走样现象的本质
7.2. 反走样的方法
如上图,通常采用的反走样的方法是,先对图形进行模糊处理然后在进行采样,之所以这样可以达到反走样的目的,它实际的原理如下
如上图,先对原始信号做模糊处理,即使用低通滤波进行过滤,就可以拿掉频谱上的高频信号,然后在使用原本的采样(冲击)函数进行采样,会发现原本混叠的部分在采样前被过滤掉了,这样信号最大限度的保持了原有的样子,又保证不会发生混叠,进而达到反走样的目的,接下来列举几个重要的反走样的方法.
7.2.1. 多重采样 MSAA
多重采样 MSAA( Multi Sampling Anti-Aliasing)取更多的点来实现反走样,把一个像素继续划分成很多个小的像素,同样每个小的像素也有各自的中心点,如下图中把一个像素分成四点小的像素,然后对每个小的像素判断是否在三角形上,然后根据小像素的在三角形中的个数得到这个像素在三角形中的覆盖率,通过覆盖率可以算出这个像素对应的颜色,MSAA实际上解决的是对图形进行模糊操作的这个过程,他只是通过近似的一种方法进行模糊,只是增加了采样点并没有提高屏幕分辨率
7.2.2. 快速近似抗锯齿 FXAA
快速近似抗锯齿 FXAA(Fast Approximate Anti-Aliasing),是一种和采样无关,在图像层面做的处理,处理过程是先找到三角形的边界,把有锯齿的边界替换为没有锯齿的边界,而且处理起来非常快
7.2.3. 时间抗锯齿 TAA
时间抗锯齿 TAA(Temporal Anti-Aliasing),最大的特点就是非常快速,是将静态的图片在时间上进行采样,相连两帧显示的图像是一样,但是可以用相邻两帧同一个像素上不同位置的点来感知是否在三角形内,计算的时候要考虑上一帧感知的结果要被应用进来,相当于是MSAA对应的样本分布在时间上,并且当前这帧没有任何额外的操作
7.2.4. 深度学习超级采样 DLSS
深度学习超级采样 DLSS (Deep Learning Super Sampling),它依赖深度学习,使用低分辨率图像(比如1080p)生成高分辨率图像(8K),再把8K图像缩回4K,得到抗锯齿图像,以代替传统的时间抗锯齿等技术