Tidy way to key selected translates & rotates of joints in Python / MEL

Tidy way to key selected translates & rotates of joints in Python / MEL

rafGCQG8
Contributor Contributor
1,363 Views
5 Replies
Message 1 of 6

Tidy way to key selected translates & rotates of joints in Python / MEL

rafGCQG8
Contributor
Contributor

Hi there,

 

I'm working on a python plugin for Maya and have recently stumbled in automating this particular function. Used when working with a mesh with multiple joints the normal (manual) flow is to shift select all bones, and then in the channel box select translate X, Y, Z & rotate X, Y, Z and right click -> Key selected. I do this across multiple keyframes.

 

Screenshot_2.png 

 

There feels like lots of room for optimisation in this manual part so I've wanted to automate it in Python, but looking at the MEL that runs when the user does this manually it looks very bulky. (below is an example from the script editor)

 

image_2023-01-05_155949646.png

 

As you can see I'd have to run this for every joint but also for each type of joint, so those in the image are the rotate Z's but there are the other rotates & translates as well. 

 

I'm able to get and select all joints in Python but using a for loop I'm not sure how to distinguish between each type required to be get and set (.tx .ty .tz .rx .ry .rz). Any help on how to proceed would be greatly appreciated, thank you.

 

 

joint_t_r = [tx, ty, tz, rx, ry, rz]

for each keyframe
  for each joint 
    for each in joint_t_r
      select each, key joint

 

above is kind of what I'm after, I think ahah

0 Likes
Accepted solutions (1)
1,364 Views
5 Replies
Replies (5)
Message 2 of 6

Kahylan
Advisor
Advisor

Hi!

 

the setKeyframe command just keys the full selection, so you can just select all the joints at the same time and run it instead of looping through all joints. It also provides you with an attribute flag, where you can tell it which attribute you want to key which also takes lists, so you also don't need to loop through the attributes in this case.

 

import maya.cmds as mc

attrs = ["tx","ty","tz","rx", "ry", "rz"]
frames = [1,5,10]
joints = mc.ls(type = "joint")
mc.select(joints)


for frame in frames:
    mc.setKeyframe(at = attrs, t = [frame,frame])

 

I'm not quite sure why you want to do this on multiple frames though, as it will just key the value that is already there, same as the "Key -> Bake Simulation" command.

 

I hope it helps!

Message 3 of 6

rafGCQG8
Contributor
Contributor

thanks so much for your response, I'm not able to get back to work on it atm but when I do I'll let you know how I got on!

regarding doing it on separate keyframes, each keyframe has a different skeleton pose on it with very different rotates / translates on joints but you're right maybe this is unnecessary, I'll have a look 🙂 

0 Likes
Message 4 of 6

rafGCQG8
Contributor
Contributor

Hey there, I implemented your solution and used it to traverse all the frames and key the translates & rotates, it worked!

However perhaps I didn't specify, the keyframes all have different translates & rotates on them ( a skeleton in various poses across each frame ). When using your solution, all frames become the same as the first frame in the list. I created a list of all frames and had it run for each frame, and afterwards they were all keyed but also all were exactly the same as keyframe 0 :(. 

Is there any further help you could provide? thank you.

0 Likes
Message 5 of 6

Kahylan
Advisor
Advisor
Accepted solution

If you want the value that is on that frame to maintain, you need to change the currentTime so Maya finds it.

You could also query the value before setting it and use the value flag, which would save you the viewport updates, but on the other hand the viewport updating will give you a sence of how far along the script is.

import maya.cmds as mc

attrs = ["tx","ty","tz","rx", "ry", "rz"]
frames = [1,5,10]
joints = mc.ls(type = "joint")
mc.select(joints)
ct = mc.currentTime(q = True)


for frame in frames:
    mc.currentTime(frame)
    
    mc.setKeyframe(at = attrs, t = [frame,frame])
    
mc.currentTime(ct)

 

I hope it helps!

Message 6 of 6

rafGCQG8
Contributor
Contributor

really helpful, thanks so much for your help on this problem!