I just updated the function...
I noticed unsightly diamond artifacts in the resulting perlin noise caused by the bilinear filtering algorithm.
I looked up bicubic filtering and discovered that was a lot more complicated than I thought. It turns out that bilinear filtering when scaling an image up is really the right way to do things. I thought it was just a crappy approximation, but it's not. Bicubic is the clever trick.
So with this knowledge in hand, and not wanting to attempt to implement bicubic, I noticed that another fellow's perlin noise function used something called "cosine weighting". I didn't look at his code to see what he was doing cause it was too much of a bother to figure out, so I just implemented what I thought cosine weighting meant, and I guess I was right because the results look really nice.
Basically what I did was use a cosine to modify the location of the subpixel sample, on each axis during the bilienar filtering.
In layman's terms... If you take a cosine, and go from 0..180 degrees, the cosine goes in a nice sine curve from 1 down through 0, to -1.
Now normally, when you'ree bilinear filtering you'll step across the tile, and at each location figure out where you are 0..1 between the two pixels, and then multiply one of them by 1.0-L#, and the other by L#, and add them, and that gives you a weighted average.
Well what I did with the cosine was instead of simply using L#, I took L# and divided it by 180. This gave me an angle 0..180 which I coudl then input into my cosine. Once I did that, my cosine output a value between 1 and -1. But for my average I needed a vlaue between 0 and 1, so I added 1 to the value, and divided by 2. This gave me the value between 1 and 0 which I needed.
Now I had a value that went between 0 and 1, but it didn't move linearly between them at a constant rate... Instead it moved along slowly at first, then approaches 0.5 quickly, and then speeds away from it, and then slows down and approaches 1.0.
This basically pushes the colors of the pixels at the four corners towards the center of the square, making the area which is the average of the colors smaller. And it makes the areas around each pixel round instead of diamond shape.
Which got rid of those diamond artifacts.
And now we both know what cosine weighted averages are, unless I lost you somwhere back near subpixel sampling!
|