Static Mesh Decals flicker when ISM components with same material are in frame

We use a Deferred Decal material on many of our assets, including as a substitute to the Decal Component.

When using the ISM Runtime Cell Transformer, we found a lot of flickering. We discovered this was due to having static mesh and instanced static mesh components in frame using the same decal material instance.

Video and sample project are attached.

OBSERVATIONS:

- Flickering occurs whenever an ISM component and a SM component of the same deferred decal Material Instance are both within frustum

- Only the SM component will flicker

- This can be observed in editor, PIE and package

- The issue can be introduced by ISM transformer, or by manually creating ISMs

- Fast geometry appears not to impact this behaviour (flickering is neither introduced nor resolved by it)

FlickeringDecals.mp4(2.64 MB)

Steps to Reproduce
(I have provided a Repro Project you can use)

  1. Project setup: substrate disabled, fast geometry plugin enabled and prerequisites met
    1. NOTE: these steps may not be necessary but they better match our own project
  2. Create a Material using Deferred Decal
  3. Place several Shape > Cube actors into the scene and set their material to the above
  4. Use Actor > Merge Actors > Batch to convert some of them to ISM
  5. Observe flickering on the ones you have not merged, whenever the ISM is also within frustum

In the repro project provided, I extend the steps to investigate ISM and Fast Geo Runtime Cell Transformers, and how they contribute to this problem by converting things to ISM (but are more complex steps to achieve the same as above)

Hi,

Thanks for reporting this bug. I’ve created the following issue for tracking which should be made public soon https://issues.unrealengine.com/issue/UE-398225

This is an issue with cached mesh draw commands (r.MeshDrawCommands.UseCachedCommands). If you want to workaround the issue without a code change you can set a Translucent Sort Priority on the Static Meshes so they aren’t the same as the ISMs. Using r.MeshDrawCommands.UseCachedCommands=0 will also fix it but at the cost of performance.

It’s likely we just need to update the logic in InstanceCullingContext.cpp

 
 
...
 
void FInstanceCullingContext::SetupDrawCommands(
{
...
    // Used to detect when we change between direct and indirect draws and break auto instancing there. ...
    bool bPrevUseIndirectDraw = false;
+++    bool bPrevFetchInstanceCountFromScene = false;
 
...
 
const bool bChangedFromDirectToIndirect = !bPrevUseIndirectDraw && bUseIndirectDraw;
+++const bool bChangedInstanceCountSource =
    bPrevFetchInstanceCountFromScene != bFetchInstanceCountFromScene;
 
bPrevUseIndirectDraw = bUseIndirectDraw;
+++bPrevFetchInstanceCountFromScene = bFetchInstanceCountFromScene;
 
 
...
 
---if (bCompactIdenticalCommands && CurrentStateBucketId != -1 && bMeshDrawCommandMatch && !bChangedFromDirectToIndirect)
+++if (bCompactIdenticalCommands && CurrentStateBucketId != -1 && bMeshDrawCommandMatch && !bChangedFromDirectToIndirect && !bChangedInstanceCountSource)

Thanks Alex! We’ll have a try with your suggestions and update here shortly.

Hi Alex, I’ve implemented your change on behalf of Mike. Looks like it’s working correctly for us in PIE. We’ll let you know if it solves the issue in builds shortly.

Upon further investigation I found that we have a fix for this issue already in latest here:

CL#54743056 (ec9288) [Instance Culling] This fixes an edge case not caught by 50097052

Previous fix only catches direct -> indirect transitions. It does not catch indirect -> direct, leading to flickering meshes.

I recommend reverting the code change I posted and integrating this simpler change instead.