延迟渲染的MSAA
前言
主要分三步骤
1.首先将场景几何图形渲染到multisample-enabled g-buffer,而后确定哪些像素是复杂的. (使用SV_Coverage或检查像素内样本之间的不连续性来确定像素是否具有多个不同的fragments)
2.为复杂像素分离Pass,以获得更好的线程一致性
3.对复杂像素及常规像素分别着色. (确定复杂像素中独立fragment的数量,并根据独立fragment加权求和自适应着色)
具体可参考Nvidia实现的Deferred Rendering 4x MSAA Demo
延迟渲染中, 会先计算非光照部分, 写入G-Buffer, 而后统一进行光照计算, 即场景几何同光照计算分离, 光照计算阶段的几何基本是Quad. MSAA主要用于解决几何锯齿, 更适用于前向渲染能直接获取边缘信息.
延迟场景中, 需优先确定哪些像素复杂,且仅以每个样本的频率着色,以最少的计算和尽可能最小的发散方式.
1. 杂像素检测
延迟着色中, MSAA首先需检测复杂像素,即包含多个独立fragment的这些像素. 有俩种方法可实现.
一种是使用SV_Coverage, 计算当前fragment覆盖的像素样本. 如下图所示
若某个像素中有一个样本的coverage mask不是1111,则将该像素标记为复杂, 将每个样本覆盖掩码是否为1111存储到multisampled buffer中, 然后显式resolve buffer,这样不必循环遍历每个样本来判断像素是否复杂
这种方法可非常有效地检测复杂像素,但存在将一些非边缘像素标记为复杂的缺点,起因是依赖于潜在的几何结构而并非是屏幕空间不连续性.
另一种是搜索像素中样本之间的法线、颜色和深度的不连续性,如果不连续性大于某个阈值,将该像素标记为复杂. 这种方法的优点是仅在边缘产生复杂像素, 这意味着需在检测过程中循环遍历像素中的样本.
2. 为复杂像素分离Pass
Light Pass阶段,我们使用复杂像素Mask来区分常规像素和复杂像素. 若像素很复杂,执行超采样,并输出每个样本的平均颜色. 这样做会存在线程一致性问题, 对于打包进一个warp的多个像素,执行一次着色的常规像素必须等待复杂像素完成,因为它们正进行超级采样. 或者可使用stencil masks将常规像素和复杂像素分成2个pass. 分离Pass的缺点是引入了生成stencil masks的开销以及每帧的额外drawcall.
3. 复杂像素的自适应着色
大多数复杂像素仅有2个独立fragments,这意味着可在复杂像素上执行更少着色,但仍能实现相同的视觉质量
同样可使用stencil masks来计算每个复杂像素中独立fragments的数量. 计算每个像素独立coverage masks的数量, 并根据覆盖的样本数量对像素中的每个独立fragment进行加权. 例如下图中有3个独立fragments. 红色fragment的权重为2/4, 而蓝色和灰色fragment的权重均为1/4.
降低了着色成本,但引入了对复杂像素中独立fragments加权求和的额外开销.
4. 参考
1.Antialiased Deferred Rendering
2.GPU 渲染管线和硬件架构浅谈
3.CUDA编程warp