DEMIENGINEDOCUMENTATION Everything is free
Project & file formats · Start here

Shared mesh and terrain surfaces, PBR maps, projection and normal conventions.

One material for meshes and terrain

Create Material from the Assets panel and open its source to edit the surface. A material has one stable asset:// ID. Assign that same ID to a Mesh Renderer, a terrain biome override, or a role in a terrain material set. There is no separate Terrain Material asset type.

The integrated material document provides map pickers, surface settings, render state, Undo/Redo and Save. Its color swatch shows the base tint; inspect actual mapped shading on a scene object or terrain. Import texture assets before assigning them. Map pickers also accept RenderTarget assets; these use their live texture contents rather than generated image mipmaps. Material import and reimport validate their references and record texture and shader dependencies for cooking.

{
  "format_version": 1,
  "mapping": "triplanar",
  "textures": {
    "albedo": "asset://surfaces/rock/color",
    "normal": "asset://surfaces/rock/normal",
    "roughness": "asset://surfaces/rock/roughness"
  },
  "parameters": {
    "tiling": 0.5,
    "normal_strength": 0.8
  }
}

These IDs illustrate the format; select assets installed in your project. The default shader is builtin://lit. Omit unused maps and default settings. parameters.base_color is an sRGB RGBA tint, default white; the mesh or biome tint still multiplies it. Roughness defaults to 0.8 and metallic to 0. Values for either scalar are in 0–1.

Map meanings

Texture keyInterpretation
albedosRGB base RGB and linear alpha.
normalLinear RGB tangent-space normal. normal_strength defaults to 1; zero removes its perturbation.
roughnessLinear red channel; dark is smooth and bright is rough.
metallicLinear red channel; zero is dielectric, one is metallic.
ambient_occlusionLinear red channel; reduces ambient illumination, not direct sun visibility.
detail_normalAdditional tangent-space normal controlled by detail_strength, default 0. Assign the map before increasing its strength.
emissivesRGB emission color. This does not illuminate nearby geometry.
heightLinear red channel biases existing terrain layer weights through height_blend_strength. Ordinary mesh shaders do not sample it. It does not displace vertices or change collision.

Color mipmaps average in linear light before returning to sRGB storage. Normal mipmaps renormalize averaged vectors; scalar maps average linear values. Color image variants use hardware sRGB decoding before bilinear and mip-level filtering; alpha remains linear. Scalar and normal variants do not decode their channels. Live scene RenderTargets contain display-sRGB in raw storage: color slots decode those contents once in the shader, after their existing raw texture filtering. A source used for different purposes can have separate GPU sampling variants, so interpreting a normal map does not change a UI texture using the same image.

Mapping and normal conventions

mapping is uv by default and uses ordinary mesh texture coordinates; terrain uses its continuous local X/Z coordinates. triplanar projects onto three local surface axes and blends them by surface orientation, avoiding the stretched top-down projection on cliffs. parameters.tiling is positive, defaults to 1, and increases repetition when raised. In UV mode it multiplies the mesh UVs; in triplanar mode it specifies repeats per local surface unit. Transform scale therefore changes the world size of the pattern.

Texture wrapping remains an import setting. Use repeat on tileable terrain maps; clamping a map intentionally stretches its edge outside its authored range. Triplanar projection does not make a non-tileable source seamless.

normal_map_convention is opengl by default (+Y/green up). Choose directx for −Y/green down maps. This describes the source image convention, independently of the rendering backend or operating system. The normal and detail-normal maps use the same convention.

Terrain layer controls

Shared Material parameters include height_blend_strength (default 0.5, range 0–1), macro_variation_strength (default 0, range 0–1), and macro_variation_scale (default 0.02, positive cycles per terrain-local unit). These control terrain layer shading and do not change mesh geometry, erosion or collision. Height strength biases normalized layer weights using the assigned linear height map; a missing height map is neutral and strength zero preserves the original weights. Macro variation darkens albedo with deterministic position-based noise, reducing visible uniform repetition; strength zero disables it. These controls do not add geometric displacement or make non-tileable textures seamless. The ordinary mesh material path retains them without applying terrain layer blending.

Terrain integration and current limits

Static meshes and MeshInstances3D can use visual wind through ordinary built-in Materials: parameters.wind_strength defaults to 0 (disabled) and sets maximum world-space displacement; wind_frequency defaults to 1 Hz and must be nonnegative; wind_height defaults to 1 and must be positive. Vertices at local Y=0 or below stay rooted; bending increases quadratically up to full strength at wind_height. Instance world positions provide stable phase variation. Color, shadow and water depth capture use the same displacement, and visibility bounds include the maximum bend. Collision and gameplay transforms stay fixed. Wind is intended for rooted grass, reeds and simple foliage, with undeformed shading normals; it does not animate skinned meshes or native terrain surfaces.

MeshInstances3D shares one static Mesh Renderer across render-only transforms. Ordinary built-in Materials, mapped PBR surfaces and inline meshes retain instanced submission, alpha cutoff and render state. Each copy receives camera culling and the Mesh Renderer's authored model LOD/cull distances; LOD requires actual reduced model assets. Transparent and custom-program surfaces retain individual submission.

Terrain material sets bind automatic roles such as ground, rock, wet ground and snow to ordinary Material IDs. Classification uses the generated terrain’s slope, erosion transport, moisture and water coverage. Set biome allow_snow: false to exclude automatic snow; its default is true. An explicit biome Material overrides automatic roles, and the biome color remains a tint.

Compatible opaque terrain uses instanced GPU patches with five material arrays: albedo, normal, packed ambient-occlusion/roughness/metallic/height, detail normal and emissive. These support mapped PBR surfaces, triplanar projection, height-biased layer weights and macro variation. The renderer decodes exact material IDs before blending the four neighboring field samples; four contributors per cell are not a four-role limit on the source material set. Terrain3D.surface_blending applies to mapped and solid materials: enabled interpolates contributors; disabled selects the original triangle’s material.

The mapped terrain path requires 12 texture sampler slots, texture-array support, vertex texture sampling and instancing. Actual device texture dimensions, array-layer limits and configured memory budgets constrain residency. Custom shaders, transparency/cutout, unsupported devices, nearest or mip-disabled image sampling, incompatible map wrapping or live RenderTarget maps use the ordinary mesh path with an explicit fallback reason. Array maps require linear filtering and enabled mipmaps. All image maps within one terrain Material must share one wrap mode; different Materials may use repeat, clamp or mirror independently. Maps are not silently dropped to keep GPU batching.

The ordinary mesh path renders individual PBR materials with discrete triangle assignments. Terrain height-weight blending and macro variation belong to the GPU layer path; they do not alter geometry or collision. Ordinary mapped meshes require nine sampler slots and report unsupported capabilities. Array tiers and detail-normal fade use the shared Environment3D terrain quality settings. These contracts describe the implemented path; they do not establish platform or visual qualification.

Starter terrain materials

Install Poly Haven Terrain Materials with demi package add polyhaven.materials.terrain@^1.2.0. It supplies six CC0 1K source surfaces, a wet-gravel variant, physical scales, provenance and an alpine material set/palette. Alpine rock/cliff roles use pale gray fractured Marble Cliff 05 at its scanned 20-metre tile width; warm brown Rock Face 03 remains available as an individual Material. Use asset://polyhaven/terrain/palettes/alpine as the terrain recipe's palette, or assign individual Material IDs to meshes and biome overrides. These are real source maps, not geometry or vegetation generators.

Migrating the retired terrain material format

The former DataAsset content type terrain_material is rejected with migration guidance. Keep the stable ID, change the manifest to type: Material with importer material, and retain format_version in both documents. Remove obsolete data-specific content_type/schema settings and unused schema dependencies. Reimport to refresh dependencies. Regenerate derived terrain and recook older outputs; the prepared terrain payload is now version 9.

Move scalar surface settings into parameters; convert the old linear base_color RGB to sRGB (alpha stays linear). Replace the maps array with a textures object and rename base_color to albedo. Replace triplanar: true with mapping: triplanar. Use detail_normal only for an actual normal map; the retired generic detail slot did not establish that meaning. Terrain material sets and palettes remain typed data assets.