Shader Patch Terrain Materials - PrismaticFlower/shaderpatch GitHub Wiki

Contents

Intro

As of v1.1 terrain can also now have SP materials applied to it but because terrain isn't drawn in the same way as regular models the process for doing so is different.

First instead of having .mtrl files each terrain has a single .tmtrl file. Next terrain materials can not share textures with other materials. (They can both use but the terrain will get it's own copy, more on this later.)

When material_munge encounters MAP.tmtrl file it first loads MAP.ter from the same folder and also loads MAP.terrain (the munged version MAP.ter) from _BUILD\Worlds\SPT\PC.

It will then generate new geometry for the terrain from MAP.ter. The old terrain geometry from the loaded MAP.terrain is discarded. (Note that this happens in memory, the original MAP.terrain on disk is never modified.)

Then the terrain geometry's triangles are sorted into segments on an 8x8 grid. These segments are then sorted into models, one for every 48 segments. Using a defined max of 6 models, but obviously currently only 2 are used. These models are appended to SP's copy of MAP.terrain.

Finally in order to make the new terrain models show up a world layer is also created and appended to MAP.terrain. This layer will define an object that references each of the terrain's models. Again up to a limit of 6. Each object will be unnamed and will use com_inv_col_8 as it's class. (However despite using an object class explicitly for the purposes of providing collision none of the terrain objects have collision, the terrain collision comes from the original collision in MAP.terrain.)

Once all that is done MAP.terrain is saved into _BUILD\Worlds\SPT\PC_SP for SP's lvl_pack to pickup and use instead of the game's regular terrain.

Next the textures for the terrain will be assembled and packed together. The textures referenced in MAP.tmtrl must have .*.tex files so that they produce .sptex files in _BUILD\Worlds\SPT\PC_SP for this step. If they are only used by the terrain then setting Uncompressed and the seldom documented NoMips both to yes in the texture's .tex file can save you some time when munging.

Each of the textures will be loaded and assembled arrays with the other textures. This let's the textures being used by the terrain be controlled at a primitive level instead of segment level and reduces GPU state changes while drawing. However it has the downside that all the textures must have the same resolution.

If the texture resolutions do not match (or they are not a power of two) then the size of the largest one will be taken, rounded to the next largest power of two in each direction (1000x400 becomes 1024x512) and all the textures will be resized to that resolution automatically.

Texture types are also packed together to reduce memory requirements. (AO is placed in the alpha channel of the diffuse texture for instance.) But the exact details of this are larger unimportant. But below is high level list of the resulting arrays.

  1. Color Maps + AO
  2. Normal Maps + Gloss (or MetallicRoughness)
  3. Height Maps

Because I'm a lazy busy person I haven't had time to refactor out the texture processing in sp_texture_munge and make it usable in material_munge so instead of the usual texture compressor DirectXTex's GPU compressor is used. This will likely cause your GPU usage go up to close to 100%, there is nothing wrong with this obviously (unless something is really wrong with your PC) but I figured I'd leave a note about it so no one gets confused/surprised.

After that the textures are saved. And then as a last step the material files to tie it all together are created for the terrain's models.

Config Files

The format of .tmtrl files is similar to .mtrl but very much distinct. Like all modder facing configs in SP it is written in YAML. Below is the documentation for each key. Example config files can be found at the bottom of this page.

Config.Global

The Global section in the config contains settings that affect all the materials that make up the terrain.

Config.Global.BlendingMode

Blending mode for the terrains textures. Options are.

  • Height - Use height maps to blend between textures.
  • Basic - Simple linear blending like stock terrain has. Cheaper than height based blending.

Defaults to Height.

Config.Global.FarTerrain

Geometry detail for terrain in the far scene. Options are.

  • Downsampled - Downsample the terrain to 64x64 grids. Has the potential for better performance in some cases. But due to the downsampling and the way the far scene works in SWBFII it is only suitable for terrains with no hills/mountains.
  • Fullres - Use the same geometry for the far scene as the near scene. Works in all cases.

Defaults to Fullres.

Config.Global.TerrainOffset

Offsets the terrain by specified amount. Can be used to work around misaligned terrain. Provide as an array of three values.

TerrainOffset: [0.0, 0.0, -8.0] # x, y, z

Config.Global.UseEnvironmentMapping

Use an envmap for reflections on the terrain. Currently only supported for normal_ext terrain and defaults to no.

Config.Global.EnvironmentMap

The name of the texture to use as the environment map. The texture should be a cubemap and should have it's sRGB value set to yes if HDR rendering is being used.

Config.Global.UseZEStaticLighting

Use diffuse lighting baked in ZE editor and mark the terrain as statically lit. Defaults to no.

Config.Global.sRGBDiffuseMaps

Equivalent of sRGB value in *.tex files for terrain diffuse texture array. Only applicable to normal_ext and defaults to yes.

Config.Global.BumpMappingType

The type of bump mapping to use. Parallax options may be unsuitable for terrain with widely varying elevation due to problems relating to normal transitions. Options are,

  • Normal Mapping - Simple normal mapping.
  • Parallax Offset Mapping - Parallax Mapping with Offset Limiting, can give the illusion of greater depth to the image at a fraction of the cost of Parallax Occlusion Mapping.
  • Parallax Occlusion Mapping - Parallax Occlusion Mapping, see documentation here.

Defaults to Normal Mapping.

Config.Global.Rendertype

The rendertype to use for the terrain. Can be normal_ext or pbr. Defaults to normal_ext.

Config.Global.DiffuseColor

Diffuse color modifier, multiplied with the blended diffuse map color before calculating lighting. Only applicable to normal_ext and defaults to [1.0, 1.0, 1.0].

Config.Global.SpecularColor

Specular color. Only applicable to normal_ext and defaults to [1.0, 1.0, 1.0].

Config.Global.BaseColor

Base color modifier, multiplied with the blended albedo map color before calculating lighting. Only applicable to pbr and defaults to [1.0, 1.0, 1.0].

Config.Global.BaseMetallicness

Metallicness modifier, multiplied with the blended metallicness map value before calculating lighting. Only applicable to pbr and defaults to 1.0.

Config.Global.BaseRoughness

Roughness modifier, multiplied with the blended roughness map value before calculating lighting. Only applicable to pbr and defaults to 1.0.

Config.Materials

The Materials section in the config contains a listing for each material or "game texture" in the terrain. They do not have to be in order but each texture must have an entry. Even though they will be listed as "Config.Materials." all keys listed below for the individual entries and are thus really of the format "Config.Materials.texture_name.".

Config.Materials.HeightScale

Height scale for parallax effects (if used). Defaults to 0.05. The terrain shaders are coded to recognize 0.0 as meaning skip parallax occlusion mapping for this texture.

Config.Materials.SpecularExponent

Specular exponent for normal_ext. Defaults to 64.0.

Config.Materials.AOMap

Texture name for ambient occlusion map.

Config.Materials.HeightMap

Texture name for height map. Used for parallax effects and blending between terrain textures.

Config.Materials.NormalMap

Texture name for normal map.

Config.Materials.DiffuseMap

Texture name for diffuse map. Only applicable for normal_ext.

Config.Materials.GlossMap

Texture name for gloss map. Only applicable for normal_ext.

If you want to effectively disable specular lighting for this entry pass $null_glossmap here.

Config.Materials.AlbedoMap

Texture name for albedo map. Only applicable for pbr.

Config.Materials.MetallicRoughnessMap

Texture name for metallic roughness map. Only applicable for pbr.

Terrain Texture Builtins

The texture assembler for terrain recognizes some of SP's builtin textures for materials and will handle them correctly. It also supports some additional ones that regular materials do not.

Name Description
$null_normalmap A normal map that always points directly away from the surface
$null_ao An AO map that never occludes.
$null_aomap An AO map that never occludes.
$null_detailmap A linear texture with the value 0.5.
$null_heightmap A linear texture with the value 1.0.
$null_metallic_roughnessmap A texture with the value 1.0 in all channels, causing the metallicness and roughness parameters to always be the BaseMetallicness and BaseRoughness values.
$null_albedomap A white texture.
$null_diffusemap A white texture.
$null_glossmap A texture with the value of 0.0, effectively removing all specular lighting from the material.

Far Scene Terrain Optimizations

Far scene terrain has a couple special things happen to it to reduce it's cost. Specifically the BumpMappingType will be set to Normal Mapping for it and the BlendingMode to Basic.

Triangle Texture Selection

Each triangle on the terrain can only blend between up to three textures at once. The way this is done is intended to be intuitive and just give the right result. So in most cases you shouldn't have to worry about it.

But for those pesky times when you're seeing hard edges with your texture blending it probably pays to know how textures are selected.

First the texture weights of the three terrain points making up the terrain are fetched and then all the weights of all their neighboring points are fetched. The badly made illustration below shows this process for a hypothetical triangle. Each black point is a point on the terrain that texture weights are being fetched from.

Points considered during selecting textures for a triangle.

The textures to use are then selected by determining what textures have the greatest total contribution across all fetched. So say you're terrain had five textures and these textures each had these hypothetical weights across all the considered points. Then the textures whose weights are bolded would be the one's chosen for use as they had the highest total contribution to the terrain points.

  1. 0.25
  2. 0.1
  3. 0.20
  4. 0.05
  5. 0.15

Example Configs

normal_ext

Global:
   UseEnvironmentMapping: no
   EnvironmentMap: cubemap
   
   UseZEStaticLighting: yes
   
   sRGBDiffuseMaps: yes
   
   BumpMappingType: Parallax Occlusion Mapping

   Rendertype: normal_ext

   DiffuseColor: [1.0, 1.0, 1.0]
   
   SpecularColor: [1.0, 1.0, 1.0]

Materials:
   Ground03_col:
      DiffuseMap: Ground03_col
      NormalMap: Ground03_nrm
      GlossMap: Ground03_gloss
      AOMap: $null_ao
      HeightMap: Ground03_disp
      HeightScale: 0.01
      SpecularExponent: 32.0

   Ground23_col:
      DiffuseMap: Ground23_col
      NormalMap: Ground23_nrm
      GlossMap: Ground23_gloss
      AOMap: Ground23_AO
      HeightMap: Ground23_disp
      HeightScale: 0.01
      SpecularExponent: 96.0

   Rocks05_col:
      DiffuseMap: Rocks05_col
      NormalMap: Rocks05_nrm
      GlossMap: Rocks05_gloss
      AOMap: Rocks05_AO
      HeightMap: Rocks05_disp
      HeightScale: 0.05
      SpecularExponent: 64.0

pbr

Global:
   BumpMappingType: Parallax Occlusion Mapping

   Rendertype: pbr

   BaseColor: [1.0, 1.0, 1.0]
   BaseMetallicness: 0.0
   BaseRoughness: 1.0
   

Materials:
   Ground03_col:
      AlbedoMap: Ground03_col
      NormalMap: Ground03_nrm
      MetallicRoughnessMap: Ground03_rgh
      AOMap: $null_ao
      HeightMap: Ground03_disp
      HeightScale: 0.01

   Ground23_col:
      AlbedoMap: Ground23_col
      NormalMap: Ground23_nrm
      MetallicRoughnessMap: Ground23_rgh
      AOMap: Ground23_AO
      HeightMap: Ground23_disp
      HeightScale: 0.01

   Rocks05_col:
      AlbedoMap: Rocks05_col
      NormalMap: Rocks05_nrm
      MetallicRoughnessMap: Rocks05_rgh
      AOMap: Rocks05_AO
      HeightMap: Rocks05_disp
      HeightScale: 0.05