pythonmayal-systems

L-Systems and the stack in Maya


So I understand the rules of an L-System and I've managed to create a Sierpinski Triangle. I'm now moving onto making different styles of trees.

The basic rules of this would be:

F: Draw forward
+: Rotate right by angle
-: Rotate left by angle
[: Push stack 
]: Pop stack

I'm using Maya to do this and I was unsure how to go about pushing and popping the stack. I know how to create a basic stack using a list as Maya has no default stack, but what exactly would I push / pop?

I can't seem to push the world matrix of an object. And as you cannot do something without creating an object first, the L-System process goes wrong. As a basic example:

F[+F] 

...would not work due to not creating the object to push/rotate.

Any tips would be really useful, as this has been stumping me for a while.


Solution

  • First, let me point out to you that Maya does indeed have a graphics stack like this. Its just that since Maya is not a immediate mode drawing tool this stack is in fact a tree. This tree is called the DAG or in other words the object parent hierarchy. This tree serves the same purpose as a stack described by the L-system. However this may or may not help you since its not, directly, of much use for your evaluation.

    So let us take a look what a simple L system rendering would look like in Maya. Lets borrow the base code from How to Think Like a Computer Scientist and let us use the slightly more exciting rule:

    F -> F[-<<<<F][+>>>>F]
    

    where > and < are rotations about a axis. Using base axiom:

    F
    

    with 4 iterations and a angle of 30 degrees results in:

    enter image description here

    Note the production ruleset is a bit redundant and tends to draw many stems at each iteration. But I am aiming at simplicity of understanding not elegance. Code used:

    import maya.cmds as cmds
    
    def applyRules(lhch):
        rhstr = ""
        if lhch == 'F':
            rhstr = 'F[+F][<<<<+F][>>>>+F]'
        else:
            rhstr = lhch  # no rules apply so keep the character
        return rhstr
    
    
    def processString(oldStr):
        newstr = ""
        for ch in oldStr:
            newstr = newstr + applyRules(ch)
        return newstr
    
    
    def createLSystem(numIters, axiom):
        startString = axiom
        endString = ""
        for i in range(numIters):
            endString = processString(startString)
            startString = endString
        return endString
    
    def drawLsystem(instructions, angle, distance):
        parent = cmds.createNode("transform", n="L_Root_#")
        saved=[]
        for act in instructions:
            if act == 'F':
               cyl = cmds.cylinder(r=0.1, ax=[0,1,0], hr=1/0.1*distance)
               cyl = cmds.parent( cyl[0], parent, r=1)
               cmds.move(0, (distance/2.0), 0, cyl[0], os=1) 
               parent = cmds.createNode("transform", p=parent)
               cmds.move(0, (distance), 0, parent, os=1) 
            if act == '-':
               parent = cmds.createNode("transform", p=parent)
               cmds.rotate(angle, 0, 0, parent, os=1) 
            if act == '+':
               parent = cmds.createNode("transform", p=parent)
               cmds.rotate(-angle, 0, 0, parent, os=1) 
            if act == '<':
               parent = cmds.createNode("transform", p=parent)
               cmds.rotate(0, angle, 0, parent, os=1) 
            if act == '>':
               parent = cmds.createNode("transform", p=parent)
               cmds.rotate(0, -angle, 0, parent, os=1) 
            if act == '[':
               saved.append(parent)
            if act == ']':
               parent = saved.pop()  
    
    
    drawLsystem(createLSystem(4, "F"),30,1)     
    

    PS: if you change the axiom to FX and rule X to [+FX][<<<<+FX][>>>>+FX] it generates less redundancy. Running the code without undo makes it light years faster due to Maya undo being pretty slow to update. And as a result you can run the rule set more times for a more complicated result. Added some scale operations to the generation rules and got this:

    enter image description here