Global Maya Logger

As a TD, you are often asked to trace a bug or a crash, and it is way more easy when you have all the actions and logs done by the user/software. To do so, you usually have to modify the userSetup.mel of the user when you can and begin the logging… Then remove it when you are done.

The Maya command cmdFileOutput is quite handy for that.

What a hassle to do that for every single user each time you want to trace and debug something. It can be very cumbersome especially if you have a lot of users to manage. So what about a global and automatic solution that activate only for specific users at a time? All you need to do is to put the script in the global startup of Maya, and activate it only if the username is in a specific file that you can access and modify very easily.

Read More

Restore the original colors of animation curves

Sometimes the colors of the animation curves in the graph editor are not in RGB anymore, either it was changed by a tool or by another human, it’s hard for you to work with those weird colors. Here is the little quick tip.

To restore the original color of a curve, select a node curve by right clicking on a red field in the Attribute Editor and uncheck ‘Use Curve Color’ in the ‘Anim Curve Attributes’ section, or use this script to do it for every animation curve in a scene:

objList = cmds.ls(type="animCurve")
for objName in objList:
    cmds.setAttr(objName + ".useCurveColor", 0)
string $objList[] = `ls -type "animCurve"`;
string $objName;
for ($objName in $objList) {
    setAttr ($objName + ".useCurveColor") 0;
}

Rainbow!
Because... why not?

Wait for user input in Maya

In my last article you may have noticed the Context commands were not actually waiting for the user input. All the commands following them would be executed even though the user didn’t complete the Context tool. The trick (without using the API) is to use a scriptJob that got executed only once, and that is immediately destroyed after its execution.

You call your context tool and create the scriptJob, then that scriptJob will execute the command when the condition you want is met.

try:
    cmds.dynWireCtx("paintMesh")
except RuntimeError:
    pass
cmds.setToolTo("paintMesh")
cmds.scriptJob(runOnce = True, event = ("SelectionChanged", "executed_after_action()"))

def executed_after_action():
    print "Done!"

If you are drawing a curve for example, the selection will change as soon as the user release its mouse button, you can then process whatever you want to process.

You still have to do some verifications in case the user didn’t cancel the tool. You can do so by checking if the new selection is what you were expecting, or/and if new nodes were created. Keep in mind that neither of those checks are full proof in this situation. The final code:

try:
    cmds.dynWireCtx("paintMesh")
except RuntimeError:
    pass
cmds.setToolTo("paintMesh")
cmds.scriptJob(runOnce=True, event=("SelectionChanged", "executed_after_action()"))


def executed_after_action():
    cmds.setToolTo( 'moveSuperContext' )
    shape = cmds.listRelatives( cmds.ls(sl=True), fullPath=True, shapes=True)
    if cmds.objectType(shape) == 'stroke':
        print "Done!"

You can even do that for each curve the user draw without exiting the current Context Tool. Do not set the scriptJob with runOnce, and destroy it once the conditions are not checked in the executed_after_action(). That’s it!

Paint Effect Tool and other Context Tools

Lately I was doing a script involving the Paint effects tool. The command is not available in the documentation so I just used, as usual, the script editor in conjunction of ‘Echo all command’ to get the mysterious MEL command: PaintEffectsTool. Everything’s good, my script is going well but one thing annoys me… I want to pause my script while the user is painting and then do something with his input. The problem is, all the following commands of my script get executed immediately after calling the Paint Effect Tool. It never waits for the user input. I continued my investigation on how to do this… and finally stepped upon the scriptCtx command:

This command allows a user to create their own tools based on the selection tool. A number of selection lists can be collected, the behaviour of the selection and the selection masks are fully customizable, etc.

It kinda worked but not quite well, and I was not satisfied with the result. I then noticed in the command reference of Maya a lot of commands with the suffix Ctx and especially the currentCtx command:

This command returns the currently selected tool context.
Read More

Funny behaviour in Maya 2014

Select an object and some channels in the Channel Box and then execute those lines in Maya 2014 one by one.

$selection = `ls -sl`;
select -clear;
select $selection;

The channels got unselected like you would have expected. But now, try to execute all those lines at once. … Strange isn’t it?

If you want to get rid of the selected channels in the Channel Box you have to defer the execution of the reselection:

$selection = `ls -sl`;
select -clear;
evalDeferred "select $selection";

It works this way…but it doesn’t feel responsive at all.

Now, what if you try the first commands in Maya 2013? It works well… This buggy behavior seems to be related to this bug fixed in Maya 2014:

MAYA-27405 Graph Editor : Channel box selection remains after selecting an animation curve in the Graph Editor

Instead of fixing the bug, Autodesk implemented some weird behavior in the program as a whole. One bug leads to another.

Update: If you want to go back to the old behaviour of the Channel Box when changing selection, there is a solution: Channel Box and Selection Change

A Mac IS a PC

Yeah, that’s it, I love that title. Just enough to alert the cortex of everyone, Apple fanboys have their blood boiling hard now, and some may think “What the hell is he talking about?”.

Because yes, the essence of Apple differentiating the two worlds of Mac and PC since several years now, is to make two different clan that feels really different to each others and have to fight for their kingdom. It’s totally marketed and it works. “Think different” is one of the adage of Apple, and its idea of making a Mac so “different” from a PC is a direct result of that.

Keep in mind that when a company is advertising, most of the time, the ads are not directed directly to new clients, but to existing clients who already know their products, this way they will tell to other people how “awesome” the product they bought is, it’s a lot more powerful and have a huge impact on the others. People need to show to other people how nice their purchase is, to convince themselves that they made the right choice for buying it. And the more the owners get remarks or feel threatened by other people, or feel unique/different, and the more they will defend it no matter what.

I am a PC. I am a Mac.
I am a PC. I am a Mac.
Read More

Re-encode entire folders with ffmpeg

If you need to re-encode a lot of videos all at once, each video being in a different folder, here is a little bash script for you. Just put everything in a file and execute it. The file needs to be executed in the main directory where all the children folders are. If you have spaces in the name of the files, it’ll still work.

#!/bin/bash

for folder in "*"/
do
    for file in "$folder"/"*".flv
    do
        ffmpeg -i $file ${file%.*}.mp4
    done
done

It’s easy to understand, so you can adapt it to your own needs easily.

Final Gather Visualizer and Render Layers

Recently a friend of mine was using the Final Gather Map Visualizer to diagnose and set the FG of the scene she was working on. One annoying thing though, it was only visible on one Render Layer. After some reading in the documentation of Maya, it appears the Final Gather Visualizer is actually a node: mapVizShape.

If it is a node, then it must be added to the Render Layer to be displayed on that specific Render Layer. To do so, filter mapViz in the outliner and then add it to the Render Layer or just execute that little piece of Python.

import maya.cmds as cmds
if cmds.objExists("mapViz*"):
    mapViz = cmds.ls ("mapViz*", transforms = True)

    renderLayers = cmds.ls(type = "renderLayer")

    for layer in renderLayers[1:]:
        listConnections = cmds.listConnections(layer, source = False)
        nodePresentInLayer = set(listConnections).intersection(mapViz)
        if not nodePresentInLayer:
            cmds.editRenderLayerMembers(layer, mapViz)

Now all your Render Layers can display the Final Gather points in the viewport! Don’t forget to execute it each time you create a new layer.

MEL: How do I find the Transforms of a list of Shape nodes?

On the great website xyz2.net there is the entry on How do I find the Shape node of a Transform? Or the Transform of a Shape node? But what if you want the Transforms of a list of Shape nodes?

proc string[] getTransform(string $shape[]) {
    string $transform[];
    for ($node in $shape) {
        if ( "transform" != `nodeType $node` ) {
            // If given node is already a transform, just pass on through
            string $parents[] = `listRelatives -fullPath -parent $node`;
            appendStringArray($transform, $parents, size($parents));
        }
    }
    return $transform;
}
def getTransforms(shapeList, fullPath=False):
    transforms = []
    for node in shapeList:
        if 'transform' != cmds.nodeType( node ):
            parent = cmds.listRelatives( node, fullPath=fullPath, parent=True )
            transforms.append( parent[0] )
    return transforms

Infinite loops? Naaah

Did it ever happen to you to feel stupid in front of your program stuck in an infinite loop?

We all now that feeling…

The documentation of Mari’s API and the Python Console are really bad to work with, but at least there is one great thing about Mari: you can very easily stop your scripts if they are stuck.

Simply hit Ctrl+C in the terminal Mari has been launched from and… that’s it, your script stopped and you can continue to work normally. It’s quite useful especially since Mari takes a lot of time to simply print some strings.