5.6 HWRT下SkinCache的优化问题

Hi,

在5.6版本,开启HWRT以后。我们发现​SkinCache会突然飙升。 通过Profile GPU,我们发现主要就是UpdateSkinningBatches和Ray Tracing Dynamic Geometry变的很高。 如果设置r.RayTracing.Geometry.SupportSkeletalMeshes=0就正常了,但是我们不希望关闭Skeleton Mesh的RT。

[Image Removed]

[Image Removed]

我们尝试了给Skeleton Mesh添加LOD,并且设置​Ray Tracing Min LOD。但好像没太大作用。

[Image Removed]

关于cvar,我们从City Sample中也提取了一些使用,这是详细的cvar列表:

[/Script/Engine.RendererSettings]
r.LumenScene.FarField=1

;Cannot be disabled while Ray Tracing is enabled as it is then required.
r.SkinCache.CompileShaders=True
r.DefaultFeature.AutoExposure.ExtendDefaultLuminanceRange=True
r.VirtualTextures=True
r.VirtualTexturedLightmaps=False
r.SupportMaterialLayers=True
r.GPUSkin.Support16BitBoneIndex=True
r.CustomDepth=3
r.GenerateMeshDistanceFields=True
r.AllowStaticLighting=False
r.ClearCoatNormal=True
r.Shadow.Virtual.Enable=1
r.AntiAliasingMethod=4
r.DefaultFeature.MotionBlur=False
r.SupportSkyAtmosphereAffectsHeightFog=True
r.ReflectionMethod=1
r.DynamicGlobalIlluminationMethod=1
r.NumBufferedOcclusionQueries=2
;r.Lumen.TranslucencyReflections.Enable=1
r.ReflectionCaptureResolution=128
r.RayTracing=True
r.Lumen.HardwareRayTracing=True
r.GPUScene.ParallelUpdate=1
r.GPUSkin.UnlimitedBoneInfluences=True
r.SkinCache.DefaultBehavior=0
r.MeshStreaming=True
;r.RayTracing.Geometry.NiagaraMeshes=0
;r.RayTracing.Geometry.NiagaraRibbons=0
;r.RayTracing.Geometry.NiagaraSprites=0
r.NormalMapsForStaticLighting=False

r.SkinCache.MemoryLimitForBatchedRayTracingGeometryUpdates=128
r.SkinCache.MaxRayTracingPrimitivesPerCmdList=1000000
r.SkinCache.MaxDispatchesPerCmdList=1000
r.SkinCache.AllowDupedVertsForRecomputeTangents=1
r.SkinCache.RecomputeTangentsParallelDispatch=1
r.SkinCache.SceneMemoryLimitInMB=148

; World Partition
wp.Runtime.RuntimeSpatialHashUseAlignedGridLevels=0
wp.Runtime.RuntimeSpatialHashSnapNonAlignedGridLevelsToLowerLevels=0
wp.Runtime.RuntimeSpatialHashPlaceSmallActorsUsingLocation=1
wp.Runtime.RuntimeSpatialHashPlacePartitionActorsUsingLocation=0

r.VolumetricFog.GridPixelSize=12
r.Lumen.TraceMeshSDFs=0
r.EarlyZPass=2
r.Lumen.TranslucencyReflections.FrontLayer.EnableForProject=False
r.ShaderCompiler.JobCacheDDC=False
r.Nanite.Allowtessellation=1
r.Nanite.Tessellation=1
r.Shadow.Virtual.NonNanite.IncludeInCoarsePages=0
r.Shadow.Virtual.ForceOnlyVirtualShadowMaps=1
r.Shadow.Virtual.OnePassProjection=1
r.Nanite.Streaming.NumInitialRootPages=5120
r.Nanite.MaxNodes=2621440
r.LumenScene.SurfaceCache.MeshCardsMergedResolutionScale=1
;r.LumenScene.DirectLighting.OffscreenShadowing.TraceMeshSDFs=0
;r.Lumen.TranslucencyVolume.TraceFromVolume=0
r.Lumen.Reflections.RadianceCache=1
r.VT.Residency.Notify=1
r.OptimizedWPO=1
;r.Lumen.HardwareRayTracing.LightingMode=0
bEnableVirtualTextureOpacityMask=True
r.AllowHDR=1
r.SkinCache.SceneMemoryLimitInMB=256

r.LightFunctionAtlas.SlotResolution=512

;启用第一人称渲染自阴影.
r.FirstPerson.SelfShadow=1

r.RayTracing.Shadows=False

r.LightFunctionAtlas.Format=1

我们想了解下,是否有什么cvar是我们不了解的?或者是否有什么其他思路能优化这部分的开销么?​

上面字数限制,cvar没有截全,做个补充:

; Begin Enable 5.6 Optimizations
 
; Enable World Partition Async update
wp.Runtime.UpdateStreaming.EnableAsyncUpdate=true
 
; Enable incremental pre-register/pre-unregister components combined with asynchronous physics state creation/destruction
p.Chaos.EnableAsyncInitBody=true
LevelStreaming.AllowIncrementalPreRegisterComponents=true
LevelStreaming.AllowIncrementalPreUnregisterComponents=true
 
; Enable asynchronous register level context (asynchronous add primitive to scene)
LevelStreaming.AsyncRegisterLevelContext.Enabled=true
LevelStreaming.AsyncRegisterLevelContext.PrimitiveBatchSize=64
 
; Allow RenderAssetStreamingManager to process primitive components in parallel
r.Streaming.AllowParallelRenderAssetStreamingIncrementalUpdate=true
; Used by AllowParallelRenderAssetStreamingIncrementalUpdate: Setting to 0 will use as much workers as possible
r.Streaming.WorkerCountForParallelRenderAssetStreamingManagerIncrementalUpdate=0
; Texture streaming optimization (optimizes FStreamingTextureLevelContext::ProcessMaterial)
r.Streaming.EnableTexturesSamplingStreamingCache=true
 
; Allow multiple levels to be in the making visible or making invisible to use the whole time limit budget (when using async tasks)
LevelStreaming.MaximumMakingVisibleLevels=8
LevelStreaming.MaximumMakingInvisibleLevels=8
 
; Allow incremental EndPlay during RemoveFromWorld
s.LevelStreamingRouteActorEndPlayForRemoveFromWorldGranularity=10
 
; End Enable 5.6 Optimizations
;-------------------------------------------------------------------------------
 
; Enable FastGeoStreaming
FastGeo.Enable=True
; Throttle async render state creation
FastGeo.AsyncRenderStateTask.TimeBudgetMS=1
; Limit async render state creation to 4 workers
FastGeo.AsyncRenderStateTask.ParallelWorkerCount=4
 
; Reduce budgets for add/remove since we use FastGeo
s.LevelStreamingActorsUpdateTimeLimit=1
s.UnregisterComponentsTimeLimit=1
 
; Enable SimpleStreamableAssetManager for FastGeo to properly stream textures
s.StreamableAssets.UseSimpleStreamableAssetManager=true
 
[ConsoleVariables]
 
Editor.HDRDisplayOutputUse10Bit=1
 
;默认关闭DLSS,交由设置系统负责开启.
r.NGX.DLSS.Enable=0
 
;为了避免影响美术效果,这个也设置为关闭.尽管现在看起来没什么区别.
r.NGX.DLSS.AutoExposure=0
r.Editor.Viewport.ScreenPercentageMode.RealTime=0
r.Editor.Viewport.ScreenPercentageMode.NonRealTime=0
 
;初始设置一个比较小的值,确保不启用dlss的话性能不会太差.
r.Editor.Viewport.ScreenPercentage=50
gpad.DefaultLeftStickInnerDeadZone=0.24
gpad.DefaultRightStickInnerDeadZone=0.27
r.Editor.SkipSourceControlCheckForEditablePackages=1

另外就是有时候发现,在HWRT下,ShadowDepth也会异常变高,有时候高达10-20ms左右。

[Image Removed]我们发现VSM的缓存似乎经常会失效。在Debug视图里面会看到大面积的蓝色。

[Image Removed]所以想了解下HWRT下VSM是否也有什么cvar调整,或者是有什么其他的优化思路。

“所以想了解下HWRT下VSM是否也有什么cvar调整,或者是有什么其他的优化思路”

我认为两者没有联系。蓝色invalidated部分非常大,是否是它投影,比如天空是否有巨大的可投影对象?像SKM或WPO飞船,云雾卡片之类。如果没有这些选中其中一个有蓝色invalidated投影部分的对象,比如岩石开关下Evaluate World Position Offset标记,验证下是否和WPO有关;如果蓝色消失麻烦把这个对象的所有母材质(如果只有一个最好)贴上来看下。

初步怀疑和WPO有关,并且母材质写了WPO,子材质虽然0但依旧计算为WPO,另外对象WPO的disable距离设置可能有问题。

Hi,

我们测试了一下,确实是WPO的问题。

[Image Removed]

部分材质函数里面,或者是材质里面有用到WPO。

[Image Removed]有些WPO Mesh的Disable Distance没有设置,都是默认的0。

因为场景中很多模型是拼接在一起的,有叠层关系 所以不太容易观察出来哪些模型是开了WPO的。 Disable Distance就没有设置上。

是否有什么好的方式检查资产中哪些材质开启了WPO? 场景中用来检查WPO的Evaluate WPO视图 因为没有WPO的会显示红色部分,导致有视觉干扰,不太容易分辨哪些物体开了WPO。所以想了解下,是否有更好的方式查看这个? 比如Advanced Search Syntax那种东西之类的。 或者Evaluate WPO视图是否有办法把红色的显示部分屏蔽掉,用来做Debug。

“因为场景中很多模型是拼接在一起的,有叠层关系 所以不太容易观察出来哪些模型是开了WPO的。 Disable Distance就没有设置上”

用到这个材质/材质函数应该都会有问题。最简单的选择方式是根据材质选择Actors。选中资产右键里操作

[Image Removed]

Hi,

你好, 我的理解是SkeletaMesh要支持HWRT,必须要开启Skin Cache,所以Skin Cache增加的开销是正常的。不过应该还是有些设置可以优化相关的性能:

  1. 可以设置r.RayTracing.DynamicGeometry.MaxUpdatePrimitivesPerFrame来控制每帧动态物体更新的三角形的数量,Fortnite目前设置的是10000
  2. 5.7有个改动可以在生成Skin Cache的时候,顺便计算其对应的Local Bounds,可以加速VSM的剔除效率,可以看一下 https://github.com/EpicGames/UnrealEngine/commit/388888248bcdd59987857e826e78e215d7316647
  3. 5.7有个改动可以控制每帧RayTracing更新SkeletalMesh的数量, r.SkeletalMesh.ThrottleGPUSkinRayTracingUpdates可以设置成5,如果有nanite的SkeletalMesh,也可以设置r.SkeletalMesh.ThrottleNaniteRayTracingUpdates,改动可以看一下 https://github.com/EpicGames/UnrealEngine/commit/86bb866a5b1d5f9eca672a64bcc60a3cf97741b3
  4. 5.7有个改动可以把所有LOD都cache下来,否则可能会造成因为LOD没有被cache而变成动态的。改动可以看一下 https://github.com/EpicGames/UnrealEngine/commit/30322aa1f75f34f8085fbfd9a4ced526b6b844cd
  5. 如果是主机平台,可以开启r.SkinCache.AsyncCompute,这应该对Dynamic Resolution有改善。

另外关于开启HWRT,VSM的Cache失效的问题,我暂时没有想法,我用简单场景没有复现,如果你有复现的简单工程,麻烦提供一下,我可以继续分析一下。

[mention removed] 如果有遗漏的地方,麻烦补充一下。

Hi,

非常感谢您的回答,我们研究下您提供的相关CL。

想请教一下,FN里面r.RayTracing.DynamicGeometryLastRenderTimeUpdateDistance是怎么设置的呢?

另外PC端的话,可以考虑开启r.SkinCache.AsyncCompute么?

VSM Cache这个我们后面看看是否能拆出来可复现的工程。原始工程比较大。我们目前是Local Light的可移动性一部分是Stationary的,一部分是Movable的,不知道是否和这个有关,我们后面测试下看看。另外想了解下,Local Light是否都改成Movable的比较好?

Hi,

FN里使用的是默认的r.RayTracing.DynamicGeometryLastRenderTimeUpdateDistance,没用改动过。

PC上因为开不了Dynamic Resolution,所以不确定开启AsyncCompute是否有性能的改善。

VSM的Cache,蓝色区域应该是代表物体​要么是有WPO,要么是SkeletalMesh,如果是static mesh感觉应该不会出现这个种情况。我也没看到跟HWRT有什么直接关系。

我从代码上理解,movable和stationary的light应该没有本质区别,只是stationary的light通常page不会变,所以可以有大一点的分辨率。​可以看文档 https://dev.epicgames.com/documentation/en\-us/unreal\-engine/virtual\-shadow\-maps\-in\-unreal\-engine\#moving\-lights

Hi,

我看巫师4的Demo是有调整:

r.RayTracing.DynamicGeometry.MaxUpdatePrimitivesPerFrame=40000

r.RayTracing.DynamicGeometryLastRenderTimeUpdateDistance=1000

以为FN也做了调整呢。我们参考一下FN的配置,再调调看。非常感谢您的解答。

VSM部分,蓝色区域很多都是static mesh,很多static mesh是有重叠的,然后拼接在一起的。不知道这些会不会有影响。感觉上可能是重叠的Mesh里面存在一些wpo之类的。我们后面再研究看看能不能发现什么,如果能拆出一个可复现工程,会在这里更新一下。

另外,我想了解一下,是否有什么调试方法可以把场景中所有开启了WPO的Actor打印出来,Evaluate WPO视图不太直观。有很多非WPO的Actor信息。

我暂时想不出来有什么别的方式,Evaluate WPO的试图我看非WPO的都是红色,你是希望红色也不显示吗?

是的,我希望可以只保留绿色部分,这样可以比较方便的辨别哪些模型是开了WPO的。有红色部分的话,不太容易识别。

Hi,

可以在NaniteVisualize.usf搜一下NANITE_VISUALIZE_EVALUATE_WORLD_POSITION_OFFSET,把最后一个分支的Result = float3(1, 0, 0);改成Result = float3(0, 0, 0);试试

Hi,

好的,非常感谢,我们试试看。

看起来这些材质是为了产生Contact Shadow做了PDO,这需要WPO做一些push避免自阴影,并且WPO应该是固定不变的。另外看上去图中选中的模型就是个普通的STM(地面或山崖),应该也不会需要移动。并且我怀疑你们场景里有大量对象使用了类似方式来产生低面模型的细节阴影。所以有大面积的蓝色。建议把这些对象Force Cache VSM(灯光方向变化还是会Invalidate VSM,如果有TOD不会有问题)

[Image Removed]以上是最简单的解决方式。但我还是建议你们做下开关WPO的对照,因为WPO对Nanite渲染效能影响比较大;虽然这种效果的WPO应该是极小的一个push,严谨考虑还是做下对比测试。如果效能影响不大最好,影响较大就得考虑远距离关闭WPO,关闭后如果没出现Contact Shadow的自阴影问题就最好了,否则可能还需要在材质里根据距离来减弱PDO的效果,或者使用Nanite Pixel Programmables Disable配合WPO Disable Distance一起在一定距离关闭。

[Image Removed]再要往细考虑这种做法如果地面模型很大,人又在地面上。WPO以Actor位置而非像素为单位来Disable的,因此无法Disable,还是会看到大面积蓝色未cache VSM。所以还是得Force Cache最好。具体得测试下看看哪种最佳吧

非常感谢文磊老师,我们参考一下。另外您说force cache vsm指的就是shadow cache invalidation behavior设置Static这个吧?

另外我想请问一下,Nanite Pixel Programmables Disable的主要作用是什么?没怎么用过这个参数。比如您截图中提到的,设置Nanite Pixel Programmables Disable=500,有怎样的意义。WPO Disable Distance倒是很常用。

对,Force cache vsm就是shadow cache invalidation behavior设置Static;对象能引起VSM invalidate的因素都会被忽略掉,包括SKM,材质的WPO等,但不影响灯动对影子缓存失效影响。

Nanite Pixel Programmables Distance是 Nanite 系统里引入的一个控制/优化机制,用于在一定距离之外关闭 Nanite 的“像素可编程光栅化(pixel programmable rasterization)”特性,以节约性能。这些特性可以是Mask和PDO效果。你们的材质如果仅关闭WPO,但开启PDO会引起的Contact Shadow的自阴影;所以如果在500单位外关闭WPO,就需要也关闭PDO,避免自阴影问题。

另外提下Nanite Pixel Programmables Distance也可以用来Disable远处的Mask,对Nanite植被有优化

明白了,感谢两位老师的指导,辛苦了!