Tutorial: Create a Sine with Nodes in Maya

Tutorial: Create a Sine with Nodes in Maya

Wow! It’s been more than a year since my last post here… Time flies 😕 Anyway, I’ve gotten a lot of questions about the procedural ribbon from my rigging reel, and I promised I’d do a tutorial on that, I’ll try to get that done next week or so 🙂

This however, is actually the thing that got me started on the procedural ribbon in the first place. My first thought was to start with getting the sine-function to work with nodes, and then work my way from there. The ribbon turned out totally different from this tutorial though, but I thought this could still be a useful technique to share.

First off, there’s several tutorials out there on how to create a sine-function in Maya, but I’ve never seen anyone do them with nodes. The main reason you would want to do things with nodes instead of using expressions is that expressions doesn’t always evaluate when you want them to, some times you have to scrub the timeline or playback the scene to force an evaluation of the expression. That can be really cumbersome if you need to adjust attributes that affects the result of the expression without seeing the changes instantly. Also, nodes evaluate way faster than expressions 🙂

The concept:

This is very basic, and the concept is very well demonstrated here, the tutorial just shows you how it can be applied to several objects in a way that lets you control the entire chain of objects affected by the sine with one controller.

Even if you know how a sine works, there’s still something to take out of doing it this way in Maya. Instead of dealing with just the math to get this to work (which you do with expressions), you’re dealing with a more practical setup, which easily can be modified to behave however you want it to. So as long as you know the “pattern” of the mathematical function, let your rigging brain take over and do a practical setup in Maya that lets you extract the behaviour of the function.

Here’s an interesting example Disney Research Lab released a little more than a year ago:
Computational Design of Mechanical Characters

The tutorial:

I’m using the translateY to output the sine in the tutorial, but remember that if you for example use this on a joint-chain, you could just connect the output to the rotate of the joints instead.

8,171 total views, 11 views today

7 comments

  1. Michael McReynolds says:

    Great tutorial, and really novel approach! I went a bit further, making it into a small python script. With this, you can choose any number of result nodes you want. Just change the ’64’ in the last line to any number you want.

    Paste the following code into a python tab in the script editor, hit Cntrl-A and Cntrl-Enter to run

    #### CreateSineViaNodes by Mike McReynolds mranim8or@aol.com
    #### automates creation of a sine function, via nodes. based on a tutorial by Jorn-Harald Paulsen
    #### paste into a python tab and run via CreateSineViaNodes(64) (change 64 to however many output cubes you’d like)

    import maya.cmds as mc
    import maya.mel as mel

    def CreateSineViaNodes(NumOutputNodes):
    try:
    mc.delete(“Sine_Master”)
    except:
    pass

    ## create all the main groups
    mc.group(n=”Sine_Master”, em=True)
    mc.group(n=”sineResult_grp”,em=True)
    mc.group(n=”sineOutput_grp”,em=True)
    mc.group(n=”sineValue_grp”,em=True)
    mc.parent(“sineResult_grp”,”Sine_Master”)
    mc.parent(“sineOutput_grp”,”Sine_Master”)
    mc.parent(“sineValue_grp”,”Sine_Master”)

    ### create a control, call it sineController
    mc.circle(r=2.5,n=”Sine_CNTRL”)
    mc.setAttr(“Sine_CNTRL.overrideEnabled”, 1)
    mc.setAttr(“Sine_CNTRL.overrideColor”, 17)

    mc.addAttr(“Sine_CNTRL”, ln=”Frequency”, at=”double”, dv=False)
    mc.setAttr(“Sine_CNTRL.Frequency”, k=True)
    mc.addAttr(“Sine_CNTRL”, ln=”Amplitude”, at=”double”, dv=False)
    mc.setAttr(“Sine_CNTRL.Amplitude”, k=True)
    mc.addAttr(“Sine_CNTRL”, ln=”Offset”, at=”double”, dv=False)
    mc.setAttr(“Sine_CNTRL.Offset”, k=True)

    mc.setAttr(“Sine_CNTRL.Frequency”,1)
    mc.setAttr(“Sine_CNTRL.Amplitude”,1)
    mc.parent(“Sine_CNTRL”,”Sine_Master”)

    mc.addAttr(“Sine_CNTRL”,ln=”ShowValueLocators”,at=”bool”)
    mc.setAttr(“Sine_CNTRL.ShowValueLocators”, k=True)
    mc.addAttr(“Sine_CNTRL”,ln=”ShowGraphObjects”,at=”bool”)
    mc.setAttr(“Sine_CNTRL.ShowGraphObjects”, True,k=True)

    mc.parentConstraint(“Sine_CNTRL”,”sineResult_grp”)
    mc.parentConstraint(“Sine_CNTRL”,”sineOutput_grp”)

    mc.connectAttr(“Sine_CNTRL.ShowGraphObjects”,”sineResult_grp.visibility”)
    mc.connectAttr(“Sine_CNTRL.ShowValueLocators”,”sineValue_grp.visibility”)

    mc.setAttr(“sineOutput_grp.visibility”,False)

    ### create s sine value locator
    mc.spaceLocator(n=”sineValue_loc_1″)
    mc.setAttr(“sineValue_loc_1.overrideEnabled”, 1)
    mc.setAttr(“sineValue_loc_1.overrideColor”, 6)
    mc.group(n=”sineValue_grp_1″,em=True)
    mc.parent(“sineValue_loc_1″,”sineValue_grp_1”)

    FrequencyAmt = (360.0 / NumOutputNodes)
    MultDiv = mc.shadingNode(“multiplyDivide”, asUtility=True, n=”MultDiv_Frequency_1″)
    mc.setAttr(MultDiv + “.input2X”, FrequencyAmt)

    mc.connectAttr(“Sine_CNTRL.Frequency”,MultDiv+”.input1X”)
    mc.connectAttr(MultDiv+”.outputX”,”sineValue_grp_1.rz”)
    mc.connectAttr(“Sine_CNTRL.Amplitude”,”sineValue_loc_1.tx”)

    ### create an output locator
    mc.spaceLocator(n=”sineOutput_loc_1″)
    mc.parent(“sineOutput_loc_1″,”sineOutput_grp”)

    ### create output geo
    mc.polyCube(n=”sineResult_1″)
    mc.setAttr(“sineResult_1.sx”,.5)
    mc.setAttr(“sineResult_1.sy”,.5)
    mc.setAttr(“sineResult_1.sz”,.5)
    mc.parent(“sineResult_1″,”sineResult_grp”)

    ### duplicate the sine value groups
    for n in range(NumOutputNodes-1):
    mc.select(“sineValue_grp_1”)
    mc.duplicate(rr=True,ic=True, renameChildren=True)

    for n in range(NumOutputNodes,1,-1):
    mc.parent(“sineValue_grp_”+str(n),”sineValue_grp_”+str(n-1) )
    mc.parent(“sineValue_grp_1″,”sineValue_grp”)

    ### connect and duplicate the sine results
    mc.connectAttr(“sineOutput_loc_1.ty”,”sineResult_1.ty”)
    for n in range(NumOutputNodes-1):
    mc.select(“sineResult_1”)
    mc.duplicate(rr=True,un=True, renameChildren=True)

    ### point constrain output locators to sine value locators
    for n in range(NumOutputNodes):
    mc.pointConstraint(“sineValue_loc_”+str(n+1), “sineOutput_loc_”+str(n+1), mo=False )

    # ### parent sine value group to sine controller, connect it
    mc.parent(“sineValue_grp”,”Sine_CNTRL”)
    mc.connectAttr(“Sine_CNTRL.Offset”,”sineValue_grp.rz”)

    for n in range(NumOutputNodes):
    mc.setAttr(“sineResult_”+str(n+1)+”.tx”, (2.0 / NumOutputNodes)*n )
    mc.setAttr(“sineResult_”+str(n+1)+”.sx”, (2.0 / NumOutputNodes) )
    mc.setAttr(“sineResult_”+str(n+1)+”.sy”, (2.0 / NumOutputNodes) )
    mc.setAttr(“sineResult_”+str(n+1)+”.sz”, (2.0 / NumOutputNodes) )

    mc.makeIdentity(“sineResult_”+str(n+1),apply=True,pn=True,t=False,r=False,s=True,n=False)
    mc.connectAttr(“Sine_CNTRL.sy”,”sineResult_”+str(n+1)+”.sy”)

    # mc.scaleConstraint(“Sine_CNTRL”,”sineResult_grp”,skip=”y”)
    mc.connectAttr(“Sine_CNTRL.sx”,”sineResult_grp.sx”)
    mc.connectAttr(“Sine_CNTRL.sz”,”sineResult_grp.sz”)

    ### lock everything that cant be animated
    for Attr in [“.tx”, “.ty”, “.tz”, “.rx”, “.ry”, “.rz”, “.sx”, “.sy”, “.sz”, “.visibility”]:
    mc.setAttr(“Sine_Master” + Attr, lock=True)
    for Child in mc.listRelatives(“Sine_Master”, ad=True, typ=”transform”):
    for Attr in [“.tx”, “.ty”, “.tz”, “.rx”, “.ry”, “.rz”, “.sx”, “.sy”, “.sz”, “.visibility”]:
    if Child != “Sine_CNTRL”:
    mc.setAttr(Child + Attr, lock=True)
    mc.setAttr(“Sine_CNTRL.sx”,lock=True)
    mc.setAttr(“Sine_CNTRL.sy”,lock=True)
    mc.setAttr(“Sine_CNTRL.sz”,lock=True)

    mc.select(“Sine_CNTRL”)

    CreateSineViaNodes(64)

  2. Aditya says:

    Hi,
    I have downloaded mecha_cat Model file
    but its not in default pose.
    Can you please share the default pose model file

    Thank you.

    • Jorn says:

      That is actually the pose in which the model initially was uploaded. I don’t even know if I still have my own rig files for the cat, so you’ll have to pose the model yourself before starting the actual rigging, sorry 🙁

  3. roman says:

    awesome!!!

  4. celia col says:

    Hello your tuto on the ribbon is great but I have a worry the last script in python for the scale of the group I have a syntax invalid while I have the same line as you. For line 1 I am on maya 2017 Please help me
    Thanks have nice day

    • Jorn says:

      As you’re getting invalid syntax, you’re most probably trying to execute the Python code from the MEL tab. In the script editor, make sure you’re running the script from the Python tab. It works in Maya 2017 here, so I’m pretty sure that should fix it 🙂

  5. badmanjam says:

    Awesome! Your technique is inspiring.
    Thank you

Leave a Reply

Your email address will not be published. Required fields are marked *