When I learned about
iterated function systems, I became very interested in them what can be done
with them. Despite not having gone over
the subject of 3D iterated function systems explicitly, there was no reason why
any of the subject matter learned in class could not be applied in 3D. It seemed like there would be non-trivial
problems to solve in converting some of the classic 2D fractals to 3D, and
hence I thought this would make a good topic for my final project.
This paper describes the
nuisances of adapting a IFS rendering algorithm to 3D. A companion program was created called IFS3d
which was made to accompany this paper and show some of the results. IFS3d’s use is explained in the next
section. We will explore the process of
adapting many famous 2D iterated function systems (such as Sierpinski’s Gasket)
to their 3D counterparts.
IFS3d is a program created
to accompany this paper, so that some of the elements of this paper may be
tested and demonstrated. It is written
in C++ and the source code is available.
IFS3d uses SDL and OpenGL to setup and render to the graphic display.
IFS3d is executed from the
command line. IFS3d take one parameter,
the name of the input file to open and read the IFS to render from. For example you may type IFS3d Gasket3D.ifs to start IFS3d displaying a 3d version of
Sierpinski’s Gasket.
When IFS3d is opened, it
will initialize with the camera looking at the center of the fractal. You can control the position of the camera in
various ways through the mouse. When the
left mouse button is pressed, mouse movements will result in rotations of the
camera. If both the left and right mouse
buttons are pressed, vertical mouse movements will be interpreted as zooming in
and out of the fractal. Pressing the ESC
key will quit the program.
When the number key 1 is
pressed, the camera will be set to a perspective projection (default). The camera can be set to an orthographic
projection by pressing 2. Orthographic
mode may be helpful in examining the 2d appearance of a 3d fractal from some
angle. Finally if 3 is pressed, the z
values of the points will be interpreted as time values, and the remaining x
and y coordinates are plotted as if we were rendering a 2d fractal. When in the mode resulting from hitting 3, z
values will continuously move from 0 to 1 over 5 seconds, and then repeat.
One may notice 8 red dots on
the display when moving the camera around.
The dots highlight the corners of the unit box (0,0,0) – (1,1,1). They are displayed to give a sense of
scale. Notice how fractals such as
Sierpinski’s Gasket always stay within the box.
The IFS file is simply a
text file. It is parsed as follows:
Name of IFS
iterations IterationCount
functionCount NumberOfFunctions
VariationName Weight a b c d e f g h j k l m
… (NumberOfFunctions times)
All italics text in the
above template means user specified values.
All non-italics text indicates a string literal that must be typed
exactly that way.
Name of IFS is simply any string terminated by a new line character which will be
used as the title of your IFS. IterationCount is the number of points that will be iterated (and
plotted). The higher this number is, the
denser (and more accurate) your IFS’ fixed point will appear. NumberOfFunctions is the number of functions that are part of the
system.
The next lines (and there
will be NumberOfFunctions of
them), define the functions that make up the IFS. VariationName can be either linear, sinusoidal or spherical. Choosing linear
will give you a standard affine transformation.
Choosing either sinusoidal or spherical will apply an extra mapping to the points after they
have been multiplied by the affine matrix.
This feature is an afterthought and not supported very well, so most
examples provided simply use linear. Weight is the weight that will be given to the current
function when the IFS plotting algorithm needs to choose a random function in
the system. The number is relative to
the total weights of all functions. The
following numbers represent entries in a 4x4 affine matrix as follows:
a b c
d
e f g
h
j k l
m
0 0 0 1
The best way to learn the
IFS file format is of course to look at any of the provided examples.
Although most aspects of
viewing fractals in 2D are unchanged when viewing them in 3D, there are still
some subtle differences. In 2D your
perspective is normally fixed, in that the resolution of the screen doesn’t
change, and so most algorithms simply snap every point produced to the closest
pixel on the screen. This is not
necessary (and even undesirable) in 3D, since the camera may zoom in or out or
rotate, all of which would look bad if every point was snapped to a grid.
Points then, are instead
stored exactly as they are generated.
The points are generated once at the beginning of IFS3d execution and
then they are simply re-rendered every frame, transformed by the camera
transform. Since the points are drawn in
their exact locations, it is possible to zoom in on one area of the fractal
until you can see individual points, and then zoom in farther right in to one
single point.
Although obvious, it’s worth
noting that no changes need to be made to the point generating algorithm, as it
works for all dimensions.
This section will analyze a
number of different popular 2D fractals, and how one would go about importing
them in to a 3D environment. It should
be noted that all 2D fractals can be created within a 3D environment by simply
j = k = l = m = c = g = 0, and treating the remaining values a, b, d, e, f, and
h as you would in a standard 2D affine transformation.
Sierpinski’s Gasket is the
popular fractal of a triangle with a triangle cut out of it (creating 3
sub-triangles of which this step is applied recursively).

Figure 1: Sierpinski's Gasket
in 2D (Gasket2D.ifs)
Sierpinski’s Gasket can be created by using 3 affine functions:
0.5 0 0 0 0.5 0
0 0.5
0 0.5 0 0 0
0.5 0 0
0 0 0 0 0
0 0 0
0 0 0 1 0
0 0 1
0.5 0 0 0.25
0 0.5
0 0.5
0 0
0 0
0 0
0 1
Which maps the unit cube in
to 3 unit squares (with z = 0, this is 2d) in a triangle formation.
One would imagine that a 3D
version of Sierpinski’s Gasket might have the form of a pyramid instead of a
triangle (or an extruded triangle).
Similar to how Sierpinski’s Gasket was constructed in 2D, we may
visualize 4 boxes lying on the ground, with 1 box sitting on the middle of all
of these. One may visualize that if we
subdivide these 5 boxes one more time, we will have the top pyramid using as a
base the bottom 4 pyramids, and we realize that this solution may be
feasible. We test our solution by
entering following matrices in to IFS3d (one function for every box, positioned
in each different location). Since we
are dealing with 3 dimensions now, we must not project away the z values to
0. The matrices follow:
0.5 0 0 0 0.5
0 0 0.5
0 0.5 0 0 0 0.5
0 0
0 0 0.5 0 0 0
0.5 0
0 0 0 1 0 0
0 1
0.5 0 0 0.5 0.5 0
0 0
0 0.5 0 0 0 0.5
0 0
0 0 0.5 0.5 0 0
0.5 0.5
0 0 0 1 0 0
0 1
0.5 0
0 0.25
0 0.5
0 0.5
0 0
0.5 0.25
0 0
0 1
And indeed, this gives us a
3D version of Sierpinski’s Gasket.

Figure 2: Sierpinski's
Gasket in 3D (Gasket3D.ifs)
One might define a 3D Cantor
Set to be {x,y,z | x belongs to C, y belongs to C, z belongs to C}. Under this definition we can see that the set
is contained within 8 cubes of side length 1/3, each in one corner of the unit
cube. Under this reasoning we may
proceed in the same fashion as we did for Sierpinski’s Gasket (by shrinking the
unit cube by 1/3 and then transforming it to a corner of the unit cube) to
obtain an 8 function system which converges to the Cantor Set in 3D.

Figure 3: Cantor Set in 3D
(Cantor3D.ifs)
The fern is a much trickier
IFS to convert to 3D, partly because it’s a trickier IFS than the previous
systems even in 2D. The 2D fern can of
course be displayed in a 3D environment, but one might expect to see the
branches popping out in a true 3D version of it (so perhaps it will be more of
a bush than a fern).

Figure 4: Fern in 2D (2DFern.ifs)
The fern is composed of four
functions. One of them is the stem, and
it projects all points on to the Y axis to form a straight line. Two functions are used to place leaves on the
left and right. These are achieved by
transforming up in the Y direction, scaling down and rotating around the Z axis
by roughly 30 degrees. The last function
represents the rest of the fern, and transforms it by shrinking it slightly,
rotating it around the Z axis slightly, and transforming up in the Y direction
a bit. The system can be examined by
looking at the example Fern2D.ifs.
A first attempt at
converting the fern to 3D might be to modify the function responsible for
drawing the rest of the fern so that it includes a rotation around the Y axis
(as well as its rotation around the Z axis).
This may be accomplished by taking the original matrix, F, and obtaining
the new matrix, F’ as follows:
F’ = F * RotY
where RotY is a matrix
representing a rotation around the Y axis.
A rotation around the Y axis can be described as:
cos(ANGLE) 0 sin(ANGLE) 0
0 1 0 0
-sin(ANGLE) 0 cos(ANGLE) 0
0 0 0 1
where ANGLE is the angle of
the rotation. Entering this new system
(Fern3D.ifs) we do indeed obtain a 3d fern, but it is very bushy and difficult
to see what is happening.

Figure 5: Fern in 3D, first attempt
(3DFern.ifs)
Certainly there must be a
more visually concise system. Much of
the incoherency of the above image is caused from the leaves also being bushy
(and so the leaves of the leaves, and etc…).
We need to find a way to keep the 3d rotations while restricting the
rotations within the leaves. One way to
accomplish this would be to, for each leaf, project our fern to the XY-plane,
and THEN rotate it. This process is
similar to how the stem is constructed, except instead of projecting to an
axis, we are projecting to a plane. A
matrix that projects to the XY-plane is given as:
1 0 0 0
0 1 0 0
0 0 0 0
0 0 0 1
And so, if we have the
original transformations for the two leaves, T1 and T2,
we can form T1’ and T2’ as follows:
T1’ = T1
* Proj
T2’ = T2
* Proj
Where Proj is the projection
matrix defined above. Running the new
system through IFS3d gives a much prettier and coherent 3D version of the fern
(ReFlattened3DFern.ifs)

Figure 6: Fern in 3D with flattened leaves (ReFlattened3DFern.ifs)

Figure 7: Flattened leaf fern viewed from above
The top down view makes it
obvious how flat the leaves really are though (even though this is not obvious
from most other angles), but perhaps we can fix this as well by having the
leaves make a slight rotation around their Y-axis after they have been
projected. This can be accomplished by
forming a rotation matrix around the Y-axis, RotY, and instead construct T1’
and T2’ as follows:
T1’ = T1
* RotY * Proj
T2’ = T2 *
RotY * Proj
Since the projection is the
last matrix in the matrix multiplication chain, it will be a plied before the
rotation around the Y-axis, so the rotation will not be lost to the projection.

Figure 8: Fern with leaves rotated around Y (Final3DFern.ifs)

Figure 9: Final version of 3D fern viewed from above
The final fern IFS is given
in Final3DFern.ifs.
Although all of the concepts
of iterated function systems remain the same, regardless of how many dimensions
we’re operating in, there are still some subtle practical considerations to
take in to account when moving from 2D fractals to 3D fractals. The algorithm itself, for example, cannot
assume anymore that we are operating on a grid, and so we must store all exact
values for points.
Clearly the set of 3D fractals contains the
set of 2D fractals (we can always project to 0 on the z-axis) and with examples
like the 3D fern, we see that there are many more complicated iterated function
systems that cannot be generated in 2D.
Given the proper knowledge of how matrix transformations can be applied
to functions in IFS to produce intended results, we can sculpt many different
shapes in 3D simply by plotting points.
Gulick, D., Encounters with
Chaos, Pp. 1-320, ©McGraw-Hill Education, 1992.