Skip to content

Instantly share code, notes, and snippets.

@WRHerbert
Created December 7, 2016 21:39
Show Gist options
  • Save WRHerbert/8ae0ca145a81989824f0c9b871035454 to your computer and use it in GitHub Desktop.
Save WRHerbert/8ae0ca145a81989824f0c9b871035454 to your computer and use it in GitHub Desktop.
'''
Snowflake Generator
This module contains all the procedures that are needed for to generate a large scale snowflake
and control the snowflake's variables using a user interface. To make this nested procedure
based script easily only one procedure has to be executed from the Maya Script Editor, this
procedure being displayUI(). However, the user interface can be bypassed allowing the user to
input any values for the variables if they wish to create more experimental snowflakes.
'''
import maya.cmds as cmds
import math
import random
def delete(*args):
'''
Selects all of the objects in the scene and deletes them.
On Exit : all objects in scene are deleted
'''
cmds.select(all=True)
cmds.delete()
def makeSnowflake(sName, Msize, ratio, thickness, branchNum, decay, angle, sideSplit, iterations):
'''
Is the main containing procedure that generates the snowflake and creates all the variables
for the nested sub-procedures to use.
Msize : determins the master size of the snowflake
ratio : is the ratio between the size of the entire snowflake and the size of the centre
thickness : controls the thickness of the centre and branches
branchNum : is the number of main branches that protrude from the centre
decay : determins the rate at which the branches shrink in size for each iteration
angle : controls the angle that the branches protrude from their parent branch
sideSplit : is the number of branches that protrude from one side of a parent branch
iterations : determins the number of times the branches split from the main branch
On Exit : a snowflake is generated using the following procedures with the defined variables
'''
Csize = ratio*Msize
Bsize = Msize - Csize
listBranches = []
cmds.setAttr("lambert1.color", 1.0, 1.0, 1.0)
if cmds.objExists(sName+'_snowflake'):
errorPopup()
quit('Error: That snowflake name is already in use.')
def makeCentre():
'''
Creates the centre portion of the snowflake using the variable defined in the
makeSnowflake procedure.
On Exit : a polyTorus is created and manipulated due to previously defined variables
'''
cmds.polyTorus(ax=[0, 0, 1], n=sName+'_snowflake', r=Csize
,sr=(0.1*Csize*thickness)
,sx=branchNum, sy=4, tw=45)
cmds.rotate(0, 0, 90, sName+'_snowflake')
cmds.scale(1, 1, 1*(1.0/(0.1*Csize*thickness)))
def makeMainBranches():
'''
Generates the first iteration of branches that protrudes from the centre, and parents
them to the central torus. These are the main branches that the sub branches grow from.
On Exit : A number of polyCubes are created and manipulated to form the main branches
subject to the previously defined variables
'''
for i in range(1, branchNum+1):
cmds.polyCube(n=sName+'_branch'+str(i), h=Bsize)
listBranches.append(sName+'_branch'+str(i))
cmds.xform(sName+'_branch'+str(i), piv=[0, -(Bsize/2), 0])
cmds.move(0, Bsize/2, 0, sName+'_branch'+str(i))
cmds.rotate(0, 0, (360/branchNum)*(i-1), sName+'_branch'+str(i))
cmds.move(0, Csize+(Bsize/2), 0, sName+'_branch'+str(i), os=True)
cmds.parent(sName+'_branch'+str(i), sName+'_snowflake')
def firstSplit():
'''
Creates the first iteration of sub branches that protrude from the main branches.
On Exit : A number of polyCubes are created and manipulated, forming the first set of
sub branches according to the previously defined variables
'''
for i in range(0, branchNum):
for j in range(1, (sideSplit*2)+1, 2):
cmds.duplicate(listBranches[i], name=listBranches[i]+'s'+str(j))
cmds.move(0, (Bsize/(sideSplit*2.0))*j, 0, listBranches[i]+'s'+str(j), r=True, os=True)
cmds.rotate(0, 0, angle, listBranches[i]+'s'+str(j), r=True)
cmds.scale(decay, decay, decay, listBranches[i]+'s'+str(j), r=True)
cmds.duplicate(listBranches[i], name=listBranches[i]+'s'+str(j+1))
cmds.move(0, (Bsize/(sideSplit*2.0))*j, 0, listBranches[i]+'s'+str(j+1), r=True, os=True)
cmds.rotate(0, 0, -angle, listBranches[i]+'s'+str(j+1), r=True)
cmds.scale(decay, decay, decay, listBranches[i]+'s'+str(j+1), r=True)
def furtherSplit():
'''
Generates and arranges the remaining branches according the defined variables.
On Exit : A number of polyCubes are created and manipulated to create the remaining
branches for the snowflake subject to the previously defined variables
'''
y = 0
z = 0
for i in range(0, iterations):
x = math.pow((2*sideSplit),i)
z = y + x
y = z
splits = z
for i in range(0, branchNum):
for j in range(1, splits):
for h in range(1,(sideSplit+1)):
sel = cmds.duplicate(listBranches[i]+'s'+str(j))
cmds.move(0, (Bsize/(sideSplit+1))*h, 0, sel, r=True, os=True)
cmds.rotate(0, 0, angle, sel, r=True)
cmds.scale(decay*decay, decay*decay, decay*decay, sel, r=True)
sel = cmds.duplicate(listBranches[i]+'s'+str(j))
cmds.move(0, (Bsize/(sideSplit+1))*h, 0, sel, r=True, os=True)
cmds.rotate(0, 0, -angle, sel, r=True)
cmds.scale(decay*decay, decay*decay, decay*decay, sel, r=True)
makeCentre()
makeMainBranches()
firstSplit()
furtherSplit()
def createUI():
'''
Creates thes basic window for the user interface after checking if one already exists.
On Exit : a simple user interface window is created
'''
if cmds.window("snowflakeUI", exists=True):
cmds.deleteUI("snowflakeUI")
cmds.window("snowflakeUI", title="Snowflake Generator")
cmds.frameLayout(marginHeight=5, marginWidth=5, labelVisible=False)
cmds.columnLayout()
cmds.showWindow("snowflakeUI")
def fillUI(a, b, c, d, e, f, g, h):
'''
Adds all the components to the user interface that allows the user to control the snowflake
variables including name fields, buttons and sliders.
On Exit : variable controlling components are added to the user interface window
'''
cmds.text(label="This is a generator that creates large scale individual snowflake models using polygons. Please refer to the instructions before use.", w= 250, ww=True)
cmds.separator(h=10, style="none")
cmds.button(label='Instructions', command=instrucPopup)
cmds.separator(h=10, style="none")
global nameField
cmds.text(label=" Snowflake Name")
nameField = cmds.textField(text = 'default')
cmds.separator(h=10, style="none")
global MsizeSlider
cmds.text(label=" Overall Size (Diameter)")
MsizeSlider = cmds.floatSliderGrp(field=True, minValue=15.0, maxValue=50.0, value=a)
cmds.separator(h=10, style="none")
global ratioSlider
cmds.text(label=" Centre Size to Overall Size Ratio")
ratioSlider = cmds.floatSliderGrp(field=True, minValue=0.2, maxValue=0.5, value=b)
cmds.separator(h=10, style="none")
global thicknessSlider
cmds.text(label=" Centre Thickness")
thicknessSlider = cmds.floatSliderGrp(field=True, minValue=1.0, maxValue=7.0, value=c)
cmds.separator(h=10, style="none")
global branchNumSlider
cmds.text(label=" Number of Initial Branches")
branchNumSlider = cmds.intSliderGrp(field=True, minValue=3, maxValue=8, value=d)
cmds.separator(h=10, style="none")
global decaySlider
cmds.text(label=" Rate of Branch Size Decay")
decaySlider = cmds.floatSliderGrp(field=True, minValue=0.3, maxValue=0.7, value=e)
cmds.separator(h=10, style="none")
global angleSlider
cmds.text(label=" Angle that Branches Protrude From")
angleSlider = cmds.intSliderGrp(field=True, minValue=1, maxValue=179, value=f)
cmds.separator(h=10, style="none")
global sideSplitSlider
cmds.text(label=" Number of Branches that Protrude from one Side")
sideSplitSlider = cmds.intSliderGrp(field=True, minValue=1, maxValue=6, value=g)
cmds.separator(h=10, style="none")
global iterationsSlider
cmds.text(label=" Number of Branch Split Iterations")
iterationsSlider = cmds.intSliderGrp(field=True, minValue=0, maxValue=4, value=h)
cmds.separator(h=10, style="none")
cmds.button(label="Input Random Values", command=randomVariables)
cmds.separator(h=10, style="none")
cmds.button(label="Generate Snowflake", command=getVariables)
cmds.separator(h=10, style="none")
cmds.button(label="Delete All", command=delete)
cmds.separator(h=10, style="none")
cmds.button(label="Close Window", command=closeUI)
def closeUI(*args):
'''
Closes the user interface. To be used with a button.
On Exit : the user interface closes
'''
cmds.deleteUI("snowflakeUI")
def randomVariables(*args):
createUI()
fillUI(30.0, 0.4, 3.5, 4, 0.5, 45, 2, 2)
def getVariables(*args):
'''
Collects the information from the text fields and sliders that the user defines and stores
it in a list to be used for the snowflake generation. Then runs the snowflake generator
through the makeSnowflake procedure according to the list information.
On Exit : varList is populated with information and the makeSnowflake procedure is executed
'''
varList[0] = cmds.textField(nameField, q=True, text=True)
varList[1] = cmds.floatSliderGrp(MsizeSlider, q=True, v=True)
varList[2] = cmds.floatSliderGrp(ratioSlider, q=True, v=True)
varList[3] = cmds.floatSliderGrp(thicknessSlider, q=True, v=True)
varList[4] = cmds.intSliderGrp(branchNumSlider, q=True, v=True)
varList[5] = cmds.floatSliderGrp(decaySlider, q=True, v=True)
varList[6] = cmds.intSliderGrp(angleSlider, q=True, v=True)
varList[7] = cmds.intSliderGrp(sideSplitSlider, q=True, v=True)
varList[8] = cmds.intSliderGrp(iterationsSlider, q=True, v=True)
makeSnowflake(varList[0], varList[1], varList[2], varList[3], varList[4], varList[5], varList[6],
varList[7], varList[8])
def instrucPopup(*args):
'''
Creates and opens a popup window containing all the instructions for using the snowflake
generator user interface. To be used with a button.
On Exit : opens the instructions window
'''
if cmds.window("instrucUI", exists=True):
cmds.deleteUI("instrucUI")
if cmds.windowPref("instrucUI", q=True, exists=True):
cmds.windowPref("instrucUI", remove=True)
cmds.window("instrucUI", title="Instructions", w = 410, h = 300)
cmds.frameLayout(marginHeight=5, marginWidth=5, labelVisible=False)
cmds.columnLayout()
cmds.text(label="Instructions", ww=True, w=400)
cmds.separator(h=10, style="none")
cmds.text(label="This is the instructions page for the snowflake generator, which should explain most of the aspects of this modelling script. To achieve the best results some experimentation is required to find combinations of values that suit your needs. All ranges of snowflakes can be created, some ordinary and some experimental, try to use the default values as a initial guide to creating an effective snowflake. If you wish to create even more experimental snowflakes, use the script module to run the procedure makeSnowflake('sName', Msize, ratio, thickness, branchNum, decay, angle, sideSplit, iterations) to input any variables you wish.", ww=True)
cmds.separator(h=10, style="none")
cmds.text(label="The 'Snowflake Name' field will append a name prefix to the model, for example the default creating the name 'default_snowflake'. Unfortunately two snowflakes cannot have the same name and using an identical name will bring up the error dialog.", ww=True)
cmds.separator(h=10, style="none")
cmds.text(label="The 'Overall Size (Diameter)' slider will control the overall size of the snowflake.", ww=True, w=400)
cmds.separator(h=10, style="none")
cmds.text(label="The 'Centre Size to Overall Size Ratio' value controls the ratio between the size of the entire snowflake and the size of the centre section.", ww=True, w=400)
cmds.separator(h=10, style="none")
cmds.text(label="The 'Centre Thickness' slider determins the thickness of the central ring.", ww=True, w=400)
cmds.separator(h=10, style="none")
cmds.text(label="The 'Number of Initial Branches' silder controls the number of main branches that protrude from the central ring. Increasing this variable to a high value can result in long loading times.", ww=True, w=400)
cmds.separator(h=10, style="none")
cmds.text(label="The 'Rate of Branch Size Decay' slider will determin the size decrease of each branch for each iteration.", ww=True, w=400)
cmds.separator(h=10, style="none")
cmds.text(label="The 'Angle that Branches Protrude From' slider will change that angle that the branches protrude at.", ww=True, w=400)
cmds.separator(h=10, style="none")
cmds.text(label="The 'Number of Branches that Protrude from one Side' slider will control how many branches protrude from one side of thir respective parent branch. Increasing this variable to a high value can result in long loading times.", ww=True, w=400)
cmds.separator(h=10, style="none")
cmds.text(label="The 'Number of Branch Split Iterations' slider will determin how man times the branches of the snowflake will split from the main branch. Increasing this variable to a high value can result in long loading times.", ww=True, w=400)
cmds.separator(h=10, style="none")
cmds.button(label="Close Window", command=closeInstrucPopup)
cmds.showWindow("instrucUI")
def closeInstrucPopup(*args):
'''
Closes the instructions popup window. To be used with a button.
On Exit : the instructions popup closes
'''
cmds.deleteUI("instrucUI")
def errorPopup():
'''
Creates and displays a error popup explaining that two snowflakes cannot have the same name.
To be used with a button.
On Exit : opens the error window
'''
if cmds.window("errorUI", exists=True):
cmds.deleteUI("errorUI")
if cmds.windowPref("errorUI", q=True, exists=True):
cmds.windowPref("errorUI", remove=True)
cmds.window("errorUI", title="Duplicate Name", w = 210, h = 80)
cmds.frameLayout(marginHeight=5, marginWidth=5, labelVisible=False)
cmds.columnLayout()
cmds.text(label="Error: The snowflake could not be generated because the snowflake name is already in use.", ww=True, w=200)
cmds.separator(h=10, style="none")
cmds.button(label="Close Window", w = 200, command=closeErrorPopup)
cmds.showWindow("errorUI")
def closeErrorPopup(*args):
'''
Closes the error popup window. To be used with a button.
On Exit : the error popup closes
'''
cmds.deleteUI("errorUI")
def displayUI():
'''
Is the main procedure to be used to open the snowflake generator user interface. Creates the
list varList and inputs default snowflake values.
On Exit : creates varList and inputs default values while opening the snowflake generator
user interface
'''
global varList
varList = ['default', 20.0, 0.3, 3.0, 6, 0.6, 50, 3, 3]
createUI()
fillUI(20.0, 0.3, 3.0, 6, 0.6, 50, 3, 3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment