GDC 2015

Hey everyone, I’ll be giving a talk at GDC for Intro to Photoshop Scripting for Artists. It’s on March 2nd at 4:30pm-5:00pm in Room 2014, West Hall.

If you wanna learn some Photoshop scripting come check it out! We also have other talks about our platform and various other topics starting at 10:00am in the same room.

http://schedule.gdconf.com/session/intro-to-photoshop-scripting-for-artists-presented-by-npnf

Rigging Dojo Apprenticeship

I recently finished the one month Rigging Dojo Apprenticeship focusing on AAA game facial rigging. I learned a lot of cool stuff and highly recommend it to anyone that was thinking about signing up.

It was a lot of hard work, but my facial rigging skills went from zero to hero!

Thanks to Rigging Dojo and Daniel McCrummen for the class!

Single Shading Switch Utility Node

In this video I show you a couple of nifty things you can do with the Single Shading Switch utility node within Maya.

Here is the source code that I use in the video:

First Example

// switchNodeName.input[element #].inSingle

setAttr "singleShadingSwitch1.input[0].inSingle" 0.5;

 

Sphere Example

for ($i = 0; $i < 16; $i++)
    setAttr ("singleShadingSwitch1" + ".input[" + $i + "].inSingle") (rand(0, 1));

 

Glow Intensity Example

for ($i = 0; $i < 17; $i++)
    setAttr ("singleShadingSwitch1" + ".input[" + $i + "].inSingle") (($i + 1) / 17.0);

 

MEL Tip 005: Toggle Booleans

In this video I explain what a boolean data type is and how to easily toggle them on or off.

A boolean is a data type that represents two different states. Those states could be true/false, on/off, yes/no, or one/zero.

In MEL we don’t have an actual data type called boolean, but instead we use the integer data type to represent them.

int $boolean = true;

$boolean = (!$boolean);
print $boolean;
// 0 will now print since the number zero represents false

In the above code we have an integer named $boolean and we’re assigning it to be true. The words true and false are keywords in MEL and they’re the equivalent to one and zero, so the following all mean the same thing:

int $boolean = true;    is the same as   int $boolean = 1;

int $boolean = false;    is the same as   int $boolean = 0;

Once line 3 is executed the $boolean variable will now equal false.

When you read line 3 you can think of the exclamation point as representing the word not. On line 1 we assign the $boolean variable to equal true, so when you read line 3 you can say $boolean is equal to not true, which in turn makes it false, because if something is not true then it must be false.

If the $boolean variable were false and we execute line 3 then the $boolean variable will equal true because if it’s not false then it must be true.

int $boolean = false;

$boolean = (!$boolean);
print $boolean;
// 1 will now print since the number one represents true

 

Here are a couple of practical examples using this technique. In this first example is a script that will toggle the Isolate Select on or off.

string $panel = `getPanel -withFocus`;

int $isolateState = `isolateSelect -q -state $panel`;

enableIsolateSelect $panel (!$isolateState);

 

And this example shows how you can use the technique to toggle the -lock flag on each of the attributes in the Channel Box:

string $objects[] = `ls -sl`;

for ($object in $objects)
{
    string $keyableAttrs[] = `listAttr -keyable $object`;
    
    for ($keyableAttr in $keyableAttrs)
    {
        string $objectAttr = ($object + "." + $keyableAttr);
        
        int $lock = `getAttr -lock $objectAttr`;
        setAttr -lock (!$lock) $objectAttr;
    }
}

Toggling boolean data types is a technique you can basically use in any of the programming languages you may learn in the future, so it’s a useful thing to know!

Key Takeaways

1. Using an exclamation point in front of a boolean variable will toggle it to the opposite state.

2. getPanel -withFocus will tell you which panel currently has focus.

3. Using enableIsolateSelect $panel $isolateState will allow you to turn on/off Isolate Select.

4. listAttr -keyable $object will return a list of all the keyable attributes within the Channel Box.

MEL Tip 004: Select Attributes in Graph Editor

In this MEL Tip I’ll be showing you how to create a script that will take the selected attributes in the Graph Editor and select those same attributes for every object you have selected.

Here is the script:

string $objects[] = `ls -sl`;

string $attrs[] = `selectionConnection -q -object graphEditor1FromOutliner`;

for ($attr in $attrs)
{
    string $buffer[];
    tokenize $attr "." $buffer;
    string $attribute = $buffer[1];

    for ($object in $objects)
    {
        if (`attributeExists $attribute $object`)
           selectionConnection -e -select ($object + "." + $attribute) graphEditor1FromOutliner;
    }
}

Key Takeaways

1. graphEditor1FromOutliner is the name Maya gives the outliner panel within the Graph Editor.

2. Use selectionConnection -q -object graphEditor1FromOutliner to query the selected attributes in the Graph Editor.

3. Use the tokenize command to separate a string based on the split character you give it.

4. The attributeExists command will check if an attribute exists on the the given node.

5. Using the command selectionConnection -e -select “objectName.AttributeName” graphEditor1FromOutliner will allow you to tell Maya what attribute you want to select inside the Graph Editor’s outliner.

Rigging Demo Reel 2014

Woohoo! Just finished my rigging demo reel featuring some of the work I’ve done in the mobile games industry. You can click here to watch it on Vimeo.


downloadDemoReel Rigging Demo Reel 2014

 

MotionBuilder 2012: Mirror Animation

In this tutorial I’m going to show you how to mirror animation using MotionBuilder 2012.

First, select the take you want to mirror, then create a new take and click Yes when the message box pops up that says, “Copy the data from the current take to the new take.”

step01 create new take 300x183 MotionBuilder 2012: Mirror Animation
Double click the character node in the Navigator and under the Character Settings tab check Mirror Animation and change CharacterSolverSelector to MB Character Solver.

step02 mirrorAnim and solver 300x138 MotionBuilder 2012: Mirror Animation
Now Bake(plot) To Skeleton then Bake(plot) To Rig.
(If you use Plot All (All Properties) under Key Controls instead of Bake(plot) To Skeleton then make sure the character’s Control Rig is unchecked.)

step03 plot to skeleton and rig 300x182 MotionBuilder 2012: Mirror Animation
After doing the above steps my character rotates in the Y axis by 180. If something like that happens to you then do the following to turn him/her/it back around:

Select the Reference control, delete its key frames, uncheck Mirror Animation, and set its rotateY to 180. (If you need the key frames on the Reference control then you’ll need to rotate the Y axis by 180 on the key frames instead.)

step04 rotate character 300x182 MotionBuilder 2012: Mirror Animation

At this point you could leave the Reference control with a value of 180 for its rotateY, but if you want to zero out its rotations then Bake(plot) To Skeleton and set its rotate X, Y, and Z back to zero. Then do Bake(plot) To Rig one more time and you’ll have a character with mirrored animation and the Reference control will have zeroed out rotations.

 

So those are the manual steps if you want to mirror an animation, but I created a script that will automatically do all those steps for you. You can download it here:

Random MotionBuilder Python Tidbits

This is how you do a bunch of random things in MotionBuilder with Python.

# set the current frame to the start frame of the current take
takeStartFrame = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame(True)
time = FBTime(0, 0, 0, takeStartFrame)
FBPlayerControl().Goto(time)

# create a copy of the current take
newTake = FBSystem().CurrentTake.CopyTake('newTakeName')

# evaluate the scene
FBSystem().Scene.Evaluate()

################################################
# delete the camera that comes from Maya
mayaCamera = FBFindModelByName('MayaCamera')

if mayaCamera:
    mayaCamera.FBDelete()

################################################
# find out which character is currently selected
character = FBApplication().CurrentCharacter

# turn on Mirror Animation
character.MirrorMode = True

# set the solver to 'MB Character Solver'
character.SetExternalSolverWithIndex(1)

# turn off the Control Rig
character.Active = False

################################################
# rotate the Reference control by 180
controlRefName = FBFindModelByName('Reference')
controlRefName.Rotation = FBVector3d(0.0, 180.0, 0.0)

################################################
# create a locator and set it to 0, 0, 0
worldScaleNull = FBModelNull('WorldScale')
worldScaleNull.Translation = FBVector3d(0, 0, 0)
# set the Look attribute to None
look = worldScaleNull.PropertyList.Find('Look')
look.Data = 0
worldScaleNull.Show = True

# parent a joint named 'C_global_bnd' to the locator and scale it
globalBnd = FBFindModelByName('C_global_bnd')

if globalBnd and globalBnd.Parent != 'None':
    globalBnd.Parent = worldScaleNull
    worldScaleNull.Scaling = FBVector3d(100, 100, 100)

################################################
# create a custom attribute on selected models
from pyfbsdk import *

attrName = 'My Custom Attr'

selectedModels = FBModelList()
FBGetSelectedModels(selectedModels)

if not selectedModels:
    FBMessageBox("Error", "Nothing selected", "OK", None, None)

for model in selectedModels:
    anAttribute = model.PropertyList.Find(attrName)

    if not anAttribute:
        trackerAttr = model.PropertyCreate(attrName, FBPropertyType.kFBPT_charptr, "String", False, True, None)
        trackerAttr.Data = 'hello'

################################################
# plot animation example
def plot(self, character, plotWhere):

    if plotWhere == 'skeleton':
        plotWhere = FBCharacterPlotWhere.kFBCharacterPlotOnSkeleton
    elif plotWhere == 'rig':
        plotWhere = FBCharacterPlotWhere.kFBCharacterPlotOnControlRig
    else:
        print "Warning: Plotting to skeleton by default."
        plotWhere = FBCharacterPlotWhere.kFBCharacterPlotOnSkeleton

    plotOptions = FBPlotOptions()
    plotOptions.PlotAllTakes = False
    plotOptions.PlotOnFrame = True
    plotOptions.PlotPeriod = FBTime(0, 0, 0, 1)
    plotOptions.RotationFilterToApply = FBRotationFilter.kFBRotationFilterGimbleKiller
    plotOptions.UseConstantKeyReducer = True
    plotOptions.ConstantKeyReducerKeepOneKey = True
    plotOptions.PlotTranslationOnRootOnly = True
    character.PlotAnimation(plotWhere, plotOptions)
    return True

MEL Tip 003: Randomize Positions

In this third MEL Tip I’m going to show you a very easy script that will randomize the positions of whatever you have selected. Here’s the source code:

string $components[] = `ls -selection -flatten`;

if (size($components) <= 0)
    warning "Nothing is selected.";
else
{
    for ($component in $components)
    {
        vector $sphrandValue = `sphrand(0.4)`;
        move -relative ($sphrandValue.x) ($sphrandValue.y) ($sphrandValue.z) $component;
    }
}

First we get a list of the current selection with the -flatten flag, which will give us a list of each individual component. I briefly touched on the -flatten flag in the last MEL Tip, so let me show you an example of why we need to use the -flatten flag and what happens if we don’t.

Let’s create a default cylinder, select vertices 0 through 19, and then run the ls -selection command without the -flatten flag. Here’s the command and the result Maya returned to us:

ls -selection;
// Result: pCylinder1.vtx[0:19] //

As you can see, Maya will group components that are in sequential order. So in this case, if we ran the randomize script above without the -flatten flag Maya will treat vertices 0 through 19 as a group and instead of giving them each a different random value it will move them all as a group with the same value.

MEL Tip 003 MEL Tip 003: Randomize Positions

After getting the current selection we do some error checking and make sure that something is selected. Then we loop through each component and on line 9 we use the sphrand command to generate a random number.

sphrand will generate a random number inside a spherical shape and the value you give it is the size of the sphere’s radius, so if you want the distance that the components will move to be smaller or larger just change 0.4 to a different number.

Then we move the component with the move command with the -relative flag which will take the component’s current position and add on the random value generated by sphrand.

Key Takeaways

1. Use the -flatten flag to keep Maya from grouping the names of sequential components.

2. sphrand($radius) will generate a random number within a spherical shape of the specified radius.

3. Using a vector data type instead of a float array can produce code that’s easier to read. Here’s a comparison between using a vector as opposed to a float array:

// vector
vector $sphrandValue = `sphrand(0.4)`;
move -relative ($sphrandValue.x) ($sphrandValue.y) ($sphrandValue.z) $component;

// float array
float $sphrandValue[] = `sphrand(0.4)`;
move -relative $sphrandValue[0] $sphrandValue[1] $sphrandValue[2] $component;

4. Using the -relative flag with the move command will move an object relative from its current position.

Best Anatomy Book for Riggers

classicHumanAnatomy 249x300 Best Anatomy Book for RiggersOne of the best anatomy books I’ve read is called Classic Human Anatomy: The Artist’s Guide to Form, Function, and Movement by Valerie Winslow.

It goes over all the bones and muscles relevant to the artist and gives great tips on drawing the human body. Not only that, it has many drawings showing the human body in movement, which is another reason why it’s so great for character riggers.

For anyone interested in human anatomy this is a must have book and I highly recommend it.