Posted on 04-11-2008 under 3ds max, Algorithm

I continued developing my method for SSAO and worked a bit on making it look better over a series of frames in an animation. So basically I ended up generating the same sphere for any given number of samples (same random seed) and then rotate the samples using by reflecting them with a per-pixel random normal, as described here.

That is all fine, but the real improvement came when I used energy minimization on my sampling sphere. Instead of just settling with random spherical coordinates I put my sphere through a energy minimization routine, and the difference is staggering. I’ll let the pictures speak for themselves:

SSAO without energy minimization
Notice how noisy and high contrast this looks.

SSAO with energy minimization
Much less noise with the same number of samples, and more realistic contrast.

So how does one do this? It is quite simple. Just generate your sample sphere with normalized vectors. Then iterate through them and apply some force between each point until they reach and equilibrium. About 100 iterations should be more than enough, and since this is done in a pre-process stage it really doesn’t matter how long it takes.

Here is some code:

// Energy minimization
int iter = 100;
while( iter– )
{
for( int i = 0; i < samples; i++ )
{
Point3 force;
Point3 res = Point3( 0.0f, 0.0f, 0.0f );
Point3 vec;
float fac;

vec = sampleSphere[ i ];
// Minimize with other samples
for( int j = 0; j < samples; j++ )
{
force = vec – sampleSphere[ j ];

fac = DotProd( force, force );
if( fac != 0.0f )
{
fac = 1.0f / fac;
res.x += fac * force.x;
res.y += fac * force.y;
res.z += fac * force.z;
}
}

res = res * 0.5f;
sampleSphere[ i ] += res;
sampleSphere[ i ] = Normalize( sampleSphere[ i ] );
}
}

After this we can randomize sphere radius lenghts…

// Randomize sphere radiuses
for( int i = 0; i < samples; i++ )
{
sampleSphere[ i ] *= random.Rand01() * radius;
}