UE5渲染 | 您所在的位置:网站首页 › mesh网格数量 › UE5渲染 |
前言:前2章分析了渲染前的准备:计算可见性与相关性;在分析相关性章节逐渐出现了新的数据结构,这些都是MeshDrawPipeline里的关键类,了解MeshDrawPipeline后自然就知道是什么了。 目的:学习这个管线是如何把UPrimitiveComponent转换为MeshDrawCommand,了解其中的流程,也能对前2章内容进行定位整合,熟悉其在这个管线中所处位置与作用。官方文档: 先按顺序来认识一下管线涉及的类: UPrimitiveComponent:这是游戏线程对物体的表示,也是UE编辑器里Actor里的Component,这类组件可以挂载mesh,我们可以在编辑器的Inspector里设置。FPrimitiveSceneProxy:这是UPrimitiveComponent在渲染线程的表示,可以理解为把渲染需要的数据Copy到Proxy里。(如果我们要自定义新增UPrimitiveComponent子类,一般需要对应实现一个Proxy类,并在CreateProxy里提供实例化),FPrimitiveSceneProxy负责通过对"GetDynamicMeshElements"和"DrawStaticElements"的回调将FMeshBatch提交给渲染器。FMeshBatch:包含了Pass所需的着色器绑定和渲染状态。FMeshDrawCommand:存储了RHI所需的关于网格体绘制的所有信息:着色器、资源绑定、Drawcall参数。FMeshPassProcessor:将FMeshBatch转换为一个特定于网格体Pass的FMeshDrawCommand。走一下整个流程: Spawn一个Actor时实例化它的Component,当执行ExecuteRegisterEvents组件注册时,Scene->AddPrimitive(this)会让渲染线程添加对应的FPrimitiveSceneProxy,保存在FScene::AddedPrimitiveSceneInfos列表里。 在每帧Update时调用UpdateAllPrimitiveSceneInfos()处理。如果是StaticMesh,则继续调用FPrimitiveSceneInfo::AddStaticMeshes() --> FPrimitiveSceneInfo::CacheMeshDrawCommands() --> PassMeshProcessor->AddMeshBatch(),将MeshBatche转换成FMeshDrawCommand并缓存起来。 而动态物体则是在ComputeViewVisibility函数收集完StaticMesh之后调用Proxy的GetDynamicMeshElements将DynamicMesh收集到FMeshElementCollector里。和StaticMesh不同,这里得到的是FMeshBatch列表。 收集工作总结:一共收集到了3类,包括:已经缓存好StaticMesh的FMeshDrawCommand、StaticMesh没有缓存需要构建的DynamicMeshCommandBuildRequests、需要绘制DynamicMesh的NumDynamicMeshCommandBuildRequestElements。 最后,将收集好的StaticMesh,DynamicMesh都交由SetupMeshPass函数,对需要用到的Pass并行化地生成FMeshDrawCommand。 在DispatchPassSetup中,可以看到MaxNumDraws,就如上面说的,把3类收集好的数量加起来,就是所有需要绘制的mesh了。然后就是初始化TaskContext,收集生成FMeshDrawCommand所需的数据,然后交由TaskGraph处理任务。 前面都在收集数据,接下来是开始处理了,由这个任务类FMeshDrawCommandPassSetupTask实现: GenerateDynamicMeshDrawCommands生成动态物体的FMeshDrawCommand;ApplyViewOverridesToMeshDrawCommands应用该View已经存在的一些MeshDrawCommandUpdateTranslucentMeshSortKeys更新半透明的排序策略:ETranslucentSortPolicy,可以指定半透明按摄像机距离排序,按Shader,PrimitiveId,材质指定的优先级等排序;Context.MeshDrawCommands.Sort(FCompareFMeshDrawCommands());排序以上,得到了当前帧需要的FMeshDrawCommand。 总结:增加MeshDrawPipeline,能够让模块解耦,更灵活。前期这个管线就可以只负责FMeshDrawCommand的转换,而FMeshDrawCommand是完全无状态的,不需要像PrimitiveComponent那样维护各种变化更新,FMeshDrawCommand的职能就是记录渲染Mesh需要的shaders、资源绑定、Drawcall参数,在转换到RHI之前,可以对FMeshDrawCommand可控地排序、缓存、合并绘制。最后,SubmitMeshDrawCommands()将FMeshDrawCommand转换为RHICommandList指令。 **************************分界线****************************** 下面整合一下前2章关于剔除和相关性的内容。 往关卡添加PrimitiveComponent,这时候会实例化对应的FPrimitiveSceneProxy,如果是StaticMesh,还会生成FMeshDrawCommand缓存起来;在Render()函数里,Scene->UpdateAllPrimitiveSceneInfos()更新GPUScene、WaitOcclusionTests()等待上一帧遮挡查询结果、InitViews()计算可见性与相关性得到当前帧需要的FMeshDrawCommand。通过一系列的RenderPass(PrePass,BasePass等)将FMeshDrawCommand转换为RHICommandList。下一篇继续往下分析FMeshDrawCommand转换为RHICommandList指令的流程。 |
CopyRight 2018-2019 实验室设备网 版权所有 |