Please enable Javascript to view the contents

UE4渲染过程

UE4渲染过程
 ·  ☕ 15 分钟 · 👀... 阅读

大概介绍以下UE4的主要渲染过程。

UE4渲染过程

延迟渲染

所谓延迟渲染,是指将一个场景的几何体(3D模型、多边形)的光照、阴影、质感搁置到一旁,先着手于绘画,然后在后半段再对光照、阴影、质感进行处理的处理方式。即给人一种把原本的多边形先绘制出来的印象,实际上不仅要绘制多边形,前者的参数还需要配合后面光照和阴影的处理。其输出目标,在成为复数缓冲时具有普遍性,但是这里的缓冲我们称之为"物理缓冲"。物体缓冲是指使用后照明和后处理特效的中间过渡环节

相关术语

RHI

渲染硬件接口,是为不同平台抽象出不同图形API的一层。所有渲染命令均通过RHI层传递,以转换为适用的渲染器。

延迟渲染

虚幻引擎4中的默认渲染器。它因将照明/阴影计算推迟到全屏过程而不是绘制每个网格时而得名。

顶点工厂

顶点工厂是封装顶点数据源并链接到顶点着色器上的输入的类。静态网格物体,骨架网格物体和过程网格组件均使用不同的顶点工厂。

着色器

在虚幻引擎中,着色器是HLSL代码(以.ush / .usf文件的形式)和材质图的内容的组合。在Unreal中创建材质时,它会根据设置(如着色模式)和用法来编译多个着色器排列。

渲染数据

相关的渲染的数据包括深度值及一些Gbuffer,如下图:

Gbuffer

几个Pass

Z Pre Pass

UE4的渲染管道,是在Bass Pass的物体缓冲写出来之前,在仅预处理深度值(Z值)之后,运行Z预阶段。

事先预处理深度值的目的,是将最终影像和同一深度缓冲的内容结果,在透视前获得。Z预阶段之后的Base Pass则是,参考预先得出的深度值缓冲进行Z预测试,因此通过在最终的画面里不留下像素痕迹(即编写后又被消去的像素),以回避像素着色器的运行。

Base Pass

使用Base Pass输出物体缓冲需要注意的两点:

  1. 不绘制没进入视线的对象

    这种"投影剔除"(Frustum Culling),一般是通过CPU端来处理;为了整体覆盖被称为"包围球"(Bounding sphere)的各个3D对象,对象是否在视野内的判定标准,是通过预先设定的包围球来实行的。

    什么程度的剔除会成功,可以通过Stat初始视图(Stat InitViews)指令的"视锥体裁剪基元(Frustum Culled Primitives)“进行确认。

  2. 不计算多余的像素

    在图像处理的流程中,使用像素着色器实际处理前,会有运行深度测试(Z 测试)的"Pre Z 测试"这一步骤。从这里着手处理的像素,会因为被某个东西所遮挡而无法绘制出来,这时可以进行撤销处理。

    但是,像半透明对象这种会伴随α测试的绘制、视差遮蔽映射这种像素着色器处理后会重新编写深度值的情况,就不进行Pre Z测试,而通过处理实行分路迂回。

UE4 绘制策略DrawingPolicy

绘制策略在UE4渲染中使用很多, 中文也不好翻译。 其实就是根据策略 使用了哪些 着色器 。

……….

UE4渲染一帧

img

渲染管道

preview

首先,虚幻的渲染由三个线程共同完成。分别是CPU线程,DRAW线程,和GPU线程。

知乎:https://zhuanlan.zhihu.com/p/57158725

渲染流水线

Render模块

调用Render()函数在Render模块RendererModule.h中,以下函数:

1
2
3
4
5
class FRendererModule : public IRendererModule
{
    // 开始渲染视图族
    virtual void BeginRenderingViewFamily(FCanvas* Canvas,FSceneViewFamily* ViewFamily) override;
}

==谁最终调用了Render?==

调用Render

实时渲染流程图:

part1:https://i.loli.net/2020/05/30/qU8vN2WZVbt9hkF.jpg

part2:https://i.loli.net/2020/05/30/3trKVpOMU5sTQfB.jpg

渲染函数Render

路径:Engine \ Source \ Runtime \ Renderer \ Private \ DeferredShadingRenderer.cpp(660)

函数:FDeferredShadingSceneRenderer :: Render()渲染路径

全局系统纹理初始化DeferredShadingRenderer.cpp(677) GSystemTextures.InitializeTextures()
保护 必要的渲染目标您是否已确保可以保护的最大目标数目?DeferredShadingRenderer.cpp(680) GSceneRenderTargets.Allocate()
初始化每个视口 设置视口显示的对象,选择使用动态阴影时显示的对象,对半透明对象进行排序DeferredShadingRenderer.cpp(683) InitViews()()
FXSystem预处理 GPU粒子正在被仿真DeferredShadingRenderer.cpp(758) FXSystem-> PreRender()
启用Z Pre-Pass时执行的早期Z绘制 不绘制Tile渲染的硬件(移动设备,Android或iOS)对于 PC或PS4,将生成深度缓冲区和HiZ,因此后续绘制速度很快成为?DeferredShadingRenderer.cpp(768) RenderPrePass()
安全GBufferDeferredShadingRenderer.cpp(774) GSceneRenderTargets.AllocGBufferTargets()
透明光传播量DeferredShadingRenderer.cpp(779) ClearLPVs()
使用DBuffer时绘制延期贴图单击此处获取 DBuffer和延期贴图DeferredShadingRenderer.cpp(796) GCompositionLighting.ProcessBeforeBasePass()
如有必要,请 在绘制线框图时清除GBuffer透明颜色缓冲区, 有些游戏在发行游戏时无法清除GBuffer或屏幕。DeferredShadingRenderer.cpp(805) SetAndClearViewGBuffer() DeferredShadingRenderer.cpp(816) RHICmdList.Clear()
渲染不透明的对象渲染 项目,这些项目根据它们是Masked还是Default,是否有LightMap等按每种排序顺序进行了精细分类DeferredShadingRenderer.cpp(828) RenderBasePass()
清除 GBuffer 的未绘制部分如果事先清除GBuffer,则不必要。DeferredShadingRenderer.cpp(851) ClearGBufferAtMaxZ()
绘制 自定义深度请参见此处以获取自定义深度DeferredShadingRenderer.cpp(860) RenderCustomDepthPass()
在这里再次模拟GPU粒子除了在这里 处理使用深度缓冲区执行碰撞检测的 粒子外,还对GPU粒子进行排序DeferredShadingRenderer.cpp(865) 场景-> FXSystem-> PostRenderOpaque()
为SceneDepthTexture创建一个半分辨率(每个方面为1/4分辨率)的缓冲区DeferredShadingRenderer.cpp(875) UpdateDownsampledDepthSurface()
执行阻塞测试 HZB的构建,执行提交 的HZB Attotempkinder这篇文章DeferredShadingRenderer.cpp(881) BeginOcclusionTests()
开始写 因为有点复杂,所以要写一些细节DeferredShadingRenderer.cpp(890)
不使用DBuffer绘制延迟的贴图CompositionLighting.cpp(293) AddDeferredDecalsBeforeLighting()
在屏幕空间中绘制环境光遮挡CompositionLighting.cpp(300) AddPostProcessingAmbientOcclusion()
后期处理环境立方体贴图CompositionLighting.cpp(305) AddPostProcessingAmbientCubemap()
到这里为止的一系列处理DeferredShadingRenderer.cpp(904) GCompositionLighting.ProcessAfterBasePass()
透明的体积光缓冲液可提高透明度DeferredShadingRenderer.cpp(908) ClearTranslucentVolumeLighting()
从此处开始的主要照明设备 收集要绘制的灯光并将其排序 不要投影,不使用灯光功能的灯光将使用“ 基于图块” 绘制(如果可能)如果不能使用“ 基于图块”关于延迟渲染,是味o,但请参见此处LightRendering.cpp(312-348) LightRendering.cpp(423) RenderTiledDeferredLighting() LightRendering.cpp(429) RenderSimpleLightsStandardDeferred()
它不会阴影,也不会使用灯光功能,但是似乎无法使用TBDR绘制的灯光 被称为标准延迟灯光。LightRendering.cpp(445) RenderLight()
如果用于半透明的体积光是有效的,则将每个光注入到体积光中 ,从而在3D纹理上绘制光效果。LightRendering.cpp(455) InjectTranslucentVolumeLightingArray() LightRendering.cpp(461) InjectSimpleTranslucentVolumeLightingArray()
使用灯光功能投射阴影的灯光将单独处理LightRendering.cpp(468-552)
首先,我在投射阴影时 绘制了一个阴影贴图;在这里我还绘制了一个 半透明的阴影贴图;我记得半透明的当然是傅立叶不透明度贴图LightRendering.cpp(495) RenderTranslucentProjectedShadows() LightRendering.cpp(497) RenderProjectedShadows()
使用LPV时绘制反射阴影贴图LightRendering.cpp(508) RenderReflectiveShadowMaps()
灯光功能图 阴影指示器图LightRendering.cpp(515) RenderLightFunction() LightRendering.cpp(522) RenderPreviewShadowsIndicator()
衰减缓冲器中的分辨 光的衰减信息是否曾经被吸入另一个缓冲器中?LightRendering.cpp(534) GSceneRenderTargets.FinishRenderingLightAttenuation()
注入体积光以获得半透明LightRendering.cpp(541) InjectTranslucentVolumeLighting()
这 是使用光功能投射阴影的光处理的结束。LightRendering.cpp(550) RenderLight()
这 是每个光的LPV 的主要注入照明过程的结尾LightRendering.cpp(561-593) Lpv-> InjectLightDirect()
注入体积光以实现环境立方体贴图的半透明DeferredShadingRenderer.cpp(916) InjectAmbientCubemapTranslucentVolumeLighting()
过滤体积光以获得半透明DeferredShadingRenderer.cpp(919) FilterTranslucentVolumeLighting()
LPV传输过程 此外,第921行的注释上写有“ copypimis”,例如“ Clear LPV buffer”。DeferredShadingRenderer.cpp(924) PropagateLPVs()
动态天光绘图DeferredShadingRenderer.cpp(928) RenderDynamicSkyLighting()
延迟的反射图形 捕获的反射图形而不是屏幕空间DeferredShadingRenderer.cpp(931) RenderDeferredReflections()
LPV的GI绘图CompositionLighting.cpp(344) AddPostProcessingLpvIndirect()
屏幕空间次表面散射(SSSSS)的后处理CompositionLighting.cpp(347-376)
如果启用了“光轴”,则绘制“光轴遮挡”DeferredShadingRenderer.cpp(953) RenderLightShaftOcclusion()
大气雾DeferredShadingRenderer.cpp(977) RenderAtmosphere()
绘图雾 这是高度雾吗?DeferredShadingRenderer.cpp(986) RenderFog()
画一个半透明的物体 在这里也画一个单独的半透明的东西DeferredShadingRenderer.cpp(1000) RenderTranslucency()
折射变形处理DeferredShadingRenderer.cpp(1008) RenderDistortion()
光轴的起霜处理DeferredShadingRenderer.cpp(1013) RenderLightShaftBloom()
距离场AO处理不能在 当前不支持多个视口 的分屏游戏中使用吗?DeferredShadingRenderer.cpp(1019) RenderDistanceFieldAOSurfaceCache()
它只是在查看网格的“距离场”的可视化处理结果吗?DeferredShadingRenderer.cpp(1024) RenderMeshDistanceFieldVisualization()
由于速度模糊而绘制运动对象的速度DeferredShadingRenderer.cpp(1034) RenderVelocities()
从这里到最后的发布过程, 这也很复杂而且很长DeferredShadingRenderer.cpp(1047) GPostProcessing.Process()
使用BeforeTranslucency设置绘制后处理材料PostProcessing.cpp(878) AddPostProcessMaterial()
景深处理 通过高斯模糊进行DOF 处理之后,正在执行散焦处理(使用指定的光圈形状的纹理进行绘制), 在此阶段似乎合并了单独的半透明缓冲区PostProcessing.cpp(888) AddPostProcessDepthOfFieldGaussian() PostProcessing.cpp(898) AddPostProcessDepthOfFieldBokeh() PostProcessing.cpp(905) FRCPassPostProcessBokehDOFRecombine (如果未启用模糊)
使用BeforeTonemapping设置绘制后处理材料PostProcessing.cpp(913) AddPostProcessMaterial()
如果要使用TemporalAA ,请在此处绘制,如果使用FXAA,请稍后再绘制PostProcessing.cpp(921) AddTemporalAA() PostProcessing.cpp(928) AddTemporalAA() (如果不使用速度缓冲区,请单击此处)
运动模糊处理 设置,分辨率下采样,高斯模糊,运动模糊绘制,组合处理PostProcessing.cpp(932-994) FRCPassPostProcessMotionBlurSetup FRCPassPostProcessDownsample RenderGaussianBlur() FRCPassPostProcessMotionBlur FRCPassPostProcessMotionBlurRecombine
SceneColor下采样PostProcessing.cpp(1000) FRCPassPostProcessDownsample
直方图PostProcessing.cpp(1006-1040) FRCPassPostProcessHistogram FRCPassPostProcessHistogramReduce
此处需要眼睛适应图直方图PostProcessing.cpp(1046) AddPostProcessEyeAdaptation()
布卢姆绘图PostProcessing.cpp(1057) AddBloom() PostProcessing.cpp(1060-1148) (对于移动设备,请单击此处)
色调映射 仅替换ReplacecingTonemapper设置工程图的一种后处理材料,但是 如果存在该材料,则执行默认色调映射PostProcessing.cpp(1155) AddSinglePostProcessMaterial() PostProcessing.cpp(1171) AddTonemapper() (默认色调映射)
如果启用了FXAA,请在此处处理PostProcessing.cpp(1177) AddPostProcessAA()
绘制一些编辑器(如选定的轮廓), 然后使用AfterTonemapping设置绘制后期处理材料PostProcessing.cpp(1244) AddPostProcessMaterial()
用于地下和GBuffer的可视化 调试PostProcessing.cpp(1246-1254)
用于HMD的后处理 Oculus或MorpheusPostProcessing.cpp(1256-1277) FRCPassPostProcessHMD FRCPassPostProcessMorpheus
之后,调试和高分辨率屏幕截图功能等。 之后,进行后处理并结束! 谢谢!PostProcessing.cpp(1279-)

哦,很长。


参考链接:

  1. 如何在C ++中从UTexture2D读取数据

  2. https://forums.unrealengine.com/development-discussion/c-gameplay-programming/1422920-casting-converting-frhitexture-to-utexture

  3. Unreal渲染相关的缓冲区

  4. https://qiita.com/mechamogera/items/a0c369a3b853a3042cae

  5. https://answers.unrealengine.com/questions/17862/access-color-and-depth-buffer-of-each-frame.html

  6. https://segmentfault.com/a/1190000012737548

  7. Gbuff数据

  8. 渲染系统概述 图片


VictorHong
作者
VictorHong
🔩工具控,⌨️ 后端程序员,🧪AI 探索者