About Code Food Work

Drawing a Sunflower with Code

Date: November 2018 Type: Side Project Role/Team: Lead Developer Code Source: Code Snippets Below
Tool(s) Used:
  • Processing
Sunflower Generative Art

The first time I encountered Generative Art was through Daniel Eden's blog post on Drawing with Numbers. I used to be an avid drawer as a child and seeing that you can create visually interesting pieces with numbers, algorithms, and randomness was fascinating to me. You can see more of his generative art pieces here. In his post, you will see that each piece has an instruction that he followed to generate a piece. In Matt Deslauriers' video on Canvas WebGL from Frontend Masters, he mentions the conceptual artist, Sol LeWitt, and its relevance to Generative Art. What Sol LeWitt did was to provide an instruction and let other people to draw it. His instructions are very much like code and they never reached the exact precision to allow some randomness to it so that it would be unique.

I followed Dan's advice from his blog post to use Processing instead of JavaScript since Processing is faster and I wanted to write code in a new syntax – in this case, Java syntax. I later appreciated Java's strict rule – for example, 1. How its array is a fixed size – which means I cannot just randomly increase my array later in my code, 2. Unlike JavaScript, its constructor must match its class name, 3. When passing an argument or declaring a variable, you also have to pass its data type next to it.

I was inspired to create this after watching many video tutorials of Daniel Shiffman (another Daniel in the same post?!) on The Coding Train. I have always admired Creative Coders' ability to create something so visually exciting by using math and physics. It was intimidating at first to implement or recall all the math related subjects (especially, the trignometry). But with Daniel Shiffman's video tutorials, it has been a fun journey 🤗. So thank you, Daniel!

Let's dive into the process of creating a sunflower 🌻

1. Creating an Individual Sunflower Seed

sunflower example step01_sunflower_seeds

As you can see in the picture of a sunflower head, not all seeds have the same shape. I simplified and grouped them into 3. The core inner part has the triangular shape seeds that are pointing towards the center (I made it less pointy in the code because I liked the look of it better), its surrounding inner area has a rounded square shape, and its border seeds have starfish shapes. In order to mimic these variety of shapes with just numbers, I used Supershapes Formula by Paul Bourke. Given certain input number value, this formula can mimic natural forms. If you would like to know more about 2D Supershapes, the link to the video tutorial by Daniel Shiffman is here.

Code Snippet not loading? Click here to see the code

In the constructor, there are 4 variables – n1, n2, n3, m. This is where we assign real numbers to determine the shape of the seed. toUpdateShape() is where we call supershape() to determine its shape and its position of the seed to mimic the Sunflower's spiral pattern. This is the blue print for each individual seed for its Particle System to define and use later.

2. Creating Sunflower Seeds Particle System

As I mentioned earlier, array is fixed in Java so I set the maximum size 2800 when creating the array. toCreateInnerHead() is where I am storing a new instance of the SunflowerSeed class as each array's value – a total of 2800 seeds. We are passing number values as parameters to create the shape that we want. Its core inner seeds are using asymmetric forms with a value of n1 = 60, n2 = 55, n3 = 30, and m = 1. Its surrounding inner area is using a value of n1 = n2 = n3 = 1 and m = 2 to add rotational symmetry to the shape. Its border seeds are using values that create starfish shapes n1 = 0.1, n2 = 1.7, n3 = 1.7, and m = 5. You can see more shapes using different numbers in Paul Bourke's article that I mentioned previously.

Snippet not loading? Click here to see the code

toCreateOuterHead() is used to create the Sunflower's spiral pattern. radians(137.5) is the magic number. This formula is the planar model that can be found in this document on page 2 to create Phyllotaxis. More in-depth tutorial on Phyllotaxis can be found here by Daniel Shiffman.

angle = n ∗ 137.5, r = c√n

n is the number of dots and c contributes to a scaling factor. If you change c from 11 to 1, you will see that our seeds get extremely small. Since this formula gives an angle and radius, we can convert it to x and y by using Polar Coordinates (r,θ) to Cartesian Coordinates (x,y) transformation x = r * cos(angle); y = r * sin(angle).

3. Creating Sunflower Petals

Snippet not loading? Click here to see the code

class SunflowerPetals is the blue print of our petals. Later in our setup(), we are going to pass the sunflower head's magnitude (length) into our newly created SunflowerPetals instance to position the petals correctly around its sunflower head. In between beginShape() and endShape(), we can set any number of arbitrary vertices. You can set vertex or any kind of vertex over and over again. In createPetals(), we are calling drawPetal() to draw around the circle. We are converting from Polar Coordinates (r,θ) to Cartesian Coordinates (x,y) to draw vertices around the circle. Curves require additional points that control the entry and exit of the curve. We have vertex(0, 0) in the beginning because all shapes created with beginShape() must start with a vertex() to define the starting point of the shape.

Having only one bezierVertex() can be enough as petals but I used two to give more volume to it. noise() returns the Perlin noise value, which is a random sequence generator that is more natural than the standard random() function. This creates the look of threads around the petals. I encourage you to play with bezierVertex() with random number values. I got some crazy looking shapes during my experiments. For example, the below bezierVertex() creates crazy circular + sunflower petals shape.

bezierVertex(50, -60 * noise(frameCount + 3), 100, -30 * noise(frameCount + 1), +150 * noise(frameCount + 1), -50);
bezierVertex(100, 30 * noise(frameCount + 3), 50, 30 * noise(frameCount + 1), 0, 0);

4. Its Setup

Snippet not loading? Click here to see the code

This is where we declare SunflowerSeeds and Petals variables and assign them a new instance of the classes that we have created – SunflowerSeedsSystem and SunflowerPetals. It's important that we call Petals() after SunflowerSeeds() to pass in the correct Seeds (or Sunflower Head) magnitutde.