Starting with version 14.04.14, Lazy Nezumi Pro can help you draw complex shapes and fractals using the Scripting engine's L-System functions.
This tutorial will teach you how to use these functions step by step.
Reference tables of all functions and instruction symbols can be found on the Scripting Reference page.
An L-System is defined by:
The system will be iterated a number of times, with symbols being changed according to the rules. This will produce a final string of symbols, which will be read as instructions to move the pen in order to draw a shape.
Let's start by looking at a famous L-System: The Koch Curve.
If we start with the Axiom and use the given rule to replace F, the system evolves like so:
How is this used to draw something? We read the final string from left to right. Each time we encounter the F symbol, we draw a straight line. If we encounter a - or + symbol, we turn left or right 90 degrees. The following image shows the results.
So how do we use this in Lazy Nezumi Pro? Start off by making a new preset. In its details, enable Scripting. Select the custom mode, and paste this code into the text box:
lsysAxiom("F");
lsysRules("F=F-F+F+F-F");
lsysDrawSymbols("F");
lsysAngle(90);
lsysLength(length);
lsysIterations(iterations);
lsysAdvance();
Then go ahead and click Compile. Since this program has two user variables, two parameter sliders should appear: length and iterations. Click on their "..." buttons to set their range to something more useful than [0..1].
Length (set with the lsysLength function) is the distance the pen travels each time the system encounters a Draw Symbol (in this case F, as set with the lsysDrawSymbols function). A value around 10 should be a good start.
Iterations (set with the lsysIterations function) is the number of times the rules should be applied (starting from the axiom string) to produce the final instruction string that will be used to draw. Usually you won't need to go above 10 iterations, so set a range between 0 and 10.
All of the L-System functions except lsysAdvance are only used when the program is being compiled. When you are drawing, lsysAdvance steps through the final L-System string until it finds a Draw Symbol, at which point it moves the current pen position and returns. This position is stored in the ox and oy variables.
All you have to do now is put your pen down in your hooked art program, and the script will start drawing by itself!
L-Systems are really good at modeling trees and other plants. Let's start with this example:
lsysAxiom("[B]");
lsysRules("B=A[-B][+B]");
lsysDrawSymbols("AB");
lsysAngle(20);
lsysLength(length);
lsysDir(0, -1);
lsysIterations(iterations);
lsysAdvance();
Here we introduce two new symbols: [ and ]. When an open bracket is encountered, the state of the system is saved (or pushed) onto a stack. When a closing bracket is encountered, the state is restored by popping the top element from the stack. The system state is composed of the following:
This allows us to easily create branches. In this example, we start off with a branch, which grows straight out (A), and then sprouts a branch going left ([-B]), and one going right ([+B]). Here's what this system looks like after 4 iterations:
But real tree branches usually get smaller and smaller. How can we simulate this with our L-System? Here's one way:
lsysRules("B=A[-B][+B],A=AA");
Adding the A=AA rule will cause each branch to grow twice as much before spawning the two other branches. Here's what this looks like after 4 iterations:
While this does have the desired effect of the branches getting relatively smaller, the tree is getting taller and taller as we increase the L-System iterations. What if instead we want the branches to shrink in absolute size? We can accomplish this with the % symbol, which will divide the current length by the Length Scale Factor. This value is set to 1.3 by default, and can be changed by calling the lsysLengthScale function.
Here's an example rule that applies the scale factor before starting both branches:
lsysRules("B=A%[-B][+B]");
Instead of multiplying the length by a factor (geometric growth), we can also add (or subtract) a constant amount to it (arithmetic growth). This is done with the & symbol, which will decrease the current length by the Length Increase Amount. This value is set to 10% of the starting length by default, and can be changed by calling the lsysLengthInc function.
Here's an example rule that applies the scale factor to the left branches, and the increase factor to the right branches, so you can see the difference it makes:
lsysRules("B=A[%-B][&+B]");
Now let's make this tree look a bit more natural, by adding a central branch and decreasing the thickness as we branch out. For this we use the ! symbol:
lsysRules("B=A!%[-B][+B]AB");
Here's what it looks like after 6 iterations. This is starting to look a lot better! For this to work correctly, don't forget to map pen pressure to line thickness in your art app's brush settings.
If you draw this, you'll notice it takes longer, since there are now 3 branches splitting off of every branch. We can make the tree look more natural and reduce some of this drawing time by randomly skipping some branches. We do this with the ? symbol. When this symbol is encountered, the instruction (or branch) after it is skipped with a certain probability. A random number between 0 and 10 is chosen, and if it is higher than the current Skip Number, then we skip the instruction. We set the Skip Number by simply writing a number somewhere in our rule string, before the ? symbol. Here's an example:
lsysRules("B=A!%7?[-B]8?[+B]AB");
What we are doing here is giving the left branch 7 chances in 10 to be drawn, and the right branch 8 chances in 10. Now that we've introduced some randomness in our L-System, every tree we draw will be slightly different! Here's an example of what we can get with this rule after 6 iterations:
Removing perfect symmetry makes things look a lot more natural. Let's add even more randomness! We can have the system add some random values to the angle and length when rotating and drawing by using the following functions:
randSeed(seed);
lsysAngleRandom(angleRandom);
lsysLengthRandom(lengthRandom);
This will make three new script parameters appear. Set the range for angleRandom to [0-45] (since it is an angle), and you can leave the range of lengthRandom to [0-1] (since it's a percentage of the current length). Small values will go a long way to make realistic looking trees. If you set these too high though, you will get some pretty crazy results which might not look like trees at all anymore. Set the range for seed to [0-1000]. If you leave this seed parameter at 0, you will get a different tree every time you draw. Otherwise, each seed value will give you a different tree, but it will always draw that same tree (which can be useful if you find one you really like, or if you need to draw it multiple times with different brush settings).
Here are some examples of what you can get after 6 iterations, with angleRandom set to around 5, and lengthRandom to 0.15. I've also set the Length Scale Factor to 1.6, to simulate leaves at the end of branches.
LNP version 21.09.12 added a way for L-Systems to draw curved lines!
To do this, the concept of draw steps was introduced. Previously, a draw symbol would draw a line of the current length in one step. Now, you can use the lsysMaxDrawSteps function to set the number of steps that will be used to draw for each draw symbol. Along with this, two new symbols were introduced: < and >. If you use these symbols instead of - and +, the line direction will be rotated gradually over the number of steps, producing curved lines.
Here's a simple script that shows how this works:
lsysAxiom("[B]");
lsysRules("B=A!%[<B][>B]");
lsysDrawSymbols("AB");
lsysAngle(25);
lsysLength(100);
lsysMaxDrawSteps(drawSteps);
lsysMinStepDist(2.0);
lsysDirAngle(-90);
lsysIterations(7);
lsysAdvance();
This script has only one parameter: drawSteps. At zero, the lines are straight, just as if we used the + and - symbols. Increasing its value will increase the smoothness of the curves. Note that this increases drawing time, so you will have to find a value that is a good compromise between quality and speed. You can also set a minimum step distance (in pixels) via the lsysMinStepDist function, so that small lines don't get cut into smaller pieces (this can increase drawing speed without reducing quality too much, as you won't notice if small lines are straight).
Starting with LNP version 21.09.12, the lsysAdvance script function also updates the d variable with the current distance from the start. This means that you can use distance-based functions to modify the output position or pressure. If you haven't already, be sure to read the scripting tutorial to understand how this works, and to give you other scripting ideas.
Here's one example that uses the noise function to add some more natural looking bulges to the branch thickness:
lsysAxiom("[X]");
lsysRules("X=F[!>%%X]F!%[<%X]>X");
lsysDrawSymbols("FX");
lsysAngle(30);
lsysLength(100);
lsysLengthScale(1.5);
lsysThicknessScale(1.5);
lsysMaxDrawSteps(5);
lsysMinStepDist(2);
lsysDirAngle(-90);
lsysIterations(6);
lsysAdvance();
n1 = op * n1Amp * noise(d/n1Period);
n2 = n2Amp * noise(d/n2Period);
op = p ? (op+n1+n2) : 0;
Here, two noise waves of different periods and amplitudes are added to the output pressure. Here's what this looks like with n1Period = 8, n1Amp = 0.38, n2Period = 2, n2Amp = 0.38.
If you open the Scripting Graph window, you can see a preview of the resulting L-System as you change its parameters. Drawing an L-System in your art app may take some time, so it's a good idea to look at the preview first to get a general idea of what you will get. Please note that the graph only displays a fixed amount of points computed by the script. You can use the Max LSystem Points slider to increase the maximum amount of points that should be generated and shown in the graph.
The scripting graph window also has animation controls. You can choose a script variable and its start and end values, and it will show you an animation of the graph as this variable's value is changed over time. Here's an example where we animate the iterations variable of the following L-System script:
lsysAxiom("F+F+F");
lsysRules("F=F-F+F");
lsysDrawSymbols("F");
lsysAngle(120);
lsysLength(5);
lsysMaxLoops(0);
lsysDir(0, -1);
lsysIterations(iterations);
lsysAdvance();
These animation controls can help you design and fine-tune dynamic L-Systems. For example, here's a script that will draw a growing plant. The t variable in this script represents time, and will vary from 0 to 1. This variable is used with various easing functions to change certain properties over time. In this instance, the angle and the length.
len = length * easeOutQuint(0,1,t);
a = angle * easeOutBounce(0.1,0.8,t);
lsysAxiom("[B]");
lsysRules("B=A!%[<C].[<C]{B,C=C!%[%_!!-<A][%_!!+>A]<C");
lsysDrawSymbols("ABC");
lsysAngle(a);
lsysAngleScale(1.5);
lsysLength(len);
lsysLengthScale(1.3);
lsysThickness(1);
lsysThicknessScale(1.4);
lsysMaxDrawSteps(drawSteps);
lsysMinStepDist(2.0);
lsysDir(0, -1);
lsysIterations(iterations);
lsysAdvance();
Here's what this looks like when we animate the t variable:
When you are happy with how your animation looks, you can then use the script with different values of the t variable to draw as many frames as you want in your art or animation program.
I hope this tutorial has sparked your interest in procedural art and that you will start exploring L-Systems on your own! If you look under the L-System category in the Scripting Mode, you will find some examples to get you started. Feel free to copy/paste the code into your own Custom mode programs to tweak them and create new patterns!
You will also find a wealth of information and examples on the internet by simply doing a Google search. There is no standard way of defining L-System instruction symbols, so you may have to do some minor translations to get them working correctly in Lazy Nezumi Pro.
Copyright © 2013-2022 Guillaume Stordeur. All rights reserved. Privacy Policy. EULA.
Lazy Nezumi is a trademark of Guillaume Stordeur. Adobe, Photoshop and Flash are trademarks of Adobe Systems Inc. Windows is a trademark of Microsoft Corp.