L-Systems and the stack in Maya

1.1k Views Asked by At

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.

1

There are 1 best solutions below

1
On BEST ANSWER

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