Posts Tagged ‘Python’

Using PSEXEC

Written by mattanimation. Posted in Maya, Python

ps- what?

What the heck is psexec you say? An admin tool from Microsoft for windows users (barf I know, but its what we got right?) that can be found here . OK? so what can it do? Well haven’t you ever wanted to send commands to another computer on your network? If not just to mess with people? This tool lets you run commands through the console to other machines on your computer.

Example

Let’s say you want to log into another computers cmd console, you would first need to

  • download psexec, a simple small .exe file
  • open your console…cmd
  • cd to the dir you saved psexec in

Now you are ready to get started. Here is a simple example of the command:


psexec \\TARGET_COMPUTERS_NAME -u username -p passwrd command stuff here

or in real case it might be something like this


psexec \\my_precious -u bilbo -p sting cmd

Something like this would result in the command console appearing to be the command console on the other computer,  from there you can run all the commands you want just like normal. Where this becomes more useful is being able to take that same command and have it run from say….python….in Maya. I recently worked on a tool that needed some functionality to select certain combinations of files, then reference them into new files, then those files were but in batch files that were then dived up between render machines, but how would you get those machines to start those renders from Maya?

By having the batch files located in a networked location the file name can be sent to each machine as an argument from psexec. Now you may say, why not use Afterburner? or what is this hackery? Well the point is, we cut the middle man out, why do I want to muck around with afterburner after the fact and spend more time when I can have it all done with one click?

See what else you can use it for!

Black Box Animation Toolset

Written by mattanimation. Posted in Maya, pyQT, Python, Rigging, UI

Well I figured I should just go ahead and start displaying what I have been working on in my secret lab the past little while in the hopes that putting it out there will actually make me finish the thing. Also to post a history of my workflow and some tips about things I have learned on the way. What is this “Black Box” you say? At first it was to be my custom modular rigging tool, and now it has become a mini character animation pipeline so to speak. The idea behind the name is to have a tool that plugs into everything so the modules are built in a way that allows changes to be made to the rig after it is deemed “complete” which never happens which is why a feature like this is important. Some features include:

  • Modular character rigging
  • Template saving and loading
  • custom character GUI layout built in
  • pose library built in
  • other TD tools for common tasks that tie into the rigs

Aside from this I plan to add a facial rigging portion dubbed “Gray Skull” that will allow for a standardized joint based rigging approach for most characters. The final tool I plan to add to this dubbed “Chop Shop” is a modular vehicle/mechanical rigging portion that will be used for..well…vehicles and stuff, it will focus more on dynamics and plugin development.

This is way too much for one to handle! Why are you doing this dummy, it has been done before!? Originally this whole thing was thought up a few years back when buddy of mine and some other friends from school were going to make a short film. I had started a rigging tool and then that dream was abruptly cut short after loosing my job (darn you federal reserve and bailouts that cause layoffs!) so it had to go on hold while I acquired some kind of vocation to support the fam, but enough sob story. I heard more about these ‘modular rigging’ things and found out, hey I need to learn Python since MEL ain’t gonna cut it anymore (although still alive just not useful outside of Maya). Needless to say, the root of this comes from a DVD by Steve Twist that is a doozy for a beginner at Python but I had somewhat of a coding background so it wasn’t too crazy, just time consuming. As of recently I have been slowly coming to the conclusion that the current system in place needs a lot of work although it works for now, much more is to be done. I think I want to convert it to PyMel as I have not yet made that jump, no time better than now right? Basically I want a tool that allows me to be my own little studio if a decent size freelance comes up I can handle it. I’ve even got a Kinect now and plan on adding a mo-cap layer in there somewhere.

So! On to the learning stuff, first stages:

  1. Think About it sit down and figure out what you are trying to accomplish and make goals
  2. Make a features list list all the “wish list” items you can think of, even if you have no idea how to do it
  3. Always Sketch the UI Before Implementation, show it to others before you get started for feedback as well.

Here are my initial sketches part of what it looks like in Maya so far:

One thing to note is all of this is still subject to change. Don’t limit yourself to just one design because it might be more work to redo it. Which brings me to my next point…keep your UI separate from your main code and other modules, this way if there IS a change then it will only affect this one file since the functionality should not be affected by the users interaction with the interface. I think this a good first post, more to come.

Some Qt Tips

Written by mattanimation. Posted in Maya, pyQT, Python

I’ve been jumping back into using Qt recently, this time in Maya and although there are many resources out there to help get started (I will be posting some below) there are a few things I ran into that might help others on the way.

  • Scroll Areas

QtGui.QScrollArea  this is interesting, even if you are in Qt Designer you can’t seem to get a preview of it working. To get this to work you need to first make a widget and a layout, set the layout of that widget to the newly created layout. Now create the QScrollArea and there is a method called “setWidget”, you want to pass the widget you first created into this method. Next you should add the scrollArea to whatever layout it’s going to be sitting in. When you want to add something to the scroll area you need to add it to the layout of the widget you first created. A little strange but makes sense once you do it once or twice, see code below.


# create a scroll area for the modules to load
myLayout = QtGui.QVBoxLayout()
scrollingWidget = QtGui.QWidget()
scrollingWidget.setLayout(myLayout)

myAwesomeScrollArea = QtGui.QScrollArea()
myAwesomeScrollArea.setWidgetResizable(True)
myAwesomeScrollArea.setEnabled(True)
myAwesomeScrollArea.setMaximumSize(375, 300)  # optional

myAwesomeScrollArea.setWidget(scrollingWidget)
scrollParentLayout.addWidget(myAwesomeScrollArea)

# add item to the scroll area
myLayout.addWidget(widgetIWantToAdd)

  • Button Click Methods

Let’s say you wanted to have a method run when you click a QPushButton, you would write something like this:


myBtn = QtGui.QPushButton('Click Me')
myBtn.clicked.connect(someMethod)

def someMethod(self, *args):
    """
    some comments
    """
    print 'something'

That works just fine and I’m happy with that. Now what if I needed to pass some values to a method when that button is clicked? If you try to add them like this:


myBtn = QtGui.QPushButton('Click Me')
myBtn.clicked.connect(someMethod(arg_1, arg_2))

def someMethod(self, knight, phrase, *args):
    """
    some comments
    """
    print 'ni!'

You will get an error! You do not want this guy –>    hanging around your code, believe me. So how to remedy this troublesome citizen? We have 2 options, “partial” and “lambda“. Partial is a module that needs to be imported from functools and it allows you to specify a method call followed by the arguments you wish to pass it all in a single line. It runs as a single function thereby letting the button do it’s thing and you can continue on your merry way. Lambda? what is this lambda you speak of? In a nutshell its a syntax in python that lets you create a function on thy fly, so we can can create a quick single function that just runs our method call with arguments passed inside. Here are your jolly examples.

using partial


from functools import partial

myBtn = QtGui.QPushButton('Click Me')
myBtn.clicked.connect(partial(someMethod, arg_1, arg_2))

def someMethod(self, knight, phrase, *args):
    """
    some comments
    """
    print 'ni!'

using lambda


myBtn = QtGui.QPushButton('Click Me')
myBtn.clicked.connect(lambda : someMethod('brave sir robin', "I don't know that"))

def someMethod(self, knight, phrase, *args):
    """
    some comments
    """
    print 'aaarrrggg!'

Here are some other links to get started using PyQt in Maya:
Kristine Middlemiss

David Coleman

There are more links in older posts as well.

Using JSON to store node information in Maya

Written by mattanimation. Posted in JSON, Maya, pyMel, Python

Recently I have been looking into ways to optimize a pose library that I made. The pose information was stored using XML. This worked great and was all dandy, but my implementation always seemed a bit clunky, having to open and close the file read write and change the information, mainly having to traverse a hierarchy then store it in as a list to make changes before re-writing the pose. I read that others have used JSON which had heard of many times and since pretty much every coding language out there has support for it, it must must be a win right? I gave it a shot and came up with this example today:

import json
import pymel.core as pm

def store(name, objs):

    pose={}
    ctrls=[]
    for o in objs:
        data={}
        for attr in pm.listAttr(str(o), keyable=True, unlocked=True):
            value = pm.getAttr(str(o)+'.'+attr)
            data.setdefault(str(attr),value)

        ctrls.append([str(o),[data]])

    pose.setdefault(name, {"ctrls":ctrls})

    f=open('/Users/yourname/Desktop/' + name + '.rp', 'w')
    f.write(json.dumps(pose))
    f.close()

def load(poseToLoad):
    f=open('/Users/yourname/Desktop/' + poseToLoad +'.rp', 'r')
    data=f.readlines()
    f.close()
    j_data = json.loads(data[0])

    ctrls = j_data[poseToLoad]['ctrls']

    for c in ctrls:
        ctrl = c[0]
        attrs = pm.listAttr(ctrl, keyable=True, unlocked=True)
        for a in attrs:
            at = c[1][0]
            val = c[1][0][a]
            pm.setAttr(ctrl + '.' + a, val)

if len(pm.ls(sl=True)):
objs = pm.ls(sl=True)
#   store("pose1",objs)
load("pose1")
Explaination

In the block above there is an example of using JSON to save the attributes of the selected nodes in maya, the node names, and a pose name associated with it. You can paste this code in a python tab in Maya and run it(make sure you insert your own file path where needed) to see the results. Basically JSON uses a few common data structures that easily recognizable even to the beginner python user, they are: dictionaries, lists, strings, and numbers. At first the structure looked way harder to read than XML but after a second glance it literally was just looking at a nested dictionary or list, and then I realized something even cooler, when I read the information back from the file, that’s exactly what they were coming in! No more traversing elements and storing into local lists, just a simple clean load right into the pyMel commands.

Now the thing that I am still working on is the actual data structure and what would be most desirable to work with, this works for now, but it would be awesome to just reference everything by the key and not worry about the indices of an array. Needless to say it’s worth looking into if you haven’t already.

*Update*

After actually implementing this and testing with my pose library I was able to shorten the code significantly. The data structure itself now looks like this:

{"poseNameHere": {"ctrls": {"pCube1": {"translateX": 2.5280296598674887, "translateY": 1.4508343627372717,
"translateZ": 11.414172610952747, "scaleX": 1.0, "scaleY": 1.0, "visibility": true, "rotateX": 0.0, "rotateY": 0.0,
"rotateZ": 0.0, "scaleZ": 1.0}, "pSphere1": {"translateX": -8.2447907269338465, "translateY": -1.2861870433449312,
"translateZ": 12.463030765724765, "scaleX": 1.0, "scaleY": 1.0, "visibility": true, "rotateX": 0.0, "rotateY": 0.0,
"rotateZ": 0.0, "scaleZ": 1.0}, "pCylinder1": {"translateX": -6.3732975936497738, "translateY": 2.1936347842880819,
"translateZ": 7.2561024617979939, "scaleX": 1.0, "scaleY": 1.0, "visibility": true, "rotateX": 0.0, "rotateY": 0.0,
"rotateZ": 0.0, "scaleZ": 1.0}}}}

you might be like wtf is that? Let’s break it down. As you might already know a dictionary is created using a key and a value, they are separated by a colon between them.

 myDict = {"keyName":value}

If I want to get the value, I refer to the key like this:

newVar = myDict["keyName"]

Now looking at the above example again we can see that the poseName’s value is actually a dictionary, that dictionary has a key called “ctrls”. The “ctrls” dictionary holds all the controls for the pose. Each ctrl name is a key as well, and thier value is a dictionary that has attributes for the key and the attr values for the values. Make sense?

Like I stated in the original post, I was working on the data structure, before I had arrays for the ctrls but I wanted to not have to reference an index and just use the names as keys for everything so here is what the read and write functions look like now:


def writePoseFile(self, objs, path, thumb, name):
    """
    Write a file that stores all the keyable attributes on a list of objects passed in.

    @type alist: list
    @param alist: the list of objects(ctrls) to iterate through and get the attr:value pair
    @type string: str
    @param string: the path that the file will be written to
    @type string: str
    @param string: the thumbnail image name
    @type string: str
    @param string: the name of the pose to be stored

    """
    ctrls={}
    for o in objs:
        data={}
        for attr in cmds.listAttr(str(o), keyable=True, unlocked=True):
            data.setdefault(str(attr),cmds.getAttr(str(o)+'.'+attr))

        ctrls.setdefault(str(o),data)

    pose = {name:{"ctrls":ctrls}}
    f=open(path, 'w')
    f.write(json.dumps(pose))
    f.close()

def setPose(self, fpn, *args):
    """
    Read a pose file and set the ctrls attr's values

    @type string: str
    @param string: the ui path to the button that was clicked

    """
    #get the name of the button clicked
    poseName = cmds.shelfButton(fpn, q=True, ann=True) #annotation of btn
    currentTab = self.tabList[cmds.tabLayout(self.UIElements['mainTabLayout'], q=True, selectTabIndex=True)-1]
    poseFilePath = self.currentCharDir +'/'+ currentTab + '/' + poseName +'.pose'

    #read the pose file
    f=open(poseFilePath, 'r')
    j_data= json.loads(f.readline())
    f.close()

    for c in j_data[poseName]['ctrls'].keys():
        attrs = cmds.listAttr(c, keyable=True, unlocked=True)
        for a in attrs:
            cmds.setAttr(c + '.' + a, j_data[poseName]['ctrls']1[a])


    #end

QStringList in Python3.x

Written by mattanimation. Posted in pyQT, Python

I decided to start going through Yasin’s awesome MVC programming tutorials in PyQt(actually doing it instead of just watch) and ran into a little snag when on the first lesson. I entered in all the same code but in the IDE I was using got an error that said:
'module' object has no attribute 'QStringList'

So after digging around and searching I found the answer and wanted to share it. I was using python ver 3.1 and according to what I read on stack overflow here , if you are using PyQt4 and python 3 then you don’t need to use QStrings, in fact that aren’t in the library which is what that error means. so if you are getting that same error simply use a python string list like this:

data = ['one', 'two', 'three', 'four', 'five']

and all should be well and dandy.

Python, Recursive Functions and Returns

Written by mattanimation. Posted in Python, Uncategorized

So, I found out the other other day that if you want to have a value returned when using a recursive function you must include the return line in each instance of the return. Example:

Incorrect way:

 def cleanMyString(self, url):
      returnURL = ''
      if ':' in str(url.encode('utf-8')):
           fixMe = url.replace(':', '_')
           self.clean(fixMe)
      elif '$' in str(url.encode('utf-8')):
           fixMe = url.replace('$', '-')
           self.clean(fixMe)
      else:
            returnURL = url
           return returnURL

The result of this method is None unless the string did not match any of the conditions to re-curse.

Correct way:

 def cleanMyString(self, url):
      returnURL = ''
      if ':' in str(url.encode('utf-8')):
           fixMe = url.replace(':', '_')
           return self.clean(fixMe)
      elif '$' in str(url.encode('utf-8')):
           fixMe = url.replace('$', '-')
           return self.clean(fixMe)
      else:
          returnURL = url
          return returnURL

 

so we can see that instead of calling the function directly we need to put return in front, otherwise we get a return value of None.

QT Interfaces in Maya

Written by mattanimation. Posted in Maya, pyQT, Python, UI

There are a many sites that have information about how to setup/create a user interface in Maya using the QT frameworks components, specifically using Qt designer. Here are a couple of links I found especially useful:

http://ivoxelstudios.com/blog/?p=51

Now this one is pretty cool because Chris covers something that I have found to be kind of annoying to with loading a UI which is wanting to be able to grab the controls from the UI.

http://www.chris-g.net/2011/06/24/maya-qt-interfaces-in-a-class/

Another great resource is from John Neumann that covers creating a UI and loading it in Maya and then adding functionality using MEL.

http://www.animateshmanimate.com/2010/07/19/maya-andqt-tutorial/

Here is a video tutorial straight from Autodesk.

http://area.autodesk.com/blogs/stevenr/maya_2011_highlight_qt_user_interface

I just wanted to add to the resource results in google and put the most basic information needed to get started which is, what do I need to do to see my interface after I have created it?

well here is the most basic code I could strip it down to(python version of course):

import maya.cmds as cmds

pathToFile = 'path/to/your/file.ui'
qtWin = cmds.loadUI(uiFile=pathToFile)
cmds.showWindow(qtWin)

Now, if that’s not easy and straight forward I don’t know what is.
But now how do you edit your components? Well, whatever you named the object in QTDesigner will be the name of the object in Maya, just refer to it in string form, for example, if I had a textScrollList in my UI I would type something like the following to add an item to it:

cmds.textScrollList('nameOfMyWidget', e=True, a='smellyFeet')

So as you can see it’s easy to type the names of widgets and edit them, but wouldn’t it be nice to have all of them stored in a dictionary somewhere for easy reference? The link to Chris G’s blog post talks about this is is a must read.

One last thing worth mentioning is the docking ability to the interface, since this IS one of those features that everyone wants at least try one time even if it’s not always necessary. This information is at the end of the autodesk video but it’s nice to just have the code you need on had right, plus google can’t really search the video for code right?

so add this to the code above and comment out the cmds.showWindow part

dockLayout = cmds.paneLayout(configuration='single', parent=qtWin)
cmds.dockControl(allowedArea='all', area='right', floating=True, content=dockLayout, label='Custom Dock')
cmds.control(qtWin, e=True, parent=dockLayout)

and thats it! You can play with some of the args to get the functionality right, like if you set “floating” to false it will start out as docked to the right side of your layout in Maya. Good Luck!