[ue4] Niagara的Indirect Draw

本文深入探讨了Niagara GPU粒子系统的实现,包括IndirectDrawBuffer、InstanceCountBuffer和FreeIDListBuffer的使用,以及粒子的更新、排序、剔除和绘制流程。Niagara利用GPU驱动粒子更新,通过IndirectDraw接口进行间接绘制,减少了CPU的负担。在粒子更新过程中,计算着色器填充各种缓冲区数据,并在GPU上完成粒子的发射、更新和剔除。粒子的排序和剔除确保了透明粒子的正确绘制,而绘制阶段则依赖于GPU生成的顶点缓冲区和特殊的顶点工厂。

[本文大纲]

概念引入

数据概述

Indirect Draw Buffer

Instance Count Buffer

FreeIDList Buffer

粒子的更新

粒子的排序和剔除

粒子的绘制

整体流程

概念引入

       Niagara是完全使用GPU驱动的粒子系统,包括了Mesh粒子、Sprite粒子和Ribbon粒子。

        简单来说,它将调用图形API提供的IndirectDraw接口进行间接绘制。之所以称为间接绘制,是因为数据并不是直接由CPU显式传递给GPU的,而是间接引用了GPU构造的数据。我们可以选择在计算着色器中完成粒子的发射和顶点相关数据的填充。

        因此,Niagara GPU粒子实现的绝大部分逻辑,都是在准备Indirect Draw所需的缓冲区数据,如Indirect Draw Buffer,以及Instance Buffer,前者提供了间接绘制所需的数据,后者提供了粒子绘制本身所需的数据。理解了这一点,将有助于我们理解后续的逻辑。

        本文将从Niagara系统涉及到的几个缓冲区开始介绍,并在此基础上,深入粒子更新、排序、剔除、绘制的流程,最终回顾粒子在整个管线的流程。

数据概述

       在整个Niagara更新流程中,涉及到了较多Buffer数据,可以对以下数据有一个初步的了解:

 Indirect Draw Buffer

        调用Indirect draw的图形绘制接口时,需要构造一个固定的IndirectArg缓冲区。这个缓冲区有固定的五位数据,是由图形API定义的必须填充的结构。每个结构对应着一次Indirect Draw的调用。

        缓冲区结构

        可以参考DirectX中间接参数缓冲结构的定义:

         ue4使用了IndirectDraw的索引实例绘制模式,并且仅填充了每个实例的索引数量(IndexCountPerInstance)、实例的数量(InstanceCount)以及索引的起始位置(StartIndexLocation),后两位设置为0。

RWDrawIndirectArgs[ArgOffset + 0] = TaskInfos[InfoOffset + 1]; 
// NumIndicesPerInstance
RWDrawIndirectArgs[ArgOffset + 1] = InstanceCount;
RWDrawIndirectArgs[ArgOffset + 2] = TaskInfos[InfoOffset + 2]; 
// StartIndexLocation
RWDrawIndirectArgs[ArgOffset + 3] = 0; 
// BaseVertexLocation
RWDrawIndirectArgs[ArgOffset + 4] = 0; 
// StartInstanceLocation

        实例的数量从GPU Buffer中读取,而索引数量和索引位置则在CPU中完成填充。这里的索引语义和直接绘制的索引语义一致。比如对于Mesh粒子而言,它和模型本身有关,索引计数为模型三角面的数量*3。

IndexInfoPerSection[SectionIdx].Key = MeshLod.Sections[SectionIdx].NumTriangles * 3;
IndexInfoPerSection[SectionIdx].Value = MeshLod.Sections[SectionIdx].FirstIndex;

         这里的Key和Value分别对应了IndexCountPerInstance和StartIndexLocation。

         执行逻辑

         Indirect Draw Arg的填充通过计算着色器完成,相关的逻辑位于NiagaraDrawIndirectArgsGen.usf。

       Indirect Draw任务在收集动态粒子图元的时候(AddMeshBatch)添加,收集动态粒子的同时会绑定Indirect Draw Buffer的位置,但此时这个缓冲区尚未初始化。

        缓冲区的填充发生在Niagara Emitter CS的计算之后,因为它依赖于粒子更新的Instance Count;此外,由于粒子可能包含GPU剔除,这会影响Indirect Draw参数的生成结果,所以Buffer的填充也需要在粒子排序和剔除的流程之后。

       填充Indirect Draw会和Instance Count的重置这两个任务,将会打包到同一个cs的不同线程中完成。

Instance Count Buffer

       Indirect Draw Buffer依赖于Instance Count数据,这个数据和场景中的粒子存在关联,因此我们需要维护一个Instance Count Buffer。

      &nb

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值