Triplanar terrain texturing with GLSL

By , last updated December 31, 2015

Stretched textures on vertical triangles is a usual bug when texturing terrain. To fix it we need to recalculate texture coordinates in 3 projections: x, y and z.

The main algorithm to apply triplanar texturing is the following. First, we 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:

Than we apply GLSL shaders:

Vertex shader

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[0] = vec4(xcoord,zcoord,0,0); //first projection
	// projection2. x is largest normal component
	// so use z and y to sample texture
	gl_TexCoord[1] = vec4(zcoord,ycoord,0,0); //second projection
	// projection3. z is largest normal component
	// so use x and y to sample texture
	gl_TexCoord[2] = 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();
}

Fragment shader

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

Here’s the result (we used 3 textures in shaders to see the result more easily):

Senior Software Engineer developing all kinds of stuff.

Comments

  1. Stretched terrain textures bug finally fixed! | Monsters are coming - [...] on how we fixed it and shader samples here. Be Sociable, [...]
  2. Vertical triangles texture bug | Monsters are coming - [...] the bug is fixed. More on how here. Be Sociable, [...]

Leave a Reply


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>

*