Make sure rigging shelf is already setup. Open the default file, found HERE Create a null group, rename it "left_hand_rig". Parent left_hand_low_poly_geo underneath. Duplicate left_hand_low_poly_geo. Rename the duplicate left_hand_high_poly_geo. Smooth the geometry on the left_hand_high_poly_geo(mesh -> smooth -> options: division levels = 2). Group the high and low geos together. Rename the group "left_hand_geo_grp." Hide left_hand_high_poly_geo, we will use it later.
Lets start by creating the basic joints for the hand. Using the joint tool from the top view, create a joint at the wrist. Rename this joint left_wrist_joint. For all the fingers and thumb create a joint chain, simular to shown below. Rename the joints in order: left_(finger)_base_joint, left_(finger)_orient_joint, left_(finger)_orient_end_joint. The fingers should be named index, middle, ring, pinky, and thumb. Parent the 5 joint chains under the left_wrist_joint. Parent left_wrist_joint under the left_hand_rig grp. Joint orient the thumb joints to the middle of the thumb, so the joints poke out. Set all joint rotation order to xzy. This can be done easily, select all the joints. In the rigging shelf press the button that looks like the rotation tool. Set the order to xzy and press the big button. Before going any further, make sure you followed joint ediquitte. no transY or Z, no rotation, zeroed out joint orient on end joints. Because the hand is very expressive, we aren't going to separate the low poly geometry into segments like we would on the body. By binding all the joints to the skin we will be able to get a better idea of how it all deforms. Select left_wrist_joint, select the left_hand_low_poly_geo. Create a smooth bind skin, make sure the "bind to:" option is joint heirarchy.
We are going to implement some ik features. The goal here is to make it so the hand can pivot at the knuckles and raise the palm without the fingers moving. We also want the hand to lean side to side, pivoting at the sides of the hand.(Pictures shown below). This setup is simular to the advanced foot setup. Lets start by creating an ik from each finger(incl. thumb). Use the IK handle tool, SCSolver, select left_(finger)_orient_joint to left_(finger)_orient_end_joint. Rename the new ik handles, left_(finger)_ik, ex left_ring_ik. Group all the IKs together. Rename the group left_hand_iks. Parent left_hand_iks under left_hand_rig. Create a locator. Rename it left_hand_bend_piv. Place it at the middle finger's knuckle Create 2 more locators. Rename them left_hand_inside_piv and left_hand_outside_piv. Place left_hand_inside_piv by the index finger's knuckle, place the left_hand_outside_piv by the pinky's knuckle. Parent left_hand_outside_piv under left_hand_inside_piv. Parent left_hand_bend_piv under left_hand_outside_piv. Parent left_hand_inside_loc under left_hand_rig. Duplicate the left_wrist_joint Delete all the children nodes under the duplicate Rename the duplicate left_wrist_pos_joint. Parent the left_wrist_pos_joint under left_hand_bend_joint. Select the left_wrist_pos_joint then left_wrist_joint, and create a parent constraint. Now if we rotate the locators the palm(not the fingers) should pivot around it.
Before we go any further we need to create an easy way to let the animator use these features. For the hand the best way is to have a anim represent a hand and fingers. You can either create your own by means of the ep curve tool, or download mine HERE. Once the curves is created, group them together. Rename the curve for the palm. left_hand_anim. Rename the finger anims, left_(finger)_anim. Rename the group left_hand_anim_grp. Parent the group under left_hand_rig. Move and rotate the group until it is positioned around the hand, in an easy way for the animator to select. Freeze transforms on the left_hand_anim_grp(by convience this also freezes transforms on the curves). lock and hide all the attrs on all the anims.
Now we can create attrs so the animator use the bend and side feature. Create 2 attrs on the left_hand_anim. "bend" and "side". the bends min, max to [0,50], and sides to [-50, 50]. Lets create some set driven keys. Select the hand anim. In the channel box select the bend attr. Open the set driven key editor, right click in channel box -> editors -> set driven key... Select the left_hand_anim, press load driver in the editor. Select left_hand_bend_piv, press load driven in the editor. On the right side in the driver section highlight bend. On the right side of the driven section highlight rotateZ. Press key, This will set the initial position or default position. Set left_hand_anim.bend to 50. Set left_hand_bend_piv.rotateZ to -75.Press Key. Now the .bend attribute will drive the .rotateZ of the bend_piv. Because this tutorial has alot of set driven keys. It is assumed from here on out that you understand how it works. For the side attribute, we will control the rotateX of both the inside_piv and outside_piv. For reference I used -75 .rotateX on outisde_piv for +50 on the side Attr, and 75 .rotateX on inside_piv for the -50 of the side attr. Now the attributes on the hand_anim will control the hand's action easily.
So If you haven't noticed we haven't created the rest of the finger joints yet. A human has three bones in each finger instead of one, lets fix this in our rig. For each finger(not including thumb): Duplicate the left_(finger)_orient_joint. Delete the effectors under the new joint chain. Using the button on the rigging shelf, split the joint into 3 joints. Move the new joints to their closet knuckle, TRANSLATE X ONLY!!!(or else) Rename the joints left_(finger)_#_joint. Parent left_(finger)_1_joint under left_(finger)_orient_joint. This last parenting makes sure the new joints don't ruin our concept of for bend and side, by moving with the hand.
This step is very simular to the rest of the fingers. Duplicate the left_thumb_orient_joint. Delete the effector under the new chain. Split the new joint into 3, yes 3, segements We need a three segements because we want the rotation to match the fingers. If we try and rotate one of the finger joints, the -rotateZ will curl the finger. We need this for the thumb, even though it is modeled sideways. Rename the joints left_thumb_twist_joint, left_thumb_1_joint, left_thumb_2_joint, left_thumb_3_joint. Set the translateX of left_thumb_1_joint to 0. By translateX move the joints to their closest knuckle. Parent left_thumb_twist_joint under left_thumb_orient_joint. Select left_thumb_2_joint. In the rigging shelf, press the add gee to skeleton button. Select the geo. Scale it down in the Z direction. Rotate the thumb twist joint until the geo is perpendicular to the finger nail. Copy the rotation of the joint to the joint orient, and clear out the rotataion. Delete the geo under the joint.
Now that we have the basic skeleton layout, lets create bind skeleton. The joints that we currently have are the set driven key joints, these joints will be controled by set driven keys, which we create later. We are also going to add a layer of fk anims which will control the bind based on a special fk setup. The goal is to have the rig use setdriven keys and fk at the same time. Using the group rename script in the rigging shelf, rename all the joint made so far to _sdk_joint(set driven key joint). Select all the joints, search for: "_joint" replace with "_sdk_joint", don't duplicate then rename. Using group rename again, select left_wrist_sdk_joint, search for :"_sdk_" replace with "_bind_", check duplicate then rename. Delete the parent constraint under the bind joint chain. For all the fingers(including thumb), parent the left_(finger)_1_bind_joint under the left_(finger)_base_bind_joint. Delete all left_(finger)_orient_bind_joints.
For each bind joint that is on a knuckle(minus thumb twist): Create a circle Vert snap the circle to the joint. Rotate scale and move, the CV's of the circle to make it easily selectable to the animator. Rename the circle to match the corresponding joint name, ex "left_pinky_1_anim", "left_thumb_2_anim". Freeze transforms on all anims.
For this setup we are going to do it by hand once then you can use my script to finish it. The fk anim and the sdk both need to rotate the bind skeleton at the same time. To do this we are going to use an addition node. Ideally the rotation of the anim plus the rotation of the sdk = total rotation of the bind joint. But before we go any further we need the anims to perfectly match the orientation of the joints. This will ensure that a rotateZ of the anim WILL match a rotateZ of the joint. There is a trick for doing this. Select the left_pinky_1_anim. Group it to itself, and rename the group left_pinky_1_sdk_rotate. The rotate group is for later use, not for orienting to joint. Select the left_pinky_1_sdk_rotate. Group it to itself, and rename the group left_pinky_1_anim_grp. Vert snap the pivot of the anim_grp to the same joint as the anim. Parent the left_pinky_1_anim_grp under left_pinky_1_bind_joint. Parenting under the hierarchy will make the anim_grp get all the rotation of the joints. Freeze transforms on the anim_grp. The anim should now match the rotation of the joint. Awesome!! Unparent the anim_group. The anim_grp should now carry all the rotation info to match the fk anim to the joint, while the fk anim itself stays frozen. Now we can create the connections. Select the left_pinky_1_anim, left_pinky_1_sdk_joint, left_pinky_1_bind_joint, and open the hypergraph. In the hypergraph, in the menus, rendering -> create render node... -> utility tab -> press the +/-Average button. Rename the new node left_pinky_1_rotate_add. Select the left_pinky_1_rotate_add. In the attribute editor press the add new item button twice under the input 3d tab. In the hypergraph connect left_pinky_1_sdk_joint.rotate to left_pinky_1_rotate_add.input3d[0]. Connect left_pinky_1_anim.rotate to left_pinky_1_rotate_add.input3d[1]. Connect the left_pinky_1_rotate_add.output3d to left_pinky_1_bind_joint.rotate Don't worry if you don't see a connection line in the hypergraph. It has do go through a unit conversion node with is defaultly hidden.
If we rotate the left_pinky_1_anim, we will see the bind joint move. If we also move the left_pinky_1_sdk_joint we should also see the bind joint move. One thing to notice is that the anim doesn't follow when the sdk joint moves. We want the anim to always stay with the bind joint. To fix this, parent left_pinky_1_anim_grp under the left_pinky_base_bind_joint(the joint above it in the hierarchy) In the hierarchy connect the left_pinky_1_sdk_joint.rotate to the left_pinky_1_sdk_rotate.rotate Now the pinky_1 joints should work properly. For the rest of the joints. You may use my script, given below. Select the anim, then the sdk joint then the bind joint, then run the script. Ex. select left_pinky_1_anim, left_pinky_1_sdk_joint, left_pinky_1_bind_joint. run script. The code is python so make sure you eval it as python code and not mel.
import maya.cmds as mc objs = mc.ls(sl = 1) anim = objs[0] sdk_joint = objs[1] bind_joint = objs[2] add = anim.replace("_anim", "_rotate_add") sdk_rot_grp = mc.group(anim, n=(anim+ "_sdk_rotate")) grp = mc.group(sdk_rot_grp, n=(anim + "_grp")) mc.parent(grp, bind_joint) mc.makeIdentity(grp, apply = 1, t=1, r=1, s=1, n=0, jointOrient =1) add = mc.createNode("plusMinusAverage",n = add) mc.connectAttr(anim + ".rotate", add + ".input3D[0]" ) mc.connectAttr(sdk_joint + ".rotate", add + ".input3D[1]") mc.connectAttr(add + ".output3D", bind_joint + ".rotate") mc.connectAttr(sdk_joint + ".rotate", sdk_rot_grp + ".rotate") bind_parent = mc.listRelatives(bind_joint,parent =1) mc.parent(grp, bind_parent)
Last thing we need for the bind is to make sure all the other bind joints rotate along with the sdk joints. Select the left_wrist_sdk_joint, then the left_wrist_bind_joint and create a parent constraint. For each of the finger chains(not the thumb) Select the left_(finger)_base_sdk_joint, then the left_(finger)_base_bind_joint and create a orient constraint. Select the left_(finger)_1_sdk_joint, then the left_(finger)_1_bind_joint and create a orient constraint. For the thumb Select the left_thumb_base_sdk_joint, then the left_thumb_base_bind_joint and create a orient constraint. Select the left_thumb_twist_sdk_joint, then the left_thumb_twist_bind_joint and create a orient constraint.
The next step before we can create accurate set driven keys is to make sure the hand geo deforms correctly. If we look at our current skin you should notice it doesn't follow our current bind joints. First delete history on the low-poly geo, this will make it lose it's current skin. Select all the bind joints except, left_thumb_twist_bind_joint, then the low poly geo. Then create a smooth bind making sure the bind to: is set to joints selected. If we bend the fingers you can see that the geometry loses volume. Lets fix this, first delete history on the low geo again. For each finger(incl thumb) for select all the finger bind joints that have a number in their name. From the rigging shelf press the add halfway joint tool. This will create alot of joints in the middle of the joint chains. Move the new joints down until they are on the border of the finger, as shown below. Rename the new joints, left_(finger)_#_volume_bind_joint. ex left_pinky_3_volume_bind_joint. These joints will help keep volume as we bend the finger. We need to create one more halfChild joint. This is for the thumb base. If you cup touch your pinky to your thumb, At the base of your thumb there is a huge bulge. This joint will help us maintain volume. Rename the new child joint, left_thumb_base_volume_bind_joint. Delete History on the low geo again. Select all the bind joints exept left_thumb_twist_bind_joint. And bind skin. Now as we bend the finger, the geo maintains volume much better.
The outliner is getting busy and we need to hide some things or organizational sake. Hide the left_hand_iks group. Hide left_hand_inside_piv. Group the left_wrist_sdk_joint and the left_wrist_bind_joint together. Rename the group left_hand_joint_grp. Hide the left_wrist_bind_joint. Much better.
Now we can start to create the set driven keys for the hands. First we need attributes which will drive the set driven keys. Select the left_hand_anim. Create the following attributes. Don't set a min or max. curl thumbCurl scrunch thumbScrunch relax cup spread midSpread thumbSpread twist lean For each of the finger anims(not the thumb), create the following attrs(again no min or max.) curl scrunch spread twist lean bend_base bend_1 bend_2 bend_3 For the thumb create the following attrs,(no min or max) curl scrunch spread orbit twist bend_base bend_1 bend_2
For all the attrs you can see you will see a picture of the of the rotations of joints for 10 then -10. For the driver will always be the left_hand_anim and the corresponding attr. The driven will the left_(finger)_(base, 1, 2, 3)_sdk_joint For the thumb, driven will be left_thumb_(base, twist, 1, 2)_sdk_joint. The driven attributes will always be all the rotates. We need to always create three keys, -10,0,10Curl positvie: fingers(no thumb) are rolled in a fist. negative: fingers(no thumb) are curled slightly upwards.
ThumbCurl positvie: thumb is rolled into a fist. negative: thumb is curled backwards(like a hitchhiker's thumb)
Scrunch positvie: fingers(no thumb look like they are scrapping a table if palm is flat. negative: fingers(no thumb) look like they are hyper extended
ThumbScrunch positvie: thumb looks like it is being pushed backwards negative: thumb looks hyperextended
Relax positvie: hand is in relaxed position, pinky-side heavy negative: hand is in relaxed position, index-side heavy
Cup positvie: thumb and pinky touch negative: (no negative value)
Spread positvie: hands are spread apart negative: hands are squeezed together
MidSpread positvie:middle fingers are spread toward pinky negative:middle fingers are spread toward index
Thumb_spread positvie: thumb is spread away from index negative: thumb is squeezed toward index
Twist positvie: fingers are rotated along the joints clockwise negative: fingers are rotated along the joints counterclockwise
Lean positvie: fingers look as though they are dragging toward the thumb negative: fingers look as though they are dragging toward the pinky
Now we have to create all the keys for the fingers. But before you panic, there is a script that will do this for us. Ex. We want the pinky_anim.curl to rotate the pinky sdk joints the same, so the animator knows how much each joint rotates, and there is consistancy. Lets run the situation once on the pinky curl then you can do the rest by yourself. Select all the pinky sdk joints that were used to the hand anim(base, 1, 2, 3) Press the "sdk copy" button on the rigging shelf. Highlight all the joints on the top left. On the top right select the attr you want to copy to the finger_anim(In this case curl). On the bottom left, press "load sel", then highlight all the joints again. Select the pinky anim, in the bottom left right click in the text field. Select pinky_anim.curl from the drop down menu. Press copy. Rinse and repeat for all fingers(incl) curl, spread, scrunch, twist, lean. Make sure you take from the right attribute. Ex the left_thumb_anim.spread should come from the left_hand_anim.thumb_spread
Lets make those bend attrs on the finger anims useful. For each joint, left_(finger)_(base, 1,2,3)_sdk_joint: Press the "sdk auto" in the rigging shelf. Select the joints corresponing finger anim. In the sdk auto editor, right click where in the field under "driver", and select the anims name. On the right half of the driver section select the bend attr that correspondes to the joints. ex. bend_2 for the left_pink_2_sdk_joint. Select the joint. Right click under where it says driven, select your joint from the drop down. To the right side of driven, highlight the .rotateZ attr. Set the influence to -1.(a -rotateZ should corresponde to a +bend) Press create. Rinse and repeat for all bends on all fingers anims(incl thumb.)
Last but not least the orbit attr on the thumb. This is a simple one, this is the same action as the cup but only for the thumb_twist_sdk and the thumb_base_sdk. Use the copy sdk scripts to copy the sdk's from the left_hand_anim.cup.
Woot. we finished all the set driven keys, kinda. Well they all do work, but they need to be edited for two reasons. One. If the curves aren't linear then the animator will have to counter animate the fingers to get them how he wants them. Two. As it stands there is a limits from the set driven keys. If the animator wanted to spread the hand further than the spread attr currently allows, he couldn't. To fix problem 1, we are going to make all the curves linear. To Fix problem 2 we are going to make the set post infinity to linear on the curves. Select all the sdk joints used when creating the sdks. Open the graph editor. On the left side select everything, press f to focus. Select curve points on the left half. set the tanget to spline. Selct the curve points on the right half. set all the tangets to linear. Select all the curves. In they graph editor, go curves -> pre infinity -> linear. and curves -> post infinit -> linear. Now when we change the attrs, on the hand_anim the rotation continues as far as the animator needs.
Select all of the fk anims. Lock and hide translate, and scales. Hide the visibility. Select the left_hand_anim. Add an attribute name fkAnims, type: enum, enum values: Hide, Show. Create a new layer. Call the Layer left_hand_fk_anims. Select all the fk anims and add them to the layer. connect left_hand_anim.fkAnims to the left_fk_anims.drawOverRide.visibility.
We should also create a wrap deformer for the high poly version. What a wrap deformer does it overlay the geometry of one, over another. We want the high poly version to stick or wrap around the lower poly version.So where ever the lower poly version does the high poly follows. This will save us from weight painting the geometry for the low poly and the high poly. Select the high poly version. Select the low poly version. Animation menu set -> deformers -> wrap deformer. usually a switch for high poly and low poly version is made on the main control. So we don't have to create one. But lets add both polygon hands into a new layer called, "left_hand_geo". and reference the layer. Now as the hand is bent the high poly version also deforms. For now hide the high poly version.
If we move the left_hand_rig group, you should notice the hand double transforms. This is because the joints move the weights of the geo, and the geometry also inherits the transformation. To fix this select left_hand_geo_grp. In the attribute editor uncheck inherits transforms. There now as we move the rig, everything stays together. :)
Last and not least we can weightpaint. If we weightpaint the low_poly version the highpoly version will be effected as well!! Just do a simple once over on the hand.