光栅化(三角形)
透视相机的视椎体
- top, bottom,left, right很难去描述一个视椎体
- 引入概念:视角fov(field of view),宽高比 aspect ratio(width/height)
- 将fov和aspect转换为top, bottom, left, right: tan(fovY/2) = top / |near|, aspect = right / top
什么是屏幕?
- 像素的数组
- 数组的大小=分辨率
- 典型的光栅成像设备
像素
- pixel: picture element缩写
- 像素是带颜色的小方块,是最小单位
- 颜色是红绿蓝的混合
定义屏幕空间
- 像素点坐标是从(0, 0)到(width -1, height - 1)的范围,且都是整数
- 像素点(x, y)中心点位于(x + 0.5, y + 0.5)
- 现在要将标准立方体[-1,1] * [-1, 1]转换成(0, width) * (0, height),分两步,先缩放到[-width/2, width/2],再做平移,等同于左乘矩阵,(width/2, 0, 0, width/2, 0, height/2, 0, height/2, 0, 0, 1, 0, 0, 0, 0, 1)
为什么选择三角形
- 最基础的多边形
- 其他多边形都拆解成三角形
- 能确定唯一的平面
- 内和外定义明确
- 三角形内任意一点,与三个顶点之间的关系,可以构成一个线性变化,即插值
如何进行光栅化?
- 采样: 给定一个函数,是连续的,给函数一个input,求output,给函数离散化
- 一般用像素中心进行采样
- 给定一个三角形tri,和坐标x,y,以及函数inside(tri, x, y),如果函数返回1,表示点在三角形内,反之则在三角形外
- 将屏幕上的所有像素中心的坐标一一代入,求解就是光栅化
- 优化方案: 无需计算所有像素点,只需要计算包含三角形的最小矩形范围的像素点即可,即包围盒
- 更优化方案: 每一行单独计算包围盒,但实际操作起来比较复杂
- 锯齿问题: 采样率过低
抗锯齿(反走样)
- 采样带来的失真
- 锯齿: 判断点是否在三角形内
- 摩尔纹: 图片采样中,去除了偶数行的像素
- 车轮效应: 人眼在时间中的采样跟不上车轮的转速
- 先对三角形进行模糊,再采样
- 频域
- 频谱图: 中间亮的部分为低频,外部黑的部分为高频
- 高通滤波: 仅保留图片的高频部分,抹除低频部分,得到的效果是图片中边界越来越明显,而非边界部分则一片黑
- 低通滤波: 仅保留图片的低频部分,抹除高频部分,得到的效果是图片模糊,边界不清
- 数字图像处理
- 滤波: 去掉一个频域的信息,=平均=卷积
- 卷积: 任意一个信号与其周围做的一次加权平均
- 卷积定理:时域的乘积 = 频域的卷积
- 抗锯齿的基本方法
- 加大分辨率: 成本过高,不现实
- MSAA: 将每个像素点进行一次拆解,拆成4x4,然后在判断每个点是否在三角形内,最后根据在三角形内点的个数做一次加权平均,得到颜色的百分比,本质是先模糊,在采样
- FXAA: 快速近似抗锯齿,属于后期处理,根据生成的图像,先找到图像中的边界,再换成没有锯齿的边界
- TAA: 将MSAA对应的样本应用在时间上,沿用上一帧的点的MSAA的结果,在静态画面中比较实用
- 超分辨率:从低分辨率到高分辨率,采样不足,使用深度学习的算法来猜测补全缺失点
深度缓存
- 解决可见性,遮挡问题
- 画家算法:先绘制远处的,在绘制近处的,无法解决深度问题,如果出现互相遮挡情况,复杂度O(nlog(n))
- z-buffer
- 针对每一个像素,记录离我们最近的一个距离
- 绘制图形的时候,除了frame-buffer存储颜色信息外,还有一个z-buffer存储深度信息
- 如果按相机放在原点,朝向-z方向,那z永远都是负的,z越大离我们越近,越小离我们越远,为了方便理解,我们将z的定义改为到原点的距离,z越小离我们越近,越大离我们越远
- 深度缓存算法: 遍历三角形的每个点,如果z小于深度缓存的值,则绘制,且更新深度缓存值,否则不绘制
- 深度缓存算法复杂度O(n)
- 深度缓存算法基于一个前提,同一个采样点深度,不会出现同样的z值,因为z是浮点数,要对浮点数做相等判断很难(强行解释)
- 深度缓存算法广泛应用在所有硬件上