Skip to content

Multi-Layer Splatting ​

RedGPU.Landscape.LandscapeMaterial and RedGPU.Landscape.LandscapeLayer provide a Multi-Layer Splatting system that blends up to 8 PBR layers across the terrain surface based on the 4 channels (R, G, B, A) of a single shared RGBA weight map (weightTexture) and height-modulated blending (heightBlendFactor).


1. Registering Splatting Layers (addLayer) ​

Call landscape.addLayer(options) to register up to 8 LandscapeLayer instances. The first layer (index 0) also acts as the base fallback layer, while each layer blends according to its designated channel ('R' | 'G' | 'B' | 'A') in the shared weightTexture.

IMPORTANT

PBR Layers vs. Weight Map (weightTexture) Support

  • PBR Material Layers (LandscapeLayer): Up to 8 layers can be registered.
  • Splat Weight Map (weightTexture): Only 1 shared RGBA weight map texture (4 channels: 'R', 'G', 'B', 'A') is supported across the terrain. (Both the near-range fragment shader and the CPU weight sampler for foliage and grass reference the RGBA channels of this single weight map.)
  • Near Range (within nearDetailDistance): Blends high-resolution PBR textures with stochastic tiling (stochasticTiling) in real time.
  • Far Range (beyond nearDetailDistance): Samples the pre-baked Virtual Blend Texture (VBT) atlas in a single lookup to save GPU texture bandwidth.
javascript
// Set the distance (in world units) within which near high-resolution texture blending is active
landscape.nearDetailDistance = 350;

const weightTexture = './assets/terrain/weightTexture.jpg';

// 1. Add Grass layer (uses 'R' channel of splat map)
const grassLayer = landscape.addLayer({
    name: 'Grass',
    baseColorTexture: './assets/terrain/layer/grass.jpg',
    normalTexture: './assets/terrain/layer/grass_normal.jpg',
    ormTexture: './assets/terrain/layer/grass_orm.jpg',
    weightTexture,
    weightChannel: 'R',
    uvScale: [25, 25],
    roughness: 0.85,
    stochasticTiling: true
});

// 2. Add Rock layer (uses 'G' channel of splat map)
const rockLayer = landscape.addLayer({
    name: 'Rock',
    baseColorTexture: './assets/terrain/layer/rock.jpg',
    normalTexture: './assets/terrain/layer/rock_normal.jpg',
    ormTexture: './assets/terrain/layer/rock_orm.jpg',
    weightTexture,
    weightChannel: 'G',
    uvScale: [7.5, 7.5],
    roughness: 0.7,
    normalIntensity: 1.2,
    stochasticTiling: true
});

Live Example: Multi-Layer Splatting ​


2. LandscapeLayerOptions Key Properties ​

CategoryPropertyDefaultDescription
Identity & StatenameRequiredUnique layer name (linked with targetLayer in foliage and grass)
enabledtrueWhether the layer is enabled
Textures & WeightbaseColorTextureundefinedBase color (Albedo) texture path or BitmapTexture
normalTextureundefinedTangent-space normal map path or BitmapTexture
ormTextureundefinedPacked Occlusion (R), Roughness (G), Metallic (B), Height (A) texture
weightTextureundefinedSplat map texture containing layer distribution weights (single shared RGBA map)
weightChannel'R'Channel to sample from weightTexture ('R' | 'G' | 'B' | 'A' or 0 ~ 3)
UV & TilinguvScale / uvOffset[20, 20] / [0, 0]Texture UV repeat scale [u, v] per tile and UV offset [u, v]
nearUVScaleMultiplier2.0UV scale multiplier applied to the near-detail region
stochasticTilingtrueEnables stochastic sampling to suppress repetitive texture tiling artifacts over large areas
stochasticScale1.0Stochastic tiling cell scale (0.01 or higher)
PBR & Blendingroughness1.0Surface roughness factor
normalIntensity / aoIntensity1.0 / 1.0Normal map bump intensity and ambient occlusion (AO) intensity
heightBlendFactor1.0Height-based layer boundary blending contrast factor using ORM alpha (0.0 ~ 5.0)

3. Querying and Managing Layers ​

Registered layers can be queried, modified, or removed by name or instance at any time, automatically updating the VBT atlas and ecosystem weights.

javascript
// Retrieve a layer by name and update its properties
const layer = landscape.getLayer('Rock');
if (layer) {
    layer.uvScale = [15, 15];
    layer.heightBlendFactor = 1.5;
}

// Remove a specific layer or clear all layers
landscape.removeLayer('Rock');
// landscape.clearLayers();


Next Step: Learn Tile Streaming