Yay! 2D and 3D noise in pixel shaders!
After tackling the Hue shader I decided to move to something even more interesting, Simplex noise.
You've probably heard of Perlin Noise, if not see Rene's post with realtime 3D noise here and also check out my Living Noise sample and Living Noise blog post .
The "Noise" can be used to make effects such as fire, water, marbles, smooth motion, hand-drawn UI, space travel effects, nebulas and a lot more!
Simplex noise has similar characteristics to Perlin noise - it's continuous, smooth and its first derivative is smooth too. The nice thing about the Simplex, is that its much easier to compute and thus can be implemented in Pixel shaders.
Another advantage of the Simplex noise over Perlin noise is that the permutation bitmaps compress very well (8KB total), making the whole XAP about 30KB total, including the sample JPEG. In comparison Perlin noise's bitmaps compress to about 350KB on my box.
Note you can also generate the maps almost instantly on the fly, eliminating the "size argument" when comparing Perlin and Simplex.
The source code download contains both 2D and 3D Pixel shader Simplex noise implementation. The 3D implementation still lacks some features - read on below.
Here is the live sample:
Download Source Code
The sample is based on this public powerpoint presentation by Natalya Tatarchu (AMD), who is the hero of today and I believe she made a lot of people happy with her great implementation of the Simplex noise! :)
I also re-visited Ken Perlin's homepage to remind myself of the noise a couple of times.
2D noise
This was (relatively) easy, since the reference implementation readily fits into PS 2.0 shaders, with lots of instructions available to experiement.
To overlay couple of noises on top of each other, I had to use the shader several times.
The biggest issue was generating the maps - I had to make sure to set the alpha to 255, otherwise weird things may happen (due to alpha premultiplication).
3D Noise
The 3d noise was more challenging - the implementation I have does not fit in PS 2.0 (84 instructions total, and PS 2.0 is 64 max).
I had to split the function in the middle, and make 2 shaders that build on top of each other. This means that the second shader works with the output from the first. There are several challenges:
1. There is color and shader information to be passed around, which means that either I have to pass the original image every time to the shader, or I have to compress the color space
I chose to compress the color space, and make it (R, S, G+B) where S is the shader value from the previous pass and RGB are the original image components. In the source code, I skipped the G+B part altogether ending with (R, S, 0) (monochrome source image), but you may change it to fix the issue.
If you do, please let me know, since I'm not planning to do it for now!
Note: in .NET 4.0 the 3D Noise shader fits into the PS 3.0 instruction limits. I left the original function in the source for people who want to use it with WPF.
Lot of writing! Hope you enjoy it!