affine transformation fractal glitch

The Sierpinski Triangle 

The Sierpinski Triangle is an example of an Affine Transformation Fractal.  The Axiom, or initial shape is the Tetrahedron, the first of five Platonic Solids.  Iteration 1 is the Triforce from Zelda.  I can't imagine a more perfect starting point for my exploration.

The algorithm is simple: the axiom is replaced by smaller copies of itself with linear or affine linear transformations applied.  These transformations include simple matrix or vector addition and multiplication to produce translation, rotation, scaling and reflection.  As long as these transformations preserve parallel relationships within each subsequent axiom they can be called affine.

Another name for this algorithm is the Multiple Reduction Copy Machine, MRCM.  I set out to build my own version in Unity C# starting with a class called AffineTransformationFractal that extends the MonoBehaviour class.  It has two main functions, Generate() and Reproduce().  In Generate() I recursively iterate to the specified depth, calling Reproduce() on each instance of the axiom.   

Here is the code for Generate()... 

// Unity C# Generate method
// member of AffineTransformationFractal : MonoBehaviour 
public void Generate() {
    List<GameObject> newMembers = new List<GameObject>();
    List<GameObject> children = new List<GameObject>(); 

    for(int i=0; i<iterations; i++){ 
        for(int m=0; m<members.Count; m++) { 
            children = Reproduce( members[m], i, m );
            // add children to the list of new members
            for( int c=0; c<children.Count; c++){
                newMembers.Add( children[c] );
        // refresh the list of members
        for( int nm=0; nm<newMembers.Count; nm++ ){
            members.Add( newMembers[nm] );
    Destroy ( generator );

The original Reproduce() function worked just fine, but it provided an inefficient artist workflow when adding new shapes and experimenting with their transformations.   My first implementation stored the affine transformations as a series of Vector3 class members.  I got the Vector3 values by observing objects in Maya and recording their values in my code.  An obvious hack, but It served as a low-tech way to get the first version up and running.   

Seen here is the 7th iteration Sierpinski triangle explored in the Unity 3D editor. It was created using the original Reproduce() method I first threw together in the hotel room on 3/06.

Mandelbrot's book, the Fractal Geometry of Nature suggested a more elegant implementation of the Reproduce() function.  He described the creation of the Koch curve where the Initiator (or axiom) is replaced by a Generator object comprised of multiple transformed copies of itself.  I realized all I had to do was save an additional 3D asset with the copies moved into place and then have Reproduce() instantiate that asset in place of each axiom.  This way Unity handles of all vector transformations automatically with no need for hard-coded values.  

This simplified technique enabled me to build all sorts of affine transformation fractals including the Koch fractal curve as seen below.  Pardon the rough edges visible in the low iterations, it was made while riding in the passenger seat of a car using only my laptop trackpad for input.  That's how easy it was to use the new technique, it didn't even require the use of Maya.

I have always been fascinated by the Koch snowflake.  A curve with theoretically infinite length and no tangents, thus defying the rules of conventional 2d curves.  Mandelbrot called it a Teragon or monster shape because of this and claimed that it exists somewhere between the first and second dimensions.  1.26(...) Hausdorff dimensions, to be exact.  I'm going to explore it more deeply and present the results in a future post.  

Here is the new and improved Reproduce() function that I used to create the Koch curve and everything thereafter...  

// Unity C# Reproduce method
// Member of AffineTransformationFractal : MonoBehaviour
List<GameObject> Reproduce( GameObject axiom, int i, int m ) {
    List<GameObject> children = new List<GameObject> ();

    // create the generator object as a child of the axiom's parent
    GameObject newGenerator = Instantiate (generator);
    newGenerator.transform.SetParent ( axiom.transform.parent );

    // copy over transforms from axiom to children
    newGenerator.transform.localScale = axiom.transform.localScale;
    newGenerator.transform.position = axiom.transform.position;
    newGenerator.transform.eulerAngles = axiom.transform.eulerAngles;

    // add children to the list of children
    for( int c = 0; c < newGenerator.transform.childCount; c++ ){
        Transform child = newGenerator.transform.GetChild(c);
        children.Add( child.gameObject );
    Destroy ( axiom );
    return children;

This easier way of setting things up opened the door for a lot of fun artistic exploration.  I tried out a variety of shapes including the rest of the Platonic Solids.  Here is a shot of what the dodecahedron looks like as an affine transformation fractal.  

That's a lot of loot engrams. 168421 to be exact, but only one exotic.



Głîtçh - "A computer glitch is the failure of a system, usually containing a computing device, to complete its functions or perform them properly." 

The next step was to bring back the glitch techniques from the old batcave sessions.  

The easiest starting point was to set the camera background to not refresh.  This causes each frame of rendering to pile up into a composite palimpsest image.  I have been calling this technique Phase Space Painting because of how each still image shows the result of motion over time.  This is similar to math and scientific visualization where a linear function is graphed repeatedly over a localized Phase Space.  Certain patterns can be observed this way that would not otherwise be visible as found in Lorenz Strange Attractors.  I got a lot of mileage out of this technique in the early batcave days.  In Unity this is done by setting the Camera.clearFlags to Depth or Nothing as opposed to the usual Skybox setting.  

It doesn't look like much in a static scene, it needs animation.  So, to get things moving I made a quick WaveGenerator utility object and used it to drive a WaveAnimator component that oscillates any transform value over time.  

Here it is applied to rotation on the Sierpinski Triangle:  


I plugged the same WaveGenerator into another script that would lerp between two colors resulting in a new ColorAnimator component.  The first version I made, which I lived with for way too long included only two hard-coded fog color values.  But that's all I needed in order to venture back into the untamed psychedelic world of the early batcave days.  With the ColorAnimator applied to the depth fog of the main camera in the Unity scene I was instantly greeted by such vibrant colors.  

I am strangely drawn to the combination of blue and pink.  Their interactions are rich and intense, calling out to me.  For some reason I feel so compelled explore this possibility space.  


Next, I sketched out code for a basic Clip Plane Slicing implementation.  This immediately yielded interesting results.  Clip Plane Slicing is a simple technique where I set the camera clip planes very close together and over time move them through objects to render cross-sections.  This works great in combination with Phase Space Painting and animated depth fog colors.  

Here are some of the initial results:


Over the next few sessions these kinds of fractal mandala images were arising.  I had a general idea where I was going with this, but over time new patterns emerged that I couldn't have predicted.  That's when I really start having fun with my art.  Now I need to let go of any intentions I might have, get out of the way and let it take on a life of its own.