Archive for January 2008
Thermal erosion 3D renderings
Introduction
I’ve made several 3D renderings with Blender in order to show how the developed thermal erosion affects real terrains, I’m really satisfied by the results and I hope you’re going to agree with me
In order to appreciate the effects of the erosion, I suggest to open the images of each group in different tabs and view them in sequence, enjoy!
EDIT 05/02/2008 - I’ve updated all the images with new renderings because the old ones had some visual “bugs” fixed by the subsurf modifier
Fault formation
The following image shows how the original map (top-left square), generated by the fault formation algorithm, is modified by 25, 50 and 100 steps of thermal erosion:
These are the 3D renderings from the SOUTH-EAST view:
Circles
The following image shows how the original map (top-left square), generated by the circles algorithm, is modified by 25, 50 and 100 steps of thermal erosion:
These are the 3D renderings from the NORTH-WEST view:
Perlin noise
The following image shows how the original map (top-left square), generated by the Perlin noise algorithm, is modified by 25, 50 and 100 steps of thermal erosion:
These are the 3D renderings from the SOUTH-EAST view:
Benchmarks: thermal erosion
Introduction
I’ve run some tests of the last erosion algorithm I’ve developed, the results are really good.
All the test are based on 1024×1024 maps, the GPU version uses 16-bits floating point textures.
GPU version
As I’ve introduced in my previous post, the GPU version of the thermal erosion is a reversed version of the original algorithm.
The following data are the execution times needed to complete a different number of iterations of the erosion phase, for each group of iterations you can see the slowest, the average and the fastest time on 10 tests.
iterations = 10 -> min = 673 ms. - avg = 682 ms. - max = 692 ms.
iterations = 30 -> min = 1089 ms. - avg = 1101 ms. - max = 1133 ms.
iterations = 50 -> min = 1496 ms. - avg = 1524 ms. - max = 1548 ms.
iterations = 70 -> min = 1881 ms. - avg = 1911 ms. - max = 1935 ms.
iterations = 100 -> min = 2514 ms. - avg = 2552 ms. - max = 2602 ms.
As it’s possible to notice the times are not linear, but they grow slowly.
CPU version
The CPU version is based on the original version of the algorithm, the program is written in C language.
The following data are the average execution times needed to complete a different number of iterations of the erosion phase.
iterations = 1 -> 2748 ms.
iterations = 5 -> 20483 ms.
iterations = 10 -> 42540 ms.
Thermal erosion (reversed)
Introduction
I’ve developed the thermal erosion algorithm originally proposed by Musgrave, Kolb and Mace using a fragment shader.
I’ve altered the algorithm in order to get over the limits of the shaders, in fact a fragment shader can’t scatter data, it can just gather (a shader can read all the fragments, but it can write just the current one).
The original algorithm
The algorithm is executed examining each cell of the map and its 8 neighbours according to a Moore scheme like showed in the following picture:

For each neighbour it’s computed the difference between the processed cell and the neighbour:
d[i] = h - h[i];
the maximum positive difference is stored in d_max, and the sum of all the positive differences that are bigger than T (this numer is n), the talus angle, is stored in d_tot.
Now it’s possible to update all the n cells (where d[i] is bigger than T) using this formula:
h[i] = h[i] + c * (d_max - T) * (d[i] / d_tot);
and the main cell with this other formula:
h = h - (d_max - (n * d_max * T / d_tot));
The Talus angle T is a threshold that determines which slopes are affected by the erosion, instead the c constant determines how much material is eroded.
My reversed version
As I’ve mentioned in the introduction I can’t implement the original algorithm with a fragment shader because it can’t update the neighbour fragments.
My implementation uses two phases to perform the erosion:
in the first phase the shader inspects all the neighbours according to the Moore scheme so to compute d_max, d_tot and n, then these values are stored in the last three component (G, B, A) of the texel, instead the first one (R) stores the height value.
the second phase (another execution of the shader) uses the values stored in all the neighbours to compute how much material has to be moved to the current fragment using the formula:
h_in = h_in + (c * (d_max[i] - T) * d[i] / d_tot[i]);
then it’s computed how much material should be removed from the current fragment using this formula:
if(n > 0) h_out = d_max - (n * d_max / d_tot * T); else h_out = 0.0;
Finally the height is updated summing the two values to the original one:
h = h + h_in - h_out;
A graphical example
The following image shows the erosion performed on a cube of rock, the 4 squares are the result of 50, 100, 150 and 200 steps of erosion:
I’ve got this result setting T=0.005 and c=0.5 .
Useful resources
Perlin noise 3D renderings
Introduction
I’ve improved my Blender skills a lot from my first posts about 3D renderings, of course I’m still a newbie and my renderings are more “experiments” than real works, but I hope you’re going to enjoy the new images
3D renderings
This is the base map I’ve generated summing 8 octaves:
and these are the 3D views from NORTH-EAST and SOUTH-EAST:
This is the same map after 2 iterations of blur (blur radius = 10.0):
And the same 3D views:
This is the original map modified by the abs() function followed by 2 iterations of blur (blur radius = 10.0):
and these are the 3D views from NORTH-WEST and SOUTH-WEST:
As it’s possible to notice in the previous images, the abs() function acts like a simple hydraulic erosion generating riverbeds among the mountains.
Instead this is the original map modified by the sqrt() function followed by 2 iterations of blur (blur radius = 10.0):
and these are the 3D views from NORTH-EAST and SOUTH-WEST:
From these images it’s possible to notice what I’ve just wrote in the post about the Perlin noise algorithm, it’s possible to generate different terrains from a single map using filter functions and it’s possible to do that in a real short time (about 2-3 ms.), this is a great feature of this algorithm!




























