Procedural Terrain Texturing on the GPU

A recent project that I was working on required me to revisit the topic of terrain texturing.

I started off by looking into an offline approach whereby a single large texture is generated from a height map and several tileable terrain textures. This seemed to work ok but most cards limit the max texture size to about 4K, and I didn’t have the time to go into any kind of terrain paging scheme. I was looking for a quick and cheap alternative.

Many sources on the web suggests that procedural terrain texturing on the GPU would give better result. My initial experiments with a fragment shader gives some pretty good results. At the moment I’m just blending 4 texture tiles and only using the height to color the terrain. I plan to add slope to the mix later on.

I haven’t found much in the way of how other people have been implementing this on the GPU. The way I’ve done it is to include 2 sets of texture coordinates with the terrain mesh vertices.

The 1st set is for the height map. The coordinates are for a single height map stretched across the entire terrain. I then use the interpolated texture coordinates to determine the exact height of that pixel on the terrain in the fragment shader.

The 2nd set of texture coordinates is what I use to give the terrain texture its overall resolution. Its how much the terrain texture tiles are tiled across the terrain. A low amount of tiling will produce results equivalent to a low res texture stretched across the terrain. The greater the amount of tiling the more detailed the resulting terrain texture will be. However too much tiling and the end result will look “funny” since the tiling will be very obvious.

I’ve posted a demo together with source on my site www.dhpoware.com .

Any feedback would be most welcomed.

That is pretty much the way to go unless you want to start working on mega texturing, a few notes though.

  1. you don’t really need the second set of coordinates as these could simply be worked out in the vertex shader using the first set if you want.

2.you can reduce tiling by assigning different texture offsets and/or scale for each source texture, also use at least two similar textures at the same time to blend between using perlin noise(see below).

  1. bake height, slope, some perlin noise and extra data(could be the area covered by forests and/or asphalt) onto each channel of a texture, this will give you a fairly good source material to work with.

  2. different surfaces doesn’t always blend as gradually as in your demo, experiment with it a little and see what works.

Hey zeoverlord, thanks for the feedback. I have some questions:

  1. you don’t really need the second set of coordinates as these could simply be worked out in the vertex shader using the first set if you want.
    I realized that I didn’t need the 2nd set of texture coordinates shortly after I made my original post :slight_smile:

2.you can reduce tiling by assigning different texture offsets and/or scale for each source texture, also use at least two similar textures at the same time to blend between using perlin noise(see below).
Still not quite sure what you mean by that last part about blending between using perlin noise :confused:

  1. bake height, slope, some perlin noise and extra data(could be the area covered by forests and/or asphalt) onto each channel of a texture, this will give you a fairly good source material to work with.
    Do you mean per texture tile (say in the alpha channel) or in a totally separate texture?
  1. different surfaces doesn’t always blend as gradually as in your demo, experiment with it a little and see what works.
    Something like getting terrain region height ranges to overlap and then lerping between them?

Originally posted by dpoon:
Still not quite sure what you mean by that last part about blending between using perlin noise :confused:
Well lets say you have a perlin noise texture and two grass textures that look similar but are not.
If you then interpolate between these two using the perlin noise texture then the tiling will be broken up and reduced, and if you want this method may actually work with the same texture as long as you have different texture offsets.

Do you mean per texture tile (say in the alpha channel) or in a totally separate texture?
I literally mean a separate texture where height is in the red channel, slope in the green, perlin in the blue and the extra stuff as alpha, this is the texture that need to span the entire area and can therefore not be baked within the tiled ones

Something like getting terrain region height ranges to overlap and then lerping between them?
I was more thinking of controlling the lerp distance, or contrast between the two textures depending of what kind of textures you are using.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.