[图形]光栅化
2022.2.8修订
经过viewing transformation的图元全都处于NDC归一化设备坐标中
接下来要将正方体里的图元画在屏幕上
Screen 屏幕
什么是屏幕?
- 是由像素组成的二维数组
- 数组大小是屏幕的分辨率
- 屏幕是光栅成像设备
像素(Pixel)是什么?
- (picture element缩写)
- 简单认为像素是一个一个的小方块,内部填充一种颜色
- 像素颜色可以用RGB表示
什么是屏幕空间?
- 左下角作为原点
- 向右是+X
- 向上是+Y
- 像素坐标是整数
- 像素中心在
Viewport Transform 视口变换
视口变换做的事情很简单
- 把NDC左下角移动到屏幕空间原点
- 把NDC拉伸覆盖整个屏幕空间
Rasterization 光栅化
经过视口变换,屏幕空间中储存的还是连续的多边形,要将其显示在一格一格的像素上,就要将其离散化
选择三角形作为基本图元
-
最基础的多边形
-
任何其他多边形都可以被拆解为很多三角形
-
三角形一定表示一个平面,而例如四边形可能会弯折
-
三角形内部外部定义清晰
-
三角形三个顶点属性确定后,三角形面上属性可以插值
Sampling 采样
采样就是将函数离散化的过程
最简单的光栅化方法就是:给定一个屏幕空间内的三角形,判断某个像素是否处于三角形内
写成伪代码就是:
1 |
|
如果不在三角形内,inside
函数会返回0,否则返回1
那么如何判断像素中心是否处于三角形内呢?
用三角形三条边分别和像素中心叉乘,如果三个结果的方向大小都是正的或负的,则说明这个像素确实在三角形内。
不过呢,万一这个像素中心点正好在三角形的边界上,怎么办?对于这类问题,在图形学中,要么不做处理,要么特殊处理。(这课里就不对它处理了233
再看看刚刚的采样伪代码,我们对一个三角形光栅化的时候,把屏幕上所有像素点都测了一遍,事实上这没必要。
三角形只可能存在于蓝色的像素内。所以我们可以先求出三角形的轴向包围盒(Axis Align Bounding Box),再对这个包围盒的范围进行光栅化
Antialiasing 反走样/抗锯齿
一个三角形是一个连续的函数,给定屏幕中任意一个点,我们可以测试这个点是不是在三角形内部。关于三角形,我们可以认为它的颜色是均匀的,所以每个在三角形内的像素,我们都可以把它们涂成三角形的颜色。但是如果只是这样做,结果会得到一个类似三角形的图案。
抗锯齿就是为了解决这个原版和光栅化后的图形不一致的问题。
(之后的关于抗锯齿都没看懂,反正就是把原图模糊一下(低通滤波,去掉高频信息,实际操作就是取该点周围点的颜色平均一下)再采样,锯齿就不明显了,大概原理是啥,用到的知识,频域啊时域啊,都是信号处理的,搞不懂,留个坑)
Z-Buffer 深度缓冲
实际场景中,空间里会有很多很多三角形,它们可能会互相遮挡。如何解决互相遮挡的问题需要深度测试。
最古老的解决这个问题的算法是画家算法(Painter Algorithm),先画远处的物体再画近处的,重叠部分直接覆盖,算法复杂度O(nlogn),因为要对所有三角形排序。基本可以保证遮挡顺序是对的。但是在某些特殊情况下
不管哪个三角形先画都有问题
因为空间中的三角形不好排先后顺序,所以深度缓冲记录的是,每个像素所在的几何图形最浅的深度
最终生成的有两张图像,一个是最终结果(frame buffer),另一个是任何一个像素对应的深度(depth buffer)
为了简化计算,我们认为相机到顶点的距离就是深度,距离永远是正数,而且越小表示离相机越近,否则越远
之前说过我们的相机放在原点,并且向负z方向看过去,这样的话所有z都是负数,所以z绝对值越小离相机越近,绝对值越大离相机越远
深度图里,越黑的地方离相机越近
这张图可以很清晰看出深度测试如何工作,更近的像素会覆盖掉更远的像素
算法大致过程:
- 将深度缓冲初始值设为无限大
- 遍历所有三角形,在对三角形光栅化后,遍历所有光栅化后的像素
- 如果像素的深度小于buffer中对应位置像素的深度,就替换掉
算法复杂度:O(n),n是三角形数量(只针对深度缓冲算法,不考虑光栅化)。能做到线性时间复杂度是因为实际上并没有对三角形进行排序,它和三角形在空间中的顺序(从摄像机到三角形)没有关系。两个三角形的某些像素深度相同的情况另说
(Zbuffer处理不了透明物体,需要特殊处理0.0