Mar 13
Its been a crazy few days at GDC. I wanted to let everyone know that me and my friend Adam Mechtley put together a video Masterclass on Python for Autodesk’s Virtual GDC. You will need to get an account with area.autodesk.com and they require you to register separately for the class as well. Its free, watch it! The class description and link to the video follows:
Class Description:
“Since the formal introduction of Python into Maya, it has been rapidly gaining ground as the scripting language of choice among technical artists and tools developers. Its host of built-in features and its support for programming with the Maya API allow Python developers to interact with Maya in many exciting ways. In this MasterClass, Adam and Ryan discuss different scenarios that may appear during production and for which Python is ideally suited to provide a quick and flexible solution. Using two example projects, Adam and Ryan will demonstrate practical applications of threading as well as Maya plug-in development.”
http://area.autodesk.com/gdc/class2
Last but not least Uncharted 2 received five awards at the 10th annual Game Developers Choice Awards including the Game of The Year award. More info here:
http://www.gamasutra.com/view/news/27649/GDC_Uncharted_2_Wins_Big_At_10th_Annual_Game_Developers_Choice_Awards.php
Cheers,
Ryan
Feb 18
I thought I would let people know that I will be giving a talk on our Character Pipeline at a conference called Evolve CG. Evolve CG’s main focus is to give students a chance to learn from people in the industry. The conference will be held at the Hilton Marina in Ft. Lauderdale, Florida on May 15-16.
http://evolve3d.net/feature-speaker-ryan-trowbridge/
Cheers,
Ryan
Feb 10
Did you ever wonder what Python does with all those variables and functions you write in the Maya script editor? No? Well I am going to tell you anyway. I recently refered to the Maya Script Editors Python global scope or main namespace as the main module to a friend. He said that I must have been tired and meant something else, but I didnt and here is why.
Type in and execute the following code into your script editor in a Maya Python tab:
print __name__
Which will print:
__main__
When you print __name__ in a module it will give you the namespace of the module itself. So why did printing __name__ work inside of the Script Editor? Now write a quick function and execute it in the Script Editor:
def test():
"""this function is a test"""
print "test"
Next type and execute the following line:
help(test)
#Result:
Help on function test in module __main__:
test()
testing
Continue reading »
Feb 06

This post has nothing to do with Python or anything to do with character rigging. With that warning given I thought I would post something I had made to remember Uncharted 2: Among Thieves. My last project was by far the best project I have ever worked on. So far we have won more awards than we can count. Last time I looked there were 98 major magazine or online publications that had given us the Game of the Year award for 2009. So to celebrate this I decided to make something to remember the game by.
I had a poster we had on hand signed by all my colleges at ND, then I had a plaque engraved with Uncharted 2:Among Thieves Game of the Year 2009. I had all of these framed in a shadow box style frame. The boarders use the black, red, and white Naughty Dog colors. The shadow box style frame let me put the game cd, box, and plaque to the side of the poster. The frame shop did a great job.
I look forward to shipping our next game,
Ryan
Feb 04
Its been awhile since I posted. Ive been creating a lot of Python UI’s of late. I have seen others struggle with creating their first UI. There are a few gotchas and the best way to set up a Python UI is different than setting it up with MEL.
A good way to setup your UI is to encapsulate the UI in a class including the functions you will use with the UI. You dont need all of your functions inside of the class. If you need to work with a function that is external to the class, you can use a partial function. When you set a button command to use a function it is best not to give it a string like you would in MEL. You should pass the functions directly to the command. You should not pass the functions as if you called them however like function() but by just giving it the name. If you need to pass an argument you need to use a partial function so the function does not get called until the user presses the UI item. You should note the UI button command happens to always pass one argument even if you dont pass anything to the function. If you pass your function one argument it will receive two, or if you pass two it will receive three. This is easily remedied by adding an extra unused argument.
I have several personal projects taking up my time right now so I am going to be brief on the how to and what does what part. The following example should help you get started. You can execute it from the script editor and start playing around with it.
import maya.cmds as cmds
from functools import partial
def myfunc(inst=None, thing=None, arg=None):
print 'arg: ', arg
print 'inst: ', inst
print 'thing: ', thing
data = cmds.button(inst.btnA, query=True, label=True)
print data
class ui():
def __init__(self, winName="winTheWindow"):
self.winTitle = "The Window"
self.winName = winName
def create(self):
if cmds.window(self.winName, exists=True):
cmds.deleteUI(self.winName)
cmds.window(self.winName, title=self.winTitle)
self.mainCol = cmds.columnLayout( adjustableColumn=True )
self.btnA = cmds.button( label='Press Me - External Func', c=partial(myfunc, self, 'say...') )
self.btnB = cmds.button( label='Press Me - Internal Func', c=partial(self.a, 'something...') )
self.btnC = cmds.button( label='Press Me - Internal Func No Args', c=self.b)
cmds.showWindow( self.winName )
cmds.window(self.winName, edit=True, widthHeight=[250,75])
def a(self, myarg=None, arg=None):
print 'myarg: ', myarg
def b(self, arg=None):
print 'buttons require an argument'
print 'the argument passed in will always be the last argument'
# create the window
inst = ui()
inst.create()
Have fun,
Ryan
Jul 17
Ive been very busy with Uncharted 2 and projects, but I thought I would post our new trailers and links to all the E3 awards we got.
Uncharted 2 Trailers -
E3 Trailer
Level Walkthrough
Dont Quite Cinematic
Continue reading »
May 22
I saw a post on www.cgtalk.com where a user wanted to render the selected meshes bounding box as a render region using the current render settings. He gave this example:

I thought this was an interesting challege that the Python API could handle since it can access the M3dView class which lets you test points in the Maya 3d space and get what pixel they are at in the viewport. Here is the finished script, also posted in my downloads section:
rtRenderSelectedMeshesRegion.zip
Cheers,
Ryan
May 18
In response to an e-mail I received I wrote back this response. I figured I would post it.
So I was given this example and asked what the u charter was for in front of each string name returned in the list.
aList = cmds.ls(selection=True)
print aList
>>[u'pSphere1', u'pSphere2', u'pSphere3', u'pSphere4']
The long and the short of it is Unicode allows more characters than ASCII. ASCII can hold 256 values and Unicode can hold 65,536 values. This allows computers to support complex languages with many characters. If you want a more complex explanation go here:
http://www.amk.ca/python/howto/unicode
Getting back to the example. So the aList returns a list of string names using Python Unicode. Thats what the u stands for. It shouldnt bother you though nor affect anything.
So if you have two spheres in your scene and you run this in the script editor it will return u’pSphere2′ and u’pSphere1′ like this:
import maya.cmds as cmds
getlist = cmds.ls(sl=True)
print getlist
>>[u'pSphere2', u'pSphere1']
Continue reading »
Apr 04
I am finally posting the poseReader plug-in I converted. You can find it in the downloads section here:
http://www.rtrowbridge.com/blog/downloads/
It was originally written by Michael B. Comet so the concept was created by him and he deserves the credit. I converted his C++ code into a Maya Python API plug-in. Hopefully with no bugs, but there very well could be some still lurking. If you find any feel free to tell me and I will look into fixing them. I think this was a good exercise in converting a plug-in. It helped me with understanding better how to read C++ into Python. Not that I will be doing that often but it is still a good learning experience.
This changes the poseReader from being a plug-in that must be compiled for every version of Maya to a plug-in that will work on any platform and for any version of Maya using Python. That’s pretty cool I think.
Feel free to pick it apart and learn from it.
Cheers,
RyanT
Mar 17
I saw a post on www.cgtalk.com requesting an example of how to create a compound attribute on a node. Here is a full working example with a detailed description of how it works following the example:
import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
kcompUtilNodeTypeName = "compoundExampleNode"
kcompUtilNodeClassify = "utility/general"
kcompUtilNodeId = OpenMaya.MTypeId(0x87325)
# define a new matrixUtilNode class derived from the MPxNode class
class rtcompUtilNode(OpenMayaMPx.MPxNode):
# class variables
compIn = OpenMaya.MObject()
compOut = OpenMaya.MObject()
input = OpenMaya.MObject()
output = OpenMaya.MObject()
def __init__(self):
OpenMayaMPx.MPxNode.__init__(self)
# arguments ( self, MPlug, MDataBlock)
def compute(self, plug, dataBlock):
# if these attributes are requested, recompute their values
if plug == rtcompUtilNode.compOut or plug.parent() == rtcompUtilNode.compOut:
# get MDataHandle's to attributes
#
try:
input_dataHandle = dataBlock.inputValue( rtcompUtilNode.input )
except:
sys.stderr.write( "Failed to get MDataHandle inputValue input" )
raise
try:
output_dataHandle = dataBlock.outputValue( rtcompUtilNode.output )
except:
sys.stderr.write( "Failed to get MDataHandle outputValue output" )
raise
# get values from dataHandle
#
input_value = input_dataHandle.asFloat()
# set the output
output_dataHandle.setFloat(input_value)
# set the plug clean so maya knows it can update
dataBlock.setClean(plug)
else:
return OpenMaya.kUnknownParameter
return OpenMaya.MStatus.kSuccess
def nodeCreator():
return OpenMayaMPx.asMPxPtr( rtcompUtilNode() )
# create and initialize the attributes to the node
def nodeInitializer():
nAttr = OpenMaya.MFnNumericAttribute()
cAttr = OpenMaya.MFnCompoundAttribute()
# create input attributes
#
rtcompUtilNode.input = nAttr.create("input", "i", OpenMaya.MFnNumericData.kFloat, 0.0)
nAttr.setWritable(True)
nAttr.setStorable(True)
nAttr.setReadable(True)
nAttr.setKeyable(True)
rtcompUtilNode.output = nAttr.create("output", "o", OpenMaya.MFnNumericData.kFloat, 0.0)
nAttr.setWritable(False)
nAttr.setStorable(False)
nAttr.setReadable(True)
# create compound attribute
#
rtcompUtilNode.compIn = cAttr.create( "compIn", "ci" )
cAttr.addChild( rtcompUtilNode.input )
rtcompUtilNode.compOut = cAttr.create( "compOut", "co" )
cAttr.addChild( rtcompUtilNode.output )
# add attribues
#
rtcompUtilNode.addAttribute( rtcompUtilNode.compIn )
rtcompUtilNode.addAttribute( rtcompUtilNode.compOut )
# Setup which attributes affect each other
rtcompUtilNode.attributeAffects ( rtcompUtilNode.compIn, rtcompUtilNode.compOut )
# initialize the script plug-in
def initializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject, "Autodesk", "1.0", "Any")
try:
mplugin.registerNode( kcompUtilNodeTypeName, kcompUtilNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kDependNode, kcompUtilNodeClassify)
except:
sys.stderr.write( "Failed to register node: %s" % kcompUtilNodeTypeName )
raise
# uninitialize the script plug-in
def uninitializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject)
try:
mplugin.deregisterNode( kcompUtilNodeId )
except:
sys.stderr.write( "Failed to deregister node: %s" % kcompUtilNodeTypeName )
raise
Continue reading »
Recent Comments