VSM r.Shadow.Virtual.UseReceiverMaskDirectional Breaks Cache Behavior Overrides

Hello, since 5.7 this CVAR has been turned on by default and I’d like to understand why and if it is intentional that it breaks / prevents shadow cache behaviour to be set as we used to in 5.6 on meshes.

r.Shadow.Virtual.UseReceiverMaskDirectional 1

Most of my work is performance related and the VSM cache viewmode has always been a great tool to find issues and reduce shadow costs, but now it can’t be used unless that CVAR is off by default.

I found a forum post that discusses this but it dismisses the issue as by design.

I have attached a video explaining and showing what 5.7 projects now behave like in detail - I believe this is not the intended design but would really appreciate some clarity on the topic.

Thanks

VSM_Issue.mp4(58.1 MB)

Steps to Reproduce
Open a Vanilla 5.7 project

Check VSM Cache view mode -> Observe that all dynamic pages are invalidated and the map is entirely blue.

Take an Object with WPO and set its invalidation behavior to be static. -> Observe shadows continue to move.

Set:

r.Shadow.Virtual.UseReceiverMaskDirectional 0

Observe cache behavior behaves as expected.

Hello,

Thanks for reporting this, this could be an unintended regression and it looks like it’s possible to address this behavior by changing VirtualShadowMapPageCacheCommon.ush, but I need to verify with my colleague who is more familiar with this area if the current behavior is intended as you mentioned. They’re currently out of office (national holiday) so I should have more information next week.

bool ShouldCacheInstanceAsStatic(uint InstanceId, bool bViewUncached, bool bAllowWPO, int SceneRendererPrimaryViewId)
{
	if (bViewUncached)
	{
		return false;
	}
    
	FInstanceSceneData InstanceData = GetInstanceSceneDataUnchecked(InstanceId);
	FPrimitiveSceneData PrimitiveData = GetPrimitiveData(InstanceData.PrimitiveId);
 
	// If WPO is allowed but material invalidations are disabled (Static behavior),
 	// still cache as static to match the intended behavior
	if (bAllowWPO)
	{
		if ((PrimitiveData.Flags & PRIMITIVE_SCENE_DATA_FLAG_DISABLE_MATERIAL_INVALIDATIONS) == 0u)
		{
			return false;
		}
	}

Quick update: I’ve created https://issues.unrealengine.com/issue/UE\-380433 to track this issue and it should be visible publicly soon.

What was happening in the repro project was that the mesh was in the “guard-band” of clipmap levels where it is cached as dynamic such that it doesn’t cause a static invalidation when it starts animating and the logic wasn’t handling the cache as static flag correctly as you noted.

Thanks so much Alex for getting back to me and investigating further ! Glad to hear you were able to find the root cause !