Hi again, I’m back with a new issue.
I was trying to set up a bunch of message attributes on an object and since I have clashing names for target object I tried to add the long name to the connection, but this doesn’t work.
Why?!
jntsLng = mc.ls(sl=1, long=1)
jntShrt = ""
jntsShrt = []
each = "hand_01_ctrl"
for i in range(len(jntsLng)):
jntShrt = jntsLng[i].rpartition('|')[2]
jntsShrt.append(jntShrt)
mc.select(each, r=1)
for i in range(len(jntsLng)):
mc.addAttr(ln=jntsShrt[i], at="message")
//here is the error, It fails to print the long name, instead takes the short name and not the path to the actual joint, resulting in a name clash since I have more than two joints named "finger_joint_E_00" under separate parents.
for i in range(len(jntsShrt)):
mc.connectAttr(str(jntsLng[i])+".message", each+"."+jntsShrt[i])
Thanks for looking!
And please help. I’m in dire need!! =/
import maya.cmds as mc
jntsLng = mc.ls(sl=1, long=1)
jntShrt = ""
jntsShrt = []
each = "hand_01_ctrl"
for i in range(len(jntsLng)):
jntShrt = jntsLng[i].rpartition('|')[2]
jntsShrt.append(jntShrt)
mc.select(each, r=1)
for i in range(len(jntsLng)):
try:
mc.addAttr(ln=jntsShrt[i], nn = jntsShrt[i], at="message")
except:
mc.addAttr(ln=jntsShrt[i] + str(i), nn = jntsShrt[i], at="message")
for i in range(len(jntsShrt)):
try:
mc.connectAttr(str(jntsLng[i])+".message", each+"."+jntsShrt[i])
except:
mc.connectAttr(str(jntsLng[i])+".message", each+"."+jntsShrt[i] + str(i))
This should work. The issue is that you can’t have the same longName as a custom attribute. So the code above adds the range number to the end of the second controller.
It’s a quick messy fix, but I think you can find a cleaner solution now.
Just a couple python tidbits, which also improve readability. Maybe you know them, but in case you don’t!
You can iterate over the actual contents of a list and avoid having to use range(len()):
for jnt in jntsLng:
jntShrt = jnt.rpartition('|')[2]
When maya.cmds returns node names they are always strings, so you don’t have to cast the node to a string before concatenating it with another. As an extension of that, python string formatting makes strings comprised of multiple variables easier to read (in my opinion):
mc.connectAttr('%s.message' % jntsLng[i], '%s.%s' % (each, jntsShrt[i]))
vs.
mc.connectAttr(str(jntsLng[i])+".message", each+"."+jntsShrt[i])
And though it’s just syntactic sugar here, you can use zip to iterate over multiple lists at the same time:
for jntLng, jntShrt in zip(jntsLng, jntsShrt):
mc.connectAttr('%s.message' % jntLng, '%s.%s' % (each, jntShrt))
Uhm. I have some questions regarding my approach to this whole problem.
What I want to achieve is to create a poser UI and when clicking a pose button, depending on the selected controller, pose that hand.
Perhaps this is not the way to go about it, cause I really want the fingers to share names(as they are to be created with the same template and rig script)
I guess I could rename the joint for each hand, but problem soon arises when keeping track of if another character has the same suffix. But, yeah this would work. message attribute finger_A will always find the correct finger.
I was thinking of using a different approach looking for finger_A_seg_01 on the selected controller. If the controller is the parent of that finger, rotate it, but then I wouldn’t use message attributes and they are so cool.
Opinions?
Thanks again guys. Tremendous help. Very thankful for all the tricks you show about Python aswell. Keep 'em coming =)
PS.
I guess I could just aswell concatenate finger_A_01 to the selected controller, like: ‘%s|finger_A_01’ % ctrl
and act on that, but it will easily look ugly having a bunch of long paths…
ex: ‘%s|finger_A_01|finger_A_02|finger_A_03’ % ctrl
[QUOTE=TheDagNode;22159]Uhm. I have some questions regarding my approach to this whole problem.
What I want to achieve is to create a poser UI and when clicking a pose button, depending on the selected controller, pose that hand.
Perhaps this is not the way to go about it, cause I really want the fingers to share names(as they are to be created with the same template and rig script)
I guess I could rename the joint for each hand, but problem soon arises when keeping track of if another character has the same suffix. But, yeah this would work. message attribute finger_A will always find the correct finger.
I was thinking of using a different approach looking for finger_A_seg_01 on the selected controller. If the controller is the parent of that finger, rotate it, but then I wouldn’t use message attributes and they are so cool.
Opinions?
Thanks again guys. Tremendous help. Very thankful for all the tricks you show about Python aswell. Keep 'em coming =)
PS.
I guess I could just aswell concatenate finger_A_01 to the selected controller, like: ‘%s|finger_A_01’ % ctrl
and act on that, but it will easily look ugly having a bunch of long paths…
ex: ‘%s|finger_A_01|finger_A_02|finger_A_03’ % ctrl[/QUOTE]
EDIT:
I put together this little code to illustrate how to find the object under the selected controller.
Is this a good idea?
Using messages to keep track of data on rigs is a really powerful approach, not sure if you’ve seen my Red9 MetaData videos but you might want to check them out, particularly the one on MetaRig as I go through this very concept with the metaData Api.
For things like storing fingers I’d say keep the names as you want them, ideally when storing poses I don’t store, or rather don’t use the node names at all. Instead I use the attr wires that network our metaRig together. Storing out per node it’s connections to a network and the network it’s a member of.
Something like this. So in this case L_Finger_Index_3 is actually stored as a connection to the L_FingerSystem via an attr ‘CTRL_Index3’, when loading I can either load / match nodes to load the data onto via this wiring, or I can use the ID index, which is the order of the connections on the networks. For fingers I use this as I know that the left and right hand systems have matching connections to their system nodes.
@Theodox
Yes, that’s the reason. To be able to act on the controller with the same command no matter how the hand is configured. Thanks.
@Mark-J
Thank you!
No, I haven’t seen those videos on metadata before, but I have now, thanks!. Looks very powerful and I guess this is just what I’m looking for. However, by the looks of it, it seems like a big undertaking to grasp or perhaps it isn’t?
The way you are using the metadata, are you utilizing maya’s message attr function? And how would that work with clashing names as I’m having issues with now =/
I can understand why maya’s message attr work that way, but to me it kinda defeats the purpose of using message attr. It shouldn’t matter what my control are named, but the hierarchy relationship and as you unaparent or rename it, it should update to reflect those changes.
Anyway, moving on.
I know I will need to rewatch your videos, but frankly this whole concept is new to me. I have followed some tutorials and written classes before, but this seems like a pretty robust system you’ve developed and I don’t really understand how you’ve begin to set it up.
For each rig, you create an obj(instance of MetaRig class) which holds all the functionality in it? So you can easily add connections and retrieve it based on your obj?
Ex : obj.get(L_finger_seg_01)
So the sole purpose of the MetaRig class is to hold data, like message attrs and act on those?
Kind of yes and no, the best thing I’d suggest is to look at the examples files in the Red9 pack. There’s a ton of help in there including macro’s to show you how to wire your setups to the systems, pretty straight forward really if you don’t want to get deep into MetaData but instead just use the API to manage how you get data back. On the surface it’s a setup that takes all the pain away from you, allowing you to just walk your rig in code. There’s examples in there showing how you can do things like:
r9Meta.L_Arm_System.L_Hand_System.getChildren()
which isn’t just walking the networks, it’s giving you back python objects which are then walking each connection… the getChildren here would get you all connected ctrl’s in the hand system. Again, have a look at the examples in there, I’ve tried to give people enough hits and I think the best way is to just play with it. There’s also a base example rig and the code that adds the systems to it, so maybe easier to follow by just looking at the code.
Finally there’s no .get in the systems, by just doing myNode.myattr it will handle all the gets and sets for you, and thos einclude message links which are treated in the same way as everything else
so:
myMeta.myMessageAttr = [‘my’,‘list’,‘of’,‘nodes’]
will actually connect the nodes to the message attr for you.
generically, if you’re just looking for a way to maintain name-independent connections between sets of objects you have two choices. you can create node connections (messages are the cheapest) or use sets, which effectively do the same but with some important differences. These days I use sets when I can, for the following reasons:
Sets can be hierarchical. For example, you could group 3 joints as a finger, and 5 finger sets into a hand. Hierarchical sets work as a unit too - so if you want to grab all the objects in the hand, select(hand_set) gets them all. Many commands will work with sets as an argument: xform -t 0 1 0 hand_set will move all the stuff in the hand at once… though in this case it would move them all to the same point, probably not what you really want
sets live in the outliner so you can inspect them without running code - nice for making sure the data looks like you think
sets are nodes, so they can have special attributes - for example, I commonly make rig sets with two attributes: one which is a list of strings defining roles that the set contains ( for example in an IK arm set I might have roles for ‘shoulder’, ‘hand’, and ‘IKHandle’) Each role also exists as a named message connection from the set member - so I add ‘.Shoulder’ to the set, and message connect the shoulder to it. If I want the whole arm, I use the set; if I want the shoulder I query the .shoulder attrib like you’r doing. BTW, that’s not a bad way to handle the finger naming issues.
sets can contain attributes and components, as well as nodes, so you can keep a list of stuff that needs to be keyed together or the like as a set
Sets can be made mutually exclusive using partitions, which can help you ensure that stuff does not get accidentally added to to many sets
Yes, using sets to store messages and attributes and information are a great way to do it, Steve covers the main points that make them great for that, the good and bad problem with sets is that you can see them and mess with them in the outliner…most of the time though people will leave them alone.
the irritating bit is the fact that you don’t call sets on the set, you call it on on objects with the set as and argument : in the example I gave, you add objects to a set by calling sets (target… target, add=my_set). Same thing for 'is this a member of that set, which would be cmds.sets(object, isMember = my_set). It’s not a functional limitation, it just strikes me as backward syntax
As for hiding sets, brads right. I encourage people to filter their outliners for just transforms for this reason, but that’s not always possible