1. 大致流程
这里直接给出流程
-
首先,深度/模板缓冲,颜色缓冲都是
4x
于原本的缓冲区。 -
除了深度/模板缓冲,颜色缓冲,还有个
Coverage Mask
的纹理,它的大小应该是等于原缓冲区,它的R G B A
通道分别对应4
个子像素采样点的覆盖情况 -
光栅化阶段,对于当前三角形片元,针对每一个子像素采样点(如上图,是
4
个)- 进行覆盖判断(
Coverage Mask
):当前子像素采样点,是否在这个三角形片元内 - 裁剪(
scissor reject
)完再执行是必须的,要得到coverage mask,不仅仅看4个sample中是否被三角形覆盖到(光栅化),还要看是否在scissor内部。
- 进行覆盖判断(
-
如果
Coverage Mask
的值是(0,0,0,0)
,则不进行后续操作——流程终止。 -
执行像素着色器,进行光照计算。只要覆盖了,无论覆盖多少个采样点,都使用当前片元的颜色进行
fragment shading
-
进行遮挡判断(深度测试)。
-
深度怎么来的?光栅化的时候应该做了:对三角形片元的三个顶点的深度,进行线性插值,得到像素中心处的深度(举个例子:红色梯形的三个覆盖采样点 ( 0 , 2 , 3 ) (0,2,3) (0,2,3),其深度都是一致的,都是当前片元,根据像素中心绿点,插值得到的深度);然后和4个子像素采样点的深度进行比较(
GL_Less
)(上一个三角形片元的深度) -
深度测试通过,而且
Coverage Mask
也通过的,则将fragment shading
得到的颜色,copy
到对应的color buffer 4x
的位置,例如:只覆盖了采样点1,那么就只给采样点1复制颜色 -
一般来说,绘制一个物体之后,不会立马进行
resolving
,而是继续绘制场景 -
时机成熟后(例如:场景都画完了),进行
Resolving
操作,其中,像素的颜色可以简单的使用如下方法求出(均值方法):
C f i n a l = ∑ i = 1 4 C s a m p l e _ i 4 C_{final}=\frac{\sum_{i=1}^{4}{C_{sample\_i}}}{4} Cfinal=4∑i=14Csample_i
而Depth\Stencil
则可以使用Min
、Max
、Sample0
三种模式。像超采样一样,过采样的信号必须重新采样到指定的分辨率,这样我们才可以显示它。这个过程叫解析(resolving)。在它最早的版本里,解析过程是在显卡的固定硬件里完成的。一般使用的采样方法就是一像素宽的box过滤器。
2. SSAA和MSAA
SSAA
所抵抗的抗锯是两个方面:- 一个方面是:光栅化阶段会产生锯齿(比如三角图元的边界)
- 另一个方面是
pixel shader stage
(shader
的本质是:通过shader
输入参数,利用一个公式计算出结果,这个公式其实是个连续函数,而我们的shader
执行次数确是有限的,所以本质上跟几何锯齿的产生原因一样,都是用离散有限的数据,表示一个连续的事物,如果要抗shader锯齿,那也自然而然是提升shader执行的次数频率,SSAA
正是这样做的)。
MSAA
只是做了几何阶段的抗锯齿(多生成了片元),而忽略shader方面的锯齿(这个就是为什么只算一次fragmen
的原因,因为他不做shader方面的抗锯齿,所以MSAA
的渲染质量其实是比SSAA
要低的,其实shader产生的锯齿大多数情况下都没有几何锯齿那样明显,所以MSAA
用这个细微的损失换来了性能上的提升)