INSODIMENSIONStudios
BiomesGuides

Terrain Material

Apply the M_AT_LayerStack layer-stack material and its three instances to a Landscape or MeshTerrain, bind paint layers to biomes, and see what Runtime Virtual Texture and Nanite displacement need from your project.

Terrain material

M_AT_LayerStack is the plugin's terrain master. It is built on Unreal's Material Layers: a stack of six layers, with five blend assets that decide where each layer above the first shows. Each layer is one of two layer assets (ML_AT_Surface for ground, ML_AT_Cliff for rock), and each blend is a rule: a painted Landscape layer, a Mesh Partition channel, a slope, a noise band or an altitude band. Three ready instances ship, one for Landscape, one for MeshTerrain and one for painted showcase biomes.

Applying the material is manual. No code in the plugin assigns the material to a Landscape or a MeshTerrain, creates a Runtime Virtual Texture volume, enables Nanite on a Landscape, or checks your RVT or Nanite settings. The shipped L_Showcase_Landscape_Texture and L_Showcase_Landscape_Volume levels do not use this material either: they use M_Showcase_BiomeLandscape, a plain Landscape Layer Blend material. Of the shipped levels, only the two MeshTerrain showcase levels use the layer stack, through MPD_AT_Showcase.


What ships

All paths are under /AgenticBiomes/LandscapeMaster/ unless stated.

AssetWhat it is
M_AT_LayerStackThe master.
MICs/MI_AT_LayerStack_LandscapeInstance for Landscape: a noise-band layer, painted Dirt, Gravel and Sand, and a slope-driven Cliff.
MICs/MI_AT_LayerStack_MeshTerrainInstance for MeshTerrain: the four lower layers read Mesh Partition channels; Cliff is slope-driven.
MICs/MI_AT_LayerStack_ShowcaseInstance for Landscape that paints Desert, BroadleafForest, ConiferousForest and Snow, with a slope-driven Cliff. No shipped level uses it.
Stack/Layers/ML_AT_Surface, ML_AT_CliffThe two layer assets.
Stack/Blends/MLB_AT_Slope, MLB_AT_Altitude, MLB_AT_NoiseBand, MLB_AT_Channel, MLB_AT_Paint_Template, and 24 paint blends named MLB_AT_Paint_<Name>.
Stack/Palette_AT_Default, Stack/Palette_AT_ShowcaseAgenticTerrainPalette assets that list paint layer names.
Layers/LayerInfo_*18 Landscape layer-info assets.
RVT/RVT_AT_Material, RVT_AT_Displacement, RVT_AT_Height, RVT_AT_Mask4.
Textures/Megascans/Eight Quixel Megascans surface sets, 4096 by 4096.
/AgenticBiomes/Landscape/LLI_*13 layer-info assets (LLI_Desert, LLI_Snow, and so on) that PaintBiomeLayers reuses or creates.
/AgenticBiomes/PCG/MeshTerrain/MPD_AT_ShowcaseA Mesh Partition definition that already uses MI_AT_LayerStack_MeshTerrain.

The 24 paint blends are Beach, BroadleafForest, ConiferousForest, Desert, Dirt, Grass, Gravel, Jungle, Land, Mountain, Mud, Puddle, Road, Sand, Shore, Snow, Soil, StoneFloor, and MS_BroadleafForest, MS_ConiferousForest, MS_Desert, MS_Landslide, MS_MountainForest, MS_Snow. Each one reads the Landscape layer of the same name.


Apply it to a Landscape

  1. Select the Landscape actor. In Details, under Landscape, set Landscape Material (LandscapeMaterial) to MI_AT_LayerStack_Landscape.
  2. Add the layers the instance paints as target layers on the Landscape, each with a layer-info asset whose layer name matches: Dirt, Gravel and Sand for MI_AT_LayerStack_Landscape. Use Landscape mode, or the AddLandscapeTargetLayer tool.
  3. Paint them.

The Dirt (auto) layer and the Cliff layer need no painting: the first is a noise band and the second follows slope.

Check the Layer Name on a layer-info asset before you use it. LayerInfo_Auto, LayerInfo_Gravel, LayerInfo_Jungle, LayerInfo_Mud, LayerInfo_Puddle and LayerInfo_Sand have no layer name stored in the asset. Layer-info assets made by a palette Build (below) or by Landscape mode carry the name.

Apply it to a MeshTerrain

A MeshTerrain takes its material from its Mesh Partition definition asset. Set the definition's Material to MI_AT_LayerStack_MeshTerrain, and make its Channel Map match what the instance reads. MPD_AT_Showcase does both. The definition's channels, in order, are:

IndexChannel
0Grass
1ForestFloor
2Dirt
3Mud
4Gravel
5Rock

MI_AT_LayerStack_MeshTerrain reads those channels with four MLB_AT_Channel blends, one per layer from layer 1 up. Each blend has a ChannelIndex parameter, the index into the definition's channel list:

LayerBlendChannelIndexChannel in MPD_AT_Showcase
1 Dirt (auto)MLB_AT_Channel2Dirt
2 DirtMLB_AT_Channel2Dirt
3 GravelMLB_AT_Channel4Gravel
4 SandMLB_AT_Channel3Mud
5 CliffMLB_AT_Slopenonenone

If your own definition orders its channels differently, change ChannelIndex on the instance. Paint-layer blends (MLB_AT_Paint_*) read Landscape layers, so use MLB_AT_Channel blends on a MeshTerrain.


The layer stack

Layer 0 is the base and has no blend. Each later layer has one blend. The three instances share one stack of layer assets: layers 0 to 4 are ML_AT_Surface and layer 5 is ML_AT_Cliff. They differ in blends and textures.

LayerNameLandscape instance blendMeshTerrain instance blendShowcase instance blend
0Grassnone (base)none (base)none (base)
1Dirt (auto)MLB_AT_NoiseBandMLB_AT_ChannelMLB_AT_Paint_Desert
2DirtMLB_AT_Paint_DirtMLB_AT_ChannelMLB_AT_Paint_BroadleafForest
3GravelMLB_AT_Paint_GravelMLB_AT_ChannelMLB_AT_Paint_ConiferousForest
4SandMLB_AT_Paint_SandMLB_AT_ChannelMLB_AT_Paint_Snow
5CliffMLB_AT_SlopeMLB_AT_SlopeMLB_AT_Slope

The layer names are the same in all three instances. In the Showcase instance they are only labels: the blends paint the biome names above.

Surface textures per layer:

LayerLandscape and MeshTerrain instancesShowcase instance
0Gravel_And_Grass_On_Soil_rmrk1gp0Gravel_And_Grass_On_Soil_rmrk1gp0
1Dry_Soil_Ground_vl4jehagRippled_Sand_vlziefgfw
2Dry_Soil_Ground_vl4jehagRocky_Forest_Floor_vl0gbbwo
3Gravel_Ground_vl3iffhgForest_Floor_peioA0
4Rippled_Sand_vlziefgfwSnow_Covered_Ground_siikchka
5Layered_Rock_Cliff_tkieffufwLayered_Rock_Cliff_tkieffufw

Each set is a folder under Textures/Megascans/ with _B (base colour), _N (normal), _ORM and _H (height) textures at 4096 by 4096, named T_<id>_4K_B and so on. All three instances also set the global Grass_*, Dirt_*, Sand_* and Snow_* texture parameters, to Gravel_And_Grass_On_Soil_rmrk1gp0, Dry_Soil_Ground_vl4jehag, Rippled_Sand_vlziefgfw and Snow_Covered_Ground_siikchka. Those parameters feed the far overlay (see RVT and Nanite).

The instances override TileSize on a few layers: 400 on layers 0 and 3 and 800 on layer 5 in the Landscape and MeshTerrain instances, and 400 on layer 0 and 800 on layer 5 in the Showcase instance.


Blend rules

Every blend shares one height-based blend function, MF_AT_HeightLerp, so a layer's height map shapes the transition. These parameters sit on every blend:

ParameterDefaultEffect
HeightBlendIntensity1How strongly the height difference between the two layers shapes the edge.
HeightContrast1Contrast applied to the height values.
HeightBias0Shifts the height values.
Smoothness1Divides the blend term: a larger value gives a softer edge.
NormalZGuardIntensity, bUseNormalZGuard1 (intensity); the switch is offWith the switch on, reduces the blend weight on surfaces whose normal points away from up.

The effects above are read from the blend function's own arithmetic. Each rule then adds its own parameters:

BlendWhere its layer showsOwn parameters (defaults)
MLB_AT_Paint_<Name>Where the Landscape layer named <Name> is painted.None beyond the shared set.
MLB_AT_ChannelWhere the Mesh Partition channel at ChannelIndex has weight.ChannelIndex (0).
MLB_AT_SlopeOn slopes. Slope is one minus the Z of the vertex normal, with optional noise on the edge.The MF_AT_SlopeMask parameters below.
MLB_AT_NoiseBandWhere a world-space noise value falls in a band. It needs no painting.NoiseTexture (T_AT_MacroNoise_RGBA_2k, red channel), MacroScale (50000), BandMin (0), BandMax (0.7), BandFalloff (0.1).
MLB_AT_AltitudeBetween two world heights.MinHeight (9000), MaxHeight (100000), Falloff (500), all world Z.

MLB_AT_NoiseBand samples the noise at world XY divided by MacroScale. MLB_AT_Altitude ships but no shipped instance uses it.

MF_AT_SlopeMask parameters: SlopeMul (1.5), SlopeContrast (5), Skirt_SlopeCenter (0.3), Skirt_BandWidth (0.15), Auto_bUseSlopeEdgeNoise (on), Auto_Slope_EdgeNoise_Scale (200), Auto_Slope_EdgeNoise_Intensity (0.15), Auto_Slope_EdgeNoise_OverallMult (0.95) and the noise texture Auto_Slope_EdgeNoise_Tex (T_AT_MacroNoise_2k).


Layer parameters

Per-layer parameters show up in the instance's Layer Parameters tab, one set per layer. ML_AT_Surface has these, in groups numbered 01 to 07:

GroupParameters (defaults)
01 TexturesBaseColor, Normal, ORM, Height, VariantNoise (engine default diffuse and normal, T_AT_Neutral_Masks, T_AT_Neutral_Height, T_AT_MacroNoise_2k), and the texture-array parameters BaseColor_Array, Normal_Array, ORM_Array and Height_Array (no default texture)
02 LookTileSize (200, slider 10 to 2000), AOIntensity (1), Specular (0.5), RoughnessMin (0), RoughnessMax (1), ColorTint (white), bUseAntiTile (on), bUseAltitudeTint (on)
03 AntiTileCellSize (150), EdgeSharpness (1), HexCellSize (3), UVScrambleStrength (0.02), UVScrambleFrequency (8), MinScale (0.85), MaxScale (1.15), OffsetStrength (1), RotationStrength (1), bUseCellBomb (off), bUseUVScramble (on), bUseHexTile (off)
04 DistanceFarTileMultiplier (5.7), FarNormalFlatten (0.85), bUseDistanceBlend (on)
05 MacroMacroStrength (0.5), MacroMinTint (grey 0.85), MacroMaxTint (grey 1.15), bUseMacroNormal (on)
06 DisplacementDisplacement (vector 1, 0, 1, 1), bUseDisplacement (on)
07 VariantVariant0_Min/Variant0_Max (0/0.5), Variant1_Min/Variant1_Max (0.5/1), Variant2_Min/Variant2_Max (1/1), VariantCellSize (2000), VariantBandFalloff (0.05), VariantAltitudeMin/VariantAltitudeMax (0/1000), VariantCurvatureScale (1), DriverIsNoise (on), DriverIsSlope, DriverIsAltitude, DriverIsCurvature (off), bUseTextureArray (off)

TileSize is the world distance of one texture repeat: the layer samples its textures at world XY divided by TileSize.

ML_AT_Cliff has the same parameters and samples triplanar. In group 02 Look it adds Slope_TriSize (566.8), Slope_TriSharpness (8), Slope_NormalStrength (1), Slope_TriSize_Far (2400), Slope_DistFadeNear (800), Slope_DistFadeFar (6000) and bUseSlopeTriDistFade, and it has a DisplacementOffset (0).

The master carries shared signals with these defaults: Sample_FadeRange (4096), Sample_FadeFalloff (4), Macro_FadeRange (1500), Macro_FadeFalloff (4), Disp_FadeRange (4096), Disp_FadeFalloff (4), Macro_Normal_Intensity (0.333), Macro_Normal_Size (80), Macro_Scale (5000), Altitude_RangeMin (0) and Altitude_RangeMax (50000).


Bind a biome to a painted layer

A biome follows a Landscape paint layer through Landscape Layer Name (LandscapeLayerName). It is a name match: the layer's name must equal this value. See Biome assets for what reads it. Three links must line up:

  1. The biome's Landscape Layer Name equals the painted layer's name.
  2. The Landscape has that layer as a target layer, with a layer-info asset of that name.
  3. The material shows it: the instance's stack needs a blend that reads that name, such as MLB_AT_Paint_<Name>. A layer can be painted, and visible to placement, without the material drawing it.

The shipped showcase biomes and the paint assets they find:

Biome Landscape Layer NameShipped MLB_AT_Paint_<Name>Used by MI_AT_LayerStack_Showcase
ConiferousForestyesyes
BroadleafForestyesyes
Desertyesyes
Snowyesyes
Beachyesno
Landslidenone (MLB_AT_Paint_MS_Landslide is a different name)no
MountainForestnone (MLB_AT_Paint_MS_MountainForest and MLB_AT_Paint_Mountain are different names)no

MI_AT_LayerStack_Landscape paints only Dirt, Gravel and Sand, which none of the showcase biomes use. To show a biome's layer in the material you need an instance whose stack paints that name.

Tools

These tools work on a Landscape only, and are described with their refusals in Toolsets reference:

ToolUse
AddLandscapeTargetLayerAdd a named target layer, with a layer-info asset, to every Landscape in the level.
PaintBiomeLayersFrom the resolved biome map, or from region bounds when there is none, create a layer per biome and write 0 and 255 weight masks. It names each layer after the biome, so a region for Biome_Desert gives layer Desert. It does not read Landscape Layer Name, so a biome whose value differs from that derived name is not found by the bake or by BuildBiomesFromPaint.
PaintLayerRectPaint one existing layer to a constant weight over a world rectangle.
BuildBiomesFromPaintThe reverse of PaintBiomeLayers: compose a biome map from painted layers, using biomes that declare a Landscape Layer Name.

PaintBiomeLayers makes layers real for placement. It does not make them visible in the material: that is the stack's job, described above.

On a MeshTerrain, Landscape weight layers cannot be read by this path. Bake Runtime Textures bakes no mask texture there, and each biome it tries to bake logs a no terrain under any of its texels warning. See Placement for the MeshTerrain routes.


Add your own paint layer

An AgenticTerrainPalette (UAgenticTerrainPalette) turns a list of names into the assets a paint layer needs. Duplicate a shipped palette (Palette_AT_Default or Palette_AT_Showcase) and set:

PropertyDefaultMeaning
Paint Layers (PaintLayers)emptyLayer names. Names that are None are skipped.
Layer Info Folder (LayerInfoFolder)A project content folderWhere LayerInfo_<Name> is created.
Blend Folder (BlendFolder)A project content folderWhere MLB_AT_Paint_<Name> is created.
Paint Blend Template (PaintBlendTemplate)MLB_AT_Paint_TemplateThe blend that is duplicated.

Press Build. For each name it creates LayerInfo_<Name> with the layer name set and the blend method set to Premultiplied Alpha Blending, and MLB_AT_Paint_<Name>, a copy of the template with its Landscape layer node renamed. It never overwrites: an existing blend asset is left as it was, and an existing layer-info asset is kept, with its blend method set to Premultiplied Alpha Blending if it differed. The report goes to the Output Log under LogAgenticBiomes, one line per name:

Dirt: LayerInfo created, Blend created
Gravel: LayerInfo exists (blend fixed), Blend exists
Moss: FAILED <reason>

A failure on one name does not stop the others. The folders are in your project, not in the plugin.

Then:

  1. Add the layer to the Landscape as a target layer with the new layer-info asset.
  2. In the instance's Layer Parameters tab, set one layer's blend to MLB_AT_Paint_<Name>.
  3. Set the biome's Landscape Layer Name to <Name>.

Do not replace a whole instance stack from script to change blends. An instance whose layers are all unlinked from the parent is merged with the parent's layers rather than replacing them. Keep the instance linked to its parent and override only the blends.

Scripting helpers

The editor module exposes UAgenticTerrainStackLibrary, an editor-only Blueprint function library (category AgenticTerrain) for editing an instance's layer stack, because the stack is not otherwise reachable from scripts: SetInstanceBlends, SetInstanceStack, GetInstanceStack, SetInstanceLayerScalar, SetInstanceLayerVector, SetInstanceLayerTexture, SetInstanceLayerStaticSwitch, DuplicateFunctionAs and ClearLandscapePaintLayer. SetInstanceBlends keeps the parent's layers and replaces only the blends: its Blends array must match the resolved stack's blend count, and a null entry keeps the parent's blend.


Runtime Virtual Texture and Nanite displacement

The master supports both. Neither is on in the shipped instances: all three set bUseNanite and bEnableRVT to off. The plugin does not turn either on for you.

Switch (on the master)GroupMaster defaultShipped instances
bUseNaniteNanite Tessellationoffoff
bEnableRVTRVToffoff
bUseLiveCliffOverlayRVTonon in the Landscape instance; not overridden in the others
bUseLiveDistanceOverlayRVTonoff

bUseLiveCliffOverlay is not connected to anything in the master graph, so changing it has no effect.

The master is flagged Used with Nanite, with tessellation and displacement fade enabled and a displacement magnitude of 0.5. From the graph wiring: bEnableRVT is the last switch before the material output. With it off, the output does not pass through MF_AT_RVTReader or the four far overlays, and bUseNanite chooses whether the displacement output is set. With it on, the output passes through the RVT reader and, when bUseLiveDistanceOverlay is on, the far overlays for Grass, Dirt, Sand and Snow, and the Nanite displacement branch is not in that path. This is read from the graph; the plugin does not ship a level that runs it.

The master always has a Runtime Virtual Texture Output node, so a terrain using it can write into runtime virtual textures whatever the switches say. MF_AT_RVTReader reads RVT_AT_Material (type BaseColor_Normal_Specular) and RVT_AT_Displacement (type Displacement). The shipped RVT assets:

AssetContent typeTile CountTile Size
RVT_AT_MaterialBase colour, normal, specular123
RVT_AT_DisplacementDisplacement123
RVT_AT_HeightWorld height93
RVT_AT_Mask4Mask491 (border 1)

Tile Count and Tile Size are the stored TileCount and TileSize properties, which the Details panel labels Size of the virtual texture in tiles and Size of each virtual texture tile. Both are powers of two: TileCount 12 is 4096 tiles, and TileSize 3 is 512 texels per tile.

What you must set up yourself, because nothing in the plugin does:

  • Unreal's virtual texture support (r.VirtualTextures, on by default in UE 5.8) and the RVT material types you use.
  • A Runtime Virtual Texture Volume in the level for each virtual texture, with its Virtual Texture property set. A volume holds one virtual texture.
  • For a Landscape, the virtual textures in the Landscape's Draw in Virtual Textures list.
  • For Nanite displacement: Nanite on the Landscape (Enable Nanite), r.Nanite.Tessellation left at its default of 1, and bUseNanite on the instance. Whether it works end to end on your terrain was not tested.

Limits

  • The plugin never assigns the material, creates RVT volumes, enables Nanite or checks those settings.
  • Shipped instances leave RVT and Nanite displacement off.
  • MI_AT_LayerStack_Landscape paints only Dirt, Gravel and Sand. No shipped paint blend exists for Landslide or MountainForest.
  • Paint-layer tools and Landscape Layer Name work on a Landscape only. A MeshTerrain uses Mesh Partition channels.
  • The layer-stack material is not editable by the agent toolsets; use the Details panel or the scripting helpers above.
  • The Megascans textures are 4096 by 4096. No performance figures are claimed for the stack.

For problems, see Troubleshooting. To ask a question, join the Discord.

Next steps