Created
May 3, 2021 17:32
-
-
Save zewt/f1082ace0532a4dc89ff3f58635c2e57 to your computer and use it in GitHub Desktop.
Freeze bound joints
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pymel.core as pm | |
from zMayaTools import maya_helpers | |
# Imported skeletons often have ugly scaling. We should be able to just turn on move skinned | |
# joints and freeze transforms, but Maya tries to be helpful and prevents us from doing this. | |
def get_descendants_depth_first(node, depth=0): | |
if not isinstance(node, pm.nodetypes.Transform): | |
return | |
yield node, depth | |
for child in node.getChildren(): | |
for result in get_descendants_depth_first(child, depth+1): | |
yield result | |
def copy_attr(src, dst, attr): | |
new_value = src.attr(attr).get() | |
old_value = dst.attr(attr).get() | |
# Don't set values if they already match. This avoids throwing errors for locked attributes | |
# that haven't changed. | |
if new_value == old_value: | |
return | |
try: | |
dst.attr(attr).set(new_value) | |
except: | |
print('Couldn\'t set %s' % dst) | |
def copy_hierarchy_transforms(to_node, from_node): | |
to_tree = list(get_descendants_depth_first(to_node)) | |
from_tree = list(get_descendants_depth_first(from_node)) | |
mapping = {} | |
# First, check that the trees match and make a mapping from source to target nodes. | |
for (to_node, depth), (from_node, unused) in zip(to_tree, from_tree): | |
# Don't match up the names for the top-level nodes, since they're usually siblings and | |
# can't have the same name. | |
if depth > 0 and to_node.nodeName() != from_node.nodeName(): | |
print('Trees don\'t match (node %s doesn\'t match node %s)' % (to_node, from_node)) | |
return | |
if to_node.__class__ != from_node.__class__: | |
print('Trees don\'t match (node %s is %s, node %s is %s)' % (to_node, to_node.__class__, from_node, from_node.__class__)) | |
mapping[to_node] = from_node | |
for to_node, unused in to_tree: | |
from_node = mapping[to_node] | |
for attr in ('t', 'r', 's', 'rotateAxis', 'rotateOrder'): | |
copy_attr(from_node, to_node, attr) | |
if isinstance(to_node, pm.nodetypes.Joint): | |
for attr in ('jointOrient', ): | |
copy_attr(from_node, to_node, attr) | |
def freeze_skinned_joint(node): | |
with maya_helpers.restores() as restores: | |
# Enable global move skinned joints mode. | |
restores.append(maya_helpers.SetAndRestoreCmd(pm.zMoveSkinnedJoints, key='enable', value=True)) | |
# Create a duplicate of the hierarchy that we can freeze transforms on. | |
node2 = pm.duplicate(node)[0] | |
# Freeze transforms on the transform, removing any scale and moving rotation into jointOrient. This | |
# will propagate changes to the children so the children don't change. | |
pm.makeIdentity(node2, apply=True, rotate=True, scale=True) | |
# Copy the resulting transforms from node2 to node. | |
copy_hierarchy_transforms(node, node2) | |
# Delete our temporary nodes. | |
pm.delete(node2) | |
freeze_skinned_joint(pm.ls(sl=True, type='transform')[0]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment