抗锯齿简介

896 阅读4分钟

锯齿产生的原因:

  • 在图像渲染里面,采样频率是由分辨率决定的,因此走样最根本的问题其实是出在屏幕上。我们都知道屏幕是由一个个的像素点组成的(矩形),而真实世界则是由微观粒子构成,像素点的边长大小大约是1⁄96英寸(约0.26毫米),而一个分子的直径都是纳米级别。也就是说,无论如何都是没法做到完全不走样的采样。当这些像素组成斜线的时候,必定是以阶梯状排列。人的肉眼无法分辨粒子组成的“阶梯”,却容易分辨像素级别的“阶梯”,这就产生所谓的锯齿了。简单点来说,像素越大锯齿就越明显,像素越小分布越多锯齿就越不明显

  • 上面所说的像素组成斜线主要发生在光栅化阶段,在光栅化阶段需要判断三角形所覆盖的片元,使用的方法是:若像素中心点在三角形内,则判定像素在三角形内,这个像素位置就会产生一个片元;否则判定像素不在三角形内,也就不会产生片元。 image.png

SSAA:

  • 其实锯齿产生的根本原因也就是采样不足导致的,所以只要采样频率高到能骗过眼睛就行了。那么好,我在1个像素里面取4个、8个甚至16个采样点,每个采样点都给它来一次着色计算(运行一次pixel shader,同时需要n倍的depth buffer,n倍的framebuffer),最后把渲染出来的颜色经过filter的重构后(一般就是颜色平均),再重新采样(Resample)混色。这种粗暴的方法就是所谓的Supersampling Anti-Aliasing(简称SSAA)。SSAA的确能渲染出非常保真的画质,但是这就意味着每一帧都要先渲染出原来一帧图像的4倍、8倍甚至16倍分辨率的图像!以普通玩家的硬件水平根本支撑不了这么大的开销。

MSAA:

  • 其实锯齿产生的原因说明了,锯齿产生主要和光栅化有关,和片元着色器关系不大,所以不需要每个子采样点都进行一次片元着色器,只有当某个像素的子采样点被三角形所覆盖的时候,这个像素所对应的片元着色器会执行一次(片元着色器所使用的数据为该像素中心点的所对应的数据,例如某个像素的四个角的uv坐标分别为(0,0),(0,1),(1,0),(1,,1),则中心点的uv左边为(0.5,0.5),片段着色器将用中心点的uv左边去图片中进行采样)。这也就引出了msaa.
  • msaa原理:一个像素素里面取n个采样点,先对每个子采样点进行early z test,记录一下该三角形真正遮住了(这里遮住的意思是显示在屏幕上的意思)哪几个子采样点,然后对该像素进行一次片元着色器(还需要再进行一次depth test,因为片元着色器有可能修改了深度值),算出的颜色值存储在所有遮住的子采样点上(也就是每个被遮住的子采样点的颜色值都一样,都是片元着色器的输出颜色),最后输出颜色值时,使用一种混色方法处理像素内的所有子采样点的颜色(例如所有子采样点颜色相加然后平均),然后在输出到屏幕

image.png

  • 虽然msaa中的每个像素只需要进行一次片元着色器,但我们仍然需要n倍的depth buffer和n倍的framebuff存储。因为一个像素可能被不同的三角形所覆盖。
  • 当后处理需要深度图而且开启msaa时,观察framdebug可以看到一个Depth prepass节点,该节点就是:场景种所有不透明物体使用depth only pass(顶点着色器只进行顶点变化,关闭颜色输出,只记录深度)渲染得到一遍,得到一张深度图,利用该深度图可以实现像素级别的early z。当然坏处就是需要多进行一遍顶点变化,光珊瑚,和深度测试。
  • 所以一般的early z就是几何体级别的,在cpu进行排序,从前向后渲染。

参考资料