Thursday, November 17, 2016

Fighting the Swiss

No, this post isn't about a battle with the people of Switzerland.  Instead, it regards a struggle to implement the "Swiss turbulence" algorithm that Giliam de Carptentier wrote about in a blog post. It is also referred to as erosive noise in his article with Radael Bidarra, "Interactive GPU-based procedural heightfield brushes."  It produces more realistic looking mountain shapes than the ridged hybrid fractal that was one of the best I'd previously found, of which I've shown screenshots.  The blog post contains the code for an implementation in Nvidia's Cg shader language, but I'm coding in C# for execution by the CPU, not GPU.  Fine, I thought, I'll just port it...

Except it relies upon computing the derivative of Perlin noise, the included implementation of which
was implemented totally differently.  In the implementation in the article, the traditional permutations and gradient arrays are implemented as two-dimensional textures containing vectors derived from RGB values, rather than one-dimensional arrays of integers and floating-point numbers.  Ugh.  OK, maybe I can still deal with this, I think to myself, and give it a go.  Alas, over the course of an hour I become very frustrated, as a whole slew of issues come up.  The vector structures I'm using from OpenTK don't support adding or subtracting vectors and single floats.  Fine.  I implement extension methods, which are rather clunky in comparison to actual operators.  That works fine, but the rest of it I just can't seem to get it right.  But then I remember that article I mentioned, which references de Carpentier's source for the Perlin noise derivative, Inigo Quilez.

A quick search turns up Inigo Quilez's web page on the subject.  But it involves calls to functions such as myRandomMagic and iGetIntegerAndFractional, that aren't defined anywhere I could find on Quilez's web site.  The second one was easy enough to puzzle out by comparison with de Carpentier's code (it computes the integral and fractional portions of a number), but myRandomMagic was more problematic.  So I do a Google search and find an implementation of Quilez's code... in Go.  I've never used Go before, but the syntax was easy enough to puzzle out, and I used what I found to construct the missing function myRandomMagic, which was simply a lookup from the gradient and permutations arrays.  Fine.  Code finally done.  Run.

Exception!  The code doesn't handle negative coordinates well. (For all I know, it doesn't handle large coordinates well, either.)  I guess its time to go through my Perlin noise implementation and see how its addressed there.  Certainly it isn't addressed at all by the example code I based my implementation on.  But that'll have to wait for another day.  I'm going to call it a night, and resume my fight  with the Swiss tomorrow evening, after work.

No comments:

Post a Comment