Using the wedge tool to rig a bellows in Maya
I just a made a short tutorial , a tip really on how to use a modeling tool to rig a bellows.
I just a made a short tutorial , a tip really on how to use a modeling tool to rig a bellows.
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")
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.
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
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.
In this tutorial I show how to setup a limb that can utilize no-flip and a pole-vector at the same time.
No-flip+Ik Limb Tutorial from Matthew Murray on Vimeo.
There have been some pretty good posts on some certain blogs lately about different facial rigging techniques so I thought to regurgitate them here. I will be adding to this list as time moves on.
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.
Another tutorial has been released! enjoy
Well I was reading this post by Nathan Horne of Naughty Dog and read this :
This abruptly caught my attention. The article itself had already convinced me to want to use PySide and PyQt to code UIs but left me on the fence wether to use the QTDesigner or not, until I read this. Either way it is a very good read, take a look and listen to the experts!
Well, go and get it!