UE5渲染 您所在的位置:网站首页 mesh网格数量 UE5渲染

UE5渲染

2023-03-13 10:56| 来源: 网络整理| 查看: 265

前言:前2章分析了渲染前的准备:计算可见性与相关性;在分析相关性章节逐渐出现了新的数据结构,这些都是MeshDrawPipeline里的关键类,了解MeshDrawPipeline后自然就知道是什么了。

目的:学习这个管线是如何把UPrimitiveComponent转换为MeshDrawCommand,了解其中的流程,也能对前2章内容进行定位整合,熟悉其在这个管线中所处位置与作用。官方文档:

MeshDrawPipeline

先按顺序来认识一下管线涉及的类:

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列表里。

FScene::AddPrimitive()里添加ENQUEUE_RENDER_COMMAND

在每帧Update时调用UpdateAllPrimitiveSceneInfos()处理。如果是StaticMesh,则继续调用FPrimitiveSceneInfo::AddStaticMeshes() --> FPrimitiveSceneInfo::CacheMeshDrawCommands() --> PassMeshProcessor->AddMeshBatch(),将MeshBatche转换成FMeshDrawCommand并缓存起来。

CacheMeshDrawCommands

而动态物体则是在ComputeViewVisibility函数收集完StaticMesh之后调用Proxy的GetDynamicMeshElements将DynamicMesh收集到FMeshElementCollector里。和StaticMesh不同,这里得到的是FMeshBatch列表。

GetDynamicMeshElements

收集工作总结:一共收集到了3类,包括:已经缓存好StaticMesh的FMeshDrawCommand、StaticMesh没有缓存需要构建的DynamicMeshCommandBuildRequests、需要绘制DynamicMesh的NumDynamicMeshCommandBuildRequestElements。

最后,将收集好的StaticMesh,DynamicMesh都交由SetupMeshPass函数,对需要用到的Pass并行化地生成FMeshDrawCommand。

FParallelMeshDrawCommandPass::DispatchPassSetup

在DispatchPassSetup中,可以看到MaxNumDraws,就如上面说的,把3类收集好的数量加起来,就是所有需要绘制的mesh了。然后就是初始化TaskContext,收集生成FMeshDrawCommand所需的数据,然后交由TaskGraph处理任务。

FMeshDrawCommandPassSetupTask

前面都在收集数据,接下来是开始处理了,由这个任务类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 实验室设备网 版权所有