2013-06-12

Harald Trailer

Here is the trailer for the last student short I worked on at Filmakademie. I was the Character/Animation TD and animated one shot.



Facebook page for the short:
https://www.facebook.com/haraldfilm

It recently got the SIGGRAPH 2013 Best Student Runners-Up award, yay!
https://siggraphmediablog.blogspot.de/2013/06/european-directors-win-majority-of.html
The Best Student award also went to a Filmakademie project called Rollin' Safari, all clips are online at: https://www.youtube.com/user/rollinsafari/videos

2013-05-02

Maya wrap deformer tips


Attributes:
  • After creating a wrap deformer the driver surface gets a dropoff and smoothness attribute. Usually the user can expect these attributes to be in the deformer ChannelBox/AttributeEditor. This has been changed for the wrap deformer for a case were there is one driver on multiple shapes, so the smoothness attribute gets connected to each wrap deformer. The smoothness only works with Falloff Mode: Volume and Exclusive Bind: off. As the name says it can help create smooth deformations. On the downside it moves unaffected neighbors of deformed vertices in the opposite direction, so that may be a reason not to use smoothness for some cases.
  • When enabled Exclusive Bind improves performance a lot, but may lead to bad deformation. Works especially well when driver and driven have a similar resolution. I used this setting a lot in the past.
  • I usually use Falloff Mode: Surface for smooth results, probably because my driver and driven object usually have a similar shape. The smoothness attribute requires Volume mode thou.
  • maxDistance 0.0 disables maxDistance
Use cases:
  • Deform highres geometry with easier to rig/cloth-simulate low-res geometry. For this case my tip is to output the lowres mesh into a separate mesh node and smooth/subdivide that and then use this highres version of the lowres mesh as wrap deformer driver on the actual highres mesh. The result is surprisingly fast when using exclusive bind etc and allows for much better deformation than using the wrap deformer the normal way and trying to adjust the wrap deformer attributes, which can never work properly (it's a non-barycentric binding) and gets really slow. As with many deformers in Maya, they are not very functional, but they are fast, so when making these procedural deformations you can compensate for the lack of features.
  • When the driving mesh just has a skinCluster I prefer to copy the skinCluster and weights to the highres, because it calculates faster than a wrap deformer and you also have the option of tweaking the weights further.
  • Use as partial blendshape, to be able to work on local area and with those patches drive the final one-piece mesh. Edit membership has to be used to avoid double transformation. Not a user friendly workflow. Exclusive Bind can be used to greatly improve speed (if meshflow is similar).
Example:


2013-04-23

Kool-Aid commercial: Rig breakdown


Kool-Aid commercial: Rig breakdown from Parzival Roethlein on Vimeo.

The complete spots:
https://vimeo.com/64086798
https://vimeo.com/64086797

The node order of the face, starting with the low resolution geometry:
-> blendShape
 -> skinCluster (for the mouth I put the joints on a curve with motion paths, to tweak the curve cvs without getting intersecting loops, see old post: Joint chain rigging techniques)
 -> bend deformer (To roughly match the body shape. Works for this range of motion, for more range I would recommend using a surface constraint / rivet on the nurbs surface and connect translation to UV values)
[lowres for animators]
 -> smooth (subdivide)
 -> sculpt deformer (project on nurbs surface with the same shape as the glass)
[highres, final shape]

And the highres geometry was used as a mask in compositing.

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.