[英]Implementing blending functions too complicated for fixed-function blending
我正在尝试在 gpu 上实现高级混合。但是每当我尝试搜索资源时,我都会被顺序独立渲染、片段着色器互锁等术语弄得不知所措。 而且我不知道哪些与我的问题相关。
简单地给出 3 个对象,( b0
, b1
, b2
),它们都位于同一个像素上并具有特定的 z 顺序。 (您可以假设对象已正确排序)。
那么设置像素的最终颜色应该是
f( b2, f( b1, f( b0, background_color ) ) )
其中f
是来自 vec4 的任意 function(在编译时决定) vec4, vec4 -> vec4
使用固定的 function 混合无法实现。
我的直觉是使用看起来像的代码
void main() {
vec4 previous_color = //...
gl_FragColor = f( object_color, previous_color );
}
然而,根据我有限的研究和理解,您不能简单地读取片段着色器中已经渲染的数据。 (因此我认为VK_EXT_fragment_shader_interlock
的原因)。
但是,如果我不能依赖这样的扩展,我还能在 GPU 上实现它吗?
还可以解释为什么“幼稚”的实施会导致问题。
基于链表的顺序独立透明性让你免费获得这个,因为该算法根本不使用固定函数混合。 解析混合时,片段着色器(或计算着色器,但 FS 很好)会获得影响特定片段的 colors 列表。 FS 必须使用这些 colors(及其距离)来计算混合结果。 所以所有的信息都在那里。
当然,OIT 并不便宜。 如果对场景进行排序很困难,那么它可能是值得的(尤其是在计算顺序涉及大量 CPU 交互的情况下),但这不是免费的。
OIT 仅依赖于拥有任意大小和原子增量的 SSBO 的能力。 这些代表 Vulkan 的基本功能。
除了 OIT,您最终要做的是让 FS 执行图像的有序、原子读/修改/写,其中“修改”操作非常重要(即:不是增量或其他)。
未扩展的 Vulkan 可以通过输入附件和管道屏障来做到这一点。
您必须有一个使用附件作为颜色附件和输入附件的子通道。 然后,您渲染一个非重叠的 object(这非常重要)。 FS 中的previous_color
现在来自subpassLoad
操作。 这个 function 没有纹理坐标,因为它总是从与当前片段位置对应的纹素中读取。 也就是说,它读取该片段下方的帧缓冲区中已有的颜色。 output 转到颜色附件,它是与输入附件相同的图像。
但是,您只能对每个像素执行一次此操作。 也就是说,每个像素只能有一次读取/修改/写入。 要获得第二个,您必须在一个 object 的绘图和下一个 object 的绘图之间发出管道屏障。这意味着每组重叠的对象都必须在子通道中分解成它们自己的块。 管道屏障本身很特殊,因为它必须使用子通道自依赖性(也在渲染通道定义中指定)。
为了高效渲染,您需要将绘图调用分解为绘图块,其中每个块内没有重叠像素。
片段着色器互锁是另一种机制,但它不适用于片段着色器的输出。 只有当你想通过图像加载/存储或 SSBO 对 memory 执行原子 RMW 时,它才有用。 因此,您必须渲染主场景,结束渲染通道,启动一个不使用该图像作为附件的新渲染通道,然后对其进行联锁图像加载/存储。 然后为您可能需要的任何其他后处理结束该渲染过程。
问题未解决?试试以下方法:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.