There are many types of inspring and beautiful fractals that you can explore once you’ve got a distance-estimate based raymarcher. We’re working up to a discussion of some really funky classes of fractal known as kaleidoscopic IFS fractals, but for today I want to talk about simpler iterative function systems to provide a bit of a primer!

Iterative function systems are the easiest type of fractal to understand and lead to an intuitive shape which can be easily understood. Probably the first fractal of this type I ever saw was the Koch curve. The principle of a Koch curve is beautifully elegant. Take the following set of objects…

And replace each of those objects with the same set of objects scaled to fit…

And again and again and again…

The script to generate this out of boxes is pretty simple and looks like the following… remember though that you don’t want to go too far down in the iteration depth because the number of primitives in each iteration is pow(4, iterations)!

rule main { recursions = 10 // koch iteration *2 koch } rule koch { {pos.x -= 1/3 kochbar} // left segment {pos.z += 0.09622504 // middle 2 {ry -=60 pos.z += 0.09622504 kochbar} {ry += 60 pos.z += 0.09622504 kochbar} } {pos.x += 1/3 kochbar} // right segment } rule kochbar { if (recursions < 1) {scale *= vec(1/3,1/3,1/30) box} else {scale *= vec(1/3,1/3,1/3) koch} }

Another iterative fractal that I've covered before is the pythagoras tree which I wrote an article on a *long* time ago. A quick image as a refresher...

There are lots of fun IFS fractals which you can find from a quick search on google, but the fun here starts to happen when we generalise these IFS fractals into distance estimators. To illustrate the principle let's start with the basic koch snowflake. As described before this is a sequence of 4 objects tied together to make the distinctive angle shape.

With distance estimators we can actually produce this shape by folding 3d space around a single object.

Let's start with a small bar that starts at -1 and continues to -0.3333 (-1/3rd). We're going to fold space back onto this primitive to build the basic shape of the koch curve. Let's start then with the basic primitive...

rule main { distancefunction(koch) distance } shader koch { diff = pos distance = box(diff, vec(0.3333,0.1,0.1), vec(-0.66666,0,0)) }

First off lets fold space along the point from -0.3333,0,0, in the direction of -0.8666,0,-0.5 (this effectively folds space around the angle of the triangle leading to the following simple shape.

shader koch { diff = pos diff = singlefold3d(diff, vec(-0.3333,0,-0), vec(-0.866,0,-0.5)) distance = box(diff, vec(0.3333,0.1,0.1), vec(-0.66666,0,0)) }

Next up we're going to fold space again, this time along the centre line to form the full basic koch primitive.

shader koch { diff = pos diff = singlefold3d(diff, vec(0,0,0), vec(-1,0,0)) diff = singlefold3d(diff, vec(-0.3333,0,-0), vec(-0.866,0,-0.5)) distance = box(diff, vec(0.3333,0.1,0.1), vec(-0.66666,0,0)) }

Now lets be a bit perfectionist and tidy up the messy corners. I'm just picking random numbers to make sure the the apex of the triangle is complete and these numbers fit. I'm sure I could do the trigonometry to work out the exact values, but it's late and I want to finish this article!

shader koch { diff = pos diff = singlefold3d(diff, vec(0,0,0), vec(-1,0,0)) diff = singlefold3d(diff, vec(-0.3333,0,-0), vec(-0.866,0,-0.5)) distance = box(diff, vec(0.5,0.1,0.1), vec(-0.66,0,0)) }

So I'm happy with that as the basic DE, but now it's time to do the iterative bit of an IFS fractal. The folds that were carried out above are going to be used again to make the fractal, but for that to lead to a fractal shape we have to start by "shrinking" the existing segment to be 1/3rd the size. This is achieved by *multiplying* space by a factor of 3. Because we've scaled space, we also need to divide our distance estimate by the same factor (3).

shader koch { diff = pos diff = (diff+vec(0.6667,0,0))*vec(3,3,3) diff = singlefold3d(diff, vec(0,0,0), vec(-1,0,0)) diff = singlefold3d(diff, vec(-0.3333,0,-0), vec(-0.866,0,-0.5)) distance = box(diff, vec(0.5,0.1,0.1), vec(-0.66,0,0))/3 }

And now we're ready to apply the folds again to iterate the fractal.

shader koch { diff = pos diff = singlefold3d(diff, vec(0,0,0), vec(-1,0,0)) diff = singlefold3d(diff, vec(-0.3333,0,-0), vec(-0.866,0,-0.5)) diff = (diff+vec(0.6667,0,0))*vec(3,3,3) diff = singlefold3d(diff, vec(0,0,0), vec(-1,0,0)) diff = singlefold3d(diff, vec(-0.3333,0,-0), vec(-0.866,0,-0.5)) distance = box(diff, vec(0.5,0.1,0.1), vec(-0.66,0,0))/3 }

Beautiful. Now my shader language doesn't have a repeat function (yet), so to iterate the fractal multiple times I'm just going to repeat the fold and scale instructions until we're at iteration 4 of the fractal. Note that we're now dividing the distance estimate from the final call by 81 (3 to the 4).

shader koch { diff = pos diff = singlefold3d(diff, vec(0,0,0), vec(-1,0,0)) diff = singlefold3d(diff, vec(-0.3333,0,-0), vec(-0.866,0,-0.5)) diff = (diff+vec(0.6667,0,0))*vec(3,3,3) diff = singlefold3d(diff, vec(0,0,0), vec(-1,0,0)) diff = singlefold3d(diff, vec(-0.3333,0,-0), vec(-0.866,0,-0.5)) diff = (diff+vec(0.6667,0,0))*vec(3,3,3) diff = singlefold3d(diff, vec(0,0,0), vec(-1,0,0)) diff = singlefold3d(diff, vec(-0.3333,0,-0), vec(-0.866,0,-0.5)) diff = (diff+vec(0.6667,0,0))*vec(3,3,3) diff = singlefold3d(diff, vec(0,0,0), vec(-1,0,0)) diff = singlefold3d(diff, vec(-0.3333,0,-0), vec(-0.866,0,-0.5)) diff = (diff+vec(0.6667,0,0))*vec(3,3,3) diff = singlefold3d(diff, vec(0,0,0), vec(-1,0,0)) diff = singlefold3d(diff, vec(-0.3333,0,-0), vec(-0.866,0,-0.5)) distance = box(diff, vec(0.5,0.1,0.1), vec(-0.66,0,0))/81 }

I'll leave converting this DE into the koch snowflake to the reader, but in case you want to know how it looks, here goes!

This basic DE is a simple way of introducing the principles that we're going to need to understand kaleidoscopic IFS fractals, which are coming up in the next article! If you'd like to play with the scripts above just click download at the top of this page to pick up the latest version of Wooscripter.

For updates and all the latest news on the progress of wooscripter, follow my twitter feed at @dom767.

Hi, Dom!

Not working for me singlefold3d…. This new option, which I do not have? (((((

http://i60.fastpic.ru/big/2015/0428/59/ea5a863c18c087e8960820cffdc69459.jpg

Apologies, I forgot to upload a new version of Wooscripter that supports this function!! Added now.

Hi, Dom!

Thanks, now it works!