Skip to content

Instantly share code, notes, and snippets.

@zewt
Created August 19, 2020 06:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zewt/7090ed6aa800109b8019e596280406ac to your computer and use it in GitHub Desktop.
Save zewt/7090ed6aa800109b8019e596280406ac to your computer and use it in GitHub Desktop.
Set joints to bind position
# Public domain
import pymel.core as pm
from pymel import core as pm
from maya.api import OpenMaya as om
def getSkinClusterConnection(node):
for conn in pm.listConnections(node.attr('worldMatrix'), d=True, s=False, p=True, type='skinCluster') or []:
skinCluster = conn.node()
idx = conn.index()
return skinCluster, idx
return None, None
def resetToRealBindPose(node, depth=0):
if not isinstance(node, pm.nodetypes.Joint):
return
skinCluster, idx = getSkinClusterConnection(node)
if not skinCluster:
# If a joint has no connected skinCluster, we don't have a bind matrix to reset
# to, but the position of the joint still matters. Set to the preferred angle
# instead.
angle = node.attr('preferredAngle').get()
# Try to set each axis. Ignore axes that we can't set, which is usually the "locked or connected"
# error. We don't check this first, since sometimes you can set connected attributes, eg. when a
# joint is constrained but constraint evaluation is turned off in the Modify > Evaluate menu.
# This is important, so you can disable constraint evaluation and reset to bind pose to return
# the skeleton to its exact original configuration (eg. to re-mirror weights or re-bind a new mesh).
for idx, axis in enumerate(('rx', 'ry', 'rz')):
output = node.attr(axis)
try:
output.set(angle[idx])
except RuntimeError as e:
pass
return
matrix = skinCluster.attr('bindPreMatrix[%i]' % idx).get()
matrix = om.MMatrix(matrix)
matrix = matrix.inverse()
segmentScaleCompensate = node.attr('segmentScaleCompensate').get()
pm.xform(node, m=matrix, ws=True)
# pm.xform turns segmentScaleCompensate on for some reason. Put it back.
node.attr('segmentScaleCompensate').set(segmentScaleCompensate)
# listRelatives -ad "returns grandchildren before children", which makes no sense. It
# should return in either depth first or breadth first order.
def getDescendantsDepthFirst(node, depth=1):
yield node, depth
for child in node.getChildren():
for result in getDescendantsDepthFirst(child, depth+1):
yield result
def go():
for node in pm.ls(sl=True):
for joint, depth in getDescendantsDepthFirst(node):
resetToRealBindPose(joint, depth)
go()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment