You are not logged in.
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):
//
// 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):
yy = -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
[ MISSING ]
Offline
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
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
No prob. Make sure you backup your forum this time LOL...
Offline
At the suggestion of icuurd12b42, I'll repost here what I posted in another topic.
I think a faster way, again only if you are willing to use separate grids for each channel, could be like this:
w = 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.w = 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