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: http://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:
http://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
http://erickmiller.com/docs/sap_434_MusculoSkeletalShapeSkinning.pdf
http://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
http://erickmiller.com/docs/iRobot_Character_Pipeline_sketches_0250.pdf
http://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:
http://www.youtube.com/user/erickmiller

And this is a more educational paper:
The Morphology of Digital Creatures
http://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

2012-04-13

prSelectionUi - dynamic Maya Python UI

(The script got updated in December 2012, so there are some inaccuracies in this post now)


prSelectionUi - Animation UI (Maya)


This post is about my prSelectionUi.py Maya script, which was written in PyMEL. It is made to manage selections and poses. This can be useful during animation. The main problem were the dynamic UI elements and how to save/load the information in Maya

This script might also be a decent example on how to write PyMEL UI code? I am not sure, since I have not seen any other PyMEL UI scripts. I just used some features from the PyMEL documentation and the posting of one of the PyMEL authors, which is mentioned at the end of this post.

I have made selection UIs before, but they had to be made for each project. This UI is flexible and should work for any project. To save the rigger time, but also allow the animator to create the selections they want on the fly. The attached video shows all the functionality and there is also the open-source download link in the Vimeo video description.

The idea came from an animator friend (Harry Fast), who was not happy with the existing freely available selection scripts. So he asked me to create a new one. It is written in PyMEL and stores all information in Maya sets. That way you can create selections in the rig-file and the script can read those sets in the animation-shot (with referenced rig file). Also the animator can always create their own selections and import/export the sets between scenes.

The code can be summarized as six classes (UI, Tab, TabElement, Pose (TabElement), Selection (TabElement), Member), which inherit from Maya UI elements (window, formlayout, menuItem). There are maya-sets for tabs, selections and poses. The member information is stored in the selection-set attributes. The set types are identified with custom attributes. That way the scene-name of the set is not important. Also it is no problem if there are name clashes. If the set is from a reference file, the attributes can be edited in the shot. (If the animator is not happy with the default order/colors). Because all elements are dynamic I did not split the UI from the functionality. But I don't have a lot of UI programming experience, so I don't know the normal way. In the past I only created UIs the Maya/MEL way. But I am happy with the current classes, because it was easy to add new features and modify the existing ones.
The basic idea to inherit from PyMEL UI elements was from this post of Ofer Koren: http://www.mail-archive.com/python_inside_maya@googlegroups.com/msg01015.html

Here is a simple UML generated from the code using PyNSource - UML tool for Python. (It does not show that UI, Tab, TabElement and Member inherit from Maya UI elements.)

2012-03-15

How to improve as a rigger

So because my studies are finishing, I reflected a little bit on the past and here are my conclusions on how to improve / learn the most from a student perspective and optimize your demoreel. I personally did not think about some points and/or did not have a choice, so my past does not fit this description very well.
But of course you should always do what you enjoy most. And most of the following points happen automatically over time anyways.
  1. Specialize in rigging. The more time you spend on other disciplines, the less time you will have spent on rigging. Note: Of course it is good to have a basic understanding of all connected areas, to improve working with the different co-workers (modelers, animators, r&d, pipeline) and to be more independent, require less feedback and be able to give better feedback. But after the basics there will be a moment, when it is better to do more rigging instead.
  2. Work closely with animators as soon as possible. Because they are the people that use your rigs?! If you are an animator yourself, this is not as important. But there are also different preferences between animators.
  3. Work with experienced/specialized co-workers. Because animators will know what they want and if they have a lot of experience with different rigs, they will request the nicest features they know and improve your rigs that way. Good modelers will ease/improve deformation. And generally the better the co-workers the better the end-result, which will make your work look better. And you can learn more from each other.
  4. Work on few projects (quality>quantity) with people that work on few projects. If everyone has more time the quality of everyone's work should be better. Also the shorter the length of the film the better the quality (animation, rendering,..).
  5. Create few character rigs (quality>quantity). Try to find projects with few characters (or do not rig all of them if there are too many). To improve quality and because you can only show a few rig demos in your demoreel. Note: It is also important to learn how to improve pipeline/workflow/speed. If you have to rig a lot of characters you are forced to do that, but you can still do it with a few characters if you want to.
  6. Rig extreme (cartoony/realistic) characters. That way you learn how to create extreme motion (2D style) and recreate anatomy (deformation focus) in CG. If your character is stylized in-between you don't learn as much about anatomy, because it is not required (same for extreme motion). It basically is about having a good/clear target to aim for. Note: Some people probably want to focus on either cartoony or realism, so the other area can be dropped. That way the quality should improve in your area, but it will reduce the amount of companies you can apply to.
  7. Rig different kinds of characters/creatures: Biped, quadruped, bird, snake, mechanical, ... Because they have different requirements and anatomy.
  8. Scripting: Learn to script, to automate repetitive tasks. Optional: It can also be good to learn programming to: 1. Write better scripts, that other people can work with 2. to create new tools for other people to improve workflow 3. Write plug-ins for new functionality 4. Design a pipeline... These things are usually done by more experienced professionals. For a student it probably is better to keep it limited (see point 1.).
So if your main focus is improvement, you are starting to study and you have all choices, you would (after you have learned the basics of cg and specialized in a discipline): Only work on two projects/shorts for a long time (one realistic, one cartoony). Each time only rig a few characters (1-3) of different types (biped, quadruped,...) and everyone involved will have specialized in their discipline with a basic understanding of everything connected to their discipline and only work on a few projects as well.

2012-03-13

My CG experience per subject
















This graph shows the amount of time I spent on the different subjects and was made for my graduation presentation at Filmakademie. I found it interesting to give myself an overview of how much time I actually spent on each discipline. The measuring unit is "full time months" (20 days, 7 hours each). And it is normalized, so if I have done multiple disciplines at the same time I had to divide the time for each of them. My resume helped me to get a fairly accurate estimation.
But of course my prior programming knowledge (B.Sc.) helped learning scripting and the Maya API faster. And most scripting was done for rigging, so they are connected quite heavily.

I guess recruiters try to extract this information from resumes, but I think it can be difficult. For example listing disciplines / software / programming language, with the number of years they have been used, is not really useful because it does not actually describe the amount of time and the context (hobby, study, job). Except if it can be matched with job descriptions etc...
Also it may be interesting to know how much time someone spent to get to the work done (productivity / efficiency?) in the demoreel and the time spend to achieve the skill level (talent?). To predict costs and growth of the employer?

Maybe I have recently looked at too many company job pages and other peoples resumes, since I am looking for my first real job after graduation. But I don't understand why students rate their own skills with "expert", "intermediate", "beginner". I personally just keep it neutral in my resume/linkedin with these lines:
Specialities
Primary: Rigging, Scripting
Secondary: R&D, Modeling, Cloth Simulation

2012-01-30

Maya API and openMP multithreading

In this post I want to write about the steps necessary to compile a Maya plug-in, that uses openMP multithreading, with Visual Studio. I assume the reader has compiled a Maya plug-in before.

Summary:
  • Enable openMP option in project properties
  • Don't use Visual Studio Express/Standard
  • Switch to Release in "Solution Configuration" to use the plug-in (.mll) on other PCs

Detailed explanation:
Writing the code is fairly straightforward (it's not a lot) and the Autodesk Maya API Guide and Reference explain openMP really well. (Check out the splatDeformer devkit example)
Now I will write the steps necessary to get the splatDeformer running (I am using Visual Studio 2008 and Maya 2010, 2011, 2012 all 64bit):
  • Open the splatDeformer.sln in the Maya devkit folder (if you copy it somewhere else you have to fix the \lib and \include paths)
  • You should be able to compile the solution already. (If not, there is probably something non-openMP related not working)
  • It's compiling because openMP is actually disabled by default in the solution and the openMP code is not used. To enable it you have to set splatDeformer: Properties > Configuration Properties > C/C++ > Language > OpenMP Support > Yes (/openmp)
  • If you are using the Express or Standard edition of Visual Studio you will get the following error:
fatal error C1083: Cannot open include file: 'omp.h': No such file or directory
  • That's because the Express/Standard edition do not support openMP. You can find some tutorials on how to install openMP manually. But I can not confirm that they are working in this case, because I switched to the professional version at my school.
  • So with a Visual Studio version, that supports openMP, you should be able to compile the plug-in successfully. And maybe it will work on your PC, but most likely not on other PCs. The error should be:
Error: The application has failed to start because its side-by-side configuration is incorrect. Please see the application event log or use the command-line sxstrace.exe tool for more detail.
  • To fix this you have to switch your Visual Studio "Solution Configuration" from Debug to Release. (Note: Release may have different Configuration Properties, so you may have to enable OpenMP Support again and set output file, etc). More experienced Visual Studio users will know this error, because it also happens if you don't use the Release mode and try to load your output file with Maya on another PC (that does not have Visual Studio installed). More information on that point (bug report)

For a more complex deformer example than splatDeformer, that is using openMP, check out my prAttractNode. I noticed an increase in performance of 10-30% from openMP. You can find the open source download link in the Vimeo description of this video:

prAttractNode - deformer (Maya API, plug-in, Python)

2012-01-27

Demoreel 2010

This is my old Demoreel. It was made in 2011/02 with content from 2010 and a breakdown in the Vimeo video description. This post is about the process of creating the reel and the results in retrospect. Because it is almost one year old, I may have forgotten a few things.

Parzival Roethlein - Character TD Reel 2010



Making-of:
  • Decided on resolution and frame rate. (720p and 25fps)
  • Made Maya playblasts (project was not rendered yet) to show animated rig. (720p, 25fps)
  • Screen captures with CamStudio (free), to demonstrate rig functionality. (720p, fps not important, since I speed up the screen captures anyways)
  • The video files from CamStudio and Maya playblasts were then converted to a image-sequence (jpg or png), using VirtualDub (also free). This way it is fast to work with the data when editing and rendering the final video. 
  • Title and description texts made in Photoshop.
  • Image sequences and texts imported to Adobe After Effects for editing and final video export. The style of rig presentation with frame-freezing, then blurring and animating the text was popularized by Victor Vinyals (I think) with his demoreel in 2007.
  • Spent one day for first version, gathered feedback, then one more day for final version.
Results:
  • Because I am a student I only applied for jobs in the two semester breaks of 2011.
  • For the first semester break in March I applied at around six German companies as a freelancer. I would say one third did not answer, the others gave nice responses, but only the one that actually had a relevant job listed on their website hired me. (Animationsfabrik)
  • For the second semester break I wanted to get a rigging-internship at a big studio in a foreign country. So I applied at two companies in London and two in the US. One of the US studios told me I was in the final selection, but I did not hear from them afterward. The other US studio send me a rejection (cg software internship). From the two London companies one did respond and I got the internship there (Framestore). I also entered this reel to the "Computer Graphics Student Awards" on cgCoach.com and won an internship there, but since I already had an internship by then, it did not really matter.

    2012-01-26

    Maya API resources

    Because I uploaded a few open source Maya Plug-ins on CreativeCrash I got some e-mails regarding basic Maya API learning material. So I wanted to write a small summary in this post, mainly to plug the free video webcast with exercises from the Autodesk Developer Center:
    Maya (intermediate) (select from in the "Course" menu. There area also other Maya API courses, but I could not do any of them yet) [Updated link: http://www.autodesk.com/developmaya]

    But mostly I use:
    - Autodesk Maya API Guide and Reference
    - Comet Cartoons (Michael Comet) Very practical information when writing code. Especially when using different attribute types for the first time.

     And during my internship at Framestore I had a chance to see the two DVDs, which sadly don't seem to be for sale anymore:
    - Writing Creature Deformers (Erick Miller). Introduction to deformers. Also a good starting point when writing your own skinCluster, cluster or partial blendshape node. This DVD was not that useful for me, because I had written a deformers already, so there were only a few small things interesting for me. But if you are starting then this DVD will certainly safe you a few days of learning.
    - Introduction to the Maya API (Barbara Balents)

    The pdf Skinning in Maya at Industrial Light & Magic (Andrea Maiolo) gives detailed information on how to managa skinCluster data including paintable attributes.

    ChadVernon.com is a nice blog as well and there is also a list of resources.