先总结一下概念:
为了解Unreal渲染时CPU做了什么,我们用源码版的引擎,一步步运行并分析。我们发现引擎是一帧帧在Engine Loop循环运行的,其中包括逻辑线程和渲染线程。我们关注的渲染管线,有三个重要的部分:
1.更新渲染资源,即更新RHICmdList的绑定命令。
2.开启对应平台的渲染线程,推送渲染命令。
3.引擎的的Tick(理解为一帧)调用Draw函数绘制图像。接下来我们继续对Draw调用的函数分析于是得到:
3.1.渲染管线入口函数Render分析。
3.2.RenderMobileBasePass如何绘制。
4.额外学习,虚幻的Mesh绘制组织
虚幻引擎学习中,希望帮助美术转TA对虚幻引擎渲染相关代码有大致概念。多多不足,请各位大佬指点补充。插播广告:欢迎加入腾讯光子TA大家庭,我们一起进步吧。
0.建立场景 开始调试 找到Engine Loop关于渲染的三个主要部分
提前准备好下载Unreal源码版并编译引擎 https://zhuanlan.zhihu.com/p/68330490
创建C++工程,新建空场景,添加小球和灯光。
一步步F10运行到LaunchEngineLoop.cpp找到引擎循环。
我们发现在LaunchEngineLoop.cpp的void FEngineLoop::Tick()中包含渲染的三个重要步骤:
1.更新渲染资源
Scene->UpdateAllPrimitiveSceneInfos(RHICmdList);
2.开启渲染线程并执行
BeginFrAMErENERtHREAD(RHICmdList, CurrentFrameCounter);
Scene->StartFrame();
3.执行当前Tick的内容并绘制界面
Gengine->Tick(Fapp::GetDeltaTime(),bIdleMode);
1.更新渲染资源 RHICmdList的绑定命令
Scene->UpdateAllPrimitiveSceneInfos(RHICmdList);
此处功能是更新RHICmdList,即是更新绑定渲染资源的命令。由于多线程不是每次都会运行到此处,我们在ENQUEUE_RENDER_COMMAND断点后按F5强制运行到此处。一步步F11进入函数观察运行过程。我们观察到了检测渲染线程,创建任务,获得渲染线程等等一系列操作。
//我们继续查看UpdateAllPrimitiveSceneInfos的定义,发现他把模型相关信息添加到SceneInfos里面。
//RHICmdList模型列表的更新
void FScene::UpdateAllPrimitiveSceneInfos(…)
{
FPrimitiveSceneInfo::AddToScene(RHICmdList, this, TArrayView<FPrimitiveSceneInfo*>(&AddedLocalPrimitiveSceneInfos[StartIndex], AddedLocalPrimitiveSceneInfos.Num() - StartIndex)…);
}
PrimitiveSceneInfo.cpp
//模型相关信息添加到SceneInfos。包含一个模型用来渲染的各种信息包括间接光Buffer,光照贴图偏移,反射球Cache,包围盒,剔除盒,静态网格等等。
void FPrimitiveSceneInfo::AddToScene(RHICmdList, Scene, SceneInfos…)
{
SceneInfo->IndirectLightingCacheUniformBuffer = …
SceneInfo->LightmapDataOffset = …
SceneInfo->CacheReflectionCaptures
AddStaticMeshes(RHICmdList, Scene, SceneInfos, bAddToStaticDrawLists);
FPrimitiveBounds& PrimitiveBo