Procedural Generation with L-Systems (very simple example)

--

Procedurally generated shrub

While working on a new project, I found myself needing to use procedural generation. This wasn’t just a “this would be something cool to add” type of thing, it was absolutely necessary (like any other feature that eventually leads to feature creep, and the project not getting completed).

So, like any reasonable person, I went down the 10-hour YouTube rabbit hole on how I would go about implementing this on my use case. To my surprise, building something like this turns out to be relatively simple. I introduce to you the L-system.

All of these beautiful plants are procedurally generated using a L-system based algorithm. A L-system (or Lindenmayer system) is a recursive system that utilizes a type of formal grammar to construct geometric structures. By using this formal grammar consisting of an alphabet, production rules, and a starting state (axiom) we can procedurally build what looks like a very complex structure out of simple rules.

So, how do we code this algorithm? Well first, let’s get a simplified overview of what a L-system is.

In a nutshell, this algorithm requires a formal alphabet (constraints), rules to apply to those constraints, and a starting state (axiom). Remember grammars from your complier class? Neither do I. So let’s go over them at a high level.

A grammar is just a set of rules to apply to an alphabet. For example:

F -> “FF+F-[+-F]”

All this means is that where ever you see “F” in an axiom, you will replace it with the string “FF+F-[+-F]”. For those that have done a calculus class think of this as a function composition.

So with this grammar (rule) and the axiom (starting state) of “FXF” we would get the derivation:

grammar: F -> “FF+F-[+-F]”

axiom: FXF -> “FF+F-[+-F]XFF+F-[+-F]”

(where “->” symbol means our derivation.)

Simple enough right? So now what do we do with these strings? Let’s apply an action to each of these characters.

F = draw forward

X = no geometric meaning

+ = 60% right

— = 60% left

[] = Start/end of branch

With these simple rules we can then draw our tree over iterations of our state.

iteration 1:

grammar: F -> “FF+F-[+-F]”

axiom: FXF -> “FF+F-[+-F]XFF+F-[+-F]”

iteration 2:

iteration1 as axiom: FF+F-[+-F]XFF+F-[+-F] -> FF+F-[+-F]XFF+F-[+-F]FF+F-[+-F]XFF+F-[+-F]+FF+F-[+-F]XFF+F-[+-F]-[+-FF+F-[+-F]XFF+F-[+-F]]XFF+F-[+-F]XFF+F-[+-F]FF+F-[+-F]XFF+F-[+-F]+FF+F-[+-F]XFF+F-[+-F]-[+-FF+F-[+-F]XFF+F-[+-F]]

Now I’m sure you have a good understanding of how these can grow and become arbitrarily complex. If I went through this too fast or if you’re a visual-audio learner like me, checkout Simon Dev’s youtube video on the subject. He does a fantastic job explaining it. The code I’m using for this tutorial is his, the only thing I did was add an express server so you can clone my git repo and run it on your local machine.

Now, let’s get this project up and running so you can play with the beauty of this simple and elegant algorithm.

Our server that will be serving the static .html, .css, and .js files

The server is serving files in a /static directory, handle this as necessary for your use case.

our base.css file
simple.html

Lastly, the javascript file that performs this algorithm:

Again, if you want a more in-depth explanation about the code, please visit Simon Dev’s youtube video as he goes into the implementation details and makes everything very easy to understand.

As for running the code, make sure to have Node installed on your computer and run npm init && npm install express in your root directory where the main.js file is. After that, just run node main.js from your command line and visit https://localhost:3000/simple.html and enjoy the work of Aristid Lindenmayer.

Circling back around to my project, this side exercise didn’t solve my project’s use case, but it is a step in the right direction. This did help me hypothetically solve what I need to do to get this project done. Check back for an implementation of this code using Swift and Metal (as our graphics library) on IOS.

Sources:

SimonDev. “Procedural Plant Generation with L-Systems.” YouTube, uploaded by SimonDev, https://www.youtube.com/watch?v=feNVBEPXAcE&t=361s.

Compton, Kate. “Practical Procedural Generation for Everyone.” YouTube, uploaded by GDC, https://www.youtube.com/watch?v=WumyfLEa6bU.

Department Ecoinformatics, Biometrics and Forest Growth, Georg-August University of Göttingen. “L-Systems.” grogra.de, http://wwwuser.gwdg.de/~groimp/grogra.de/grammars/lsystems.html.

--

--

gianni 🧙🏻‍♂️
gianni 🧙🏻‍♂️

Written by gianni 🧙🏻‍♂️

Solutions Engineer { I work on designing software systems for enterprise customers. Current focus is on AI/ML applications and infrastructure }

No responses yet