Maya

autodesk Maya

Profiling code.

I’ve been wondering lately, when it comes to finding nodes in a scene, nodes which may or may no exist, which will be faster?

using a Try, Except?
or using maya’s built in objExists command?

My theory was that the Try, Except would be faster as objExists would have to loop over all nodes in the scene. At least as far as I assume.
So i put it to the test.

The first thing I neede ws a profiler. A little googling and I turned up Pyhtons Timeit module.

This can be imported using

import timeit

print timeit.timeit(function)

This will print the result of running the specified function one milling times. Its is run this many times to ensure consistency in the results.
That can be reduced by adding the number flag, to specify how many times the code is run, so:

import timeit

print timeit.timeit(function, number = 10000)

This will run the code ten thousand times. Its quicker and consistant enough for my requirements.

Getting into the problem at hand, I setup two functions, one as a Try, Except and another as objExists.
I ran each one in an empty scene and each one in a scene which included a complex character rig.
The code and results are below:

import maya.cmds as cmds
import timeit

def exists():
    found = cmds.objExists('locator1')
    return found

def select():
    found = False
    try:
        cmds.select('locator1')
        found = True
    except:
        found = False
    return found

print timeit.timeit(select, number = 10000)

The results

The Try, Except took:
0.398722180715 in an empty scene and
0.376243066404 in a complex rig scene

where as the objExists took
0.0698589508479 in an empty scene and
0.0415636909748 in a complex rig scene

astonishing, and, contrary to my expectations, the Try, Except took nearly ten fold longer than the objExists!
From this I learned: Using specific commands looks to be faster than using Try, Except! I’ll have to test more commands and find out :)
If you’d like to try this code yourself, you can see the result for each funstion by changing this line:

print timeit.timeit(select, number = 10000)

To this:

print timeit.timeit(exists, number = 10000)

Cheers!

Removing unknown nodes from your scene

I’ve recently found myself working in files with which
a co-worker has used a plugin which I don’t have.
Said plugin has created nodes which my version of Maya
does not recognize, so on load I get the classic error raised :

errors

Through dealing with this I’ve developed a solution:
Find and delete said nodes!….. Brutal.

Now we can find these nodes using

import maya.cmds as cmds
unknownNodes = cmds.ls(type = 'unknown')
print unknownNodes 

But if we try to delete them we get an error “#Error: Node is locked and cannot be deleted.”

so we need to unlock them with:

for node in unknownNodes:
    cmds.lockNode(node, lock = False)

then we can delete them with:

for node in unknownNodes:
    cmds.delete(node)

No bringing it all together in one script:

import maya.cmds as cmds
unknownNodes = cmds.ls(type = 'unknown')
for node in unknownNodes:
    print 'deleting: ' + node
    cmds.lockNode(node, lock = False)
    cmds.delete(node)

And there you have it! No longer shall you be plagued by errors on boot up :)

Its been a while..

I’ve been knuckled down with working full time! But its time to get back onto this blogging business.
Starting with revisiting an old tool feels appropriate!
Having written a tool for upsaving your scene some years ago
I’ve since learned a lot about string formatting and array navigation in Python.
The tool is simple, it finds out where your current scene is located and its name,
then looks for a number at the end of the name, adds 1 to it and saves the file, with the new name in
the same directory.

def upSaveScene():
	currentFileLocation = cmds.file( query = True, location = True )
	currentFileName = currentFileLocation.split( '/' )[-1]
	if '.mb' in currentFileName:
		stripExtension = currentFileName.replace('.mb','')
	if '.ma' in currentFileName:
		stripExtension = currentFileName.replace('.ma','')
	versionNumberString = stripExtension.split( '_' )[-1]
	if versionNumberString.isdigit():
		versionNumber = int(versionNumberString)
		newVersionNumber = versionNumber + 1
		newFilename = currentFileName.replace( str(versionNumber), str(newVersionNumber) )
	if not versionNumberString.isdigit():
		newFilename = stripExtension + '_01'
	newFilenamePath = currentFileLocation.replace( currentFileName, newFilename )
	
	cmds.file( rename = newFilenamePath )
	cmds.file( save = True, f = True )

Set project button!

Nice little tool which looks for you ‘scenes’ folder and sets the project to that location:


import maya.cmds as cmds
import maya.mel as mel
import maya.OpenMaya as om
 
def setProj():
    # find directory
    currentDir = cmds.file( query = True, location = True )
    # dicect directory and set project
    try:
        projectDir,garbage = currentDir.split( 'scenes' )
    except:
        return om.MGlobal.displayError( 'You need to have you file in a project folder structurte first' )
    mel.eval( 'setProject ' + '"' + projectDir + '"' )
    om.MGlobal.displayInfo( 'current project set to : ' + projectDir )
    del projectDir
    del garbage
setProj()

Updated save tool!

I’ve updated the savetool to keep a master version of the file! I’m now refefing to it as an Up Save tool.

################################################################################################
################################################################################################
###                             Save new version of current scene                            ###
###                                  By Alastair Richardson                                  ###
###                                         May, 2013                                        ###
###                               Intended for Maya Ascii files                              ###
###          Use:                                                                            ###
###             padding is the number of digits in the version number.                       ###
###                                                                                          ###
###             versionIndicator is the characters that come before                          ###
###             the version number. May be _V or _v depending on your                        ###
###             pipeline.                                                                    ###
###                                                                                          ###
###             fileCountNumbering can be set to True or False.                              ###
###             If set to True, the next version number will be obtained                     ###
###             by counting the number of files in the working folder.                       ###
###             This method is unpredictable if folder contains additional                   ###
###             files or folders.                                                            ###
###                                                                                          ###
###             If set to False, the next version number will be obtained                    ###
###             using the current version number, can be risky if rolling                    ###
###             to old versions is required.                                                 ###
###                                                                                          ###
################################################################################################
################################################################################################
 
padding = 3
versionIndicator = '_v'
fileCountNumbering = False
masterFileName = '_v000'
 
################################################################################################
###                                                                                          ###
###                             Change script at your own risk                               ###
###                                                                                          ###
################################################################################################
import maya.cmds as cmds
from pymel.core import *
import maya.OpenMaya as om
import os
 
def saveNewVer():
    a = ''
    b = ''
    # find directory
    currentDir = cmds.file( query = True, location = True )
    splitDir = currentDir.split('/')
    length = len(splitDir)
    lessOne = length - 1
    shortDir = splitDir[0:lessOne]
    directoryToOpen = '/'.join(shortDir)
    # create next version number of file
    if fileCountNumbering == True :
        # find the next version based on number of files on directory
        currentFileName = splitDir[length -1]
        versionSpilt = currentFileName.split(versionIndicator)
        currentName = versionSpilt[0]
        files = os.listdir( directoryToOpen )
        mayaAscii = []
        for i in files:
            try:
                a,b = i.split('.')
            except:
                print i + ' has no extension'
            if b == 'ma':
                mayaAscii.append(i)
            else:
                print str(i) + ' is not a Maya ASCII'
        nextVersion =  len(mayaAscii) + 1  
    else:
        # find version by disecting current file name at _v
        currentFileName = splitDir[length -1]
        versionSpilt = currentFileName.split(versionIndicator)
        sansMA = versionSpilt[1].split('.')
        currentVersion = sansMA[0]
        currentName = versionSpilt[0]
        nextVersion = int(currentVersion) + 1
    # do the saving
    newDirName = directoryToOpen + '/' + currentName + versionIndicator + str(nextVersion).zfill(padding)
    Mel.eval( "source addRecentFile.mel" )
    Mel.eval('addRecentFile "%s" "%s";' % (newDirName + '.ma', 'mayaAscii'))
    masterName = directoryToOpen + '/' + currentName + masterFileName
    cmds.file( rename = masterName )
    cmds.file( save = True )
    cmds.file( rename = newDirName )
    cmds.file( save = True )
    om.MGlobal.displayInfo( 'saved to ' + newDirName )
saveNewVer()

Breaking Skinclusters?

Skin Clusters break sometimes. Or you just want to copy skinning from one character to another.

Usually when I have a skin cluster playing up I rebind a duplicate of the mesh to the joints and copy the skin weights from the original mesh.
To do this:
1. Duplicate mesh
2. bind duplicated mesh to the same joints as the original
3. copy skin weights over from old mesh with Skin > Edit Smooth Skin > Copy Skin Weights

Gives you a fresh skin cluster but with the skinning you’d setup already.