Texture Splatting with Three.Js

Texture splatting with Three.js

Challenge accepted!

First, you can write a vertex shader that takes a grayscale image and uses it as a heightmap, and includes a varying float (called vAmount below) to pass to the fragment shader to determine the texture(s) to display(blend) at that point.

uniform sampler2D bumpTexture;
uniform float bumpScale;

varying float vAmount;
varying vec2 vUV;

void main()
vUV = uv;
vec4 bumpData = texture2D( bumpTexture, uv );

vAmount = bumpData.r; // assuming map is grayscale it doesn't matter if you use r, g, or b.

// move the position along the normal
vec3 newPosition = position + normal * bumpScale * vAmount;

gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );

Next comes the fragment shader, which can include however many textures you need for different elevations, and there is a great built-in function called smoothstep that makes smooth transitions much easier to calculate.

An example of code for such a fragment shader:

uniform sampler2D oceanTexture;
uniform sampler2D sandyTexture;
uniform sampler2D grassTexture;
uniform sampler2D rockyTexture;
uniform sampler2D snowyTexture;

varying vec2 vUV;

varying float vAmount;

void main()
vec4 water = (smoothstep(0.01, 0.25, vAmount) - smoothstep(0.24, 0.26, vAmount)) * texture2D( oceanTexture, vUV * 10.0 );
vec4 sandy = (smoothstep(0.24, 0.27, vAmount) - smoothstep(0.28, 0.31, vAmount)) * texture2D( sandyTexture, vUV * 10.0 );
vec4 grass = (smoothstep(0.28, 0.32, vAmount) - smoothstep(0.35, 0.40, vAmount)) * texture2D( grassTexture, vUV * 20.0 );
vec4 rocky = (smoothstep(0.30, 0.50, vAmount) - smoothstep(0.40, 0.70, vAmount)) * texture2D( rockyTexture, vUV * 20.0 );
vec4 snowy = (smoothstep(0.50, 0.65, vAmount)) * texture2D( snowyTexture, vUV * 10.0 );
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0) + water + sandy + grass + rocky + snowy;

Then you can use a THREE.ShaderMaterial to use this for a given mesh. The above code is implemented at http://stemkoski.github.io/Three.js/Shader-Heightmap-Textures.html and produces a result like this:

Sample Image

Hope this helps you get started. Happy coding!

Setting texture to geometry in Three.js

This really not that hard to understand, let me walk you through the logic.

In your case, you don't want to use a displacement map. So, you need to set up a varying height on your vertexShader to map your vertices up-coordinates [0,1] to your fragmentShader.

varying vec2 vUV;
varying float height;

void main() {

vUV = uv;

float maxPosition = 30.0; // this is an example value.
height = max( 0.0, min(1.0, position.y/maxPosition ) ); // assuming +y is up

gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );


Now you can access height from your fragmentShader and use that information to select where you want your transitions to occur.

uniform sampler2D grassTexture;  
uniform sampler2D snowTexture;

varying vec2 vUV;
varying float height;

void main(){

vec4 grass = (1.0 - smoothstep( 0.48, 0.52, height)) * texture2D( grassTexture, vUV);
vec4 snow = (smoothstep(0.48, 0.52, height) - 0.0) * texture2D( snowTexture, vUV);

gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0) + grass + snow;


The link provided uses function smoothstep to make a gradual transition between the textures. We can create transitions using the follow pattern ( a - b ) * textureColor.

In this case, a controls when the texture starts to contribute to the fragment color.
b controls when the texture stops contributing.

In other words, your grass texture will have already started contributing at every height, so we map a to 1.0. It stops contributing around 0.5, so we give b a smooth fade-out as it approaches that 0.5.

Your snow texture, on the other hand, will only start contributing around 0.5. So, we give a a smooth fade-in as it approaches 0.5. It will never stop contributing, so we set b as 0.0.

Hope this clears things up for you.

ThreeJS: First shader attempt - blending two textures

You have run into the following issue:


Just assign your textures after you have merge the uniforms.


three.js R112

three.js: rendering 3d text with custom texture

Here is an example of 3D text with a texture applied:


Hope it helps!

Related Topics

Leave a reply