OverlayMaterial on Nanite Fallback

We had a similar situation as described here:

[Content removed]

We came up with a similar solution by duplicating DrawStaticElements() from FStaticMeshSceneProxy before coming across the thread. We also had the same issue of the overlay material working in Editor but not in a cooked build. We tried the solution in the thread, including the FDrawCommandRelevancePacket::AddCommandsForMesh modification, but neither seem to work. Any ideas what else could be an issue?

[Attachment Removed]

Steps to Reproduce
We had a similar situation as described here:

[Content removed]

Make a simple material that shows red color as output,

set it into overlay slot

if nanite on mesh, nothing will render, disable nanite on mesh, it will show red

[Attachment Removed]

Debugging into it a little more, I put a conditional breakpoint in AddCommandsForMesh with the condition (bIsNaniteMesh && StaticMeshRelevance.bOverlayMaterial) and it was never hit in a cooked build, but did in Editor.

[Attachment Removed]

Hello,

I’ve attached the full .diff of the changes I was testing with in 5.8+, but should work in 5.7, let me know if that still doesn’t work for you.

[Attachment Removed]

Same problem, works in Editor, not in cooked (Development) build.

Interestingly, it seems GetViewRelevance is not being called for the SceneProxy in the cooked build, but was called in the Editor.

[Attachment Removed]

I managed to debug and found that it was caused by the AlwaysVisible flag. Setting “r.Visibility.SkipAlwaysVisible” to 0, or setting “bIsAlwaysVisible” in Nanite::FSceneProxy to 0 when there is an overlay material fixes the issue. Is this a proper fix?

[Attachment Removed]

Good catch! Thanks for debugging that, yes, setting bIsAlwaysVisible = false; in FSceneProxy::FSceneProxy and FSkinnedSceneProxy::FSkinnedSceneProxy inside the added code blocks where OverlayMaterial code was added should disable that optimization on Nanite meshes with overlays so the overlays are not skipped.

[Attachment Removed]

Thanks! Static meshes are working perfectly now. However I tested skeletal meshes and got this crash

UnrealEditor-Engine.dll!FSkeletalMeshObjectNanite::GetSkinVertexFactory(const FSceneView * View, int LODIndex, int ChunkIdx, ESkinVertexFactoryMode VFMode) Line 650	C++
 	UnrealEditor-Engine.dll!Nanite::FSkinnedSceneProxy::GetDynamicMeshElements(const TArray<FSceneView const *,TSizedDefaultAllocator<32>> & Views, const FSceneViewFamily & ViewFamily, unsigned int VisibilityMap, FMeshElementCollector & Collector) Line 3042	C++
 	UnrealEditor-Renderer.dll!FDynamicMeshElementContext::GatherDynamicMeshElementsForPrimitive(FPrimitiveSceneInfo * Primitive, unsigned char ViewMask) Line 4172	C++
 	UnrealEditor-Renderer.dll!FDynamicMeshElementContext::LaunchAsyncTask::__l2::<lambda_1>::operator()() Line 4132	C++
 	UnrealEditor-Renderer.dll!UE::Tasks::Private::FTaskBase::TryExecuteTask() Line 518	C++
.
.
.

I figured it was because we don’t have raytracing enabled and thus the vertex factory was not initialized. After enabling raytracing though, we get a different crash

Log: Attempted to set null uniform buffer

>	[Inline Frame] UnrealEditor-Engine.dll!FMeshDrawSingleShaderBindings::Add(const FShaderUniformBufferParameter &) Line 143	C++
 	UnrealEditor-Engine.dll!FGPUSkinVertexFactoryShaderParameters::GetElementShaderBindings(const FSceneInterface * Scene, const FSceneView * View, const FMeshMaterialShader * Shader, const EVertexInputStreamType InputStreamType, ERHIFeatureLevel::Type FeatureLevel, const FVertexFactory * VertexFactory, const FMeshBatchElement & BatchElement, FMeshDrawSingleShaderBindings & ShaderBindings, TArray<FVertexInputStream,TSizedInlineAllocator<7,32,TSizedDefaultAllocator<32>>> & VertexStreams) Line 1069	C++
 	[Inline Frame] UnrealEditor-Engine.dll!TVertexFactoryParameterTraits<0,TGPUSkinVertexFactory<0>>::GetElementShaderBindings(const FVertexFactoryShaderParameters *) Line 1076	C++
 	UnrealEditor-Engine.dll!GetVertexFactoryParametersElementShaderBindings<TGPUSkinVertexFactory<0>>(EShaderFrequency ShaderFrequency, const FVertexFactoryShaderParameters * Parameters, const FSceneInterface * Scene, const FSceneView * View, const FMeshMaterialShader * Shader, const EVertexInputStreamType InputStreamType, ERHIFeatureLevel::Type FeatureLevel, const FVertexFactory * VertexFactory, const FMeshBatchElement & BatchElement, FMeshDrawSingleShaderBindings & ShaderBindings, TArray<FVertexInputStream,TSizedInlineAllocator<7,32,TSizedDefaultAllocator<32>>> & VertexStreams) Line 308	C++
 	[Inline Frame] UnrealEditor-Renderer.dll!FVertexFactoryType::GetShaderParameterElementShaderBindings(EShaderFrequency) Line 391	C++
 	UnrealEditor-Renderer.dll!FMeshMaterialShader::GetElementShaderBindings(const FShaderMapPointerTable & PointerTable, const FScene * Scene, const FSceneView * ViewIfDynamicMeshCommand, const FVertexFactory * VertexFactory, const EVertexInputStreamType InputStreamType, const FGenericStaticFeatureLevel FeatureLevel, const FPrimitiveSceneProxy * PrimitiveSceneProxy, const FMeshBatch & MeshBatch, const FMeshBatchElement & BatchElement, const FMeshMaterialShaderElementData & ShaderElementData, FMeshDrawSingleShaderBindings & ShaderBindings, TArray<FVertexInputStream,TSizedInlineAllocator<7,32,TSizedDefaultAllocator<32>>> & VertexStreams) Line 499	C++
 	[Inline Frame] UnrealEditor-Renderer.dll!FMeshMaterialShader::GetElementShaderBindings(const TShaderRefBase<FMeshDecalsVS,FShaderMapPointerTable> & Scene, const FScene * ViewIfDynamicMeshCommand, const FSceneView * FeatureLevel, const FVertexFactory *) Line 115	C++
 	UnrealEditor-Renderer.dll!FMeshPassProcessor::BuildMeshDrawCommands<TMeshProcessorShaders<FMeshDecalsVS,FMeshDecalsPS,FMeshMaterialShader,FMeshMaterialShader,FMeshMaterialShader>,FMeshMaterialShaderElementData>(const FMeshBatch & MeshBatch, unsigned __int64 BatchElementMask, const FPrimitiveSceneProxy * PrimitiveSceneProxy, const FMaterialRenderProxy & MaterialRenderProxy, const FMaterial & MaterialResource, const FMeshPassProcessorRenderState & DrawRenderState, const TMeshProcessorShaders<FMeshDecalsVS,FMeshDecalsPS,FMeshMaterialShader,FMeshMaterialShader,FMeshMaterialShader> & PassShaders, ERasterizerFillMode MeshFillMode, ERasterizerCullMode MeshCullMode, FMeshDrawCommandSortKey SortKey, EMeshPassFeatures MeshPassFeatures, const FMeshMaterialShaderElementData & ShaderElementData) Line 188	C++
 	UnrealEditor-Renderer.dll!FMeshDecalMeshProcessor::Process(const FMeshBatch & MeshBatch, unsigned __int64 BatchElementMask, int StaticMeshId, const FPrimitiveSceneProxy * PrimitiveSceneProxy, const FMaterialRenderProxy & MaterialRenderProxy, const FMaterial & MaterialResource, ERasterizerFillMode MeshFillMode, ERasterizerCullMode MeshCullMode) Line 378	C++
 	[Inline Frame] UnrealEditor-Renderer.dll!FMeshDecalMeshProcessor::TryAddMeshBatch(const FMeshBatch &) Line 305	C++
 	UnrealEditor-Renderer.dll!FMeshDecalMeshProcessor::AddMeshBatch(const FMeshBatch & MeshBatch, unsigned __int64 BatchElementMask, const FPrimitiveSceneProxy * PrimitiveSceneProxy, int StaticMeshId) Line 244	C++
 	UnrealEditor-Renderer.dll!GenerateDynamicMeshDrawCommands(const FViewInfo & View, EShadingPath ShadingPath, EMeshPass::Type PassType, FMeshPassProcessor * PassMeshProcessor, const TArray<FMeshBatchAndRelevance,TLinearArrayAllocatorBase<FSceneRenderingBlockAllocationTag,0>> & DynamicMeshElements, const TArray<FMeshPassMask,TLinearArrayAllocatorBase<FSceneRenderingBlockAllocationTag,0>> * DynamicMeshElementsPassRelevance, int MaxNumDynamicMeshElements, const TArray<FStaticMeshBatch const *,TLinearArrayAllocatorBase<FSceneRenderingBlockAllocationTag,0>> & DynamicMeshCommandBuildRequests, const TArray<enum EMeshDrawCommandCullingPayloadFlags,TLinearArrayAllocatorBase<FSceneRenderingBlockAllocationTag,0>> DynamicMeshCommandBuildFlags, int MaxNumBuildRequestElements, TArray<FVisibleMeshDrawCommand,TLinearArrayAllocatorBase<FSceneRenderingBlockAllocationTag,0>> & VisibleCommands, FDynamicMeshDrawCommandStorage & MeshDrawCommandStorage, Experimental::TRobinHoodHashSet<FGraphicsMinimalPipelineStateInitializer,DefaultKeyFuncs<FGraphicsMinimalPipelineStateInitializer,0>,TSizedDefaultAllocator<32>> & MinimalPipelineStatePassSet, bool & NeedsShaderInitialisation) Line 638	C++
 	UnrealEditor-Renderer.dll!FMeshDrawCommandPassSetupTask::AnyThreadTask() Line 1091	C++
 	[Inline Frame] UnrealEditor-Renderer.dll!FMeshDrawCommandPassSetupTask::DoTask(ENamedThreads::Type) Line 1169	C++
 	UnrealEditor-Renderer.dll!TGraphTask<FMeshDrawCommandPassSetupTask>::ExecuteTask() Line 696	C++
.
.
.

Any advice?

[Attachment Removed]

Figured it out, you have to call “VertexFactory->UpdateUniformBuffer(RHICmdList)” in “FSkeletalMeshObjectNanite::UpdateBoneData”

[Attachment Removed]

Good catch, that is needed. I haven’t had much time to look into this but I’m still not getting the overlay to appear on a Nanite skel mesh (Manny) after adding the change above, I suspect something is going on with ray-tracing. Did you get the overlay to appear successfully?

[Attachment Removed]

Yes. I had to move UpdateBoneData(RHICmdList) in UpdateDynamicData_RenderThread() out of the if-block. This was in 5.7 btw, 5.8 changed it quite a bit.

I did also have to change some code so that the vertex factories are created even when raytracing is disabled, but if raytracing is enabled those were not needed.

[Attachment Removed]