[GLSL] Terrain multitexturing shader is too slow

Hey guys,
I came up with a terrain multitexturing technique that works great but it doesn’t run fast enough on intel / older graphics cards. I don’t know if there’s anything I can really do about this. My game runs at 60fps on my ATI card but will hover at around 8-10fps on my intel HD 4000. I was wondering if anyone could look at my technique / GLSL code and see if there’s anything significant I could do to improve it?
My other solution is to just have an option to disable multitexturing on slower PCs, where they would instead just use a single texture with coloured polygons. This kind of sucks because the map/level will look a lot worse but maybe it’s the only other way.

Because of some PC’s only supporting 4 texture units, instead I am using a 2048x2048 “virtual texture” (See image below)

This allows me to have as many textures as I want (up to 32) as long as they fit inside the virtual texture (as “tiles” like in a spritesheet), with a maximum of 4 textures blended per pixel.

My technique requires 4 textures.

  1. Colour map (just for painting colours on the terrain, omitted from the code)
  2. Virtual texture (described above)
  3. Tile map (contains 4 tiles for each pixel) where R=0 is tile 0, R = 1 is tile 1, up to 32. EG. RGBA=(0,1,2,3) will be the first 4 tiles
  4. Mix map (contains opacity of the 4 tile textures for each pixel, for blending them together)

I also pass an array of tiles (x,y,width,height) so that I can calculate the location on the virtual texture for each pixel.

I send 2 sets of UV coords to the shader, worldUV is the true polygon UV coordinates, mixmapUV is the polygon’s UV coordinates relative to the map bounds (from 0 to 1).

I multiply the UV coordinates by the tile size so that smaller textures don’t repeat more than larger (higher quality) textures.

If something isn’t clear please let me know! :slight_smile:


uniform vec4 tiles[MAX_MAP_TEXTURES]; //contains the x,y,width,height of each tile in the virtual texture
uniform sampler2D tileTexture; //contains 4 texture indexes used to get the texture tile from the virtual texture
uniform sampler2D virtualTexture; //2048x2048 packed texture containing all individual terrain textures
uniform sampler2D mixmapTexture; //contains opacity to blend a maximum of 4 textures together

vec4 calculateColour(vec2 worldUV, vec2 mixmapUV)
{
	vec4 textureLocations = texture2D(tileTexture, mixmapUV);
	vec4 mixmapColour = texture2D(mixmapTexture, mixmapUV);
	
	vec4 finalColour = vec4(0.0,0.0,0.0,1.0);
	for(int i=0;i<4;i++)
	{
		int tileLoc = int(textureLocations[i]*256.0);
		
		vec4 tile = tiles[tileLoc];
		float minTextureSize = min(tile.p, tile.q);
		vec2 wrapped = vec2(tile.s + abs(mod(worldUV.x * minTextureSize, tile.p)), tile.t + abs(mod(worldUV.y * minTextureSize, tile.q)));
		textureColours[i] = texture2D(virtualTexture, wrapped);
		
		finalColour.rgb = mix(finalColour.rgb, textureColours[i].rgb, mixmapColour[i]);
	}
	
	return finalColour;
}