View Full Version : multiple outputs from a single SDK in mel?

08 August 2010, 09:25 AM
Okay so I considered posting this to the mel forum but it strikes me as the sort of thing riggers would encounter.

Basically I've got this really nice node network and I'm now scripting it's creation but it relies heavily on SDKs with their outputs driving multiple attrs downstream. I naively thought I might be able to use the same SDK code and have it somehow magically know that it needs to use the same node but instead I end up with two. This is uneccesary and annoying I don't want to manage two nodes.

What I don't understand is that the SDK command returns only the number of keys. Is it me or is this a particularly useless piece of info when what I really need is the name of the node so I can use it's output and plug that into another node.

So the question how would you go about scripting this without hardcoding in a name for the SDK which for me seems like a poor option (also I'd have to guess at the name cause it isn't returned, why!?). Oh and another thing why is their no -name flag on the SDK. All of this seems silly to me. Anyway just thought I'd ask some experienced riggers what they'd do here. I'm sure I could force things but I'm sure there's an elegant solution out there.

I thought about using set ranges but honestly I never seem to be clever enough to get the functionality I need out of them in a cycle with offset situation.


08 August 2010, 12:54 PM
I'm not following exactly what you want to achieve - perhaps you could provide a simple example.
Finding the SDKs connected to an object is a bit tricky. You need to use listConnections and look at the name of the each node that is returned.
I just finished a script for working w/SDK based rigs. Here's the code (in PyMel) to parse all the SDK connections to a controller which drives a group of joints (in a facial rig). If you don't know Python, you can still see the flow of commands. Note that PyMel is installed w/Maya 2011. If you are using a previous version, you need to manually install PyMel or you could try changing 'import pymel.core as pm' to 'import maya.cmds as pm'. This will call Maya Python rather than PyMel. While that would not always work, I think it would in this case.
import pymel.core as pm
def parseDriverSDKs(driver):
commandListTmp = []
echoResults = True
print 'Parsing SDKs for driver: ', driver
# Get list of outgoing connections to driver, parse out animCurveU*, which are the SDK channels
cnxnsTmp = pm.listConnections( driver, s=0, scn = 1) # List connections of controller - Turn off Source connections and skip unitConversions
for item in cnxnsTmp:
# Start new command string for this node:
tmpCmd = ''
#print '\n'
#print '%s%s%s' % (item,': nodeType: ',nodeType(item) )

# Parse out the AnimCurveU* nodes
# If the nodeType starts w/ 'animCurveU', its an SDK channel
if pm.nodeType(item).startswith('animCurveU'):
#print ' ',item,'is an SDK animCrv'
#Get the connections to the animCurveU*. There are 3 types of SDK connection (or more?)
# Direct to a transform on the driven node, blendweighted, unitConversion (which can be bypassed with listConnections (scn = 1) )
# Also, the blendWeighted node can have a unitConversion downstream
# If the connection is a blendWeighted node, there is more than one connection to the target
# thus we need to list another generation of downstream connection (from the blendWeighted node) in order to find the target channel
#When we get to the end of the branch of connections, the target attr is found using connection info
ULCrvCnxns = pm.listConnections (item, s=0, scn = 1)
#print '%s%s%s%s' % (' ',item,' connected to: ', ULCrvCnxns[0])


# TEST FOR blendWeighted - probably most common connection.
# If its a blendWeighted node, there is more than one SDK connection to the target (requires one more listConnections)
if pm.nodeType(ULCrvCnxns[0]) == 'blendWeighted':
if echoResults: print ' ',item,'\'s is connected to a blendweighted node: \"',ULCrvCnxns[0], '\", check for another unitConversion'

# Use one more listConnections for blendWeighted node.
# We could go directly to connectionInfo, but then we have to test for a unitConversion node which can't be bypassed with connectionInfo
# The final destination should be a transform - the target object.

# cnxnsTmp = pm.listConnections( ULCrvCnxns[0], s=0)
blendCnxn = pm.listConnections( ULCrvCnxns[0], s=0)[0]
if pm.nodeType (blendCnxn) != 'unitConversion':
finalConnectionTmp = ULCrvCnxns[0]
else: finalConnectionTmp = blendCnxn

# If not a blendShape, we should be at the target node (a transform):
if echoResults: print ' ',item,'\'s first connection is a transform node: \"',ULCrvCnxns[0],'\". ',item,' is last connection.'
finalConnectionTmp = item

# Get the source/target channels and write the command:
# Get Target by tracing the output of the final connection node:
# Setup '.output. attr and get connectionInfo:
finalConnectionOutput = '%s.output' % finalConnectionTmp
drivenAttrTmp = pm.connectionInfo(finalConnectionOutput, destinationFromSource=True) #dfs will return a list of strings in unicode, which Maya can use in commands
if echoResults: print drivenAttrTmp
drivenAttrTmp = drivenAttrTmp[0].encode("ascii","ignore") # For consistency, convert unicode to ascii

#Get the Source by tracing the input of the animCurveU*
# Setup '.input. attr and get connectionInfo:
SDK_CrvInputTmp = '%s.input' % item
driverAttrTmp = pm.connectionInfo(SDK_CrvInputTmp, sfd=True) #sfd will return a string, which requires ' (QUOTE) to define it in cmds

#print drivenAttrTmp,' driven by ',driverAttrTmp
#print 'We\'re done with this branch!'
# Write command for this driven object

# Add to command list

# Initailize var to hold command
tmpCmd = ''
tmpCmd += 'pm.setDrivenKeyframe(\''
tmpCmd += drivenAttrTmp
tmpCmd += '\',currentDriver=\''
tmpCmd += driverAttrTmp
tmpCmd += '\')'
commandListTmp.append(tmpCmd)Hope that helps.

08 August 2010, 01:09 PM
Ah 2011 if only. I'm still running 2008 at work. I'll look at this and post what I come up with. I was afraid the solution might involve listConnections. I'm trying to learn python so I sort of understand the syntax so yes I can follow mostly. I see there's not even a way to really get the name of the node in pymel (using the setDrivenkeyfrane command) which is really strange. Will try and post an example if I can't solve this based on what you've shown me.


More complicated than I would have liked but I won't need to do it again now. And I thought seeing as you showed me yours I should show you mine.

There's no error checking but it works fine so long as you give it the right args. Thanks for the help.

//this little util creates a set driven key between two objects
//it then connects that SDK's output to all the respective
//objects in the argument

global proc bg_multiSDK (string $driver, float $driverVal[], string $drivenObj[], float $drivenVal[]){
int $i = 0;
for ($eachNumber in $driverVal){
-driverValue $driverVal[$i]
-value $drivenVal[$i]
-currentDriver $driver

string $sdkName = `connectionInfo -sourceFromDestination $drivenObj[0]`;

for($g = 1; $g < size($drivenObj); $g++)
connectAttr $sdkName $drivenObj[$g];

08 August 2010, 01:36 PM
I see there's not even a way to really get the name of the node in pymel (using the setDrivenkeyfrane command) which is really strange.
Which node are you trying to get the name of?

08 August 2010, 03:21 PM
Which node are you trying to get the name of?

I'm a noob so please excuse my ignorance but looking at the pymel docs the setDrivenKeyframe command is a direct translation none of the fancy cleverness that I've seen in other commands like connectAttr with the whole attr >>> attr thing. Mostly just rambling. Ie there's no way to get the name or is there. I really need to get into python properly again.

CGTalk Moderation
08 August 2010, 03:22 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.