Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
87 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

  Contents

 Introduction
 Spectral Synthesis
 The Algorithm
 Adding Some
 Water

 Links & Files

 Printable version

 


The Algorithm

Well, I hope I've given you some appreciation for how cool this stuff is - let's take a look at the algortihm.

Spectral synthesis is just slightly more complicated than throwing a bunch of random numbers into a 2d array. The difference is in how the 2d array is treated. Instead of just treating the 2d array as the texture itself (aliased white noise), it smooths it (with a spline function in this case) to produce some sort of continuity in the data.

But that still wouldn't generate a very convincing or useful (except in some cases) texture. The real cool part comes in when you start adding multiple passes. In this way, spectral synthesis is a sort of fractal function. It iterates a function with varying parameters over an array that accumulates the values. The varying parameters in this case are wavelength and amplitude. Here's an example (forgive the low quality of the images, they're taken from the app, which wasn't made for looking at the 2d data).

ss1.jpg ss2.jpg
1 pass 2 passes

ss3.jpg ss4.jpg
3 pass 4 passes

ss5.jpg ss50.jpg
5 pass 50 passes

I only used 4 passes for my project, but you can see how well it works at higher number of passes. Now you wouldn't get these results if you just kept accumulating smoothed random noise - the higher frequency data would determine too much of the texture. What you want is for the lowest frequency pass to define the basic shape and further higher frequency passes to add detail. So there is an added scale for each pass related to the pass number. The above images were generated with a scaling factor of 0.8 per pass, while I used 0.4 in my project.

The fracSynthPass(...) function:

/* * fracSynthPass(...) * * generate basic points * interpolate along spline & scale * add to existing hbuffer */ void fracSynthPass( float *hbuf, float freq, float zscale, int xres, int zres ) { int i; int x, z; float *val; int max; float dfx, dfz; float *zknots, *knots; float xk, zk; float *hlist; float *buf; // how many to generate (need 4 extra for smooth 2d spline interpolation) max = freq + 2; // delta x and z - pixels per spline segment dfx = xres / (freq-1); dfz = zres / (freq-1); // the generated values - to be equally spread across buf val = (float*)calloc( sizeof(float)*max*max, 1 ); // intermediately calculated spline knots (for 2d) zknots = (float*)calloc( sizeof(float)*max, 1 ); // horizontal lines through knots hlist = (float*)calloc( sizeof(float)*max*xres, 1 ); // local buffer - to be added to hbuf buf = (float*)calloc( sizeof(float)*xres*zres, 1 ); // start at -dfx, -dfz - generate knots for( z=0; z < max; z++ ) { for( x=0;x < max;x++ ) { val[z*max+x] = SRANDOM; } } // interpolate horizontal lines through knots for( i=0;i < max;i++ ) { knots = &val[i*max]; xk = 0; for( x=0;x < xres;x++ ) { hlist[i*xres+x] = spline( xk/dfx, 4, knots ); xk += 1; if( xk >= dfx ) { xk -= dfx; knots++; } } } // interpolate all vertical lines for( x=0;x < xres;x++ ) { zk = 0; knots = zknots; // build knot list for( i=0;i < max;i++ ) { knots[i] = hlist[i*xres+x]; } for( z=0;z < zres;z++ ) { buf[z*xres+x] = spline( zk/dfz, 4, knots ) * zscale; zk += 1; if( zk >= dfz ) { zk -= dfz; knots++; } } } // update hbuf for( z=0;z < zres;z++ ) for( x=0;x < xres;x++ ) hbuf[z*xres+x] += buf[z*xres+x]; free( val ); free( buf ); free( hlist ); free( zknots ); }




Next : Adding Some Water