L system
Code and Testing


return to main index



Introduction

This page presents a number of scripts that implement a L system that can generate graphics for Maya and RenderMan. Download all code.

    maya/
       |_ scripts/
                |_ LMelProcs.mel 
                |_ lsys/
                      |_ lsystem.py
                      |_ lscriptreader.py
                      |_ lgenerator.py 
                      |_ lmel.py 
                      |_ mayasocket.py 
                      |_ lrib.py  
                      |_ lprocedural.py 
    cutter/
         |_ archive_tester.rib    
         |_ procedural_tester.rib 
         |_ tree.dat  

Running the L system - Input & Output(s)

The data that "drives" the L system is contained in a .dat file. It specifies the axiom, the (substitution) rules and the number of times the rules should be applied - the generations. It also contains values that control a number of other aspects of the L system. For example, a script called tree.dat is shown below.


tree.dat

title	"tree"
axiom "G"
generations 5
rule G "1{>zG}{<zgG}1bG"
rule 1 "11"

angle 17
scale 0.9
display "mel"
seed 1
#port 2222
curvewidth 0.3
rgb_delta 0.3

Generating Graphics for Maya
Step 1

Open tree.dat and lsystem.py in Cutter. Edit the last line of text of lsystem.py ie.
    run('FULL_PATH/tree.dat')
so that the full path to the .dat file is correctly specified.
Step 2
Execute the lsystem.py script in Cutter using control+e, alt+e or Apple+e. If no errors occur a file named tree.mel will be saved in the same directory as tree.dat.
Step 3
Launch Maya, open the script editor and enter the following mel command,
    source "PATH_TO/tree.mel";
Ensure the path to the .mel file correctly specified. The graphic shown in figure 1 should appear in the viewport. Delete the graphics. Next, open a port in Maya using this mel command,
    commandPort -n ":2222";
Remove the comment character ("#") from the tree.dat script. Execute the lsystem.py script again in Cutter. If communication across the port is working the graphic shown in figure 1 will again appear in the Maya viewport



Figure 1 - output via mel


Generating Graphics using RenderMan
Step 1

In the tree.dat script change,
    display "mel"
to
    display "rib"
Step 2
Execute the lsystem.py script. If no errors occur, an archive rib file named tree.rib will be saved in the same directory as tree.dat.
Step 3
Open the file named archive_tester.rib in Cutter. Edit the folowing line,

    ReadArchive "FULL_PATH_TO/tree.rib"

so that the full path to tree.rib is correctly specified. Execute the archive_tester.rib script. If no errors occur the graphic shown in figure 2 will be dispayed.
Step 4
Open the file named precedural_tester.rib and edit the lines shown in blue that the full paths to the lprocedural.py and tree.dat are specified correctly.

    Procedural "RunProgram" 
        ["/usr/bin/python  FULL_PATH_TO/lprocedural.py" 
         "FULL_PATH_TO/tree.dat, generations 3, angle 20 30"] 
        [-1000 1000 -1000 1000 -1000 1000]

Execute the precedural_tester.rib script. If no errors occur the graphic shown in figure 2 will be dispayed. The module lprocedural has been written such that any values in the .dat script can be overriden by the call to Procedural. For example, an extra rule could be added - figure 3,

    Procedural "RunProgram" 
        ["/usr/bin/python  FULL_PATH_TO/lprocedural.py" 
         "FULL_PATH_TO/tree.dat, rule *G 4"] 
        [-1000 1000 -1000 1000 -1000 1000]


Figure 2 - output via rib


Figure 3 - adding data via a procedural


System Architecture

The python and other scripts that implement the L system are shown in figure 4. lscriptreader.py, as its name suggests, reads an input script, for example tree.dat, and stores its information in a python dictionary. lgenerator.py rewrites the axiom and generates a L string. Depending on display statement in the input .dat file either lmel.py or lrib.py is used to render the L string.




Figure 4
L System architecture


Default Values

The lscriptreader module contains a default dictionary of L system statements and their values. An input .dat script can override any of the values. For example, the default value of a statement named "port" is 0. If a .dat script does not set a port value in excess of 1024 the lmel module will not attempt to send the output .mel file to Maya via a socket. Some statements/values are relevent only for rib output. For example, "curvewidth" is irrelevant when generating geometry for Maya.


Extending the LSystem

Adding new characters to the L system is relatively straightforward. For example, to add 'T' to mean "turn the current coordinate system 180 degrees around the x-axis".
Step 1 - lmel.py
Add the following code to the end of the list of elifs in the render() procedure.

    elif char == 'T': mel.append('rotate -r 180 0 0 $tnode;\n')

Step 2 - lrib.py
Add the following code to the end of the list of elifs in the render() procedure.

    elif c == 'T': rib.append('Rotate 180 1 0 0\n')

Here are some suggestions for extending the L system.

Shapes
    0    "Disk"
    1    "Curve" <<-- done
    2    "Cylinder"
    3    "Sphere"
    4    "Cone"  <<-- done
    5    "Polygon"
    6    "Torus"
  
 Transformations 
    >    "Positive rotation"     <<-- done
    <    "Negative rotation"     <<-- done     
    s    "Scale x, y and z"      <<-- done
    S    "invert scale"
    +    "Moves will be positive"<<-- done
    -    "Moves will be negative"<<-- done
    T    "Turn 180.0    1 0 0"

Attributes    
    r    "Reduce the red component"     <<-- done
    g    "Reduce the green component"   <<-- done
    b    "Reduce the blue component"    <<-- done
    R    "increase the red component"   <<-- done
    G    "increase the green component" <<-- done
    B    "increase the blue component"  <<-- done

In addition to extending the list of characters that control object creation, placement and coloration, it is also worth including some special control characters that effect the way that lgenerator performs string rewriting. For example, the following characters are already implemented but others could be added.

    ~    apply the rule randomly                        <<-- done
    *    apply the rule ONLY on the last rewrite        <<-- done
    !    do NOT apply the rule on the final rewriting   <<-- done

The tilde rule modification character enables the same rule to have several substitutions ie.

    "~a"     "xxy2"
    "~a"     "xyyy2"

The tilde character, in the example shown above, says, "sometimes use "xxy2" and sometimes use "xyyy2". The decision is made on a random basis.




© 2002- Malcolm Kesson. All rights reserved.