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 witch 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):

GD Star Rating
loading...
GD Star Rating
loading...
Tagged with:
 

4 Responses to Triplanar terrain texturing with GLSL

  1. [...] on how we fixed it and shader samples here. Be Sociable, [...]

  2. [...] the bug is fixed. More on how here. Be Sociable, [...]

  3. Perfect work you have done, this site is really cool with excellent information.

    GD Star Rating
    loading...
    GD Star Rating
    loading...

Leave a Reply

Your email address will not be published. Required fields are marked *

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=""> <strike> <strong>