# GMLscripts.com

Discuss and collaborate on GML scripts

You are not logged in.

## #1 2008-01-02 11:14:29

leif902
Member
From: Georgia, USA
Registered: 2007-10-09
Posts: 24

### Grid Smoothing and Random Terrain Generation

Today I decided to take a stab at smoothing out random values in grids, useful in random terrain generation and anywhere else you need random numbers grouped in predictable ways.

Therefore I created the following script for smoothing over grids (Well, I say created, it's a commonly used algorithm):

Expand//
// ds_grid_smooth
// Smooths the randomly generated contents of a grid, useful for
// random terrain generation.
// Arguments
//    argument0 - The grid to populate
//    argument1 - The size of each sub-division (About 4 for optimal results, less than four will take longer to calculate
//                       and give you less of an effect, more than 4 will calculate faster and give you more smoothing)
//

var step, xx, yy, w, h, grid, total, y_local, x_local, average;
grid = argument0;
step = argument1;
w = ds_grid_width(grid);
h = ds_grid_height(grid);

for(yy = 0; yy < h; yy += step)
{
for(xx = 0; xx < w; xx += step)
{
total = 0;
for(y_local = yy; y_local <= yy + step; y_local += 1)
{
for(x_local = xx; x_local <= xx + step; x_local+= 1)
{
total += ds_grid_get(grid,x_local, y_local);
}
}
average = total / sqr( step );
for(y_local = yy; y_local <= yy + step; y_local += 1)
{
for(x_local = xx; x_local <= xx + step; x_local += 1)
{
ds_grid_set(grid, x_local, y_local, average );
}
}
}
}

To test it I populated a grid randomly with values 0 - 3 (Simple enough):

Expandyy = -1;
while ( yy < h )
{
xx = 0;
yy += 1;
while ( xx < w )
{
ds_grid_set(grid, xx, yy, floor ( random( 3 ) ) );
xx += 1;
}
}

and drew the results by subtracting a normalized version of each grid value from the value of the color black, this is using a step value of 4:

As opposed to the non-smoothed version (not the same grid):

There are better ways to do this, but this one is easy. I found a better way and created a GML script, but I'm still toying with it as it only semi-smooths it at the moment.

Last edited by leif902 (2008-01-02 11:15:58)

Leif902

Offline

## #2 2009-01-11 00:28:11

icuurd12b42
Member
Registered: 2008-12-11
Posts: 303

[ MISSING ]

Offline

## #3 2009-12-16 01:43:34

icuurd12b42
Member
Registered: 2008-12-11
Posts: 303

### Re: Grid Smoothing and Random Terrain Generation

I found my missing smoother method

//argument0 - grid
//argument1 - size of mean radius
//argument2 - deform factor (0-much deform, >0 less deform)
var w,h;
w = ds_grid_width(argument0)
h = ds_grid_height(argument0)
var g; g = ds_grid_create(w,h)
var xx,yy;
yy = 0;
var av;
var ct;
repeat(h)
{
xx = 0;
repeat(w)
{
av = argument2*ds_grid_get(argument0,xx,yy);
av += ds_grid_get_disk_mean(argument0,xx,yy,argument1)
ds_grid_set(g,xx,yy,av/(argument2+1));
xx+=1;
}
yy+=1;
}

ds_grid_copy(argument0,g);
ds_grid_destroy(g);

Last edited by icuurd12b42 (2009-12-16 02:23:57)

Offline

## #4 2009-12-16 05:57:04

xot
Registered: 2007-08-18
Posts: 1,240

### Re: Grid Smoothing and Random Terrain Generation

Ah, cool, thanks for posting that again.

ds_grid_get_disk_mean is definitely the way to go here. Even a chunky box-filter using ds_grid_get_mean would be much better than doing it all in GML.

In my opinion the overall construction of your version is much more appropriate for a function of this description. The original only averages in discreet blocks leading to discontinuities. It's more of a "pixelation" filter than a smoothing one. Your version appears far more continuous and should be completely smooth across all cell boundaries.

Abusing forum power since 1986.

Offline

## #5 2009-12-16 06:47:30

icuurd12b42
Member
Registered: 2008-12-11
Posts: 303

### Re: Grid Smoothing and Random Terrain Generation

No prob. Make sure you backup your forum this time LOL...

Offline

## #6 2009-12-19 12:12:35

xot
Registered: 2007-08-18
Posts: 1,240

### Re: Grid Smoothing and Random Terrain Generation

At the suggestion of icuurd12b42, I'll repost here what I posted in another topic.

xot wrote:

I think a faster way, again only if you are willing to use separate grids for each channel, could be like this:

Expandw = ds_grid_width(source);
h = ds_grid_height(source);
destination = ds_grid_create(w, h);
ds_grid_copy(destination, source);
ds_grid_add_grid_region(destination, source, 0, 0, w, h, -1,  0);
ds_grid_add_grid_region(destination, source, 0, 0, w, h,  1,  0);
ds_grid_add_grid_region(destination, source, 0, 0, w, h,  0, -1);
ds_grid_add_grid_region(destination, source, 0, 0, w, h,  0,  1);
ds_grid_multiply_region(destination, 0, 0, w, h, 0.2);

You could easily give the center pixel extra weight with another ds_grid_multiply_region call after the copy.

Expandw = ds_grid_width(source);
h = ds_grid_height(source);
destination = ds_grid_create(w, h);
ds_grid_copy(destination, source);
ds_grid_multiply_region(destination, 0, 0, w, h, 12);
ds_grid_add_grid_region(destination, source, 0, 0, w, h, -1,  0);
ds_grid_add_grid_region(destination, source, 0, 0, w, h,  1,  0);
ds_grid_add_grid_region(destination, source, 0, 0, w, h,  0, -1);
ds_grid_add_grid_region(destination, source, 0, 0, w, h,  0,  1);
ds_grid_multiply_region(destination, 0, 0, w, h, 0.0625);

Abusing forum power since 1986.

Offline