tim at jenkz dot org
September 2005
Blended textures are often applied to three dimensional terrain meshes to create realistic looking terrain for computer graphics applications, notably computer games. Many existing techniques were designed around multi-pass rendering that does not take advantage of modern day programmable GPU architectures. We propose a simple way to implement real time texture composition on a programmable GPU to produce unique textures for use in terrain rendering.
Texturing in computer graphics is used to add detail, colour and effects to otherwise plain geometry. Textures are applied to three-dimensional terrain meshes to create the illusion of a rich landscape – grassy plains, sandy shores, snowy mountain peaks and rocky cliff faces.
The first terrain texturing techniques used 2D tiles – each land type had it’s own set of tiles, for grass, sand, mud, snow and these tiles were textured per-quad at relevant positions on the terrain mesh. Harsh seams between different tiles are visible; the solution was to create a set of blending tiles to use between areas of adjoining texture types.
Later and more effective techniques, such as that outlined by Bloom, C. (2000), blend textures using hardware multi-texturing to create seamless and unique blending between different textures applied to the terrain mesh.
Many modern techniques use multi-pass rendering to achieve their desired effects, which is not a suitable technique for modern programmable GPU architectures. This article extends upon the article by Glasser, N. (2005) and describes a simple and fast way of implementing terrain texture blending on modern programmable graphics hardware.
Bloom, C. (2000) Terrain Texture Compositing by Blending in the Frame-Buffer
Bloom, C. (2000) outlines the first publication of terrain
texture blending which has been the groundwork of the majority of terrain
texture blending since. Bloom, C. (2000) describes the basics of alpha blending
overlaying textures, known in the article and to many since as “Splats”, using
the fixed function pipeline and multiple passes on hardware that cannot support
multi-texturing.
Bloom, C. (2000) outlines a detailed method of generating alpha
values for the texture splats considering neighbouring textures, heights,
slopes and normalization of the alpha values to produce better results.
Whilst the work is the foundation of much of this article and
articles and publications since, the work carried out is less applicable to
modern graphics hardware as it was produced before programmable graphics
hardware was available.
Corpes, G. (2001) reviews some history of terrain rendering and texturing from the early 1990s and explains a brief introduction to terrain “prototexture” blending.
Luna, F.D. (2003) describes how to implement basic multi-texturing in a pixel shader using HLSL. Multi-texturing and texture combination are the basis for terrain texture blending and therefore this introduction to multi-texturing using HLSL is an important step to implementing terrain texture blending on programmable GPUs.
Glasser, N. (2005) explains Bloom, C. (2000) texture splatting in more detail alongside an implementation description using both the fixed function pipeline and an assembly pixel shader
Terrain texture blending is achieved by overlaying different textures on top of each other depending on the height of the terrain mesh, or another attribute such as the gradient of the terrain at that particular point. This overlaying is achieved using alpha blending.
A large terrain mesh is usually split into chunks when dealing with rendering, these chunks vary in size but we will assume a 17x17 vertex regular grid. For each texture that will be applied to the terrain chunk in question an associated alpha map is created either procedurally by the engine or manually by an artist using a tool. This alpha map indicates what areas of the terrain chunk the texture should apply to.
A base texture is first applied over the whole of the chunk, with further textures blended on top of the base texture depending on their alpha map. Figure 1 shows this texture combination.
*
= 
Figure 1: Texture Blending
using Alpha Maps. Textures from Glasser, N. (2005) and Nvidia.
For each terrain texture an alpha maps matching the size of the terrain chunk must be created. A unique alpha map texture can be generated and stored separately for each terrain chunk, however a more efficient method is to store the alpha values for four maps in a single RGBA texture – one channel per alpha map.
This technique allows four alpha maps to be stored in a single texture, saving texture memory.

Figure 2: Combining two alpha maps into one RGB texture. Textures from Glasser, N. (2005)
Figure 2 shows three separate alpha maps and their combination in the RGB channels. Programmable GPUs allows a pixel shader to extract the individual alpha maps from the combined texture separately by reading from the four channel intensities separately.
Exactly how the alpha map is generated is left up to the reader, as the method chosen varies between application and what final terrain appearance is required.
A basic procedural method is to separate the terrain chunk into four sections by height, allowing for four different textures to be placed starting with low-lying land through to mountain peaks.
Minimum, maximum and average terrain heights for the chunk can be used to separate the terrain into these sections, then for each texture upper and lower bounds can be declared. If a vertexes height falls within a particular textures bounds then it’s alpha value can be set in the alpha map texture. Figure 3 outlines basic psudeo-code for this approach:
for each vertex in the terrain chunk:
if height
of the terrain mesh applies to texture 1:
set
the red channel intensity to desired alpha
elif
height of the terrain mesh applies to texture 2:
set
the blue channel intensity to desired alpha
elif
height of the terrain mesh applies to texture 3:
set
the green channel intensity to desired alpha
elif
height of the terrain mesh applies to texture 4:
set
the alpha channel intensity to desired alpha
Figure 3: pseudo code for procedural height based alpha map generation
The alpha value indicates the intensity of the texture coverage at that point on the chunk – High alpha values mean the texture will overlay all lower textures in that area, low alpha values mean the texture will barely be visible, if at all.
Using the upper and lower bounds example above, if the height of the vertex falls in the middle of a textures height influence, it could have a high alpha value set making the texture prominent. If the height falls nearer to the bounds then a lower alpha value is set.
In the computer gaming industry it is important to leave a large proportion of influence with the artists. An artist in a world-editor tool could generate the alpha map for a texture to explicitly design where the texture would be visible. Such a world-editing tool would allow the artist to interactively change the alpha map of a particular texture and see the changes in real time. The alpha maps can then be exported and then loaded into the rendering application at terrain chunk load or page time.
Alternatively, another manual approach could be to edit the alpha maps in imaging editing software. Alpha maps created using this approach would be pre-generated and stored on disk to later be loaded by the.
These approaches however are not realistic for very large
terrain visualization due to the number of static alpha maps that would need to
be produced. For very large terrains a procedurally generated alpha map is a
better choice.
It is possible to implement the above techniques in hardware using the DirectX fixed function pipeline without the need of a programmable GPU. However, the fixed function pipeline does not allow for the explicit reading of individual texture colour channels in hardware, therefore combined alpha maps would not be possible using the fixed function pipeline and each terrain texture would require it’s own alpha map in texture memory.
Programmable GPUs using a pixel shader allows for the reading of individual texture colour channels, allowing for a combined alpha map and saved texture memory.
To achieve the desired result using the fixed function pipeline the D3DBLEND_INVSRCALPHA texture operation must be performed. This operation performs the following:
ResultantColor = Alpha * Texture + (1 – Alpha) * PreviousColor
This operation is what must be implemented on the programmable GPU.
For both HLSL and assembly implementations the general approach is as follows:
In this implementation five textures are used to blend four terrain textures using the HLSL. The five textures are:
The textures once loaded are associated with the pixel shaders constant table for sampling, and the resulting constant table references are used in the texture stages. The constant table and texture stages are shown in Figure 5.
The HLSL pixel shader to perform the blending operation is displayed in Figure 4.
// Globals
sampler AlphaMap;
sampler BaseTex;
sampler TextureOne;
sampler TextureTwo;
sampler TextureThree;
// Structures
struct PS_INPUT
{
float2
alphamap : TEXCOORD0;
float2
base : TEXCOORD1;
float2
textureone : TEXCOORD2;
float2
texturetwo : TEXCOORD3;
float2 texturethree
: TEXCOORD4;
};
struct PS_OUTPUT
{
vector
diffuse : COLOR0;
};
// Main
PS_OUTPUT Main(PS_INPUT input)
{
// zero
out members of output
PS_OUTPUT
output = (PS_OUTPUT)0;
// sample
textures
vector b
= tex2D(BaseTex, input.base);
vector a
= tex2D(AlphaMap, input.alphamap);
vector i
= tex2D(TextureOne, input.textureone);
vector j
= tex2D(TextureTwo, input.texturetwo);
vector k
= tex2D(TextureThree, input.texturethree);
//
combine texel colors
float4
oneminusx = 1.0 - a.x;
float4
oneminusy = 1.0 - a.y;
float4
oneminusz = 1.0 - a.z;
vector l
= a.x * i + oneminusx * b;
vector m
= a.y * j + oneminusy * l;
vector n
= a.z * k + oneminusz * m;
// save
the resulting pixel color
output.diffuse
= n;
return
output;
}
Figure 4: HLSL
implementation. Code a modification from Luna, F.D. (2003)
Firstly each textures is sampled to a pixel colour vector. The vector’s l,m and n are the linear interpolation blending implementation described above using the Alpha * Texture + (1-Alpha) * PreviousColour operation. These operations achieve the blending required.
AlphaMapHandle = CT->GetConstantByName(0,
"AlphaMap");
CT->GetConstantDesc(AlphaMapHandle,
&AlphaMapDesc, &count);
Dev->SetTexture(AlphaMapDesc.RegisterIndex,
AlphaMap);
Dev->SetSamplerState(AlphaMapDesc.RegisterIndex,
D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
Dev->SetSamplerState(AlphaMapDesc.RegisterIndex,
D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
Dev->SetSamplerState(AlphaMapDesc.RegisterIndex, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
Figure 5: Constant Table manipulation and Texture Stages for AlphaMap texture in HLSL implementation.
Assembly Implementation
Similarly with the HLSL implementation, the assembly implementation uses five textures as follows:
The assembly implementation does not require manipulation of the constant table and merely retrieves texture samplers from their respective texture stages. The texture stages for the assembly implementation are displayed in Figure 7. Figure 6 displays the assembly implementation.
ps_1_4
// Sample textures
// r0: combined alphamaps
// r1 - r4: textures
texld r0, t0
texld r1, t1
texld r2, t1
texld r3, t1
texld r4, t1
// Combine textures together based off of their
alphamaps
mul r1, r1, r0.w
lrp r2, r0.x, r2, r1
lrp r3, r0.y, r3, r2
lrp r0, r0.z, r4, r3
Figure 6: Assembly implementation. Code a modification from Glasser, N. (2005)
The texld instructions sample the textures in their respective texture stages.
The mul instruction blends the base texture with the base alpha map stored in the alpha channel of the alpha texture (r0.w) This alpha channel is set to 255 (full alpha) and is rendered without blending.
The lrp dst, src0, src1, src2 instruction is the linear interpolation instruction which performs:
dest = src0 * src1 + (1-src0) * src2
As clear from the operation performed, the lrp instruction performs the desired blending of the three remaining textures, the final lrp instruction stores the result in r0 which is the resultant register and the final pixel colour.
Dev->SetTexture(0, AlphaMap);
Dev->SetTexture(1, BaseTex);
Dev->SetTexture(2, TextureOne);
Dev->SetTexture(3, TextureTwo);
Dev->SetTexture(4, TextureThree);
Figure 7: Texture Stages for
the five textures in assembly implementation
We have outlined a fast and efficient method for implementing terrain texture blending in real time that is suitable for use on current GPU architectures and beyond. Using high detail base textures and intuitive alpha maps generation the resulting terrain texture effect can be quite impressive. Figure 8 shows an example 17x17 vertex terrain chunk rendered using this technique.

Figure 8: Terrain Texture
Blending using assembler implementation
Care must be taken when generating alpha values at the edge of the alpha map when considering adjoining terrain chunks. Texture glitches may be visible on joining chunks if non-repeating terrain textures are used and thoughtful alpha map generation is not used.