# Triplanar terrain texturing with GLSL

By , last updated November 25, 2019

Stretched textures on vertical triangles is one of a million possible bugs when texturing terrain with shaders. To fix it we need to recalculate texture coordinates in 3 projections: x, y and z.

The main algorithm to apply triplanar texturing of a 3D terrain with shaders is as following:

Compute the vertex’s normal vector and check what the larger component of the normal is, out of x, y and z. If x is the larger component, we use the geometry z coordinate as the texture coordinate s, and the geometry y coordinate as the texture coordinate t. If z is the larger component, we use the geometry x coordinate as the texture coordinate s, and the geometry y coordinate as the texture coordinate t.

Here’s how terrain looked like before we used shaders: Here’s a simple example of GLSL vertex and fragment shaders for texturing terrain in 3D:

```varying float v;
varying float xcoord,ycoord,zcoord;

void main ()
{
//Texture Coordinates
xcoord = gl_Vertex.x;
zcoord = gl_Vertex.z;
ycoord = gl_Vertex.y ;

// projection1. y is largest normal component
// so use x and z to sample texture
gl_TexCoord = vec4(xcoord,zcoord,0,0); //first projection
// projection2. x is largest normal component
// so use z and y to sample texture
gl_TexCoord = vec4(zcoord,ycoord,0,0); //second projection
// projection3. z is largest normal component
// so use x and y to sample texture
gl_TexCoord = vec4(xcoord,ycoord,0,0); //third projection

//gl_Normal is the vertex's normal vector.
//We compare it's absolute values with each other to find which projection to use
float x = abs(gl_Normal.x);
float y = abs(gl_Normal.y);
float z = abs(gl_Normal.z);
if(x > y && x > z)
{
//v is a variable used in fragment shader to distinguish textures
v = 1;
}
if(y > x && y > z)
{
v = 0;
}
if(z > y && z > x)
{
v = 2;
}

gl_Position = ftransform();
}
```

```varying float v;
uniform sampler2D myTexture0;
uniform sampler2D myTexture1;
uniform sampler2D myTexture2;
void main (void)
{
if ( 0 == v )
{
gl_FragColor = texture2D( myTexture0, gl_TexCoord.st);
}
if ( 1 == v )
{
gl_FragColor = texture2D( myTexture1, gl_TexCoord.st);
}
if ( 2 == v )
{
gl_FragColor = texture2D( myTexture2, gl_TexCoord.st);
}
}
```

Here’s the result (we used 3 textures in shaders to visualize the result):  Senior Software Engineer developing all kinds of stuff.

You may use these HTML tags and attributes: `<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> `