Games101 - 光栅化
学之前你必须知道
视锥
这是透视相机的概念,用来衡量视距的大小。一般用2种属性来描述一个视锥:
- near面的宽高比
- 垂直视角 Vertical Field of View
有了上面2个确定值,然后再自己定义一个near的值(近平面与相机的距离),就能确定成像了,视锥完成。
屏幕上的概念
分辨率,也就是1080p、2k等,就是像素的多少。
屏幕 Raster,德语中的屏幕的意思,而屏幕是一个光栅成像设备。
光栅化 Rasterize,把东西画在屏幕上的过程。
像素 Pixel,全名picture element,是最小单位的小正方形,它的颜色由Red、Green、Blue三个色(0~255)来混和成。
屏幕发展过程
过去方式
- 示波器
- 阴极射线管 Cathode Ray Tube:和示波器原理相同,用很多电子打在屏幕上。通过扫描一样的方式,一条一条画横线,组成图像。
隔行扫描 Raster Scan:上面的画横线,优化的话还会在一帧只画1、3、5…奇数行,下一帧再只画偶数行。这样省去了一半的工作量,也能一定程度欺骗到肉眼。
现代方式
- 液晶显示器 LCD(Liquid Crystal Display):通过液晶扭曲光的方向,让其可以通过对应的光栅。
- 控制发光二极管的显示器 LED(Light Emitting diode array)
- 电墨水:通过电子控制只有黑、白像素的电墨水,实现电纸书的页面刷新。
帧缓存技术 Frame Buffer(Memory for a Raster Display):将显卡中的一块内存区域中,存储的内容反映到屏幕上。
光栅化一个Cube
视口变换 Viewport
光栅化之前要做的事。将一个 [-1,1] x [-1,1]
的2维平面,转换成[width,0] x [0,height]
的笛卡尔坐标系内来表示。这叫做视口变换,看下:
最后算出,变换矩阵如下:
光栅化
我们将原图形分解成很多个三角面,投影到屏幕的像素点上。
首先,怎么判断一个像素点与三角形的位置关系?
靠前面的知识,已经可以做到任何一个点都确定性地投影到屏幕上了。
那么如果想判断一个像素点是否在一个三角面内呢?也就是问,如何确定这个像素的着色?
可以通过判断这个像素点的中心点与三角形的位置关系来确定,为了方便,就定义一个判断函数Inside()
。而这个函数就是进行3次叉积。
然后,哪些像素点需要判断呢?
如果需要把整个屏幕的点都进行一次Inside()
判断,实在是没有必要,那么哪些需要、哪些不需要,这就涉及到包围盒了。
简单介绍一个AABB包围盒,它就是取三角面3个顶点的Min(x), Min(y), Max(x), Max(y),
作为他的盒子。
最后,成像完有锯齿 (Jaggies) 怎么解决?
又叫做反走样(Aliasing )、抗锯齿。
在解决之前先理解为什么会有这类问题?取哪些像素点来表示这个三角面,叫做采样(Sample)。而采样会有3种瑕疵(Artifacts)
- 锯齿 Jaggies
- 摩尔纹 Moire
- 运动速度过快 Wagon wheel effect
产生原因是信号变化的速度太快,而采样速度跟不上了。
那么怎么抗锯齿?
可以对三角面做预处理,比如滤波、模糊,之后再进行采样。
抗锯齿 Anti-Aliasing
前面了解了为什么会产生锯齿,以及大致的抗锯齿技术(滤波、模糊)。这里细说。
频域 Frequency Domain:描述信号在频率方面特性时用到的一种坐标系。想象一下cos2Π的图。
滤波 Filtering:把某个时段内,特殊的频率给过滤掉。
傅里叶变换:变幻的具体内容不要深究,只要知道,可以通过傅里叶变换把一张图变换为频域图,这样就能知道哪些地方的信号量多、少。中心定义为低频、周围定义为高频。最后,得到的频域图,是可逆的!
// TODO 下面的都只简单理解,更为深入要去学习 数字图像处理
先傅里叶变换,再过滤一张图 FFP
中心定义为低频、周围定义为高频。当颜色变化差异巨大的时候(比如人物边缘),会产生高频信息。
为什么会有十字线?没有学过信号学不能看懂这张频谱图,只能理解为傅里叶变换前会把这一张图复制很多份拼起来,来取样。拼起来之后每张图的4个边的边界之间的信息差异巨大,就有巨大的高频信息,而这十字线的高亮就是边界的映射。
高通率波
High-pass,就是只有高频能通过,低频直接忽略的滤波方式。可以看到,逆变换回来的图几乎只保留了边界信息(人物描边),这是因为边界处的信号量差异很大,这就是高频的信息。
低通滤波
滤掉高频,也就是滤掉边界信息,那么就会像下面这样。
高低滤波
卷积定理
只简单概述结论:
在空间域中,对一张图进行卷积滤波 = 对一张图进行傅里叶变换、再对其乘以卷积核的傅里叶变换、最后逆傅里叶变换回去
采样 Sample
稀疏采样会产生更多混叠,导致走样;密集采样更少混叠,所以映射结果更好一些。
怎么较少走样,也就是如何反走样?
本质上,就是想办法增大傅里叶副本之间的距离来减少混叠。
1.增加采样率(更高分辨率的屏幕)
2.抗锯齿,通过对图像模糊预处理(使用傅里叶来低通滤波)再采样
常规采样流程
先用低通滤波器模糊原图,然后再采样。
抗锯齿:模糊操作
取像素颜色时,根据三角面的在该像素块中覆盖的面积,来设置灰度。
这个理论很简单,但是实现比较困难,于是采用一种类似的方法,对一个像素块再进行划分、进行更多的采样,也就是**多重采样抗锯齿 MSAA (MultiSampling Anti-Aliasing) **来实现。
下图就是一个MSAA的例子:把一个像素格分成了2x2,来确定0%、25%、50%、75%、100%。
工业界会优化,想要2x2的效果不会这么单纯的分割成4个正方形,而是一些其他不规则图形,甚至可能多个像素块复用一个点,这么做都是为了减少需要检测的点数量。
其他抗锯齿方法
FXAA(Fast Approximate AA):快速近似抗锯齿,是一种后处理,会对有锯齿的地方进行修正。
TAA(Temporal AA):利用时间而不是空间采样,对于静止的连续帧,上一帧有效的采样点才继续采样。
DLSS(DeepLearning SuperSimple):当低分辨率拉伸成高分辨率时,会有很多锯齿,此时用深度学习来猜测描绘。