Barnsley's Leaf

Barnsley's Leaf

Sierpiński’s Triangle, Game Design and The Origins of Life

·

7 min read

Draw 3 points and label them A, B and C. Then, number each corner accordingly: A: 1,2, B:3,4, C:5,6. Mark a fourth point anywhere on the page. Take a 6-sided die and roll. If it is a 1 or 2, mark another point halfway from your first point to corner A —and likewise for corners B or C. As you roll the dice, your next point will jump randomly halfway towards each corner of the board.

This is a slow process —but once you use a computer to iterate this faster, an unusually clear pattern begins to appear.

This is Sierpiński’s Triangle. It is a fractal pattern which has been created by randomly plotting points within a confined directional space. This method has been used to create other patterns in 3D modelling and game design.

One of the most famous images generated by iteration methods is Barnsley’s Fern. Similar to Sierpiński’s Triangle, Barnsley's Fern is an iterative process but involves much more complex transformations.

The fern is created by iteratively applying a set of mathematical transformations to a point in the plane. These transformations involve scaling, rotating, and translating the point. Each time the transformation is applied, the resulting point is plotted on the plane. As the process is repeated many times, a complex pattern emerges that resembles a fern. The fern is self-similar, meaning that it contains smaller copies of itself at different scales. It is also a fractal, meaning that it has a fractional dimension that is greater than its topological dimension, just as Siepinki’s triangle does.

Although it is technically possible to draw Barnsley's Fern by hand with a pen and graph paper, the sheer number of iterations required, which can reach tens of thousands, practically requires the use of a computer. Today, numerous computer models of the fern are popular among mathematicians. As long as the correct mathematical transformations are programmed into Barnsley's matrix of constants, the same fern shape will always be produced.

The fern is generated by iteratively computing new points starting from the origin (x0 = 0, y0 = 0) and randomly applying one of four coordinate transformations. The first transformation is selected 1% of the time and creates the base of the stem. The second transformation is chosen 85% of the time and generates successive copies of the stem and bottom fronds. The third and fourth transformations are each selected 7% of the time and create the two bottom fronds on the left and right. The fractal nature of the process guarantees that each frond is a smaller replica of the whole fern.

By changing the coefficient parameters applied to the transformation, you can form multiple ‘mutations’ of the fern:

More coefficients can be found here: https://www.dcnicholls.com/byzantium/ferns/fractal.html

In game design, especially designing a forest for your player to roam through, designers are turning to simple iteration programs which can draw these shapes based on simple algorithms. Instead of drawing them individually and repeating them in 3D space, one can generate them naturally, and then iterate them by changing the parameters to customise for different factors such as light, air density, wind and variation, thereby creating a realistic setting rather than copying a single drawing.

This method uses far less computational power and puts less stress on the GPU — and takes much less time to create and makes the gameplay more realistic.

Skyrim

The Elder Scrolls: Skyrim (2011)

Assassin's Creed: Black Flag (2013)

The Last of US (2013)

It’s not surprising that something resembling a natural lifeform is created by iterating simple algorithms. Yet the process of creating true life is still a mystery and one which leaves much work to be done on the biology and physics fronts. When biologists lack the responsibility to understand these complex processes of creating life, the opportunity for physicists arises. Biology is multi-component, multi-dimensional and requires a physical description of the chemical circus which goes on in the cellular world. I welcome many physicists —especially theorists —to tackle some of the basic problems in biology. Exactly how, where, and when did life on Earth originate? Which, if any, of the many hypotheses is correct? What were the metabolic pathways used by the earliest life forms? Exactly how and when did different groups of viruses originate?

These are some of the toughest unanswered questions in biology today, and a physical description involving iterative chemical reactions and mathematical beauty could be a resolution. The biggest issue with replicating the origin of life is time. With Sierpiński’s triangle, it takes over a million iterative pathways to finally generate a conceivable picture. Furthermore, according to what and when is that picture appearing? Did the picture (and perhaps life) appear at the one-hundredth or the one-thousandth iteration? When does the sequence of chemical reactions multiply themselves to resemble something akin to life?

Barnsley himself speculated that these ‘codes’ are understood fundamentally by the genes of the plant:

IFSs [Iterative Function Systems] provide models for certain plants, leaves, and ferns, by virtue of the self-similarity which often occurs in branching structures in nature. But nature also exhibits randomness and variation from one level to the next; no two ferns are exactly alike, and the branching fronds become leaves at a smaller scale. V-variable fractals allow for such randomness and variability across scales, while at the same time admitting a continuous dependence on parameters which facilitates geometrical modelling. These factors allow us to make the hybrid biological models... ...we speculate that when a V -variable geometrical fractal model is found that has a good match to the geometry of a given plant, then there is a specific relationship between these code trees and the information stored in the genes of the plant.

—Michael Barnsley et al.

These questions are also philosophical (and perceptive) in nature, as your resolution of the problem ranges from the creation of the leaf to the cells that make up the leaf, to the molecules which make up the cells, cells within cells within cells….I have no doubt that biology is the next frontier for mathematicians and physicists who are exploring these problems of understanding our natural world.

If you enjoyed this article and would like to generate some of the plots mentioned in this article, copy this Python code into your IDLE making sure to have the correct libraries installed:

Barnsley's Fern

import matplotlib.pyplot as plt
import random

x = 0
y = 0

fig, ax = plt.subplots()
fig.patch.set_facecolor('black')
ax.set_facecolor('black')

# hide the x and y axes
ax.set_xticks([])
ax.set_yticks([])

for n in range(100000):
    ax.plot(80 * x, 37 * y - 252, '.', color='green', markersize=0.1)
    r = random.random()
    if r < 0.01:
        x, y =  0.00 ,  0.16 * y
    elif r < 0.85:
        x, y =  0.85 * x + 0.04 * y, -0.04 * x + 0.85 * y + 1.60
    elif r < 0.93:
        x, y =  0.20 * x - 0.26 * y,  0.23 * x + 0.22 * y + 1.60
    else:
        x, y = -0.15 * x + 0.28 * y,  0.26 * x + 0.24 * y + 0.44

plt.show()

Sierpiński’s Triangle

import numpy as np
import matplotlib.pyplot as plt
import random


#Plot the 3 initial points of the triangle

triangle = [(1,2),(3,4),(5,6)]

p = np.sqrt(75)
x = [0, 5, 10]
y = [0, p, 0]


#Create a random point on the board
initial_x = random.uniform(0,10)
initial_y = random.uniform(0,10)

x.append(initial_x)
y.append(initial_y)

#Create a random dice which decides on the point

new_point = []

for i in range(3,100000):
    direction = random.randint(1,3)

    if direction == 1:
        new_point = (np.array([x[i],y[i]]) + np.array([x[0],y[0]]))/2

        new_x = new_point[0]
        new_y = new_point[1]
    elif direction ==2:
        new_point = np.array([x[i],y[i]])+(-np.array([x[i],y[i]]) + np.array([x[1],y[1]]))/2

        new_x = new_point[0]
        new_y = new_point[1]
    else: # The 3rd corner
        new_point = np.array([x[i],y[i]])+(-np.array([x[i],y[i]]) + np.array([x[2],y[2]]))/2

        new_x = new_point[0]
        new_y = new_point[1]

    x.append(new_x)
    y.append(new_y)


fig, ax = plt.subplots()

# set background color to black
fig.patch.set_facecolor('black')
ax.set_facecolor('black')

# hide the x and y axes
ax.set_xticks([])
ax.set_yticks([])

plt.scatter(x,y, s = 0.05, color ='green')
plt.show()