|
首先,老规矩:
<font color=red>**未经允许禁止转载**</font>(防止某些人乱转,转着转着就到蛮牛之类的地方去了)
<font color=red>B站:Heskey0</font>
<hr/>
《Gpu Gems》《Gpu Pro》《Gpu Zen》系列读书笔记
为方便阅读(再次吐槽知乎),本文已搬运至: 【深入解析UE】渲染篇 - Heskey0 - 博客园 (cnblogs.com)
虚幻5渲染编程专栏概述及目录 - 知乎 (zhihu.com)
UE基础
架构
- ULevel是UE的关卡,是场景中物体的集合,存储着一系列Actor
- UWorld是ULevel的容器。每个UWorld实例必须包含一个主关卡(Persistent Level),还可能包含若干个流式关卡(Streaming Level,可选,非必需,可按需动态加载和卸载)
- 常见的WorldType有游戏(Game)、编辑器(Editor)、编辑器播放(PIE)以及预览模式(EditorPreview、GamePreview)等。编辑器内的场景其实也是个World,类型为Editor。
内存
GC
- UObject提供了GC
- 标记清除法
- 将可达对象标记为TRUE
- 收集待清理对象(UE增加了一步)
- 清理不可达对象
- 原子性GC过程
- 获取GC锁,防止GC被其它线程操作
- 执行GC
- 释放GC锁
多线程渲染
UGameEngine::Tick()
- UWorld::Tick() : [LevelTick.cpp]
*
单线程渲染:CPU和GPU可能相互等待
UE的线程(FRunnableThread)
- 游戏线程(Game Thread)(也称作主线程)(UGameEngine::Tick)
- 渲染线程(FRenderingThread)
- 专门用于生成渲染指令 (FRenderCommand) 和渲染逻辑的独立线程
- RHI线程(RHI Thread)
- 转换渲染指令到指定图形API,创建、上传渲染资源到GPU
- RHI全称是Render Hardware Interface(渲染硬件接口), 封装了众多图形API(DirectX、OpenGL、Vulkan、Metal)之间的差异
线程同步
- 渲染命令栅栏(FRendeLauchEngineLooprCommandFence)
- 同步(FFrameEndSync)
- 在引擎循环的帧末尾添加游戏线程和渲染线程的同步事件
渲染机制
剖析虚幻渲染体系(03)- 渲染机制 - 0向往0 - 博客园 (cnblogs.com)
Draw Call 的产生
UE5
- RHI层的变动主要在于将各种顶点、索引Buffer统一成了FRHIBuffer。
- Renderer层增强了光线追踪,特别是屏幕空间的光线追踪,加强了距离场的各种应用,同时删除了LPV。
- Engine层主要围绕着RHI、Renderer层的变动做了相应修改和调整
Nanite
渲染特性:
Component:
- 不支持:
- skeletal animation
- morph target / blend shape
- spline mesh
Preview
1. VSM (Virtual Shadow Map):一种新的阴影投射方法
UE5中VirtualShadowMap的简易实现原理(一) - 知乎 (zhihu.com)
UE5 虚拟阴影贴图 (VirtualShadowMaps)的优势和局限性 - 知乎 (zhihu.com)
- 开启后,会替换传统阴影技术(CSM, SDF,......),GPU上实现
- 开启后,SMRT (Shadow Map Ray Tracing) 可以利用VSM生成阴影
Algorithm Overview:
- 假设有一张分辨率极高的 Virtual ShadowMap(16K)
- 通过坐标转换,找到深度图中像素对应到 Virtual ShadowMap中的格子 (Virtual Tile),然后标记为Used,每个标记的格子挨个(紧密)存放到一张UAV (Tile Padding)
- 利用UAV走正常的shadowmap流程,没有标记的 Virtual Tile 用不到
Mipmap适配:
- 生成不同分辨率的Virtual ShadowMap(Mipmap)
- 根据深度算出当前屏幕对应的Mipmap Level级别
裁剪图(Clipmap):
- 单张虚拟阴影贴图无法提供足够的分辨率来覆盖大型区域
- 定向光源使用裁剪图(Clipmap)结构来扩展摄像机周围的范围
- 每个裁剪图级别都有其单独的16K VSM
2. SMRT (Shadow Map Ray Tracing):利用VSM生成软阴影
PCF过于模糊
Algorithm Overview:
3. TSR (Temporal Super Resolution):替换传统TAA
Core
Cluster :
- 一组相邻三角形的集合 ( 在早前已被育碧和寒霜引擎使用 )
- Cluster可以和相邻的Cluster动态合批
Lumen
Surface Cache
- Lumen为场景表面附近生成Surface Cache
- 用于快速查找射线命中点的光照
屏幕追踪
- Lumen先对屏幕进行追踪
- 追踪失败,则使用更可靠的方法
光线追踪
- 软件光线追踪(ray marching)
- 依赖于距离场,较大网格会有不良表现
- Detail Tracing(默认):前两米使用网格距离场,其它距离使用全局距离场
- Global Tracing:利用全局距离场快速追踪,损失画质效果
补充(非Lumen):DFAO
- DFAO中网格距离场没有合并到全局距离场
- 所有的网格距离场atlas到一张体贴图上(300M显存)
- step1 : 光源出发Trace,剔除掉不会相交的距离场
- step2 : 从场景出发沿光源做Trace
Shader
第一梯队的shader模块是最底层最基础的模块,这些模块不会引用其它模块,但会被其它很多模块引用。这些模块主要有:
- BasePassCommon.ush
- BRDF.ush
- CapsuleLight.ush
- Common.ush
- 图形API或Feature Level相关的宏、类型、局部变量、静态变量、基础工具接口
- FeatureLevel: Feature levels in Direct3D - Wikipedia
- // FEATURE_LEVEL的宏定义
#define FEATURE_LEVEL_ES2_REMOVED 1
#define FEATURE_LEVEL_ES3_1 2
#define FEATURE_LEVEL_SM3 3
#define FEATURE_LEVEL_SM4 4
#define FEATURE_LEVEL_SM5 5
#define FEATURE_LEVEL_MAX 6
- CommonViewUniformBuffer.ush
- Definitions.usf
- 定义了一些常见的宏,防止其它模块引用时出现语法错误
- FP16Math.ush
- Platform.ush
- 图形API(DirectX、OpenGL、Vulkan、Metal)和FEATURE_LEVEL相关的宏、变量及工具类接口
- ShaderVersion.ush
- LightGridCommon.ush
- LocalVertexFactoryCommon.ush
- Get/Set :
- Color
- LightMapCoordinates
- Tangent
- 图元id(PrimitiveId)
- ShadingCommon.ush
- 定义了材质所有着色模型ID,并提供了少量相关的工具类接口
- // 材质着色模型, 每种类型都有对应的光照算法和流程.
#define SHADINGMODELID_UNLIT 0
#define SHADINGMODELID_DEFAULT_LIT 1
#define SHADINGMODELID_SUBSURFACE 2
#define SHADINGMODELID_PREINTEGRATED_SKIN 3
#define SHADINGMODELID_CLEAR_COAT 4
#define SHADINGMODELID_SUBSURFACE_PROFILE 5
#define SHADINGMODELID_TWOSIDED_FOLIAGE 6
#define SHADINGMODELID_HAIR 7
#define SHADINGMODELID_CLOTH 8
#define SHADINGMODELID_EYE 9
#define SHADINGMODELID_SINGLELAYERWATER 10
#define SHADINGMODELID_THIN_TRANSLUCENT 11
#define SHADINGMODELID_NUM 12
#define SHADINGMODELID_MASK 0xF // ShadingModelID只占用了GBuffer的4bit.
- ShadowDepthCommon.ush
- ShadowProjectionCommon.ush
- SHCommon.ush
- (......)
第二梯队的重要或基础模块会引用第一梯队的基础模块,但也会被其它梯队或模块引用:
- CapsuleLightIntegrate.ush
- DeferredLightingCommon.ush
- 光源数据 struct FDeferredLightData
- 阴影射线检测ShadowRayCast
- 光照计算接口
- DeferredShadingCommon.ush
- 颜色,法线,GBuffer数据的编码解码
- GBuffer数据集合:struct FGBufferData
- 屏幕空间数据:
//包含了GBuffer和AO.
struct FScreenSpaceData
{
// GBuffer (material attributes from forward rendering pass)
FGBufferData GBuffer;
float AmbientOcclusion;
};
- LocalVertexFactory.ush
- // 从绑定的顶点Buffer中获取的顶点输入数据.
struct FVertexFactoryInput{}
- MaterialTemplate.ush
- RectLight.ush
- RectLightIntegrate.ush
- ShadingModels.ush
- 着色模型以及光照计算相关的类型和辅助接口
- Light结构体
- struct FAreaLight区域光
- struct FDirectLighting直接光
- struct FShadowTerms阴影数据
- 光照接口
- 能量归一化EnergyNormalization
- DualSpecularGGX
- RefractBlend
- ShadingModel光照
- SimpleShading
- DefaultLitBxDF
- HairBxDF
- ClearCoatBxDF
- SubsurfaceProfileBxDF
- ClothBxDF
- SubsurfaceBxDF
- (......)
- //会根据ShadingModelID调用上面不同的接口
- IntegrateBxDF
- EvaluateBxDF
- ShadingModelsMaterial.ush
- VertexFactoryCommon.ush
- 顶点变换接口
- TransformLocalToWorld
- TransformLocalToTranslatedWorld
- RotateLocalToWorld
- RotateWorldToLocal
- UnitToOct
最后是第三梯队的模块,重要模块的实现,会引用第一、第二梯队的模块:
- BasePassPixelShader.usf
- BasePassVertexShader.usf
- CapsuleShadowShaders.usf
- DeferredLightPixelShaders.usf
- DeferredLightVertexShaders.usf
- ShadowProjectionPixelShader.usf
- ShadowProjectionVertexShader.usf
- (......)
FShader
继承
graph BT
FGlobalShader-->FShader;
FMaterialShader-->FShader;
基础概念
Shader :
- FMaterialShader
- 由FMaterialShaderType指定的材质引用的Shader
- 材质蓝图实例化后的shader子集
ShaderType :
- FShaderType
- FGlobelShaderType
- 最简单的Shader
- 每个ShaderType只有一个实例
ShaderParameter
- 由CPU的C++层传入GPU Shader并存储于GPU寄存器或显存的数据,提供Bind()进行数据绑定。着色器参数可以绑定任何GPU类型的资源或数据 ,但不同的类只能绑定特定的着色器类型
- FShaderParameter
Vertex Factory
- 支持网格类型( 静态网格、蒙皮骨骼、程序化网格以及地形等等)
- 渲染线程包含了Vertex Factory对象,横跨CPU和GPU两端
- FVertexFactory封装了可以链接到顶点着色器的顶点数据资源
编译机制
usf文件编译成对应目标平台的shader代码【Shader: 一段文本,GPU硬件上执行】
Shader Map
- 存储编译后的Shader代码(Shader Permuation)
- FGlobalShaderMap
- FMaterialShaderMap
- FMeshMaterialShaderMap
- 可以把它理解成一个三维矩阵,长度为每个材质类型,宽度为每个渲染阶段Pass,高度为每个顶点工厂类型,矩阵的每一个方格都对应了一组着色器组合(顶点着色器,像素着色器),材质也不一定参与全部阶段,所以这个三维矩阵中是存在有很多空缺的
Uber Shader设计:Shader Permutation
编译与跨平台
1. 编译2. Shader跨平台
UE造了个轮子HLSLCC (HLSL Cross Compiler)
HLSLCC (以GLSL为例):
- Preprocessing,预处理阶段。通过类似C风格的预处理器运行,在编译之前,UE使用MCPP进行预处理,因此跳过了这一步。
- Parsing,语法分析阶段。通过Mesa的**_mesa_hlsl_parse**接口,HLSL将被分析成抽象语法树,Lexer(语法分析)和Parser分别由flex和bison生成。
- Compilation,编译阶段。利用 _mesa_ast_to_hir,将AST(抽象语法树)编译为Mesa IR。在此阶段,编译器执行隐式转换、函数重载解析、生成内部函数的指令等功能,也将生成 GLSL 主入口点,会将输入及输出变量的全局声明添加到IR,同时计算HLSL入口点的输入,调用HLSL入口点,并将输出写入全局输出变量。
- Optimization,优化阶段。主要通过do_optimization_pass对IR执行多遍优化,包括直接插入函数、消除无用代码、传播常量、消除公共的子表达式等等。
- Uniform packing,全局变量打包。将全局统一变量打包成数组并保留映射信息,以便引擎可将参数与一致变量数组的相关部分绑定。
- Final optimization,最终优化阶段。打包统一变量之后,将对IR运行第二遍优化,以简化打包统一变量时生成的代码。
- Generate GLSL,生成GLSL。最后步骤,将已经优化的IR转换为GLSL源代码。除了生成所有构造及统一变量缓冲区的定义以及源代码本身以外,还会在文件开头的注释中写入一个映射表。
在UE4.25,Shader的跨平台示意图如下:
img
注:
Direct3D和OpenGL虽然在标准化设备坐标一致,但在UV空间的坐标是不一致的:
UE为了不让shader的开发人员察觉到这一差异,采用了翻转的图片,强制使得UV坐标用统一的范式:
这样做的后果就是OpenGL的纹理实际上是垂直翻转的(从RenderDoc截取的UE在OpenGL平台下的应用也可佐证),不过渲染后期可以再次翻转就行了。但是,UE采用颠倒(Upside down)的渲染方式,并且将颠倒的参数集成到投影矩阵:
因此,看起来标准化设备坐标和D3D下的纹理都是垂直翻转的。
调试
虚幻5渲染编程专栏概述及目录 - 知乎 (zhihu.com)
step1: 开启指令,方便RenderDoc调试
Engine\Config\ConsoleVariables.ini
命令行 | 解析 | r.ShaderDevelopmentMode=1 | 获得关于着色器编译的详细日志和错误重试的机会。 | r.DumpShaderDebugInfo=1 | 将编译的所有着色器的文件保存到磁盘ProjectName/Saved/ShaderDebugInfo的目录。包含源文件、预处理后的版本、一个批处理文件(用于使用编译器等效的命令行选项来编译预处理版本)。 | r.DumpShaderDebugShortNames=1 | 保存的Shader路径将被精简。 | r.Shaders.Optimize=0 | 禁用着色器优化,使得shader的调试信息被保留。 | r.Shaders.KeepDebugInfo=1 | 保留调试信息,配合RenderDoc等截帧工具时特别有用。 | r.Shaders.SkipCompression=1 | 忽略shader压缩,可以节省调试shader的时间。 | 修改了某些Shader文件, 控制台输入RecompileShaders即可重新编译
Material
FMaterialRenderProxy负责接收游戏线程的数据,然后传递给渲染器去处理和渲染
FMaterial有3个功能:
- 表示材质到材质的编译过程,并提供可扩展性钩子(CompileProperty等) 。
- 将材质数据传递到渲染器,并使用函数访问材质属性。
- 存储缓存的shader map,和其他来自编译的瞬态输出,这对异步着色器编译是必要的。
渲染
UE4渲染模块分析 - 简书 (jianshu.com)
类型 | 解析 | UPrimitiveComponent | 图元组件,是所有可渲染或拥有物理模拟的物体父类。是CPU层裁剪的最小粒度单位。 | FPrimitiveSceneProxy | 图元场景代理,是UPrimitiveComponent在渲染器的代表,镜像了UPrimitiveComponent在渲染线程的状态。 | FPrimitiveSceneInfo | 渲染器内部状态(描述了FRendererModule的实现),相当于融合了UPrimitiveComponent and FPrimitiveSceneProxy。只存在渲染器模块,所以引擎模块无法感知到它的存在。 | FScene | 是UWorld在渲染模块的代表。只有加入到FScene的物体才会被渲染器感知到。渲染线程拥有FScene的所有状态(游戏线程不可直接修改)。 | FSceneView | 描述了FScene内的单个视图(view),同个FScene允许有多个view,换言之,一个场景可以被多个view绘制,或者多个view同时被绘制。每一帧都会创建新的view实例。 | FViewInfo | view在渲染器的内部代表,只存在渲染器模块,引擎模块不可见。 | FSceneRenderer | 每帧都会被创建,封装帧间临时数据。下派生FDeferredShadingSceneRenderer(延迟着色场景渲染器)和FMobileSceneRenderer(移动端场景渲染器),分别代表PC和移动端的默认渲染器。 | FMeshBatchElement | 单个网格模型的数据,包含网格渲染中所需的部分数据,如顶点、索引、UniformBuffer及各种标识等。 | FMeshBatch | 存着一组FMeshBatchElement的数据,这组FMeshBatchElement的数据拥有相同的材质和顶点缓冲。 | FMeshDrawCommand | 完整地描述了一个Pass Draw Call的所有状态和数据,如shader绑定、顶点数据、索引数据、PSO缓存等。 | FMeshPassProcessor | 网格渲染Pass处理器,负责将场景中感兴趣的网格对象执行处理,将其由FMeshBatch对象转成一个或多个FMeshDrawCommand。 | 渲染模块由如下几个部分组成:
1. 场景的描述
UE4场景管理相关的数据结构如下:
- FScene 场景类
- FPrimitiveSceneProxy 场景里的几何体类
- FPrimitiveSceneInfo 场景里的结点(拥有几何体和状态信息)
每个几何体具有材质属性,相关的数据结构如下:
- FMaterial 材质接口类,提供材质属性的查询(eg. blend mode)和shader查找。
- FMaterialResoruce UMaterial实现的具体的FMaterial
- FMaterialRenderProxy 渲染线程用的Material对象,提供FMaterial的访问和材质参数的访问(eg. scaler, vector, texture parameter等参数)。
2. 场景的遍历和拣选
可见性判断
2.1 从FPrimitiveSceneProxy到FMeshBatch
基本概念:
- UPrimitiveComponent是图元组件,是所有可渲染或拥有物理模拟的物体父类。是CPU层裁剪的最小粒度单位。
- FPrimitiveSceneProxy是游戏线程UPrimitiveComponent在渲染线程的镜像数据
- FMeshBatch包含了绘制Pass所需的所有信息,解耦了网格Pass和FPrimitiveSceneProxy(FMeshBatch作为中间层),所以FPrimitiveSceneProxy并不知道会被哪些Pass绘制
- FMeshBatch存着一组FMeshBatchElement,这组FMeshBatchElement的数据拥有相同的材质和顶点缓冲
FMeshBatch记录了一组拥有相同材质和顶点工厂的FMeshBatchElement数据. 一个FMeshBatch拥有一组FMeshBatchElement、一个顶点工厂和一个材质实例,同一个FMeshBatch的所有FMeshBatchElement共享着相同的材质和顶点缓冲 (大部分情况一个FMeshBatch只有一个FMeshBatchElement)
FMeshElementCollector和FSceneRenderer是一一对应关系,每个FSceneRenderer拥有一个收集器。
2.2 从FMeshBatch到FMeshDrawCommand
【MeshPassProcessor.h】
- 收集完动态的MeshElement,紧接着会调用SetupMeshPass来创建FMeshPassProcessor , FMeshPassProcessor充当了将FMeshBatch转换成FMeshDrawCommands的角色。
- FMeshBatch转换成FMeshDrawCommand后,每个Pass都对应了一个FMeshPassProcessor,每个FMeshPassProcessor保存了该Pass需要绘制的所有FMeshDrawCommand,以便渲染器在合适的时间触发并渲染。
FMeshPassProcessor的主要作用是:
- Pass过滤。将该Pass无关的MeshBatch给过滤掉,比如深度Pass过滤掉透明物体。( 不同的MeshPass处理FMeshBatch会有所不同 )
- 选择绘制命令所需的Shader及渲染状态(深度、模板、混合状态、光栅化状态等)。
- 收集绘制命令涉及的Shader资源绑定。
- Pass的Uniform Buffer,如ViewUniformBuffer、DepthPassUniformBuffer。
- 顶点工厂绑定(顶点数据和索引)。
- 材质绑定。
- Pass的与绘制指令相关的绑定。
img
最终,FMeshDrawCommand接入RHI层
2.3 静态与动态绘制路径
img
UE存在3种网格绘制路径(橙色为每帧动态生成,蓝色为只生成一次后缓存)
- 第1种是动态绘制路径,从FPrimitiveSceneProxy到RHICommandList每帧都会动态创建,效率最低,但可控性最强
- 第2种是需要View的静态路径,可以缓存FMeshBatch数据,效率中,可控性中
- 第3种是不需要view的静态绘制路径,可以缓存FMeshBatch和FMeshDrawCommand,效率最高,但可控性差,需满足的条件多。
(1) 动态
通过GetDynamicMeshElements接口来收集FMeshBatch
3. 渲染的执行
1)多Pass绘制
Pass_0: PrePass/Depth Only Pass
Pass_1: BassPass
Pass_2: Issue Occlusion Queries / BeginOcclusionTests
Pass_3: ShadowMap
Pass_4: Lighting
Pass_5: Draw atmosphere
Pass_6: Draw Fog
Pass_7: Draw translucency
Pass_8: Post Processing
延迟渲染
简介
1. Overview:
两个Pass
- Geometry Pass (UE称为Base Pass):生成 GBuffer
- 所有的不透明物体(Opaque)和Masked物体 使用Unlit材质进行渲染
- 将几何信息写入RT中
- Depth
- Normal
- 材质参数(Diffuse Color, Emissive Color, Roughness, , Shading Model, AO, ......)
Coding in Unreal Engine:
void RenderBasePass()
{
SetupGBuffer(); // 设置几何数据缓冲区。
// 遍历场景的非半透明物体
for each(Object in OpaqueAndMaskedObjectsInScene)
{
SetUnlitMaterial(Object); // 设置无光照的材质
DrawObjectToGBuffer(Object); // 渲染Object的几何信息到GBuffer,通常在GPU光栅化中完成。
}
}
void RenderLightingPass()
{
BindGBuffer(); // 绑定几何数据缓冲区。
SetupRenderTarget(); // 设置渲染纹理。
// 遍历RT所有的像素
for each(pixel in RenderTargetPixels)
{
// 获取GBuffer数据。
pixelData = GetPixelDataFromGBuffer(pixel.uv);
// 清空累计颜色
color = 0;
// 遍历所有灯光,将每个灯光的光照计算结果累加到颜色中。
for each(light in Lights)
{
color += CalculateLightColor(light, pixelData);
}
// 写入颜色到RT。
WriteColorToRenderTarget(color);
}
}
2. 优劣:
优
- 复杂度 O(N_{light}\times W_{RT}\times H_{RT}) ,跟场景的物体数量解耦,只跟Render Targe尺寸相关
- 避免了很多本被遮挡的物体光照计算
劣
- 多一个通道来绘制几何信息,需要多渲染纹理(MRT)的支持,更多的CPU和GPU显存占用,更高的带宽要求
- 有限的材质呈现类型
- 难以使用MSAA等硬件抗锯齿,存在画面较糊的情况等等
- 应对简单场景时,可能反而得不到渲染性能方面的提升
Unreal Engine Implementation
graph BT
FMobileSceneRenderer-->FSceneRenderer
FDeferredShadingSceneRenderer-->FSceneRenderer
- FMobileSceneRenderer是用于移动平台的场景渲染器,默认采用了前向渲染的流程。
- FDeferredShadingSceneRenderer虽然名字叫做延迟着色场景渲染器,但其实集成了包含前向渲染和延迟渲染的两种渲染路径,是PC和主机平台的默认场景渲染器。
1. FSceneRenderer创建
FSceneRenderer
- 处理和渲染场景,生成RHI层的渲染指令
- 由游戏线程的 FRendererModule::BeginRenderingViewFamily负责创建和初始化,然后传递给渲染线程。
- 渲染线程会调用FSceneRenderer::Render(),渲染完返回后,会删除FSceneRenderer的实例。也就是说,FSceneRenderer会被每帧创建和销毁。
class UGameEngine : public UEngine
UGameEngine::Tick()
- called UGameEngine::RedrawViewports()
- called UGameViewportClient::Draw()
- called FRendererModule::BeginRenderingViewFamily()
FRendererModule::BeginRenderingViewFamily(..., FSceneViewFamily* ViewFamily)
{
FScene* const Scene = ViewFamily->Scene->GetRenderScene();
FSceneRenderer* SceneRenderer = FSceneRenderer::CreateSceneRenderer(ViewFamily, ...);
}
创建FSceneRenderer之后发送指令给渲染线程
- 调用FSceneRenderer->Render(RHICmdList);
- 等待SceneRenderer的任务完成然后清理并删除实例
2. FDeferredShadingSceneRenderer
In deferred shader, the SSAO uses the GBuffer and must be executed after base pass. Otherwise, async compute runs the shader in RenderHzb()
3. PrePass
浅谈HiZ-buffer - DeepDream
PrePass又被称为提前深度Pass、Depth Only Pass、Early-Z Pass,用来渲染不透明物体的深度。
此Pass只会写入深度而不会写入颜色,写入深度时有disabled、occlusion only、complete depths三种模式,视不同的平台和Feature Level决定。
通常用来建立Hierarchical-Z,以便能够开启硬件的Early-Z技术,还可被用于遮挡剔除,提升Base Pass的渲染效率
绘制深度时,由于不需要写入颜色,那么渲染物体时使用的材质肯定不应该是物体本身的材质,而是某种简单的材质 UMaterial::GetDefaultMaterial(MD_Surface)( 在engine.ini配置文件中指定 )
ResolvedPath = L&#34;/Engine/EngineMaterials/WorldGridMaterial.WorldGridMaterial&#34;
非常值得一提的是:WorldGridMaterial使用的Shading Model是Default Lit,材质中也存在冗余的节点。如果想要做极致的优化,建议在配置文件中更改此材质,删除冗余的材质节点,改成Unlit模式更佳,以最大化地缩减shader指令,提升渲染效率。
4. BasePass
- 用来渲染不透明物体的几何信息,包含法线、深度、颜色、AO、粗糙度、金属度等等,这些几何信息会写入若干张GBuffer中
- Base Pass正常情况下使用的是FMeshBatch收集到的材质,也就是网格自身的材质,唯一不同的是shader中不会启用光照计算,类似于Unlit模式。
- 遍历所有view, 每个view渲染一次Base Pass.
OverView : O(n^3)
foreach(dscene in scenes)
{
foreach(view in views)
{
foreach(mesh in meshes)
{
DrawMesh(...) // 每次调用渲染就执行一次BasePassVertexShader和BasePassPixelShader的代码.
}
}
}
RenderBasePass
- RenderBasePassInternal
- SetupBasePassState: 初始化BassPass所用的渲染状态(渲染设置)
执行Shader
BasePass绘制时使用的VS和PS分别是TBasePassVS和TBasePassPS (BasePassRendering.h)
template <typename LightMapPolicyType>
void GetBasePassShaders(const FMaterial& Material, ...)
{
(......)
VertexShader = Material.GetShader<TBasePassVS<LightMapPolicyType, false> >(VertexFactoryType);
PixelShader = Material.GetShader<TBasePassPS<LightMapPolicyType, false> >(VertexFactoryType);
(......)
}
- TBasePassVS和TBasePassPS 提供了获取Shader绑定、更改编译环境和只编译指定的排列组合shader等接口,此外还拥有反射球、光照图类型等属性
执行Shader文件:BasePassVertexShader.usf ,BasePassPixelShader.usf
BasePassPixelShader的主要步骤:
- 初始化ResolvedView、GBuffer等数据。
- GetMaterialPixelParameters:获取材质的参数,从材质编辑器编辑的材质节点和插值数据而来。详细数据由FMaterialPixelParameters定义
// Engine\Shaders\Private\MaterialTemplate.ush
struct FMaterialPixelParameters{}
- CalcMaterialParametersEx:根据FMaterialPixelParameters计算额外的材质参数。
- 根据FMaterialPixelParameters的数据和从顶点插值而来的数据计算GBuffer数据。
- 计算次表面散射、贴花、体积光照图等数据。
- SetGBufferForShadingModel:设置前面步骤收集到的参数到GBuffer。
- 计算或处理速度缓冲、高光颜色、漫反射颜色、环境法线、AO,叠加次表面散射颜色到漫反射中。
- 处理预计算的非直接光照和天空光、非直接AO,计算最终的漫反射项。
- 处理前向渲染光照或平行光,处理透明物体光照。
- 计算雾效果,包含高度雾、指数雾、体积雾、逐像素雾、云体雾,以及天空大气效果。
- 处理自发光。
- EncodeGBuffer:将GBuffer基础数据编码到MRT中。
- 将GBuffer的非基础数据写入到后面几个RT,如速度缓冲、逐物体阴影等。
- 处理预曝光。
即:
5. LightingPass
负责间接阴影、AO、透明体积光照、光源计算、LPV、天空光、SSS等
FDeferredShadingSceneRenderer::RenderLights
graph TB
FinalColor-->LightAccumnulator;
FinalColor-->View.PreExposure;
LightAccumnulator-->Color;
Color-->Fogging.a;
Color-->+;
+-->Fogging.rgb;
+-->DiffuseColor;
+-->Emissive;
DiffuseColor-->AOMultiBounce;
AOMultiBounce-->GBuffer.BaseColor;
AOMultiBounce-->DiffOcclusion;
DiffuseColor-->\(+);
\(+)-->*;
*-->DiffuseIndirectLighting;
*-->GBuffer.DiffuseColor;
\(+)-->**;
**-->SubsurfaceIndirectLighting;
**-->SubsurfaceColor;
RHI
RDG
RDG的理念不在GPU上立即执行Pass,而是先收集所有需要渲染的Pass,然后按照依赖的顺序对图表进行编译和执行,期间会执行各类裁剪和优化。(Pass的管理者)
UE5
- 增加实例化裁剪模块:InstanceCulling、InstanceCullingManager等,包含FInstanceCullingRdgParams、EInstanceCullingMode、FInstanceCullingContext、FInstanceCullingManager等类型,主要用于Nanite技术。
- 虚拟纹理增加或完善了数据读写和FVirtualTextureFeedbackBuffer、RenderPages、RenderPagesStandAlone等接口。
- 全局距离场数据(FGlobalDistanceFieldParameterData)增加了Mipmap和VT数据和接口。
- HairStrand增加EHairBindingType、EHairInterpolationType、FHairStrandsInstance等类型。
- 增加或完善FVertexFactoryShaderPermutationParameters的类型。
- MeshPassProcessor:
- EMeshPass增加VSMShadowDepth、LumenCardCapture、EditorLevelInstance等专用通道。
- 增加EFVisibleMeshDrawCommandFlags、FCompareFMeshDrawCommands、FMeshPassProcessorRenderState等类型。
- 增加FSimpleMeshDrawCommandPass类型,用于处理不需要并行处理绘制命令的地方,减少开销。
- FVisibleMeshDrawCommand增加EFVisibleMeshDrawCommandFlags以及用于GPUCull的FMeshDrawCommandSortKey、InRunArray等。
- FDynamicPassMeshDrawListContext的FinalizeCommand阶段增加了NewVisibleMeshDrawCommand.Setup阶段。
- 摒弃SetInstancedViewUniformBuffer、SetPassUniformBuffer、GetInstancedViewUniformBuffer等UniformBuffer接口。
- 新增Nanite模块:
- 新增NaniteRender:FNaniteCommandInfo、ENaniteMeshPass、FNaniteDrawListContext、FCullingContext、FRasterContext、FRasterResults、FNaniteShader、FNaniteMaterialVS、FNaniteMeshProcessor、FNaniteMaterialTables、ERasterTechnique、ERasterScheduling、EOutputBufferMode、FPackedView等等类型及处理接口。
- FPrimitiveFlagsCompact增加bIsNaniteMesh标记。
- FPrimitiveSceneInfo增加NaniteCommandInfos、NaniteMaterialIds、LumenPrimitiveIndex以及CachedRayTracingMeshCommandsHashPerLOD、bRegisteredWithVelocityData、InstanceDataOffset、NumInstanceDataEntries实例化和光追相关的等数据和处理接口。
- 新增Lumen模块:
- 涉及的模块非常多,总结起来有DiffuseIndirect、Scene、HardwareRayTracing、Mesh、Probe、Radiance、Radiosity、TranslucencyVolume、Voxel以及数据结构、工具箱等。
- 替换传统Shader绑定接口到RDG,如SHADER_PARAMETER_TEXTURE改成SHADER_PARAMETER_RDG_TEXTURE。
- 增加或完善RuntimeVirtualTextureProducer、FSceneTextureExtracts、EMobileSceneTextureSetupMode、Strata地层。
- 增强后处理效果,如增加了Temporal Super Resolution(TSR)。
- 增强了光照追踪模块,如RTGI、RTAO、RTR、RTShadow、RTSkyLight等。
- DeferredShadingRenderer:
- 增加Lumen、IndirectLightRender、SSRT、TranslucencyLightingVolume等相关的模块、类型和步骤。
- 增加FLumenCardRenderer、TPipelineState、EDiffuseIndirectMethod、EAmbientOcclusionMethod、EReflectionsMethod、FPerViewPipelineState、FFamilyPipelineState等类型。
- 增加或增强了BasePass、DepthPass、SDF、GPUScene、GlobalDistanceField、BVH、GenerateConservativeDepthBuffer、LightRendering、InrectLightRendering、MeshDrawCommands、Shader、ScreenSpace、Shadow、MobileRender等等渲染模块。
从UE4.26到5.0EA,重要和基础的渲染模块都做了大大小小的修改。
Appendix
Compute Shader
Compute Shader : Optimize your game using compute - 知乎
为了执行通用计算,NV推出了CUDA,Khronos推出了OpenCL,Microsoft推出了DirectCompute,也就是后来的Compute Shader,然后,各种图形API也相继推出了CS
DX虽然从10开始支持Compute Shader/Direct Compute,但是限制比较大。DX11的Compute Shader拥有更强大的功能(当然肯定还有DX12)[6]。所以我们一般在Unity中使用CS,还是要求shader target4.5(也就是shader model 5) |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|