Simplepbr stencil(texture splatting)

Hello, I was wandering if there is any way to obtain texture splatting(with stencils) using simplepbr. Does anybody have any hint on where to start?

1 Like

Simplepbr does not currently support texture splatting. I am open to adding it if an appropriate UX/API can be designed for it. Is there a workflow you were using for the shader generator that supported splatting? If so, I can see what inputs may be missing for simplepbr to support it.

Hi, thanks for your answer.
I have developed a small terrain generator(GitHub - someoneetc/Panda3dTerrainGenerator: A terrain generator for panda3d) which is based on a pre-existent heightfield generator.

It uses a simple shader(not the shader generator) which takes 4 textures(base color only) and chooses how to blend them according with the terrain height.
For convenience, here is the fragment shader and the function which computes the weight:

float computeWeight(TerrainRegion terrainRegion, vec4 vertex){
    float regionRange = terrainRegion.max - terrainRegion.min;
    return max(0.0,(regionRange - abs(vertex.z - terrainRegion.max)) / regionRange);

void main() {
  vec4 texel0 = texture2D(p3d_Texture0, * TexScaleFactor0).rgba;
  vec4 texel1 = texture2D(p3d_Texture1, * TexScaleFactor1).rgba;
  vec4 texel2 = texture2D(p3d_Texture2, * TexScaleFactor2).rgba;
  vec4 texel3 = texture2D(p3d_Texture3, * TexScaleFactor3).rgba;

  vec4 heightMapTexel = texture2D(Heightmap,;
  vec4 slopeImageTexel = texture2D(SlopeImage,;

  //texel0 = mix(texel0,texel1,heightMapTexel);
  //texel0 = mix(texel0,texel2,slopeImageTexel);

  float scale = 500.0;
  float w0 = 0.0, w1 = 0.0, w2 = 0.0, w3 = 0.0;
  vec4 terrainColor = vec4(0.0,0.0,0.0,0.0);

  TerrainRegion dirtRegion;
  dirtRegion.min = -100.0/scale;
  dirtRegion.max = 0.0/scale;
  w0 = computeWeight(dirtRegion,vertex);

  TerrainRegion grassRegion;
  grassRegion.min = 1.0/scale;
  grassRegion.max = 200.0/scale;
  w1 = computeWeight(grassRegion,vertex);

  TerrainRegion rockRegion;
  rockRegion.min = 201.0/scale;
  rockRegion.max = 400.0/scale;
  w2 = computeWeight(rockRegion,vertex);

  TerrainRegion snowRegion;
  snowRegion.min = 401.0/scale;
  snowRegion.max = 500.0/scale; 
  w3 = computeWeight(snowRegion,vertex);

  terrainColor = texel0 * w0 + texel1 * w1 + texel2 * w2 + texel3 * w3;

  p3d_FragColor = terrainColor; 

as you could guess from the simplicity of the shader I’m not an advanced shader programmer :smiley:
I have no idea on how to do pbr so I’m not sure if, in order to embed something like that in simplepbr would involve applying the same procedure to all other textures.
Moreover, the weight function should be generalized(I believe) by using another texture(an heightmap, for example).

Is it called stencil technique? It’s just mixing textures by mask. Panda supports this, but I have no idea if this method allows you to mix more than two textures. (739.6 KB)

Hi, yes it does :slight_smile: . The shader I’ve posted allows to mix up to 4 textures

In fact, this is a simple technique. You can mix more than 4 textures by adding another texture as a mask. You can bake lighting and AO and shadows. In fact, I also have a similar shader. :stuck_out_tongue:

#version 150

uniform sampler2D mask_1;

uniform sampler2D sand_layer;
uniform sampler2D ground_layer;
uniform sampler2D grass_layer;
uniform sampler2D rock_layer;

uniform sampler2D light_layer;
uniform sampler2D details_layer;

in vec2 multi_texture_coord_0;

in vec2 tex_coord_sand;
in vec2 tex_coord_ground;
in vec2 tex_coord_grass;
in vec2 tex_coord_rock;

out vec4 p3d_FragColor;

void main(){

    vec4 rgba_mask_1 = texture2D(mask_1, multi_texture_coord_0.xy);
    vec4 sand = texture2D(sand_layer, tex_coord_sand.xy) * rgba_mask_1.x;
    vec4 ground = texture2D(ground_layer, tex_coord_ground.xy) * rgba_mask_1.y;
    vec4 grass = texture2D(grass_layer, tex_coord_grass.xy) * rgba_mask_1.z;
    vec4 rock = texture2D(rock_layer, tex_coord_rock.xy) * rgba_mask_1.w;

    vec4 light = texture2D(light_layer, multi_texture_coord_0.xy);
    vec4 details = texture2D(details_layer, multi_texture_coord_0.xy);

    p3d_FragColor = (sand + ground + grass + rock)*light*details;
    p3d_FragColor.a = 1.0;

The only difference is that I use output masks from Gaea software.

Oh, nice! :smiley: