本文系统解析光栅化技术,涵盖三角形光栅化、视口变换及屏幕显示原理(CRT/LCD/LED)。深入探讨反走样方法,结合信号处理与傅里叶变换分析走样成因,并详解MSAA、FXAA、TAA等抗锯齿技术,以及深度缓冲与超分辨率的应用。(Generated by DeepSeek r1)
光栅化
什么是光栅化
Raster 是德语中的屏幕(Screen),光栅化就是将变换后的标准正方形显示在屏幕上的过程。
屏幕
屏幕可以理解为二维的像素阵列。
像素 Pixel 是 Picture Element 的缩写,我们暂时认为像素是屏幕显示的最小单位,内部有一个由红蓝绿混合而成的、统一的颜色。
屏幕空间由许多的像素构成,像素的坐标由两个整数构成,从 $(0, 0)$ 开始到 $(\mathrm{width} - 1, \mathrm{height} - 1)$,坐标为 $(x, y)$ 的像素的中心为 $(x + 0.5, y + 0.5)$。
转换目标
暂时不考虑 Z 轴,我们需要将 $[-1, 1]^2$ 的平面变换到 $[0, \mathrm{width}] \times [0, \mathrm{height}]$,该矩阵称为视口变换(viewport)。
$$
M_{\mathrm{viewport}} = \begin{bmatrix}
\frac{\mathrm{width}}{2} & 0 & 0 & \frac{\mathrm{width}}{2} \
0 & \frac{\mathrm{height}}{2} & 0 & \frac{\mathrm{height}}{2} \
0 & 0 & 1 & 0 \
0 & 0 & 0 & 1
\end{bmatrix}
$$
光栅显示设备
阴极射线管 Cathode Ray Tube
通过调整 XY 两轴的偏转电压使得发射极电子打在荧幕的特定位置,以此成像。
- 示波器 Oscilloscope
- 早期电视
隔行扫描技术:在划分好的行中,每次加载图像只读取一半的行(奇数行或偶数行)。
液晶显示器 Liquid Crystal Display
显示存储在内存中的画面信息,应用在现代电子设备上。
- 低分辨率,计算器等
- 高分辨率,手机等
工作原理
每一个像素上,前后有两个偏振化方向垂直的光栅,中间充满液晶。自然光经过第一个光栅后,直接穿过第二个光栅的光强为 $0$。在激活状态下,液晶会改变光线的振动方向,使其穿过第二个光栅的光强增大。
发光二极管 Light Emitting Diode
二极管有预先设计好的颜色,只有发光与不发光两种状态。
使用 Bayer pattern 设计的屏幕,绿色元件的个数会更多(R : G : B = 1 : 2 : 1),这是因为人眼对绿色更为敏感,绿色的调整会使得画面更加自然
三角形的光栅化
最重要的步骤:判断像素和三角形的内外关系
采样
对于离散的一系列点,求函数在这些点上的值。
定义
$$
\mathrm{inside}(t, x, y) = \begin{cases}
1 & (x, y) \in \triangle t\
0 & \mathrm{otherwise}
\end{cases}
$$
那么显示一个三角形可以转化为
for(int x = xmin; x < xmax; x++)
for(int y = ymin; y < ymax; y++)
image[x][y] = inside(tri, x + 0.5, y + 0.5);
根据向量知识,$\mathrm{insdie}$ 可以转化为 $(x, y)$ 和 $t$ 的三条边做方向判断,如果同在左边/右边就为 $1$。
$[\mathrm{xmin}, \mathrm{xmax}] \times [\mathrm{ymin}, \mathrm{ymax}]$ 称为轴对齐的包围盒(Axis-Aligned Bounding Box),在包围盒外的部分不可能受到该三角形影响。
其他的加速方法:Increment Triangle Traversal,计算每行的最左端最右端,对于窄长的三角形较适用。
引发的严重问题:采样率过低(走样),产生锯齿
反走样
信号处理理论
采样在图形学中无处不在:图片(按位置采样)、视频(按位置 + 按时间采样)
采样会产生瑕疵 Artifacts:锯齿、摩尔纹、视错觉(Wagon Wheel Illusion)
原因:信号变化的频率太快,导致采样的速度跟不上
模糊操作
在采样之前,先对原始图片做模糊处理(又称滤波)。
如果先采样再模糊,称为 blurred-aliasing。
傅里叶变换
傅里叶变换是将任意函数 $f(x)$ 表示为频率不同的正弦函数的积分:
$$
F(\omega) = \int{-\infty}^{\infty} f(x) e^{- 2 \pi i \omega x} \mathrm{d}x
$$
同时也可以得到
$$
f(x) = \int{-\infty}^{\infty} F(\omega) e^{2 \pi i \omega x} \mathrm{d} \omega
$$
这个过程中函数从实域变换到频域。
对图像做傅里叶变换可以得到二维图像,中心表示低频率、外围表示高频率,亮度表示信息的多少。
出现轴线的原因:平铺图像导致在边界有剧烈的信息变化,对应高频信号。
频率分析
在采样频率过低时,我们的采样结果很难反应实际的变化情况:
这个时候就会产生走样。
滤波
滤波实质上是去除函数的特定频率。在傅里叶变换的图像上,可以按半径区分信号。
高通滤波
只保留高频信号的处理方法。
在图像的边界上,信号发生剧烈的变化,对应变换后的高频信号,所以在滤波之后只剩下了图像的内容边界。
低通滤波
只保留低频信号的处理方法。
只剩下低频信息后,边界的内容(细节)被删除,画面看起来变模糊了。
带通滤波
通过舍弃一部分高频和一部分低频信号,我们留下了一些不太明显的边界特征。
与加法卷积的联系
滤波等于卷积:通过与一个滤波数组做加法卷积,我们可以将原信号处理成另一个信号。
直接给出结论:
对实域的卷积等价于对频域的乘积,对实域的乘积等价于对频域的卷积。
借助该结论我们可以使用两种方法完成滤波:
- 直接在实域上将图像和滤波器卷积
- 将图像和滤波器做傅里叶变换,函数直接相乘,再将结果做傅里叶逆变换(类似 FFT 的思路)
采样
从卷积的角度理解,采样实际上和滤波一样,都可以做乘法得到。
不过采样的直观做法是将实域与只在离散的点上为 $1$、其余位置为 $0$ 的函数直接相乘,这样的函数称为冲激函数。
反映在频率上,因为冲激函数在频域上仍然是冲激函数,所以频域上的卷积表现为原始信号频谱的重复。
这也解释了走样的原因:采样不够快会导致频谱的重复间隔太小,产生了混叠。
模糊操作的可行性
通过学习,我们已经知道了模糊操作等于高通滤波,丢弃的高频信号就相当于去掉了频域上函数的两端,这样采样之后就不会发生混叠了。
实践中的反走样
Multisample Antialiasing (MSAA)
近似的反走样方法。
假设每一个像素被划分成了更小的区域(如 $4 \times 4$),对每个区域的中心分别求出是否被覆盖,然后计算每个像素的覆盖率。
之后进行一个简单的采样,每个像素的覆盖率就是采样的结果。需要注意的是,MSAA 完成的是模糊步骤。
通过不同的划分方案、点的复用等可以降低实际计算的点数。
Fast Aproximate Antialiasing (FXAA)
与采样无关的后期处理方法。
通过找到生成图像中的边界,将有锯齿的部分替换成没有锯齿的结果,来减少锯齿。
Temporal Antialiasing (TAA)
与时间相关的处理方法。
每一帧生成时计算像素内不同位置的被覆盖情况,并复用前几帧的位置信息来计算覆盖率。
可以理解成将 MSAA 一帧所需的计算量分布在时间上连续的几帧。(处理静态图像时效果较好)
超分辨率
和抗锯齿不太一样,是指将低分辨率的图转换为高分辨率。
可以理解成采样的分辨率低于图像的分辨率产生的走样。
DLSS:通过深度学习,补全丢失的细节。
深度缓冲
如何将多个物体显示在屏幕上,同时正确地体现遮挡关系?
Painter's Algorithm
一个简单的思路是,将物体按从远到近的顺序显示,像素由最后一个遮盖的投影决定。
在一些情况下,这个算法非常自然,油画也会使用这种思路来作画。
但是在处理相互遮挡的关系时,或者距离和顺序不好判定时,该算法可能发生错误。
需要 $O(N \log N)$ 时间对物体排序。
Z-Buffer
既然对于每个物体不一定有渲染偏序,我们可以将其拆分,改为对每个像素储存一对信息,表示最浅的深度和对应的颜色。
这样在渲染时可以直接通过深度决定是否要覆盖当前颜色,同时生成了颜色图和深度图。
for(triangle T : vecT)
for(auto [x, y, z, rgb] : T)
if(isNear(z, zbuffer[x][y])) // z < zbuffer for left-hand coord, z > zbuffer for right-hand
framebuffer[x][y] = rgb,
zbuffer[x][y] = z;
else continue; // do nothing
在认为单个三角形的处理时间为大致相近的常数,那么时间复杂度为 $O(N)$。
通过在 GPU 硬件中做并行计算,我们可以进一步加速渲染,因此这是一个非常重要的算法。