Skip to content

Commit

Permalink
adding copySkin
Browse files Browse the repository at this point in the history
  • Loading branch information
morganloomis committed Nov 1, 2016
1 parent 0ab3c11 commit c0c0219
Show file tree
Hide file tree
Showing 2 changed files with 212 additions and 3 deletions.
207 changes: 207 additions & 0 deletions ml_copySkin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
#
# -= ml_copySkin.py =-
# __ by Morgan Loomis
# ____ ___ / / http://morganloomis.com
# / __ `__ \/ / Licensed under Creative Commons BY-SA
# / / / / / / / http://creativecommons.org/licenses/by-sa/3.0/
# /_/ /_/ /_/_/ _________
# /_________/ Revision 1, 2016-10-31
# _______________________________
# - -/__ Installing Python Scripts __/- - - - - - - - - - - - - - - - - - - -
#
# Copy this file into your maya scripts directory, for example:
# C:/Documents and Settings/user/My Documents/maya/scripts/ml_copySkin.py
#
# Run the tool by importing the module, and then calling the primary function.
# From python, this looks like:
# import ml_copySkin
# ml_copySkin.ui()
# From MEL, this looks like:
# python("import ml_copySkin;ml_copySkin.ui()");
# _________________
# - -/__ Description __/- - - - - - - - - - - - - - - - - - - - - - - - - - -
#
# Copy a skinCluster from one mesh to another, or to a selection of vertices.
# If no skin exists on the destination, one will be created with the same influences.
# Otherwise any missing influences will be added in order to copy accurate weights.
# ___________
# - -/__ Usage __/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#
# Input a source mesh into the "Source Mesh" field by selecting a mesh and pressing the
# "Set Selected" button.
# Select destination meshes or vertices, and press the "Copy Skin" button.
# ________________
# - -/__ UI Options __/- - - - - - - - - - - - - - - - - - - - - - - - - - -
#
# [Copy Skin] : Copy the Source Skin to selection.
# __________________
# - -/__ Requirements __/- - - - - - - - - - - - - - - - - - - - - - - - - -
#
# This script requires the ml_utilities module, which can be downloaded here:
# http://morganloomis.com/wiki/tools.html#ml_utilities
# __________
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /_ Enjoy! _/- - -
__author__ = 'Morgan Loomis'
__license__ = 'Creative Commons Attribution-ShareAlike'
__category__ = 'riggingScripts'
__revision__ = 1

import maya.cmds as mc

try:
import ml_utilities as utl
utl.upToDateCheck(24)
except ImportError:
result = mc.confirmDialog( title='Module Not Found',
message='This tool requires the ml_utilities module. Once downloaded you will need to restart Maya.',
button=['Download Module','Cancel'],
defaultButton='Cancel', cancelButton='Cancel', dismissString='Cancel' )

if result == 'Download Module':
mc.showHelp('http://morganloomis.com/download/animationScripts/ml_utilities.py',absolute=True)


def ui():
'''
User interface for copy skin
'''

CopySkinUI()


class CopySkinUI(utl.MlUi):
'''Inherited from MlUi
'''

def __init__(self):

super(CopySkinUI, self).__init__('ml_copySkin', 'Copy SkinClusters', width=400, height=180,
info='''Select a skinned mesh to add to the Source Mesh field below.
Select a destination mesh, or vertices to copy the skin to.
Press the button to copy the skin weights.''')

self.buildWindow()

self.srcMeshField = self.selectionField(label='Source Mesh',
annotation='Select the mesh to be used as the source skin.',
channel=False,
text='')

mc.button(label='Copy Skin', command=self.copySkin, annotation='Copy the Source Skin to selection.')

self.finish()


def copySkin(self,*args):

sourceMesh = mc.textFieldButtonGrp(self.srcMeshField, query=True, text=True)

if not mc.objExists(sourceMesh):
raise RuntimeError('Input a source mesh into the UI to copy skin from.')

sel = mc.ls(sl=True, fl=True)

if not sel:
raise RuntimeError('Select a mesh or vertices to copy the skin to.')

meshSel = []
vtxSel = []
for each in sel:
if '.vtx[' in each:
vtxSel.append(each)
else:
meshSel.append(each)

if vtxSel:
copySkinComponents(sourceMesh, vtxSel)

if meshSel:
for each in meshSel:
copySkinCluster(sourceMesh, each)


def getSkinCluster(mesh):

shapes = mc.listRelatives(mesh, shapes=True, path=True)

for shape in shapes:
history = mc.listHistory(shape, groupLevels=True, pruneDagObjects=True)
if not history:
continue
skins = mc.ls(history, type='skinCluster')
if skins:
return skins[0]

return None


def copySkinInfluences(source, dest):

sourceSkin = getSkinCluster(source)
if not sourceSkin:
return False

joints = mc.skinCluster(sourceSkin, query=True, influence=True)

destSkin = getSkinCluster(dest)

if not destSkin:
destSkin = mc.skinCluster(joints, dest, toSelectedBones=True)[0]
else:
destJoints = mc.skinCluster(destSkin, query=True, influence=True)
for joint in [x for x in joints if x not in destJoints]:
mc.skinCluster(destSkin, edit=True, addInfluence=joint, lockWeights=False, weight=0)

return destSkin


def copySkinComponents(source, destinationVerts):

if not mc.listRelatives(source, shapes=True):
raise RuntimeError('Source object must be geometry.')

sourceSkin = getSkinCluster(source)

if not sourceSkin:
raise RuntimeError("Source mesh doesn't have a skinCluster to copy from.")

destMesh = mc.ls(destinationVerts[0], o=True)[0]
destMesh = mc.listRelatives(destMesh, parent=True)[0]
destSkin = copySkinInfluences(source, destMesh)

tempSet = mc.sets(destinationVerts)

mc.select(source, tempSet)

mc.copySkinWeights(noMirror=True,
surfaceAssociation='closestPoint',
influenceAssociation='closestJoint',
normalize=True)

mc.delete(tempSet)
mc.select(destinationVerts)


def copySkinCluster(source, destination):

sourceSkin = getSkinCluster(source)
if not sourceSkin:
raise RuntimeError("Source mesh doesn't have a skinCluster to copy from.")

destSkin = copySkinInfluences(source, destination)

mc.copySkinWeights(sourceSkin=sourceSkin, destinationSkin=destSkin, noMirror=True,
surfaceAssociation='closestPoint',
influenceAssociation='closestJoint', normalize=True)

return destSkin



if __name__ == '__main__':
ui()

# ______________________
# - -/__ Revision History __/- - - - - - - - - - - - - - - - - - - - - - - -
#
# Revision 1: 2016-10-31 : First publish.
8 changes: 5 additions & 3 deletions ml_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# / __ `__ \/ / Licensed under Creative Commons BY-SA
# / / / / / / / http://creativecommons.org/licenses/by-sa/3.0/
# /_/ /_/ /_/_/ _________
# /_________/ Revision 23, 2016-10-12
# /_________/ Revision 24, 2016-10-31
# _______________________________
# - -/__ Installing Python Scripts __/- - - - - - - - - - - - - - - - - - - -
#
Expand Down Expand Up @@ -34,7 +34,7 @@
__author__ = 'Morgan Loomis'
__license__ = 'Creative Commons Attribution-ShareAlike'
__category__ = 'animationScripts'
__revision__ = 23
__revision__ = 24

import maya.cmds as mc
import maya.mel as mm
Expand Down Expand Up @@ -83,7 +83,7 @@ def upToDateCheck(revision, prompt=True):
defaultButton='Download Latest Revision', cancelButton='Ignore', dismissString='Ignore' )

if result == 'Download Latest Revision':
mc.showHelp('http://morganloomis.com/download/animationScripts/ml_utilities.py', absolute=True)
mc.showHelp('http://mDynamicAnimUIorganloomis.com/download/animationScripts/ml_utilities.py', absolute=True)
elif result == "Don't Ask Again":
mc.optionVar(intValue=('ml_utilities_revision', revision))
return False
Expand Down Expand Up @@ -2143,3 +2143,5 @@ def __exit__(self, *args):
# Revision 22: 2016-10-01 : changing frameRange to return consistent results when returning timeline or selection.
#
# Revision 23: 2016-10-12 : Tangent bug fixes for 2016.5
#
# Revision 24: 2016-10-31 : Adding selection field to mlUI

0 comments on commit c0c0219

Please sign in to comment.