Monday, January 15, 2018

Ranger Rig Production Part2

I just accidentally deleted the original draft of this so I'm posting again.  Sadly I dropped this project for a while, however I do intend to return to it at some point.

Two words that are stuck in my brain when it comes to animation requirements are dependability, and predictability. Nice words right, but what do they mean in context to a rig? A dependable rig shouldn’t break. Stretchy limbs should always stretch, matching should always match, and all those other super high-tech features should stay super. Predictability comes into play when you’re creating multiple rigs for a production. If one rig has certain features, control shapes, and so on, then all the rigs should have those features. You don’t want to call your arm to head space switch attribute “head switch” on one rig and “noggin toggle” on another. So listen, this all sounds great, but stuff always happens on the first pass of any rig. Maybe you didn’t understand all of the animators requirements, or the animator will need the rig to do some crazy thing for a specific shot. Animator: “In this shot I need the character to shove his foot in his mouth while doing the chicken dance”. You also need to consider that you are just a human. You are going to make mistakes, or miss some connection somewhere that causes the rig to turn into a ball of polygons when a particular set of controls are used in combination. That’s okay. Animators are generally understanding people who are willing to laugh at with you when when something explodes, but it’s the Character TD’s job to make sure that the chance of errors have been minimized before the rig is delivered.
So how do we minimize the margin for error? Doing things procedurally goes a long way toward that goal. While you may have had a rough night drinking craft beer samplers at your sister's birthday party, your code will be a bit more sensible. Knowing it has to work in the morning, your code will refrain from any any heavy partying thus allowing it to perform predictably the next day. It’s also important for you to talk to the animators before creating the rig they will use. I know they can be king of intimidating standing over there talking about acting choices and motivation while they wildly swing around a plastic sword, but it’s unlikely they will strike you “intentionally” if you go over to discuss the requirements for the shot or animation sequence they will be working on.
Lastly you should consider technical requirements. If you are working on a game you may be up against a joint limit and you are probably limited to the types of deformers you can use. In most case you won’t be able to use any deformers to effect the actual skinned mesh, but you can use deformers to drive the rig. And let’s not forget number of influences per vertex! In my opinion these limitations are the factors that make game rigging so interesting and challenging. Game rigs need to push toward that cinematic quality without crazy deformers, muscle systems, and per shot rigs. Okay I’m slipping into a tangent. What other technical requirements should we consider. Well we will probably want the rig to run at more than one frame per second. This means we need to be smart with our deformer use, expressions, muscle systems, and all that fancy stuff that makes a rig fancy. Time for another shameless shout out to the Rigging Dojo who has some excellent information on the topic of rig performance.
Above all else, the animator wants to create the pose they want as quickly and easily as possible without counter animating! If you remember that one thing, you are sure to be surrounded by happy animators

Now for those of you who refused to read all those boring words above, I present a synopsis in bullet point form.
Designing a great rig

  • Dependability and Predictability.
  • The animator can get the poses they need as easily as possible with no counter animating.
  • The rig can achieve the requirements of a particular shot, a series of shots, or an animation set.
  • The rig should be fast enough to allow for real time playback.
  • The rig should Saweet! 

With all of the previous stuff in mind I will now set out to define the requirements for the Ranger Rig.
Ranger Rig Requirements
  • Audience: The animation community at large.
  • Use: I have no idea what you are going to do with this thing and I don’t plan on asking each of you personally so I will defer to some general requirements.
  • General Requirements:
  • Cinematic quality face with minimal controls to drive toward major poses like mouth corner wide and brow up. Sub-controls will allow for fine tuning the pose.
  • Beny controls.
  • Stretchy limbs.
  • Automated correctives.
  • Commonly used space switches.
  • 360 degree twist extractors to prevent flipping.
  • The foot.
  • Heel to toe roll.
  • Animatable points for twist and pivot.
  • Toe twist, flap, and pivot.
  • Breathing controls.
  • Weapon controls with the ability to easily sheath the sword.
  • Possibly the ability to remove the boots, and armor. 
  • Optional dynamics for little dangly bits.
  • The rig should be built procedurally where possible. This means all the artsy things like nice face shapes should be handled by math and junk, with an optional layer that uses blendshapes, and deformers.
  • It must be fast! This may mean things like proxy geometry, total abandonment of expressions, and systems optimized for multithreading.
  • Support for older versions of Maya.
That looks like a pretty good list for the moment. I would love to hear your opinions on what makes for a great rig with some specific information on features you would like to see on the Ranger. I think my next pose will talk about my plans for the face as I'm psyched up to get started on that. That’s all for now everyone.
The kids and I have started a new project where we are exploring art, animation, music, and more.  Every week or so we work on some project like an animated video which we post on YouTube.  We then follow that up with a video showing how we did what we did.  I was inspired to take on this project because it offers us an opportunity to learn and grow as a family while providing a learning experience and hopefully some entertainment to our viewers.  I encourage you to please show your support for this endeavor by visiting our YouTube channel and our blog.  We would be pleased if you could subscribe so you can keep up to date on all of our latest creations.
I would't feel right if I left the post here without giving you a sample of the sort of things we are working on.  So without further delay I present The Kids Say What's first creation.  The Fluffy Rainbow Butterfly Unicorn Kitty.

Saturday, March 05, 2016

Ranger Rig Production Part1

Every year or so I like to take on a big personal rigging project so I can pick up some new tricks without the pressures and constraints of an actual production. This time around I will be mixing in several ventures all aimed at creating a film quality rig that can be distributed to the animation community at large. I will start off by outlining the goals of this project while giving a few details on how I plan on achieving these goals. Now before I get too deep into this, let me issue a fair warning that I have a son on the way any day now, so this project could go several weeks without anything to report. Alrighty then, with my excuses out of the way, let's push on.


  • Work with a small team to develop some rigging tools.  Except for the artsy stuff,  I hope to generate every part of this rig procedurally.  Details on this small team and that development process will be coming soon.
  • Develop a robust facial rigging solution that looks great without a bunch of fancy deformers,  but is able to layer in deformers and blendshapes to push the look to the next level.
  • Push myself to push my skills at cinematic quality rigging.
  • Teach all of you about my process.  Hopefully we will both learn something new!  I won't be going full tutorial style on everything I do here, however I may make tutorials available in one form or another later on.  For now you can check out the Rigging Dojo, where you can get my Python class along with a ton of information on everything rigging related.

If I'm going to rig a character, I suppose I will need to start with a model.  No, not just any model.  It needs to be a great model.  Fortunately for me, the extremely talented Daniel Williams has offered up one of his creations for this mad science project.  I highly encourage you to check out his work.  This is typically the section where I would talk about good topology for rigging, but Danny's models already have fantastic topology.  I will talk briefly about what makes topology "fantastic", and I will do some comparisons between what I look for in a cinematic mesh versus a game ready mesh in later posts.  Before we get into all of that I want to show you what we'll be working with.


Check out this link to see the Ranger in all his rendered glory.

Here are some reasons why I think this topology is Fantastic!

  • The continuous line across the brow.
  • The edge that flows from the nose to the mouth furrow line.
  • The clean circular edges around the mouth.
  • The extruded face between the brows for a nice brow furrow.

While this is a great model, I will suggest the following edits to the face topology.

That's all I have time for tonight.  In my next post I want to start designing the requirements for this rig so I can break the work into chunks.  We will talk about how I determine those requirements, and my process for plotting out how to meet them.  Thanks for stopping by and I hope to see you here next time.

Thursday, March 03, 2016

Surface Based Facial Rigging POC

I pulled out this face rig proof of concept that illustrates the idea of controlling interpolation through the use of surfaces.  All of the animation is driven by just 3 controls, with a set of minor controls that follow along with the majors so you can fine tune.

SurfaceFacePOC_01 from ryan griffin on Vimeo.

Tuesday, March 01, 2016

Leg Rigging in Maya

I wrote up this little leg rigging tutorial with the Python code I captured while manually rigging.  I thought this might be a handy resource for aspiring riggers.  This is basically the process I use when figuring out some new rigging technique.  Later on I will go back and refine the code to make it more concice and versatile.

IK Stretchy no Flip Leg Tutorial

In this tutorial I will walk you through the creation of a robust ik leg setup.  This is not the only way to build a leg, but I feel this setup introduces some pretty useful concepts that can be applied to your own rig.  Lets get started.

Step1:  Create the joints
First we need to draw our joint chain.  In my example I have named the joints ( jnt_pelvis, ikj_hip, ikj_knee, ikj_ankle, ikj_ball, and ikj_toe).  Once the joints are created, you should orient them using Skeleton/Orient Joint.  I chose to use X down the bone and Y up.  This orientation will be important later on, so just make a mental note if you decide to use a different orientation.

Step2: Drawing the IK:
Draw an ikRP solver from ikj_hip to ikj_ankle.
Draw an ikSC solver from ikj_ankle to ikj_ball.
Draw an ikSC solver from ikj_ball to ikj_toe.
Here is an example of how we could do this with Python.
cmds.ikHandle(n= "ikh_leg", sj= "ikj_hip", ee= "ikj_ankle", sol = "ikRPsolver")
cmds.ikHandle(n= "ikh_ball", sj= "ikj_ankle", ee= "ikj_ball", sol = "ikSCsolver")
cmds.ikHandle(n= "ikh_toe", sj= "ikj_ball", ee= "ikj_toe", sol = "ikSCsolver")

Step3:  Grouping the IK:
We need to create groups to use for rotating the toe, foot roll, and so on.  The setup I am presenting is a bit different than most tutorials I have seen, and we need to create some extra groups to accommodate that fact.
Create the following groups.  I will write this in Python format.

footGroups = ("grp_footPivot", "grp_heel", "grp_toe", "grp_ball", "grp_flap")
for item in footGroups:, empty=True, world=True)

grp_footPivot should be left at the origin.
grp_heel should be moved to the heel of the foot geometry.
grp_toe should be moved to ikj_toe.
grp_ball should be moved to ikj_ball.
grp_flap should be moved to ikj_ball
You can move these by first getting the position of the joints using cmds.xform
You can then place the groups with xform again.
hipPos = cmds.xform("ikj_hip", q=True, ws=True, t=True)
anklePos = cmds.xform("ikj_ankle", q=True, ws=True, t=True)
ballPos = cmds.xform("ikj_ball", q=True, ws=True, t=True)
toePos = cmds.xform("ikj_toe", q=True, ws=True, t=True)
cmds.xform("grp_toe", ws=True, t=toePos)
cmds.xform("grp_ball", ws=True, t=ballPos)
cmds.xform("grp_flap", ws=True, t=ballPos)
The heel is tricky. We need an object to set the position

Now we need to put our groups and ik handles into a hierarchy.  

cmds.parent('grp_heel', 'grp_footPivot')
cmds.parent('grp_toe', 'grp_heel')
cmds.parent('grp_ball', 'grp_toe')
cmds.parent('grp_flap', 'grp_toe')
cmds.parent('ikh_leg', 'grp_ball')
cmds.parent('ikh_ball', 'grp_ball')
cmds.parent('ikh_toe', 'grp_flap')
cmds.parent(‘grp_footPivot’, ‘ctrl_leg’)

Step 4:  Foot Control
Create a control object to control your foot.  Snap the controls pivot to your ikj_ankle and be sure to freeze transforms.  I named my foot control “ctrl_leg”.  Now you can parent the “grp_footPivot” to “ctrl_leg”

Step 5:  No Flip Knee
Create a locator. Name it “lctrPv_leg”, and snap it to the position of “jnt_pelvis”. Parent the locator under “jnt_pelvis”.  
pelvisPos = cmds.xform('jnt_pelvis', q=True, ws=True, t=True)
cmds.xform('lctrPv_leg', ws=True, t=pelvisPos)

Select the locator, then the “ikh_leg”, and execute Constrain > Pole Vector.
cmds.poleVectorConstraint ('lctrPv_leg', 'ikh_leg', weight=1)
Create a float attribute called "Twist" on the ikFootCtrl controller.  Select the ctrl_leg and execute this command.
cmds.addAttr( shortName='Twist', longName='Twist', defaultValue=0, k=True)

Create a plusMinusAverage utility, and call it pmaNode_LegTwist.
Create a multiplyDivide utility and call it mdNode_LegTwist.
cmds.shadingNode("plusMinusAverage", asUtility=True, n='pmaNode_LegTwist')
cmds.shadingNode("multiplyDivide", asUtility=True, n='mdNode_LegTwist')

Set up the connections using the following commands :
cmds.connectAttr('ctrl_leg.Twist', 'mdNode_LegTwist.input1X')
cmds.connectAttr('ctrl_leg.ry', 'mdNode_LegTwist.input1Y')
cmds.connectAttr('jnt_pelvis.ry', 'mdNode_LegTwist.input1Z')
cmds.setAttr('mdNode_LegTwist.input2X', -1)
cmds.setAttr('mdNode_LegTwist.input2Y', -1)
cmds.setAttr('mdNode_LegTwist.input2Z', -1)
cmds.connectAttr('mdNode_LegTwist.input1X', 'pmaNode_LegTwist.input1D[0]')
cmds.connectAttr('mdNode_LegTwist.input1Y', 'pmaNode_LegTwist.input1D[1]')
cmds.connectAttr('pmaNode_LegTwist.output1D', 'ikh_leg.twist')

Step 6:  Create the Stretchy IK
Start by creating all of the nodes we will need for the stretch.
cmds.shadingNode("addDoubleLinear", asUtility=True, n='adlNode_LegStretch')
cmds.shadingNode("clamp", asUtility=True, n='clampNode_LegStretch')
cmds.shadingNode("multiplyDivide", asUtility=True, n='mdNode_LegStretch')
cmds.shadingNode("multiplyDivide", asUtility=True, n='mdNode_KneeStretch')
cmds.shadingNode("multiplyDivide", asUtility=True, n='mdNode_AnkleStretch')

Add a “Stretch” attribute to ctrl_leg.‘ctrl_leg’)
cmds.addAttr( shortName='Stretch', longName='Stretch', defaultValue=0, k=True)

Create a distance tool to measure the distance between our hip and ankle joints.
Use Create/Measure Tools/Distance Tool.
Snap one locator to ikj_hip and name it ‘lctrDis_hip’.  Parent this locator to ‘jnt_pelvis’
Snap the other locator to ikj_ankle and name it ‘lctrDis_ankle’.  Parent this locator to grp_heel’
hipPos = cmds.xform('ikj_hip', q=True, ws=True, t=True)
anklePos = cmds.xform('ikj_ankle', q=True, ws=True, t=True)
disDim = cmds.distanceDimension(sp=(hipPos), ep=(anklePos))

cmds.rename('distanceDimension1', 'disDimNode_legStretch')
cmds.rename('locator1', 'lctrDis_hip')
cmds.rename('locator2', 'lctrDis_ankle')
cmds.parent('lctrDis_hip', 'jnt_pelvis')
cmds.parent('lctrDis_ankle', 'grp_ball')

Next we will need to figure out the length of the leg when it is fully extended.  We could do this by moving the leg control until the leg is straight, and querying the distance tools distance attribute, but this is inaccurate and can not be scripted.  Instead we will use python to get the translateX values of our joints.  We will then add those values.

kneeLen = cmds.getAttr('ikj_knee.tx')
print kneeLen
ankleLen = cmds.getAttr('ikj_ankle.tx')
print ankleLen
legLen = (kneeLen + ankleLen)
print legLen

Enter our new found length values into the corresponding Nodes.
cmds.setAttr('adlNode_LegStretch.input2', legLen)
cmds.setAttr('mdNode_LegStretch.input2X', legLen)
cmds.setAttr('mdNode_KneeStretch.input2X', kneeLen)
cmds.setAttr('mdNode_AnkleStretch.input2X', ankleLen)

Connect the nodes to get the final stretch value that will be applied to our joints.

The clamp node lets us control the amount of stretch.
cmds.connectAttr('ctrl_leg.Stretch', 'adlNode_LegStretch.input1')
cmds.setAttr ("clampNode_LegStretch.minR", 12.800084)
cmds.setAttr ("mdNode_LegStretch.operation",  2)

Connect the distance dimension so we always know the current length of the leg.
cmds.connectAttr('disDimNode_legStretch.distance', 'clampNode_LegStretch.inputR')
cmds.connectAttr( 'adlNode_LegStretch.output', 'clampNode_LegStretch.maxR')

Now we feed the total value into a multiply divide so we can distribute the value to our joints.
cmds.connectAttr('clampNode_LegStretch.outputR', 'mdNode_LegStretch.input1X')
cmds.connectAttr('mdNode_LegStretch.outputX', 'mdNode_KneeStretch.input1X')
cmds.connectAttr('mdNode_LegStretch.outputX', 'mdNode_AnkleStretch.input1X')

Finally, we output our new values into the translateX of the knee and ankle joints.
cmds.connectAttr('mdNode_KneeStretch.outputX', 'ikj_knee.tx')
cmds.connectAttr('mdNode_AnkleStretch.outputX', 'ikj_ankle.tx')

Step 7:  Create the Foot Roll
By now you are hopefully familiar with what the lines of code are doing.  For this next part I will not offer too much in depth explanation.  We will create a foot roll attribute that goes all the way from the ball to the toe roll.  We will do this using only nodes.  It may be easier to accomplish this with set driven keys, but I prefer not to use SDKs when possible.

Create Attributes on the ctrl_foot'ctrl_leg')
cmds.addAttr( shortName='Roll_Break', longName='Roll_Break', defaultValue=0, k=True)
cmds.addAttr( shortName='Foot_Roll', longName='Foot_Roll', defaultValue=0, k=True)
Setup the foot roll
Create utility nodes
cmds.shadingNode("condition", asUtility=True, n='conNode_ballRoll')
cmds.shadingNode("condition", asUtility=True, n='conNode_negBallRoll')
cmds.shadingNode("condition", asUtility=True, n='conNode_toeRoll')
cmds.shadingNode("plusMinusAverage", asUtility=True, n='pmaNode_ballRoll')
cmds.shadingNode("plusMinusAverage", asUtility=True, n='pmaNode_toeRoll')
cmds.shadingNode("condition", asUtility=True, n='conNode_heelRoll')
cmds.setAttr('pmaNode_toeRoll.operation', 2)
cmds.setAttr ("conNode_toeRoll.operation", 2)
cmds.setAttr ("conNode_toeRoll.colorIfFalseR", 0)
cmds.setAttr ("conNode_toeRoll.colorIfFalseG", 0)
cmds.setAttr ("conNode_toeRoll.colorIfFalseB", 0)
cmds.setAttr ('conNode_heelRoll.operation', 4)
cmds.setAttr('conNode_heelRoll.colorIfFalseB', 0)
cmds.setAttr('conNode_heelRoll.colorIfFalseR', 0)
cmds.setAttr('conNode_heelRoll.colorIfFalseG', 0)
cmds.setAttr("pmaNode_ballRoll.operation", 2)
cmds.setAttr ("conNode_negBallRoll.operation", 3)
cmds.setAttr ("conNode_ballRoll.operation", 3)

Setup Toe
cmds.connectAttr('ctrl_leg.Foot_Roll', 'conNode_toeRoll.firstTerm')
cmds.connectAttr('ctrl_leg.Foot_Roll', 'conNode_toeRoll.colorIfTrueR')
cmds.connectAttr('ctrl_leg.Roll_Break', 'conNode_toeRoll.secondTerm')
cmds.connectAttr('ctrl_leg.Roll_Break', 'conNode_toeRoll.colorIfFalseR')
cmds.connectAttr('ctrl_leg.Roll_Break', 'pmaNode_toeRoll.input1D[1]')
cmds.connectAttr('conNode_toeRoll.outColorR', 'pmaNode_toeRoll.input1D[0]')
cmds.connectAttr('pmaNode_toeRoll.output1D', 'grp_toe.rx')

Setup Heel
cmds.connectAttr('ctrl_leg.Foot_Roll', 'conNode_heelRoll.firstTerm')
cmds.connectAttr('ctrl_leg.Foot_Roll', 'conNode_heelRoll.colorIfTrueR')
cmds.connectAttr('conNode_heelRoll.outColorR', 'grp_heel.rotateX')
Setup Ball
cmds.connectAttr('ctrl_leg.Foot_Roll', 'conNode_ballRoll.firstTerm')
cmds.connectAttr('ctrl_leg.Foot_Roll', 'conNode_ballRoll.colorIfTrueR')
cmds.connectAttr('ctrl_leg.Roll_Break', 'conNode_negBallRoll.secondTerm')
cmds.connectAttr('ctrl_leg.Roll_Break', 'conNode_negBallRoll.colorIfTrueR')
cmds.connectAttr('conNode_negBallRoll.outColorR', 'pmaNode_ballRoll.input1D[0]')
cmds.connectAttr('grp_toe.rx', 'pmaNode_ballRoll.input1D[1]')
cmds.connectAttr('pmaNode_ballRoll.output1D', 'grp_ball.rx')
cmds.connectAttr('conNode_ballRoll.outColorR', 'conNode_negBallRoll.firstTerm')
cmds.connectAttr('conNode_ballRoll.outColorR', 'conNode_negBallRoll.colorIfFalseR')

Make a Toe Flap
We will need to make a new attribute called Toe_Flap on ctrl_foot.  Then we can connect Toe_Flap to grp_flap rotateX.'ctrl_leg')
cmds.addAttr( shortName='Toe_Flap', longName='Toe_Flap', defaultValue=0, k=True)
cmds.connectAttr('ctrl_leg.Toe_Flap', 'grp_flap.rx')

Step 8:  Pivot for Bank and Twist
Create a new control object.  I am using something that looks like a pin.  Name the control ‘ctrl_footPivot’
Move the control to the grp_ball.
ballPos = cmds.xform('grp_ball', q=True, t=True, ws=True)
cmds.xform('ctrl_footPivot', t=ballPos)

Deselect the ctrl_footPivot, and create an empty group at the origin.  Name the group ‘grp_ctrl_footPivot’.'grp_ctrl_footPivot', empty=True)
Parent the grp_ctrl_footPivot  to  ctrl_footPivot.
cmds.parent('grp_ctrl_footPivot', 'ctrl_footPivot')
Parent the ctrl_footPivot to ctrl_foot and freeze transforms on ctrl_footPivot.
cmds.parent('ctrl_footPivot', ‘ctrl_foot’)
cmds.makeIdentity( apply=True )

Now we will connect the grp_ctrl_footPivot.translate to grp_footPivot.rotatePivot
cmds.connectAttr('grp_ctrl_footPivot.translate', 'grp_footPivot.rotatePivot')
Move grp_ctrl_footPivot to the position of grp_ball.
cmds.xform('grp_ctrl_footPivot', t=ballPos)

Make a couple more attributes for twist and bank, then hook those up to the grp_footPivot.'ctrl_leg')
cmds.addAttr( shortName='Foot_Pivot', longName='Foot_Pivot', defaultValue=0, k=True)
cmds.addAttr( shortName='Foot_Bank', longName='Foot_Bank', defaultValue=0, k=True)
cmds.connectAttr('ctrl_leg.Foot_Pivot', 'grp_footPivot.ry')
cmds.connectAttr('ctrl_leg.Foot_Bank', 'grp_footPivot.rz')

Please email me with any questions or errors.  I do not claim that this is the perfect leg rig.  I designed this to try some new ideas and to incorporate some time tested methods.
-Ryan Griffin