Summary
On a Nanite-enabled landscape, painted weightmap layers render collapsed/shrunk toward each component’s UV origin (the painted pattern almost disappears, leaving the base layer). The same landscape renders correctly with Nanite disabled. This is a regression between 5.7.4 (correct) and 5.8.0 (broken).
Root cause: texcoords that a material uses only in the pixel shader and does not customize are zeroed in the Nanite vertex-factory path, so the landscape weightmap UV (TexCoord3) reaches the pixel shader as (0,0).
What Type of Bug are you experiencing?
Rendering (Graphics / Niagara)
Steps to Reproduce
- Open/create a World Partition map with a landscape whose material has painted layers (Landscape Layer Blend / Landscape Layer Weight nodes, i.e. weightmap sampling at TexCoord3).
- Paint at least one non-default layer in a recognizable pattern.
- On the Landscape → Details → Nanite → Enable Nanite, and build the Nanite data.
- Observe the painted layers in the viewport.
Expected Result
Painted layers appear in the same place as with Nanite disabled (they follow the paint).
Observed Result
Painted layers collapse/fade toward each component’s UV origin (toward the SW). The base layer dominates and the painted pattern is largely lost. Toggling Enable Nanite off restores correct paint. A Nanite rebuild does not.
Affects Versions
5.8
Platform(s)
Windows
Upload an image
Additional Notes
Root cause findings
- The landscape weightmap is sampled at TexCoord3 (
FHLSLMaterialTranslator::StaticTerrainLayerWeight→TextureCoordinate(3)). The material reads this UV only in the pixel shader and does not expose it as a Customized UV. - Generated
GetMaterialCustomizedUVs(MaterialTemplate.ush) zero-initialises allNUM_TEX_COORD_INTERPOLATORSentries, then writes only the customized indices[0, NUM_CUSTOMIZED_UVS). - In the Nanite path (
NaniteVertexFactory.ush,TransformNaniteVerts), all pixel texcoords are delivered to the pixel shader viaOutVerts[].CustomizedUVs[](filled solely byGetMaterialCustomizedUVs, then barycentric-interpolated inGetPixelAttributes). There is no separate raw-texcoord interpolant path as in the raster vertex factories. - So non-customized, pixel-only texcoords (weightmap UV3) are zeroed and never refilled from the decoded vertex UVs → the weightmap samples its origin texel everywhere → paint collapses to the UV origin.
- The raw vertex UVs are decoded correctly (
NANITE_NUM_TEXCOORDS_TO_DECODE = max(vertex, pixel)UVs) and the CPU bake writes correct UV0/UV3 → verified. The loss is purely in populatingCustomizedUVs.
Confirmation
Adding, right after GetMaterialCustomizedUVs() in TransformNaniteVerts:
OutVerts[i].CustomizedUVs[3] = InVerts[i].TexCoords[3]; // raw decoded UV
fully restores correct painted layers, demonstrating the value is correct up to the customized-UV population stage and is lost only there.
Suggested fix
In the Nanite vertex factory, after GetMaterialCustomizedUVs() / GetCustomInterpolators(), refill the non-customized texcoord interpolators from the decoded vertex UVs for indices [NUM_CUSTOMIZED_UVS, NUM_MATERIAL_TEXCOORDS):
OutVerts[i].CustomizedUVs[idx] = InVerts[i].TexCoords[min(idx, NANITE_MAX_UVS - 1)];
applied at every GetMaterialCustomizedUVs call site in NaniteVertexFactory.ush (and the parallel path in NaniteTranslucencyFactory.ush). This restores pre-5.8 behaviour where raw pixel-only texcoords reach the Nanite pixel shader, without clobbering customized UVs or custom vertex interpolators.

