Description

On Nanite meshes, placing a VertexInterpolator node in a material graph without using it (unconnected, or routed through a disabled static switch) silently breaks the Opacity Mask and the material rasterizes as fully opaque. Connecting at least one interpolator restores correct masking. Non-Nanite paths are unaffected.

Turning off r.Material.UseShaderCompilationParameters fixes the issue therefore I suspect that it was introduced in CL 51712304 "Fix conservative parameters leading to excessive amount of shaders being compiled." submitted by @cristian.bobescu

Root cause summarized by LLM (unverified):

Two independent sources disagree on whether the material uses a vertex interpolator:

  • Presence - FMaterialCachedExpressionData::bHasVertexInterpolator is set by mere node presence in FMaterialCachedExpressionData::UpdateForExpression, it does not trace connectivity or evaluate static switches.
  • Actual usage - FMaterialCompilationOutput::bUsesVertexInterpolator is set only when the interpolator is genuinely compiled into the pixel shader.

With r.Material.UseShaderCompilationParameters=1, the two diverge:

  • Shader compilation uses usage: InitializeShaderLayoutParamsFromCompOutput sets bHasVertexInterpolator = InCompilationOutput.bUsesVertexInterpolator. IsVertexProgrammable therefore decides the material is not vertex-programmable, so only the non-vertex-UV raster permutation is compiled.
  • Runtime bin/relevance selection uses presence: FMaterialResource::HasVertexInterpolator() returns the cached-expression flag > MaterialRelevance.bUsesVertexInterpolator > RasterPipeline.bVertexUVs, and PackMaterialBitFlags.

The runtime requests a vertex-UV / vertex-programmable Nanite raster+shading bin that was never compiled, the lookup misses the programmable permutation, and rasterization falls back to the fixed-function opaque path - which never runs the pixel discard. The pre-existing comment at NaniteShared.h:470-473 already notes this class of conservative-flag/static-switch mismatch.

Steps to Reproduce

Steps to Reproduce

  1. Verify r.Material.UseShaderCompilationParameters=1
  2. Create a material with Blend Mode: Masked and wire up Opacity Mask. Don't use tessellation or WPO.
  3. Verify opacity mask works on a nanite mesh.
  4. Add a VertexInterpolator node and leave its output unconnected (or feed it through a static switch whose active branch bypasses it).
  5. Observe that on the nanite mesh opacity mask stops working, mesh renders opaque.

 

Now you have a couple workarounds how to get opacity mask working again but with some drawbacks:

  • Delete the unconnected VertexInterpolator (can be problematic in case of using a static switch)
  • Set r.Material.UseShaderCompilationParameters=0 and restart editor (increases shader counts)
  • Enable nanite tessellation (but then you get per triangle masking so edges might appear jagged)
  • Disallow nanite on the mesh.

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-383600 in the post.

0
Login to Vote

Unresolved
ComponentUE - Rendering - Architecture
Affects Versions5.8
CreatedJun 8, 2026
UpdatedJun 9, 2026
View Jira Issue