179 lines
13 KiB
Markdown
179 lines
13 KiB
Markdown
---
|
||
title: VirualShadowMap优化笔记
|
||
date: 2023-02-08 12:29:43
|
||
excerpt:
|
||
tags: VSM Nanite
|
||
rating: ⭐
|
||
---
|
||
# 前言
|
||
VirualShadowMap与Nanite关系很大,如果场景中有很多非Nanite物体就需要将其都穿成Nanite,之后可以用Nanite Tool或者VirualShadowMap Cache显示模型来检查场景,具体可以参考[[Nanite学习笔记]]。具体优化步骤可以参考[[#优化案例]]。
|
||
|
||
# 相关命令(某个A站作品使用的参数)
|
||
## VT
|
||
- r.VT.MaxUploadsPerFrameInEditor 8
|
||
- r.VT.MaxUploadsPerFrame 8
|
||
- r.VT.MaxContinuousUpdatesPerFrameInEditor 2
|
||
- r.VT.MaxContinuousUpdatesPerFrame 2
|
||
- r.VT.MaxAnisotropy 8
|
||
|
||
## Lumen相关命令
|
||
- r.MeshDrawCommands.DynamicInstancing 0
|
||
- r .Shadow.Virtual.NonNanite.IncludeInCoarsePages 0
|
||
- r.Lumen.Reflections.DownsampleFactor 1.98
|
||
- r.Lumen.ScreenProbeGather.Temporal.DistanceThreshold 1.7
|
||
- r.RayTracing.NormalBias 5.0
|
||
- r.Lumen.ScreenProbeGather.MaxRayIntensity 10
|
||
- r.Lumen.ScreenProbeGather.ScreenTraces.HZBTraversal 0
|
||
- r.Lumen.Reflections.HierachicalScreenTraces.MaxIterations 4
|
||
|
||
## VirualShadowMap
|
||
- r.Shadow.RadiusThreshold 0.05
|
||
- r.ShadowVirtualClip .LastLevel 15
|
||
- r.Shadow.Virtual.ResolutionLodBiasDirectional -1.1
|
||
- r.Shadow.Virtual.Clipmap.UseConservativeCulling 0
|
||
- r.Shadow.Virtual.Cache.MaxMaterialPositionInvalidationRange 3500
|
||
- r.Shadow.Virtual.ForceOnlyVirtualShadowMaps 1
|
||
- r.Shadow.Virtual.0.CulingFarCulingFar
|
||
|
||
# 其他优化思路
|
||
其次,local灯光的数量对VSM的性能有较大影响。一方面可以考虑减少不必要的局部光源数量,此外可以尝试使用One Pass Projection功能(实验性),来提高性能。开启方法如下:
|
||
- `r.UseClusteredDeferredShading 1`
|
||
- `r.Shadow.Virtual.OnePassProjection 1`
|
||
|
||
然后还可以通过调整下列CVar(默认值16)到更小的数字,来强行限制每个像素受到影响的灯光数量,来提高性能。
|
||
`r.Shadow.Virtual.OnePassProjection.MaxLightsPerPixel`
|
||
|
||
此外,还有一些实践思路供参考,例如:
|
||
减少屏幕上大面积像素受到多个大范围局部灯光的影响(**减少多个局部灯光重叠影响同一片大面积区域**);
|
||
减小局部灯光的**Source Radius**属性和方向光的**Source Angle**属性可以降低**VSM Ray的数量**;
|
||
关闭数量庞大的**次要模型的投影**;
|
||
关闭**超远距离**的背景物体模型的**投影**等;
|
||
|
||
# VirualShadowMap使用笔记(浓缩自官方文档)
|
||
启用**VirualShadowMap**之后:
|
||
1. 无论距离如何,**Nanite几何体**始终使用**虚拟阴影贴图**渲染阴影,因为这是性能最高的选项,可提供最高质量。可以通过控制台变量 `r.Shadow.Virtual.UseFarShadowCulling 0` 使非Nanite几何体的行为方式与Nanite相同。
|
||
2. **静态烘焙阴影**将会失效。
|
||
3. **距离场阴影**主要作用于非Nanite物体(比如大量植被)超出**动态阴影距离可移动光源(Dynamic Shadow Distance Movable Light)** 距离的阴影渲染。
|
||
4. 局部光源(**点光源和聚光光源**)不受影响,依然会使用**距离场阴影**进行渲染。
|
||
5. **光线追踪阴影**的优先级仍然高于VSM
|
||
|
||
## 相关命令
|
||
- r.Shadow.Virtual.ResolutionLodBiasLocal:调整分辨率。
|
||
- r.Shadow.Virtual.NonNanite.IncludeInCoarsePages 0 :尝试禁止非Nanite对象渲染到CoarsePages。
|
||
- 可视化参数
|
||
- r.Shadow.Virtual.Visualize [mode] :在Virtual Shadow Map可视化模式下,此命令指定要显示的通道。**Cache** 和 **vpage** 是用于可视化的两个常用选择,**none** 可禁用vsm可视化。
|
||
- mask
|
||
- Mip
|
||
- vpage
|
||
- cache
|
||
- raycount
|
||
- clipmapvirtual
|
||
- ShowFlag.VisualizeVirtualShadowMap:指定可视化模式时,启用虚拟阴影贴图可视化。
|
||
- r.Shadow.Virtual.Visualize.Layout:选择虚拟阴影贴图可视化的布局。
|
||
- **0** 表示全屏
|
||
- **1** 表示缩略图
|
||
- **2** 表示分屏
|
||
- r.Shadow.Virtual.Visualize.DumpLightNames:将带有虚拟阴影贴图的当前光源列表输出到控制台。
|
||
- r.Shadow.Virtual.Visualize.LightName [光源名称]:按名称指定光源,接受部分或全部匹配。
|
||
- r.Shadow.Virtual.Cache.DrawInvalidatingBounds 1:显示缓存失效边界。
|
||
- r.Shadow.Virtual.Cache 0:禁用缓存。
|
||
|
||
## 相关可视化
|
||
- View Modes-Virtual Shadow Map:在大纲中选中光源可以查看对应光源的渲染信息。
|
||
- Show > Visualize > **仅绘制导致VSM失效的几何体(Draw only Geometry Causing VSM Invalidation)**
|
||
- r.ShaderPrintEnable 1:显示计数器
|
||
- r.Shadow.Virtual.ShowStats 1(或2,以仅显示页统计数据)
|
||
|
||
## 非Nanite多边形渲染
|
||
可变形多边形(SkeletalMesh、WorldPositionOffset、PixelDepthOffset)都会使**VirtualShadowCache** 失效。
|
||
|
||
在某些情况下,例如草,有时是植被,仅使用[接触阴影](https://docs.unrealengine.com/5.1/zh-CN/contact-shadows-in-unreal-engine)足以替代高分辨率阴影贴图。如果前景中需要细节丰富的阴影,请考虑以下事项以帮助降低性能开销:
|
||
- 非Nanite对象仍然遵循常规的阴影CPU剔除设置,例如 `r.Shadow.RadiusThreshold`。使用这些来帮助控制将这些对象渲染到虚拟阴影贴图的开销。
|
||
- 在有大量植被的场景中,强烈建议使用 `r.Shadow.Virtual.NonNanite.IncludeInCoarsePages 0` 禁用粗页中的非Nanite对象。或者,如果不需要,请考虑[完全禁用粗页](https://docs.unrealengine.com/5.1/zh-CN/virtual-shadow-maps-in-unreal-engine#%E7%B2%97%E9%A1%B5)。
|
||
- 使用网格体LOD在效果不再明显的距离处切换到不使用WPO/PDO的材质。在某些情况下,可以为远处的这些对象**关闭动态阴影投射**,并完全依赖屏幕空间**接触阴影**。
|
||
|
||
对于定向光源,还有其他可用选项:
|
||
- 距离场阴影替代超出 **Dynamic Shadow Distance Movable Light** 距离范围的非Nanite几何体,该距离通过光源的级联阴影贴图(Cascaded Shadow Maps)分段设置。为远处的非Nanite切换到**距离场阴影**,可以大大提高性能,因为此几何体没有Nanite提供的细粒度LOD缩放。
|
||
- 在某些情况下,创建移除WPO/PDO的材质LOD可能不切实际,但这些转换的最终效果在远处不明显。使用 `r.Shadow.Virtual.Cache.MaxMaterialPositionInvalidationRange` 设置距离(以厘米为单位),超过该距离时,将忽略这些材质的缓存失效。
|
||
|
||
# Shadow Map Ray Tracing(阴影贴图光线追踪)
|
||
一种渲染**软阴影**的方式。可通过以下命令来设置采样数值:
|
||
- `r.Shadow.Virtual.SMRT.RayCountLocal` :每个像素采样光线数量。
|
||
- `r.Shadow.Virtual.SMRT.RayCountDirectional`:每个像素采样光线数量。
|
||
- `r.Shadow.Virtual.SMRT.SamplesPerRayLocal`:每个像素受到VSM的光线追踪影响的数量。
|
||
- `r.Shadow.Virtual.SMRT.SamplesPerRayDirectional`:每个像素受到VSM的光线追踪影响的数量。
|
||
- `r.Shadow.Virtual.SMRT.MaxRayAngleFromLight`:通过降低半影的精度来优化性能。
|
||
- `r.Shadow.Virtual.SMRT.RayLengthScaleDirectional`:通过降低半影的精度来优化性能。
|
||
|
||
# ## GPU分析和优化
|
||
- **RenderVirtualShadowMaps(Nanite)** 包含所有与Nanite几何体渲染到VSM中相关的内容。所有定向光源都在单个Nanite通道中渲染,所有局部光源都在第二个通道中渲染。
|
||
- **RenderVirtualShadowMaps(非Nanite)** 负责处理非Nanite几何体的渲染。每个可见光源都有一个单独的通道,各种对象和实例拥有单独的绘制调用,这点与传统阴影贴图渲染相同。
|
||
- **图集(Atlas)** 和 **立方体贴图(Cubemap)** 与其他类似通道(包括VSM通道),都只是渲染传统阴影贴图。在虚拟阴影贴图的路径中,仍有少部分类型的几何体不受支持,它们遵循传统路径。如果没有不受支持的几何体投射阴影,这些通道将不会运行或分配阴影贴图存储。这些通道和相关的开销可以使用cvar `r.Shadow.Virtual.ForceOnlyVirtualShadowMaps 1` 完全禁用,在这种情况下,所有不受支持的几何体类型都完全不会投射阴影。
|
||
|
||
## 提升非Nanite性能
|
||
除了改进缓存之外,还有许多方法可以提高非Nanite阴影渲染的性能。
|
||
|
||
- 在你的项目的几何体中**尽可能多**的部分上**启用Nanite**。
|
||
- Nanite几何体在虚拟阴影贴图中的渲染效率要高得多,无论多边形数量如何,都应该在每个适用的情况下作为首选。
|
||
- Nanite几何体可以遮挡非Nanite几何体并避免虚假缓存失效。因此,唯一的非Nanite对象应该是Nanite本身不支持的对象,例如变形对象(蒙皮网格体),或使用世界位置偏移(WPO)和像素深度偏移(PDO)的材质。
|
||
- **非Nanite对象**应具有**完整的网格体LOD层级设置**。
|
||
- 非Nanite网格体具有LOD设置很重要,否则渲染到小页的开销会非常高。
|
||
- 如果可以,建议在**距离太远**而使效果不明显时切换到**非变形网格体(无WPO/PDO材质)**。
|
||
- CPU剔除控制台变量对于渲染到虚拟阴影贴图的非Nanite网格体仍然有用
|
||
- 使用控制台变量 `r.Shadow.RadiusThreshold`,调整渲染到虚拟阴影贴图中的非Nanite对象的CPU剔除值。这有助于控制远处小型对象的开销。
|
||
- 将[距离场阴影](https://docs.unrealengine.com/5.1/zh-CN/distance-field-soft-shadows-in-unreal-engine)用于非Nanite对象的远距离阴影投射。
|
||
- 对于定向光源,在超出某个范围时通常需要切换到距离场阴影,与级联阴影贴图相同。使用虚拟阴影贴图,仅非Nanite几何体将切换到使用距离场阴影,而Nanite几何体仍采用全细节阴影。
|
||
- 在粗页中禁用非Nanite几何体可以提高性能
|
||
- 在粗页中禁用非Nanite几何体通常可以实现大幅的性能提升,因为非Nanite几何体在渲染到大页中时通常效率低下。
|
||
|
||
## 阴影投射
|
||
**阴影投射(Shadow Projection)** 类别是使用阴影贴图光线追踪对阴影贴图取样产生的开销。这些通道位于 **光源(Lights) | DirectLighting | UnbatchedLights** 之下,通常每个相关光源都有一个VSM投射通道。产生最高开销的通道一般都是 **VirtualShadowMapProjection** 中的主SMRT循环。其余的开销应该相对较低。
|
||
|
||
# 其他
|
||
## 虚拟现实
|
||
虚拟阴影贴图尚未完全支持虚拟现实。右眼视角可能存在定向光源瑕疵。
|
||
|
||
## 分屏
|
||
分屏受到的测试极少,性能可能很差。
|
||
|
||
## 物理页池溢出
|
||
使用虚拟阴影贴图,场景中所有光源的所有阴影数据都存储在一个大型纹理池中。默认池大小受 **阴影(Shadow)** 可扩展性设置的影响,但在具有许多使用高分辨率阴影的光源的场景中,可能需要进行调整。
|
||
|
||
或者,可能需要在低端硬件上进行调整,以节省显存。
|
||
|
||
页池大小可以使用 `r.Shadow.Virtual.MaxPhysicalPages` 进行调整。连续使用 `r.ShaderPrintEnable 1` 和 `r.Shadow.Virtual.ShowStats 2` 启用虚拟阴影贴图统计数据,将显示有关当前页池使用情况的统计数据。
|
||
|
||
## 场景捕获
|
||
在一些情况下,场景捕获组件会导致整个虚拟阴影贴图缓存无效化。具体症状体现为 _Invalidations_ 在虚拟阴影贴图数据中变低,但是缓存的页面也变低(甚至会变为0),缓存的页面会全部变成红色。
|
||
|
||
发生该情况,试着隐藏或移除场景中的场景捕获Actor来验证它们是否在导致这个问题。
|
||
|
||
## 材质
|
||
**仅支持简单的次表面材质**。尚未实现次表面轮廓和传输。如果某个材质正在使用它们,则该材质将被遮蔽,就好像它不透明一样。
|
||
|
||
### 阴影分辨率
|
||
与传统阴影贴图相比,虚拟阴影贴图的分辨率显著提升,但浅光源角(或投影锯齿)和非常大的局部光源可能耗尽可用的虚拟分辨率。根据几何体的表面,这可能会呈现为盒状阴影和偏差问题。
|
||
定向光源裁剪图不太容易耗尽分辨率,但非常窄的摄像机视野最终也会耗尽这些分辨率。
|
||
|
||
阴影贴图的投影锯齿并没有简单的解决方案。即使使用虚拟阴影贴图,也必须注意避免最坏的情况,并平衡分辨率和性能。
|
||
|
||
# 优化案例
|
||
## 场景存在问题
|
||
1. 场景中的很躲静态物体没有启用Nanite,使得VirualShadowMap性能变低。
|
||
2. 远景的天空球(SM_Skybox_Mesh)、雾气面片、近景3个人 投射阴影。
|
||
3. 植被问题。
|
||

|
||
|
||
## 解决方法
|
||
1.让场景模型启用Nanite。
|
||

|
||
|
||
可以通过ViewMode - VirualShadowMap - Cache模式来显示缓存失效情况,,以此来找到非Nanaite物体。
|
||
|
||

|
||
|
||
之后使用Show > Visualize > 仅绘制导致VSM失效的几何体(Draw only Geometry Causing VSM Invalidation)来精准查找未开启Nanite的物体。
|
||

|
||
|
||
2. 关闭远景天空球(SM_Skybox_Mesh)、雾气面片与近景3个人模型的 Cast Shadow选项。尝试启用远景天空球的Nanite选项。
|
||
3. 植被分两种情况:有/无WorldPositionOffset。无的话直接转成Nanite即可。有的话建议去除 Cast Shadow选项,并且勾选Contact Shadow。 |