I recently took a trip down the intersection between art and programming after some discussions I had with a designer at work comparing what we do every day. This got me thinking about the viability of code as a means of artistic expression.

This idea doesn't seem too far fetched at the surface level; after all, it's easy enough to view programming as a craft when looking at fields like the video game industry or digital art careers such as modern art and special effects. However, these tend to focus more on the application of software as a medium for story telling. I wanted to take this thought a step further by posing the question can programming or code be the primary medium through which artists express themselves?

Unsurprisingly, such a field does exist. It's known as Generative art. Wikipedia defines quite succinctly as

... art that in whole or in part has been created with the use of an autonomous system.

For a more elaborate and insightful definition, I invite you to read a fantastic article by Jason Bailey on the subject[1].

Writing an automated tool to generate art

I tasked myself to generate an impressionist[2] style painting in code. I wanted to achieve a similar feel to the starry night by Van Gogh. This requires some logic to guide the brush strokes in the background which can be accomplished using a Perlin noise flow field[3].

Perlin noise aims to create a random sequence that has a more harmonic sequence as opposed to standard Random Number Generators (RNG). It's possible to visualize this in 2 dimensions by normalizing it between 0 and 255. This creates an effect similar to the render clouds function in Photoshop. Using the same technique on a standard RNG function, produces a result similar to static on an old TV.

noise

Taking the noise in 2 dimensions can be abstracted into a sequence of vectors that have a similar but different direction as their closest neighbors.

val noiseValue = noise(x, y)
val vector = Vector.fromAngle(noiseValue * 2 * PI)

flow-field

Applying this field to particles placed on the canvas by allowing their magnitude and direction to be influenced by the flow field.

fun applyForce(force: PVector) {
    acceleration.add(force)
}

After a few iterations with a strong enough magnitude applied, they begin to cluster in the general direction of the field.

random

After a few thousand iterations, there is a clear clustering around lines of the field.

clustering

To simulate brush strokes we want to start off with really large particles and gradually make them smaller as well as short-lived so they only apply a color selected from the same position to the canvas for a brief moment. Once a particle reaches the end of its life, it can be randomly placed on some other part of the canvas and assigned a new color. This process can be repeated indefinitely or until the artist is satisfied with the resulting image.

private fun renderParticle(p: Particle) {
    if (p.life < 0) {
        p.reset(createVector(), life = getLifespan())
    }

    if (p.color == null) {
        p.color = sourceImage.get(
            p.position.x.toInt(), 
            p.position.y.toInt()
        )
    }

    applyFlowFieldToParticle(p, flowField)
    p.update()
    matrixScope {
        ...
        strokeWeight(weight)
        line(
            p.position.x, 
            p.position.y, 
            p.previousPosition.x, 
            p.previousPosition.y
        )
        ...
    }
}

Here's a sample output

glaciers

And the source image to compare

glaciers-original

My implementation was done using the Processing SDK directly in a Kotlin project and is available on GitHub.


  1. Bailey, J. (2018). Why Love Generative Art?. [online] Artnome. Available at: https://www.artnome.com/news/2018/8/8/why-love-generative-art [Accessed 11 Nov. 2018]. ↩︎

  2. Medium. (2018). Generative Impressionism – Matt DesLauriers – Medium. [online] Available at: https://medium.com/@mattdesl/generative-impressionism-afa98ccb97da [Accessed 11 Nov. 2018]. ↩︎

  3. David's Creative Coding. (2018). Perlin Noise Flow Field. [online] Available at: https://davenewt.github.io/perlin-noise-flow-field/ [Accessed 11 Nov. 2018]. ↩︎