2013-04-03

Adventure Time - A Glitch is a Glitch

Yesterday aired the Adventure Time episode "A Glitch is a Glitch" (AT S5E15 AGIAG).
It was a special 3D episode (usually the show is 2D) and directed by David OReilly.
The rigging was done by Mark Feller and me at Studio Soi in July 2012. My main responsibility were the faces and spines. The faces were made by hand, some parts I could import and adjust after the first one was done. The mouth joints were sliding on a nurbs surface, that had the shape of the face polygons. For the spines I wrote a script (ribbon based. See older post: Joint chain rigging techniques).

This is a clip from the episode:

2013-03-01

Maya Naming Conventions

(updated on 2014-09-10)

Summary

  • L_arm_1_upper_joint  >  L_arm_2_lower_joint
  • Prefix = Region: Side ("L_..." / "R_..." / none for center) + region ("...arm_", "spine_", ...)
  • Middle = Hierarchy numbering starting at 1 (not 0) followed by descriptive string ("...1_upper...", "...2_lower...")
  • Suffix = Nodetype: Default Maya nodenames ("..._blendColors", "..._multiplyDivide", ...)

Motivation

This is a simple naming convention that currently seems the most logical to me, after having used different ones of myself and coworkers in the past. The main goals are:
  1. Readability (from the name know what it is and where it is used. But not too long)
  2. Simplicity (easy to learn, avoid confusion, hard to make mistakes, few exceptions)
  3. Functionality (easy to work with: string search / filter)

Prefix = Region ("L_arm_...", "spine_...")

If a region is in the center and/or only appears once start with it "spine_...", "head_...". Else insert side shortcut before region "L_...", "R_..." ("L_arm_...", "R_leg_..."). Reasons:
  • For regions that appear multiple times (L_arm, R_arm, ...) all related nodes will have unique names, just by adding the side prefix
  • Abbrevation to save reading time and space. If a name is too long for a Maya UI element (ChannelBox, graph editor, ...) the name usually (always?) gets cut of at the right side. So having a short prefix delays that. Opposed to using the more descriptive, but longer versions "Left_"/"Right_" or "Lf_"/"Rt_".
  • This is a "special rule" (anti readability and simplicity), but it is such a simple one and used so frequently that is hard to use wrong or forget.

Middle = Hierarchy ("...1_upper...", "...2_lower...")

  • Start with number, counting in the cranial (spine) / distal (limbs, fingers) / lateral (clavicle) direction, to allow for alphabetic ordering, which can be useful in the paint skin weights tool for example. For most people it is more intuitive to start counting at 1. Opposed to loop variables usually starting at 0 (Python: for x in range(..)).
  • Followed by a string description to understand where the element actually is (readability). This string could be standardized, but this post is about a simple naming convention. 
  • Going from general to detail is easy to read and helps with isolating regions for string search / filter ("L_hand_2_index*"). 
  • All this also helps to have unique transform node names. Which can have the same name, if they are not in the same hierarchy level. Opposed to "pure" DG (dependency graph) nodes (multiplyDivide, skinCluster,...).
Examples:
L_arm_1_upper_... > L_arm_2_lower_... > L_arm_3_wrist_...
L_hand_1_thumb_1_metacarpal_... > ...
L_hand_2_index_1_metacarpal_... > L_hand_2_index_2_phalanxProximal_... > L_hand_2_index_3_phalanxIntermediate_... > L_hand_2_index_4_phalanxDistal_...


Suffix = Nodetype ("..._multiplyDivide", "..._locator")

The nodetype is usually the suffix. Theoretical that should not be necessary, since command searching allows for a type filter (pm.ls('L_arm*', type='joint')). But when manually working in a scene it helps to read graphs / history and it also helps at having unique names.

Usually it is also shortened to 2-3 letters, which I used to do as well (joint = jn/jnt, blendColors = bc, multiplyDivide = md). But after changing my "rules" over the years and using different ones at companies I suddenly wondered what the purpose of these abbrevations even is. Since they always introduce special rules, exceptions and may not even be readable from an outsider.

So my conclusion was to just use the full default Maya node names / types as suffix:
"..._blendColors", "..._multiplyDivide".
In the beginning, when more nodes were created manually, it might have been more convenient to only type a few letters as suffix. But by now most are generated with scripts anyway.  And even when working manually and following this rule the default Maya behavior will generate the suffix by default (minus the 1 at the end).
But more importantly this rule creates unique, easy to learn, obvious suffixes for almost all nodes. There are a few exceptions, but even their solution are partly given from Maya. So they always make sense to Maya users.

Exceptions - from Maya:
  • Default transforms will get different names in Maya, depending on how they got created: null1 (empty group), group1 (group for transforms), transform1 (actual node name). Most people call default transforms (no shape / special function) groups, so I stick with group as well. To prevent hard to read suffixes when using stacked groups ("..._group_group_group") I like to use descriptive names ("..._null_group", "..._sdk_group", "..._space_group").
  • Transforms with shapes get names from the shape nodeTypes (locator1, annotation1, ...). So Maya already gave an answer how to name those transforms. Shapes themselves will get the Shape suffix.
  • Transform Handles (deformer handles) get named: "nodetypeXHandle" in Maya. So I also use this convention, except for the number in between, so it's only "deformertypeHandle". Example: L_cheek_clusterHandle (cluster itself: L_cheek_cluster)
  • ... (probably more)

Exceptions - from user:
  • Animation transforms: Usually transforms are the only nodes animators are exposed to. That's why they often get named differently. For this convention I prefer "_control" over "_nurbsCurve".
  • ... (probably more)

Code

# python examples
import pymel.core as pm
my_module = 'L_arm_'
my_joint = pm.createNode('joint')

# manual
my_joint.rename('{0}1_upper_{1}'.format(my_module, my_joint.type()))

# if you have a function to detect the suffix:
my_auto_suffix_rename(my_joint, name='{0}1_upper'.format(my_module))

# if you are in a rig module instance that detects the module:
self.my_auto_rename(my_joint, name='1_upper')

Notes: 
  • Maybe lowered prefix letter (Pro: Consistency, closer to PEP8 Python recommended variable names [lower_case_with_underscores]. Con: Lower L looks like capital i)
  • Maybe have a prefix for all areas for consistency ("C_" = center, ...)

2013-02-11

prHeatDeformer

update: fStretch is open source since 2015-03 http://www.cgaddict.com/

Description
I recently finished a heat/tension based deformer / Maya-API plug-in. Depending on the amount of stretching and compression on the surface, vertices get deformed along the normal or with blendshapes. The most common application would be to blend in wrinkles on skin and clothing.


Motivation
To have an extra tool to improve deformation for many different types of rigs. I was also personally interested in the subject, and I had some downtime between projects.

Video

prHeatDeformer - deformer (custom node) from Parzival Roethlein on Vimeo.

Breakdown
  • I had not used the Maya API for over half a year, so I was a bit rusty at first.
  • I always had to take a break when there was a project I had to work on. Which is less efficient for me than continuously working on it, because it always takes a bit to get back into it.
  • The first two weeks were spent writing a complete Python API version. I implemented all features, but with little calculation optimization. I always like writing Python versions, because you do not have to compile, so the iterations are really fast. On the downside I have to use a lot of printing and complex debugging is actually more easy in C++ / Visual Studio, because you can set breakpoints and use "attach to process" for interactive debugging, which I used the first time on this plug-in. So in retrospect it definitely would have been faster to skip the Python version. But I got more experience with the Python API.
  • After the Python version was working (and terribly slow) I wrote the C++ version in one week. This was the hardest part, because I had to implement a lot of performance increasing stuff, so that the deformer does not slow down the rig as much. There will definitely be a geometry resolution switch for the animators, but I still want them to be able to see the heatdeformed highres mesh with decent speed and also when working with it as a rigger it is always better to have the deformer as fast as possible. To make the deform fully production ready it had to work with transforms that have any number of shapes and each shapes vertices can be inside or outside of the deformer membership. Combined with the speed improvements they were the most difficult things to get done. 
  • I wrote a lot of common features for the first time (tangent space, smooth, grow, some of the speed optimizations). So that slowed me down. And will improve development time on future nodes.
  • The Python version has 800 lines, the C++ version 1400 lines (including header file, comments etc)
Conclusion
In retrospect I was surprised how quickly it was done. Especially if I had skipped the Python API implementation. Because it is one of the more technical and difficult tasks in rigging, it also feels quite rewarding when you get it done.

Todo
Additional features and performance improvements

Related
  • (2007) Siggraph 2007 presentation "Realtime wrinkles, Christopher Oat": This is the oldest reference I could find for this idea. The second half has "dynamic wrinkles" that are tension based.
  • (2008 or earlier) The Maya (Comet) muscle skinDeformer has a "wrinkle" option included to the "relax" feature. It moves vertices along the normal vector when being compressed. This feature is not usable, because there is only one global attribute to control the strength and one paintable map. So there is no limit and no way to control the acceleration etc. And the biggest problem is that the algorithm does only work properly on primitive geometry (sphere,..) because it is only considering neighbor vertices that have continuous numbering (or a random one, if there is no proper neighbor id). This is a bit hard to explain, but the result on a production mesh is that it calculates the compression differently on neighbor vertices (except if you scale everything from the same pivot), so you get spikes and have no real control over the shape.
  • (2010) fStretch: I think this is the most well known version of this technique. It is a commercial plug-in by Matthieu Fiorilli. It seems very sophisticated, but it is a commercial plug-in that costs money/effort and the license model is not so good for the place I work at.
  • (2012) tenshionBlendshape: Inside of the SOuP plug-ins, it does not have tangent space, which makes it unusable and I also did miss some other features and the base algorithm also had some problems with different sized geometries. I did send them the feedback thou, so maybe some day there will be a usable free version of this technique.

2013-01-30

Fish rig - Beck's Sapphire

The last project I worked on at Psyop. I was responsible for the rigging. 
Update: HD version

Beck's Sapphire "Serenade" from Psyop on Vimeo.

2012-12-25

prAttractNode

I never made an extra blog post for my prAttractNode. So since I just uploaded an update and also made a better demo video with more useful work examples (Read Vimeo description for explanation), I think it is a good time.

The plug-in is open source (download link in Vimeo description), so the following Maya API parts might be useful to others:
- How/Where to properly initialize a ramp attribute
- How to setup everything in a single .py/.mll file, for easy installation
- (C++) OpenMP usage (Extra blogpost: https://pazrot3d.blogspot.com/2012/01/openmp-and-maya-api.html )

prAttractNode - deformer (custom node) from Parzival Roethlein on Vimeo.

2012-12-12

prSelectionUi updates


prSelectionUi - Animation UI (Maya) from Parzival Roethlein on Vimeo.

I recently updated the prSelectionUi quite a bit. The Vimeo video got updated as well, but since there have been new script updates, it does not show all new features. You can find the download link in the Vimeo description.

There is some background information in my old blogpost:
https://pazrot3d.blogspot.com/2012/03/prselectionui.html

2012-11-29

Rig performance tips

A rig should always be as fast as possible to improve productivity of animators. It is also more fun to interact with a fast rig in general and maybe even allows for viewing the animation in realtime inside of the viewport. So there is no need to create a playblast all the time.

The biggest factor is the geometry resolution (lowres/highres/..) and the kind of setup the rigger chooses  Hopefully always balancing quality and speed. This is very project and people dependent. So I'm not going into that here. This post should just be a small list of things that always work and are not that well known (?):
  • Remove vertices from the deformer, if they are not affected, with the "Edit Deformers > Edit Membership Tool". I almost always use this for lattice, wrap, wire, sculpt, .. There are probably cases for all deformers. This can also be achieved by only selecting the affected vertices when creating the deformer.
  • Use few skinClusters by merging geometries. This should be used carefully of course, because it can be annoying to skin overlapping geometry (maybe skin multiple geometries and copy skin weights on the final merged mesh when publishing the rig) and other steps in the pipeline have to be considered as well.
  • Remove unused influences from skinCluster. Use "Skin > Edit Smooth Skin > Prune Small Weights" before. Each influence costs a little bit of performance, so if you have multiple geometries that are skinned to all skinning-joints this can make quite a difference.
  • Connections instead of constraints. A lot of point/orient/parent/scale-constraints can be replaced by simple translate/rotate/scale connections, if the hierarchy is setup in the right way (Maybe by creating an extra null-group to have the same local transformation values). BlendColor nodes can be used for blending. I think scaleConstraints are always the worse option, and can be avoided completely.
  • Don't use clusters to deform curves. Instead use a skinCluster (use component editor to tweak skinning weights) or [Credit to Francisco Naranjo:] connect locatorShape1.worldPosition[0] into the curveShape1.contolPoints[x] attribute
  • Delete unused Orig shapes. This does not effect the rig speed when interacting, but is about filesize, which increases file-opening / reference-loading time. Whenever you create a deformer, maya also creates an Orig shape (intermediate object). If you duplicate a geometry that had an orig shape, it will get copied as well, but ignored for future deformers. So it basically just increases the filesize with no benefits. You have to remember to delete it, or delete the history before you duplicate. (An easy shortcut-combination to select the orig shape: Arrow down (child), arrow left (latest child)

2012-11-12

Joint chain rigging techniques

Comparing different joint-chain-like rigging techniques. The idea is always to attach the skinning joints to a simple nurbs-curve or surface, which can easily be rigged. They all have squash/stretch/twist behavior. This kind of setup is useful for spine, bendy limbs, face (lips, eyebrows, muscle), snake, hair, tail...

They can be categorized as parametric and non-parametric. Meaning that joints will keep relative distance between each other (non-parametric) when changing the driving surface or not (parametric).
I recently compared them. Mainly for performance reasons, but keeping functionality in mind. The screenshots are from simplified setup versions.

Spline-IK
Spline-IK
  • Non-parametric
  • + Fastest non-parametric setup
  • - Limited twist control: Only start and end. No center twist control
  • - Undesirable behavior when modifying curve-cvs (overshooting joints)
  • - Gets exponentially slower when increasing joint count
  • + Easy to add dynamics/simulation on curve (because it is only one)

Ribbon
Joints attached to nurbs surface
Ribbon
  • Parametric
  • + Full local control
  • Average speed

Curve / Upcurve
Two curves. One has the skinning joints attached to it. The skinning joints either aim at the next skinning joint (spline-IK like behavior) or are rotated at the average of aiming to next/previous (ribbon like behavior). On the second curve are the up-objects for the aimconstraints. Both curves are deformed in the same way, so that rotation along the joint-curve (twist) will only deform the Upcurve, so there will be a smooth twist driven by the up-objects.
PointOnCurveInfo
MotionPath
  • + Can be non-parametric (motionpath) or parametric (pointOnCurveInfo)
  • + Fastest setup when using pointOnCurveInfo (only when using one aimconstrain upwards)
  • - Slowest setup when using motion path
  • + Full local control between start and end, depending on setup
  • Note: motion path rotation should be used carefully (almost never?). Following curve results in more extreme rotation (bigger difference between neighbors) than average of aiming up+down. So deformation will look bad in most cases.
  • Note: Motion path should be created manually (createNode motionPath). Because the MEL command (motionPath) creates unnecessary doubleLinear nodes that create cycle warnings and the command is not undoable.

Muscle Spline
Muscle > Bonus Rigging > Create Muscle Spline...
Muscle Spine
  • Parametric
  • (+) Has a lot of functionality by default
  • - Joints get oriented to curve (same problem as motion path rotation... The average of aiming on upper and lower joint is probably always better)
  • + Nice tangent/curve control attributes from start/mid/end ctrls
  • + Seems to be a bit faster than Spline-IK (but it is not non-parametric like the Spline-IK. So they are not fully comparable)
  • + Jiggle options (for hair, props, tail, antenna, .. ?)
  • Local twist, but limited control over it (flip at 180), because it is calculated in blackbox node.
  • Note: For easy to animate curves set small "Tangent Length" value (0.01) on start/end ctrl and increase on the center ctrl to have automated bend when moving center ctrl. Also edit "uValue" attribute on first (from 0.0 to 0.01) and last joint (1.0 to 0.99), so they get oriented to the curve.


Related
  • Wiredeformer is parametric
  • Curve added as influence to skinCluster (component mode on) is non-parametric

Conclusion
Curve / Upcurve setups are the most flexible and offer the most control, which probably results in the best deformation for most cases. But can be slower depending on the setup.
To get a better idea what "fastest" / "slowest" for these setups mean. Here are the fps numbers when adding eight chains (two for each limb, six joints each) of either type to a base rig that runs at 34 fps

34.0 base rig
28.6 (-5.4) pointoncurve
27.7 (-6.3) splineik
27.2 (-6.8) ribbon
26.7 (-7.3) motionpath
26.3 (-7.7) pointoncurve avrg


2012-10-16

Rigging papers

Because of the boring commute / subway riding I have been reading papers/sketches. Here are some of my favorites. I really hope to find some time in the near future to write a few more Maya plug-ins / nodes or improve my old ones.

Spiderman 3 Muscle and Skin Musculoskeletal Skinning
https://erickmiller.com/docs/sap_434_MusculoSkeletalShapeSkinning.pdf
https://www.youtube.com/watch?v=fNCB9wZP8k8&feature=relmfu
  • Muscle shape: NURBS surface from curves, keep volume
  • Muscle to skin deformer: paintable linear or dual quaternion interpolation, paintable sliding (bulge/shrink along attachment vector)
  • Pose space deformer
  • Jiggle deformer: For muscle shapes, spring based solver/equasion
  • Skin tension: spring based, projected back on mesh (closest point), user defined smooth/average steps
iRobot Character Pipeline Tools and Methods
https://erickmiller.com/docs/iRobot_Character_Pipeline_sketches_0250.pdf
https://www.youtube.com/watch?v=mX9rMQv4TC0
  • Animation curve re-mapping with NURBS surface
  • Gaussian filtering on animation against motion pops
  • Pose based deformation
  • Custom wrap deformer
  • Animation friendly jiggle node
  • Custom cluster deformer
  • Deform eye geometry to fake eye refraction
Basically all papers by Erick Miller are super-cool, especially if you look at how old some of them are. He uploaded most (or all?) of the demo videos on his YouTube account:
https://www.youtube.com/user/erickmiller

And this is a more educational paper:
The Morphology of Digital Creatures
https://www.tim-mclaughlin.com/wp-content/uploads/2012/06/Morphology_of_Digital_Creatures-SIGGRAPH_2007_course.pdf

2012-10-07

My default Maya settings

Here are some Maya settings I prefer over the default ones. Maybe there is something useful for someone else. It's all MEL code, so it can be copied in the script editor.
//

// Switch file browsing to OS native browser
// Reason: _Slow_, missing features, bugs 
//  (delete shortcut to folder will delete folder, ...)
// Menu: Window > Settings/Preferences > Settings > Files/Projects
optionVar -iv FileDialogStyle 1;
 
// To show file extensions in filter settings
optionVar -iv FileDialogHideExtension false;

// Increase undo queue size
// Window > Settings/Preferences > Preferences > Settings > Undo
undoInfo -length 150;

// Disable mouse scroll wheel in viewport (will still work in menus, etc)
// Reason: Undo gets broken if you scroll the mouse, while the mouse-wheel is pressed.
// Menu: Windows > Settings/Preferences > Preferences > Interface > Devices > Mouse scroll wheel
mouse -enableScrollWheel false;
 
// hotBox transparency to 0%
// Reason: It is easier / faster to read
// Menu: Right quarter in hotbox: Hotbox controls > Set transparency
hotBox -tr 0;
 
// Grey background color, like the default in older Maya versions
// Menu: Windows > Settings/Preferences > Color Settings
// Default shortcut: alt+b
displayRGBColor "background" 0.631 0.631 0.631;
// displayRGBColor -q "background";// Get current background color:
 
// Hide UI elements 
// Reason: Increase viewport space. 
// Menu: Display > UI Elements > ... 
// Or right click on a double dotted line on the edge of a visible UI element (status bar, timeline, ...) 
// Or hotBox, left-click in empty space in the right quarter. 
ToggleModelEditorBars;// Every option can be reached with two clicks 
toggleUIComponentVisibility "Tool Box";// Using default shortcutsQWERZY... instead. And top quarter of hotbox for camera setups 
//toggleUIComponentVisibility "Range Slider";// I rarely change it 
toggleUIComponentVisibility "Help Line";// Not usefull after using Maya for years 
//toggleUIComponentVisibility "Status Line";
toggleUIComponentVisibility "Shelf"; 
 
// Disable the interactive Polygon / NURBS creation. 
// Reason: To save clicks / time. I get to the desired shape faster using modeling tools. 
// Menu: Create / NURBS Primitives / Interactive Creation 
/*// only works after menu has been opened 
optionVar -intValue createNurbsPrimitiveAsTool 0;// nurbs 
menuItem -e -cb 0 toggleCreateNurbsPrimitivesAsToolItem; // nurbs 
optionVar -intValue createPolyPrimitiveAsTool 0;// poly 
menuItem -e -cb 0 toggleCreatePolyPrimitivesAsToolItem;// poly 
*/
// Playback range of 100 frames. 
// Reason: More frames for deformation test animations. Still easy to identify each frame 
playbackOptions -min 1 -max 100; 
// This is also a "New Scene" option, so to fix it there: 
optionVar -fv playbackMinDefault 1; 
optionVar -fv playbackMaxDefault 100; 
optionVar -fv playbackMinRangeDefault 1; 
optionVar -fv playbackMaxRangeDefault 100; 
 
// Hotbox show one type only (animation, ...)  
// Reason: I use the hotbox for most operations, so I want it to be small to be able to click faster. 
hotBox -ao; setMenuMode animationMenuSet;// updateHotboxOptionVarSettings(); 
 
// Remove viewcube  
// Reason: Save space, it does not help me. 
viewManip -visible off; optionVar -iv viewCubeShowCube 0; 
 
// More precise channel box attribute sliding 
channelBoxSettings hyperbolic true; 
 
// More precise channel box display 
global string $gChannelBoxName; 
channelBox -e -precision 4 $gChannelBoxName; 
 
// Heads-up display 
// Display > Heads Up Display > Poly Count 
setPolyCountVisibility 1; 
// Display > Heads Up Display > Frame Rate 
setFrameRateVisibility 1; 
 
// Linear animation curves (for test animations / skinning) 
keyTangent -global -itt linear; keyTangent -global -ott linear; 

// Reduce camera animation time
// Window > Settings/Preferences > Preferences > Settings > Camera > Animate Camera Transitions > Total Time
optionVar -fv "totalAnimateRollTime" 0.1;

// command line: hold focus
// Preferences > Interface > Interface > Command Line [] Hold focus
optionVar -iv commandLineHoldFocus true; commandLine -e -holdFocus true $gCommandLine;
 
// Save preferences 
SavePreferences; 
saveToolSettings; 
 
// -----------------------------------------
// MANUAL SETTINGS / TEST
// -----------------------------------------
// Disable "Automatic Orient Joints" in Move tool 
// The following command does not work, because it will not get stored to the default move tool context. 
// string $myMoveContext = `manipMoveContext`; 
// manipMoveContext -e -orientJointEnabled 0 $myMoveContext; 
 
// Hypershade: Hide left and top areas, so only work area is left. Also change material display from icon to list, so materials/textures do not get loaded when opening hypershade 
// Note: Hypershade settings do not seem to get stored (except position and window size, maybe write in usersetup file)?... 
 
// In Paint skin weights tool disable "Display > XRay Joints" because when leaving tool xray joint stays active and I rarely use it in the first place 
 
// Show > Isolate Select > Auto Load New Objects 
// string $eachPanel; 
// for ($eachPanel in `get all panels`){ 
// isoSelectAutoAddNewObjs $eachPanel true; } 
//
// -----------------------------------------
// 2014
// -----------------------------------------
// ignore version
optionVar -intValue fileIgnoreVersion true;
// incremental save
// edge flow 1.0 everywhere
// 
//

Some Maya related Windows settings I like to change::
  • Computer > Properties > Advanced System settings > Advanced > Performance > Visual Effects > Adjust for best performance
  • Mouse: Increase speed, disable "precision" (mouse accelleration)
  • Taskbar: Small icons, do not combine icons/tabs

Result will look like this on Windows 7