深圳雅迅公司网站建设,深圳网站制作问,手机本地图片生成链接,免费crm试用本文基于UE4版本4.25.3#xff0c;对Cascade粒子系统的移动端渲染管线进行简单的概括和描述。Game Thread部分粒子系统Actor被Spawn#xff08;或所在的Level被加载#xff09;的时候#xff0c;UParticleSystemComponent注册和初始化#xff0c;并通过CreateSceneProxy函…本文基于UE4版本4.25.3对Cascade粒子系统的移动端渲染管线进行简单的概括和描述。Game Thread部分粒子系统Actor被Spawn或所在的Level被加载的时候UParticleSystemComponent注册和初始化并通过CreateSceneProxy函数注册和创建FParticleSystemSceneProxy。UParticleSystemComponent的主要数据成员是TArraystruct FParticleEmitterInstance* EmitterInstances包含粒子系统的所有粒子发射器。每一个粒子发射器对应一个FParticleEmitterInstance管理当前发射器下所有的粒子。FBaseParticle为粒子数据结构保存粒子的Location、Rotation、Size和Velocity等数据。FParticleEmitterInstance用uint8* ParticleData指向保存FBaseParticle类型数据集合的连续内存空间。UParticleSystemComponent关联的所有粒子数据内存空间只由GameThread访问。在帧结束的时候通过UpdateDynamicData函数创建一份包含粒子内存数据的拷贝——FParticleDynamicData并异步传递给FParticleSystemSceneProxy供RenderThread渲染使用。大部分情况下UE4通过给渲染线程生成一份渲染数据拷贝和函数线程专用比如函数后缀加_RenderThread的方式来防止出现多线程渲染的Race Condition问题。GameThread部分调用示意图Render Thread部分在FParticleDynamicData被GameThread传递过来之后粒子系统的渲染真正开始。粒子系统的渲染始于FParticleSystemSceneProxy::GetDynamicMeshElements函数输出FMeshBatchs。FMeshBatch是FParticleSystemSceneProxy到MeshDrawCommand之间的一个中间数据结构主要包含顶点数据流FVertexStream、IndexBuffer和材质等。粒子系统渲染用到的顶点数据流主要有两个索引为0的几何数据流和索引为1的Instanced数据流由FParticleSpriteVertexFactory创建和关联。几何数据流描述每个粒子的几何结构为4个顶点构成的单位大小的正方形。Instanced数据流为粒子数据集合用于以Instanced的方式绘制这些粒子正方形。Instanced数据流由FParticleDynamicData初始化而来。因为FParticleDynamicData的数据内容主要是GameThread使用的FBaseParticle类型数据集合的拷贝所以RenderThread通过FDynamicSpriteEmitterData::GetVertexAndIndexData函数把原类型数据集合转换成渲染使用的FParticleSpriteVertex类型数据集合。FParticleSpriteVertex定义了需要传入GPU的顶点数据结构与ParticleSpriteVertexFactory.ush 定义的顶点输入类型FVertexFactoryInput对应。为什么GameThread和RenderThread要分别定义粒子数据结构GameThread对粒子的抽象是一个Pivot点更新的是这个Pivot点的位置、旋转和Size等信息。而RernderThread把粒子点几何化为一个4个顶点2个面构成的单位正方形渲染的时候基于粒子Pivot点的位置、旋转和Size等信息把粒子的4个顶点计算并绘制出来。FMeshBatch生成后进入到MeshDrawCommand的构建阶段。FMeshBatch与MeshDrawCommand可理解为一对n的关系n的值取决于该Mesh会被多少个EMeshPass处理。比如产生实时阴影的不透明Mesh会被DepthPass、CSMShadowDepth和BasePass 三个EMeshPass处理来分别构建MeshDrawCommand。为什么需要定义不同的EMeshPass不同的EMeshPass绘制关联的顶点数据流Shader和渲染状态等不一样比如DepthPass的绘制只需要设置顶点位置数据流PositionOnlyStream关联的Shader主要功能为Vertex的空间变换和Pixel的深度输出不用做光照计算等。对粒子系统来说一般不写场景深度不产生阴影所以DepthPass和CSMShadowDepth的MeshDrawCommand构建过程会被过滤掉。BasePass的构建始于FMobileSceneRenderer::SetupMobileBasePassAfterShadowInit函数在关联好Shader设置好TaskContext渲染状态等之后调用BuildMeshDrawCommands函数真正进行MeshDrawCommand的构建。所有相关EMeshPass的MeshDrawCommand构建好之后开始MeshDrawCommand的提交和绘制。BasePass的绘制始于FMobileSceneRenderer::RenderMobileBasePassBasePass函数然后根据构建阶段生成的TaskContext渲染状态设置PipelineState根据MeshDrawCommand关联的顶点数据流设置StreamSource等最后调用RHICmdList::DrawIndexedPrimitive完成绘制。构建MeshDrawCommand阶段引擎默认是渲染线程起Work线程来并发执行可以设置Console命令r.MeshDrawCommands.ParallelPassSetup0来关掉并发最后的Mesh绘制可以设置r.RHIThread.Enable0来关掉RHI线程平台相关的绘制API的调用这样上述所有阶段都在RenderThread依次顺序执行方便调试。RenderThread部分调用示意图PSUE4引擎的代码量巨大流程庞杂单扣一个小细节就可能要研究上好几天想要用短短几页文字把渲染管线描述清楚难度很大而且还需要一些写作技巧使得描述不失偏颇有点理解官网文档的“言简意赅”了doge~~~参考文献Mesh Drawing PipelineThreaded Rendering