Mesh Terrain is incompatible with Material Layer Blend (MLB) assets

Summary

When using Mesh Terrain, if you put a MeshPartitionResource and MeshPartitionChannelSample node inside a Material Layer Blend, the result is always 0. The setup works if the nodes are used in the material directly instead of the MLB asset.

This means material layer blending is impossible with Mesh Terrain. A material must instead hoist all layer definitions and blend logic into the material itself, bypassing Unreal’s layer system entirely.

What Type of Bug are you experiencing?

World Creation Tools

Steps to Reproduce

  1. Make an Open World level. Add Mesh Terrain and assign an MPD that has a channel (e.g., Dirt) and a material with at least one layer (not including the Background layer)
    • Important: the layer MUST have a Material Layer Blend (MLB) asset assigned.
  2. Add a brush modifier and paint Dirt onto the terrain.
  3. In the MPD material, pipe MeshPartitionResource into MeshPartitionChannelSample (Channel = Dirt) and then into Base Color. The painted area will be visible.
  4. Now put that same MeshPartitionResource + MeshPartitionChannelSample inside the MLB asset. Connect it straight to the blend’s Alpha. Assign the blend to a layer on the instance. The painted area will not be visible.
    • Note: this matches the example shown in the Mesh Terrain docs.

Expected Result

Mesh Terrain channel sample data should be returned when when using the MeshPartitionResource + MeshPartitionChannelSample nodes inside a Material Layer Blend asset.

Observed Result

Mesh Terrain channel sample data is always zero inside Material Layer Blend assets.

Affects Versions

5.8

Platform(s)

Windows

Video

Additional Notes

The attached video demonstrates:

  1. MeshPartitionChannelSample works when used directly in a material.
  2. MeshPartitionChannelSample does not work when used in an MLB asset.
  3. Sanity check: MLB is configured correctly.
2 Likes

UE-391544 has been added to our ‘To Do’ list. Someone’s been assigned this task.

I have made an engine side edit to MeshPartitionMaterialExpressionUtils.cpp(45) to get it working.

#if WITH_EDITOR
int32 UMaterialExpressionMeshPartitionResource::Compile(class FMaterialCompiler* Compiler, int32 OutputIndex)
{
    {
       UTexture* TextureToUse = TextureParameter.Get();

       if (!TextureToUse)
       {
          return Compiler->Errorf(TEXT("Missing MeshPartition Texture."));
       }

       // The channel texture is bound per section as a global parameter (SetTextureParameterValue(ChannelTextureParameterName)).
       // When compiled inside a material layer or blend function, the compiler scopes parameters to the current owner
       // (LayerParameter/BlendParameter + index), which would not match the global override and fall back to the default texture.
       // Force the global association, like FHLSLMaterialTranslator::StaticTerrainLayerWeight does for landscape weightmaps.
       Compiler->PushParameterOwner(FMaterialParameterInfo());

       // Return the TextureObject (used by other expressions like samplers)
       const int32 TextureParameter_IDX = Compiler->TextureParameter(ChannelTextureParameterName, TextureToUse, EMaterialSamplerType::SAMPLERTYPE_Masks);

       Compiler->PopParameterOwner();

       return TextureParameter_IDX;
    }
}

If you have a custom build of the engine, this can be implemented to make the MeshPartitionRessource work from inside a Material Layer Blend asset.
Hope this can be of help while waiting for a proper fix from epic !

1 Like