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.
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:
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: