Monday, May 25, 2009

An Oscar Algorithm - Silverlight Real-time 3D Perlin Noise

Perlin Noise Cloud SkyPerlin Noise is a computer graphics algorithm, which is widely used in computer games and movies as a visual effect. It was developed by Ken Perlin in the early 1980's and was used in the movie TRON. In 1997 Perlin received a Technical Achievement Award from the Academy of Motion Picture Arts for his work. So Perlin Noise is an Oscar-winning algorithm and I'm pretty sure almost everyone has seen it before.
Perlin Noise could produce pseudo-random semi-natural textures with fractal characteristics and is mostly used for procedural image generation. The algorithm can be controlled with various parameters and is able to produce good looking cloud / sky, fire, smoke, wood or marble textures and height maps, just to name a few.
In short, the Perlin Noise algorithm generates random noise functions with various frequencies and amplitudes, sums them up and smoothes the result. I don't want to bore you with more mathematical details, which were already explained several times on the web. If you are interested, I refer you to the Wikipedia article and the link section, Ken Perlin's site and to this excellent explanation. 

Live
My Silverlight implementation is the three dimensional improved Perlin Noise algorithm.

The initial Frequency and the Amplitude of the noise function can be changed. The Octaves parameter defines how many iterations of the noise function are summed up. Like in music the frequency is doubled in every subsequent octave. The Persistence controls how much the amplitude changes after each iteration. Press the Randomize button to reinitialize the noise function with new pseudo-random seeds.

How it works
The Perlin Noise computing loop:
for (int i = 0; i < this.Octaves; i++)
{
   noise += Noise(x * freq, y * freq, z * freq) * amp;
   freq  *= 2;
   amp   *= Persistence;
}

Each frame the Perlin Noise for every pixel of the 2D destination image is computed in real-time and is used as the alpha value for blending the noise color over the base color, then the z-value is increased. The noise's third dimension, the z-value, is actually used as time for the animation. So each frame the next slice of the 3D noise cube is computed and shown, thus resulting in a smooth animation.
For the source of the destination image the great RawPngBufferStream from the open source GameEngine Balder is used.
int off = 0;
for (int y = 0; y < bufferStream.Height; y++)
{
   for (int x = 0; x < bufferStream.Width; x++)
   {
      float a = perlinNoise.Compute(x, y, perlinZ);
      float ai = 1 - a;
      bufferStream[off + aOff] = (byte)(a * noiseColor.A + ai * baseColor.A); 
      bufferStream[off + rOff] = (byte)(a * noiseColor.R + ai * baseColor.R);
      bufferStream[off + gOff] = (byte)(a * noiseColor.G + ai * baseColor.G);
      bufferStream[off + bOFF] = (byte)(a * noiseColor.B + ai * baseColor.B);
      off += 4;
   }
   off++;
}
if (Chk3D.IsChecked.Value)
{
   perlinZ++;
}
imgSource.SetSource(bufferStream);


Source code
You can download the Silverlight 2 version here. Feel free to use or modify it as you like. If you do so please drop me a line, because I'm curious to know where (you want to) use it. Have fun!

Update 07-26-2009
I updated the project to Silverlight 3. Now it uses the WriteableBitmap instead of Balder's RawPngBufferStream. You can download the updated Visual Studio 2008 solution from here.

Shout it Submit this story to DotNetKicks

12 Kommentare:

Anonymous said...

I like it. Thxs.

Anonymous said...

Very nice effect. It probably will be much faster if you port it to Silverlight 3.

Rene Schulte said...

Thanks.
I wanted that as many as possible can watch, but Silverlight 3 and it's WriteableBitmap would surely run faster. I'm looking forward to the 10th of July, when SL3 will probably be released.

nfBarata said...

You have a random var... for us to create heightmaps we have to have the same output to the same input vars...

nfBarata said...

I think you have to use a seed parameter

Rene Schulte said...

@nfBarata If you always need the same noise, then you should use this Random class ctor: http://msdn.microsoft.com/en-us/library/ctssatww.aspx, this will result in a identical permutation vector.

nfBarata said...

Yes, I did that, I added a get/set parameter to the class called seed and used it as a parameter to the random constructor

Rene Schulte said...

@nfBarata Glad you like and use it. You use it for heightmap generation? Is it live somewhere?

nokola said...

Hi Rene!
I was just about to drop you a comment, when I saw yours on the Living Noise :) Thanks!
Your perlin noise sample is very cool.

Rene Schulte said...

Thanks Nikola!

Kai said...

Very nice. Have you tried porting it to Silverlight 3, using WriteableBitmaps? I'd love to see that if you have.

Rene Schulte said...

Thanks.
I've updated it to SL3 shorly after SL3 came out, please read the last paragraph: "Update 07-26-2009".

Post a Comment