One of my programming inspirations is the youtube channel The Coding Train, which frequently features breakdowns and implementations of scholarly articles that can be used for generative art. While I started watching as a beginner, I’ve recently found some success looking into their source material for more information.
I’ve also been trying to learn the processing-adjacent library OpenFrameworks, which isn’t covered by the Coding Train channel, so I decided to go searching out my own source to re-implement.
This project is an implementation of the lichen pattern generation algorithm described by Robert Sumner in his thesis, Pattern Formation in Lichen. It’s written in C++ using the OpenFrameworks library, and I did it without any external resources beyond the OpenFrameworks documentation.
The system essentially works by using random walkers to emulate the two forces that drive a lichen’s shape; there is the growth force that causes branches to expand quickly the less competition they have from other lobes, but also the limiting force that causes growth to slow the further away the branch is from the centre body of the mass.
While randomly moving particles sticking to each other don't reflect the real biological mechanics of lichens, by creating rules about how they stick we can create visually similar patterns.
The rule in this case is that a particle is more likely to stick if there are more stuck particles around it. This mixes with the typical rule that the outer fringes of the mass will be more likely to be hit to create those two opposing forces mentioned above.
My first low resolution simulations went well, but when I started to make the cell size smaller and the cell count larger, that’s when things started to get interesting.
As you can see here, it developed into a single large, spiralling arm, not a rounded lichen at all. I think this is because I’m spawning all of my particles at the same time, not one at a time as the paper does.
I didn’t think it would make a difference, but the paper mentions that they should be spawned far enough away their behaviour is the same as if they originated infinitely far away. Maybe the little bits of interaction that happen when multiple particles stick at the same time is enough to throw off the mathematical equilibrium and create a single long arm like this? It happened every time with these small particles and large spawning radius, and it cleared up when I switched to sending them one at a time.
Even then, there’s still a visible clockwise spiral. I think that one's because of one of the ‘sticking’ steps.
The paper doesn’t mention how this rotation is calculated, and my initial improvised approach was always rotating them clockwise, which creates these spirals. Instead, I used this line of code float clockwise_Adjust = ceil(ofRandom(2)) == 1? 0.1 : -0.1; to randomise which direction the random walker rotates in. This reduces the obvious spiralling pattern, although I still feel like there’s some bias.
Maybe it’s just my imagination, but do you notice how the anticlockwise faces seem to be a bit smoother?
I did some measurements of generation speed, and I found that one of the major delays was when a particle would get stuck moving at the slowest speed in an area without any settled clusters.
One of the optimisations the paper suggests is to make the particles take larger steps when they are outside of the settled cluster’s range, which speeds up the random walks immensely, but it only tests the range with a radius, assuming it’s a perfect circle. In extremely not-round cases, this slows the particles down drastically without any chance of them meeting the settled cluster.
Instead, by using a rectangular bounding box, we can speed up the steps without adding much more computational load. There’s still cases where the particle is wandering around in the middle of nowhere, but the worst-case scenarios are limited. This optimisation becomes less useful the more exactly circular the lichen becomes, but my generations seem to generally end up with an off-centre profile.
In its current state, my simulation's a bit slow, especially compared to the paper's speeds of 100,000 elements in 15 minutes. It's not putting any strain on my computer, so I think I need to more fully understand how to make use of the full computing power available to me. I've added a few visualisation options in the code file, but it's a bit of a hassle to change the variables manually.
If I was to come back to this, I'd like to speed it up and add a Ui that could expose those options and let other people experiment with it. OpenFramworks and C++ aren't quite as easy to embed in a webpage as P5.js, but I've seen that there are ways, and it would be nice to add the tool to this website.