Skip to content

Instantly share code, notes, and snippets.

@Onefabis
Last active July 27, 2016 15:11
Show Gist options
  • Save Onefabis/56b87796f02d0ac3f059ad80bccb3202 to your computer and use it in GitHub Desktop.
Save Onefabis/56b87796f02d0ac3f059ad80bccb3202 to your computer and use it in GitHub Desktop.
Allows to tweak skin weights more precise in Maya.
import maya.cmds as mc
from functools import partial
class skinTweakTool( object ):
def __init__( self ):
global stInfluenceObjects
try:
stInfluenceObjects
except:
stInfluenceObjects = None
def skinTweakUI( self ):
global stClustrName
global skinTweakTree
global filterName
global filterField
try:
filterName
except:
filterName = None
stClustrName = None
windowName = 'SkinTweak'
windowNameDocked = 'SkinTweakDock'
if mc.window( windowName, exists=1 ):
mc.deleteUI( windowName )
if mc.dockControl( windowNameDocked, ex=1 ):
mc.deleteUI( windowNameDocked )
# Dock initial data
if mc.optionVar( ex=( 'STDockState' ) ):
floatState = mc.optionVar( q='STDockState' )
else:
mc.optionVar( iv=( 'STDockState', 0 ) )
floatState = 0
if mc.optionVar( ex=( 'STDockArea' ) ):
dockArea = mc.optionVar( q='STDockArea' )
else:
mc.optionVar( sv=( 'STDockArea', 'left' ) )
dockArea='left'
# Create window and dock
self.STMainWindow = mc.window( windowName )
# Create main layout, control layout and main tree
self.mainLayout = mc.formLayout( p=self.STMainWindow )
skinTweakTree = mc.treeView( w=100, numberOfButtons=1, p=self.mainLayout )
self.controllLayout = mc.formLayout( p=self.mainLayout, w=150 )
# Create filter and arrange section
filterField = mc.textField( ec=lambda *args: self.skinTweakInfluence(), cc=lambda *args: self.skinTweakInfluence(), p=self.mainLayout )
if filterName:
mc.textField( filterField, e=1, tx=filterName )
mc.popupMenu( p=filterField )
mc.menuItem( l='Clear', c=lambda *args: self.clearFilterName() )
self.sTradioSortCollection = mc.radioCollection( p=self.mainLayout )
self.alphabetRB = mc.radioButton( label='Alphabetically', cl=self.sTradioSortCollection, onc=partial(self.controllerChanged,'sort'), p=self.mainLayout )
self.hiRB = mc.radioButton( label='By Hierarchy', cl=self.sTradioSortCollection, onc=partial(self.controllerChanged,'sort'), p=self.mainLayout )
# Query which sort order radio to select
if mc.optionVar( ex='STSort'):
radioSelected = mc.optionVar( q='STSort')
if radioSelected == 1:
mc.radioButton( self.alphabetRB, e=1, sl=1 )
elif radioSelected == 2:
mc.radioButton( self.hiRB, e=1, sl=1 )
else:
mc.optionVar( iv=('STSort',2) )
mc.radioButton( self.hiRB, e=1, sl=1 )
# Create skin controllers
# Operation controller set
self.operationLable = mc.text( l='Operation', p=self.controllLayout )
self.sTradioOpCollection = mc.radioCollection( p=self.controllLayout )
self.replaceRB = mc.radioButton( label='Replace', cl=self.sTradioOpCollection, onc=partial(self.controllerChanged,'operation'), p=self.controllLayout )
self.blendRB = mc.radioButton( label='Blend', cl=self.sTradioOpCollection, onc=partial(self.controllerChanged,'operation'), p=self.controllLayout )
# Query which operation controller radio to select
if mc.optionVar( ex='STOption'):
radioSelected = mc.optionVar( q='STOption')
if radioSelected == 1:
mc.radioButton( self.replaceRB, e=1, sl=1 )
elif radioSelected == 2:
mc.radioButton( self.blendRB, e=1, sl=1 )
else:
mc.optionVar( iv=('STOption',1) )
mc.radioButton( self.replaceRB, e=1, sl=1 )
# Normalize weights controller block
self.normalizeLable = mc.text( l='Normalize', p=self.controllLayout )
self.sTnormalizeOM = mc.optionMenu( p=self.controllLayout, cc=partial( self.controllerChanged, 'normalize' ) )
mc.menuItem( l='Off' )
mc.menuItem( l='On' )
# Query which normalize to select
if mc.optionVar( ex='STNormalize'):
normalizeSelected = mc.optionVar( q='STNormalize')
mc.optionMenu( self.sTnormalizeOM, e=1, sl=normalizeSelected )
else:
mc.optionVar( iv=('STNormalize',1) )
mc.optionMenu( self.sTnormalizeOM, e=1, sl=2 )
# Adjust weights controller block
# Slider block
self.adjustSlider = mc.floatSlider( min=0, max=1.0, s=0.1, value=0, dc=partial( self.skinChangeValue, 'slider', 0 ), cc=partial( self.skinChangeValue, 'slider', 1 ), p=self.controllLayout )
self.sTadjustField = mc.textField( tx=0, w=32, h=24, ec=partial( self.skinChangeValue, 'field', None ), p=self.controllLayout )
mc.popupMenu()
for x in xrange( 0, 110, 10 ):
mc.menuItem( l=x / 100.0, c=partial( self.skinChangeValue, 'menu', x / 100.0 ) )
self.adjustLable = mc.text( l='Adjust', p=self.controllLayout )
self.increaseVal = mc.iconTextButton( st='iconOnly', i1='arrowUp.png', bgc=(0.2,0.2,0.2), w=20, h=10, c=partial( self.changeStep, 'button', 1, 1 ), p=self.controllLayout )
self.dereaseVal = mc.iconTextButton( st='iconOnly', i1='arrowDown.png', bgc=(0.2,0.2,0.2), w=20, h=10, c=partial( self.changeStep, 'button', -1, 1 ), p=self.controllLayout )
self.ststepField = mc.textField( w=32, h=24, ec=partial( self.changeStep, 'field' ), p=self.controllLayout )
mc.popupMenu()
for x in xrange( 0, 110, 10 ):
mc.menuItem( l=x / 100.0, c=partial( self.changeStep, 'menu', x / 100.0 ) )
# Query which step to set
if mc.optionVar( ex='STStep'):
stepValue = mc.optionVar( q='STStep')
mc.textField( self.ststepField, e=1, tx=stepValue )
else:
mc.optionVar( fv=('STStep', 0) )
mc.textField( self.ststepField, e=1, tx=0 )
self.increaseWeight = mc.iconTextButton( st='iconOnly', i1='nudgeRight.png', bgc=(0.2,0.2,0.2), w=30, h=22, c=partial( self.skinChangeValue, 'button', 1, 1 ), p=self.controllLayout )
self.dereaseWeight = mc.iconTextButton( st='iconOnly', i1='nudgeLeft.png', bgc=(0.2,0.2,0.2), w=30, h=22, c=partial( self.skinChangeValue, 'button', -1, 1 ), p=self.controllLayout )
# Layout main components
mc.formLayout( self.mainLayout, e=1, af=[ ( filterField, 'top', 6 ), ( filterField, 'left', 1 ) ] )
mc.formLayout( self.mainLayout, e=1, ac=( filterField, 'right', 0, self.controllLayout ) )
mc.formLayout( self.mainLayout, e=1, ac=( self.alphabetRB, 'top', 3, filterField ) )
mc.formLayout( self.mainLayout, e=1, af=( self.alphabetRB, 'left', 2 ) )
mc.formLayout( self.mainLayout, e=1, ac=( self.hiRB, 'top', 3, filterField ) )
mc.formLayout( self.mainLayout, e=1, ac=( self.hiRB, 'left', 2, self.alphabetRB ) )
mc.formLayout( self.mainLayout, e=1, ac=( skinTweakTree, 'top', 4, self.alphabetRB ) )
mc.formLayout( self.mainLayout, e=1, af=[ ( skinTweakTree, 'left', 2), ( skinTweakTree, 'bottom', 2) ] )
mc.formLayout( self.mainLayout, e=1, ac=( skinTweakTree, 'right', 0, self.controllLayout ) )
mc.formLayout( self.mainLayout, e=1, af=[ ( self.controllLayout, 'top', 2 ), ( self.controllLayout,'right', 2 ), ( self.controllLayout,'bottom', 2 ) ] )
# Layout all controllers
mc.formLayout( self.controllLayout, e=1, af=( self.operationLable, 'top', 7 ) )
mc.formLayout( self.controllLayout, e=1, af=( self.operationLable, 'left', 9 ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.replaceRB, 'top', 7, self.operationLable ) )
mc.formLayout( self.controllLayout, e=1, af=( self.replaceRB, 'left', 9 ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.blendRB, 'top', 7, self.operationLable ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.blendRB, 'left', 9, self.replaceRB ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.normalizeLable, 'top', 11, self.blendRB ) )
mc.formLayout( self.controllLayout, e=1, af=( self.normalizeLable, 'left', 9 ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.sTnormalizeOM, 'top', 7, self.normalizeLable ) )
mc.formLayout( self.controllLayout, e=1, af=( self.sTnormalizeOM, 'left', 9 ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.adjustLable, 'top', 11, self.sTnormalizeOM ) )
mc.formLayout( self.controllLayout, e=1, af=( self.adjustLable, 'left', 9 ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.sTadjustField, 'top', 7, self.adjustLable ) )
mc.formLayout( self.controllLayout, e=1, af=( self.sTadjustField, 'left', 9 ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.adjustSlider, 'top', 12, self.adjustLable ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.adjustSlider, 'left', 5, self.sTadjustField ) )
mc.formLayout( self.controllLayout, e=1, af=( self.adjustSlider, 'right', 5 ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.increaseVal, 'top', 11, self.adjustSlider ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.increaseVal, 'left', 2, self.ststepField ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.dereaseVal, 'top', 2, self.increaseVal ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.dereaseVal, 'left', 2, self.ststepField ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.ststepField, 'top', 10, self.adjustSlider ) )
mc.formLayout( self.controllLayout, e=1, af=( self.ststepField, 'left', 9 ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.increaseWeight, 'top', 11, self.adjustSlider ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.increaseWeight, 'left', 5, self.dereaseWeight ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.dereaseWeight, 'top', 11, self.adjustSlider ) )
mc.formLayout( self.controllLayout, e=1, ac=( self.dereaseWeight, 'left', 5, self.increaseVal ) )
# Create the dock
self.skinTweakDock = mc.dockControl( windowNameDocked, area=dockArea, w=350, fl=floatState, content=self.STMainWindow, fcc=partial( self.changeDockState ), l=windowNameDocked, aa=('left', 'right' ) )
self.skinTweakInfluence()
global jobSTId
try:
jobSTId
except:
jobSTId = []
if jobSTId:
pass
else:
jobSTId = mc.scriptJob( e=['SelectionChanged', 'skinTweakTool.skinTweakTool().skinTweakInfluence()'] )
def skinTweakTreeFunc( self, parent, parentname ):
global stInfluenceObjects
# list all the children of the parent node
children = mc.listRelatives(parent, children=1, path=1) or []
# loop over the children
for child in children:
# childname is the string after the last '|'
childname = child.rsplit('|')[-1]
# print parentname, childname
if mc.ls( childname, typ='joint' ) and childname in stInfluenceObjects:
# create the leaf in the treeView, named childname, parent parentname
mc.treeView(skinTweakTree, e=1, addItem=( childname, parent ) )
mc.treeView(skinTweakTree, e=1, bti=( childname, 1, '' ), pc=(1, partial( self.skinTweakLockToggle) ) )
lockState = mc.getAttr( childname + '.liw' )
if lockState == 0:
mc.treeView(skinTweakTree, e=1, i=( childname, 1, 'Lock_OFF_grey.png' ) )
else:
mc.treeView(skinTweakTree, e=1, i=( childname, 1, 'Lock_ON.png' ) )
# call this function again, with child as the parent. recursion!
self.skinTweakTreeFunc( child, childname )
def skinTweakInfluence( self ):
global stClustrName
global stInfluenceObjects
global skinTweakTree
global filterName
global filterField
try:
stClustrName
except:
stClustrName = None
# find the selected object
sel = mc.ls( sl=1 )
selComponents = mc.ls( sl=1, typ='float3' )
selMesh = mc.ls( sl=1, typ='transform' )
clusterName = None
radioSortSelected = mc.optionVar( q='STSort')
try:
self.radioSortCheck
except:
self.radioSortCheck = 2
try:
self.filterNameCheck
except:
self.filterNameCheck = None
if sel:
allparents = []
if selComponents:
compList = mc.polyListComponentConversion( selComponents, tv=1 )
objectsSkinned = set( mc.listRelatives( compList, f=1, p=1 ) )
skinnedObjectName = list( objectsSkinned )[0]
checkClusterName = mc.listConnections( list( objectsSkinned )[0], t='skinCluster' )
if checkClusterName:
clusterName = checkClusterName[0]
# print clusterName
elif selMesh:
shapeName = mc.listRelatives( selMesh[0], f=1, s=1 )
if shapeName:
for s in shapeName:
checkClusterName = mc.listConnections( s, d=1, t='skinCluster' )
if checkClusterName:
clusterName = checkClusterName[0]
skinnedObjectName = s
# Query the filter text field
filterName = mc.textField( filterField, q=1, tx=1 )
if stClustrName != clusterName or self.radioSortCheck != radioSortSelected or filterName != self.filterNameCheck:
stClustrName = clusterName
self.radioSortCheck = radioSortSelected
self.filterNameCheck = filterName
if clusterName is not None:
stInfluenceObjects = mc.skinCluster( skinnedObjectName, q=1, inf=1 )
longInflPt = mc.ls( stInfluenceObjects, l=1 )
for l in longInflPt:
allparents.append( l.split('|')[1] )
if filterName:
tempInfuences = []
if len( filterName )>1 and filterName[0] == '*' and filterName[-1] != '*':
for s in stInfluenceObjects:
if s.endswith( filterName[1:] ):
tempInfuences.append( s )
stInfluenceObjects = tempInfuences
elif len( filterName )>1 and filterName[ -1 ] == '*' and filterName[0] != '*':
for s in stInfluenceObjects:
if s.startswith( filterName[:-1] ):
tempInfuences.append( s )
stInfluenceObjects = tempInfuences
elif len( filterName )>1 and filterName[-1] == '*' and filterName[0] == '*':
for s in stInfluenceObjects:
if filterName[1:-1] in s:
tempInfuences.append( s )
stInfluenceObjects = tempInfuences
elif len( filterName )==1 and filterName == '*':
pass
else:
for s in stInfluenceObjects:
if s == filterName:
tempInfuences.append( s )
stInfluenceObjects = tempInfuences
mc.treeView( skinTweakTree, e=1, ra=1 )
if radioSortSelected == 2:
for a in list( set( allparents ) ):
if mc.ls( a, typ='joint' ) and a in stInfluenceObjects:
# create the root node in the treeView
mc.treeView( skinTweakTree, e=1, addItem=(a, ''), hideButtons=False )
mc.treeView( skinTweakTree, e=1, bti=( a, 1, '' ), pc=(1, partial( self.skinTweakLockToggle) ) )
lockState = mc.getAttr( a + '.liw' )
if lockState == 0:
mc.treeView( skinTweakTree, e=1, i=( a, 1, 'Lock_OFF_grey.png' ) )
else:
mc.treeView( skinTweakTree, e=1, i=( a, 1, 'Lock_ON.png' ) )
# enter the recursive function
self.skinTweakTreeFunc( a, '' )
elif radioSortSelected == 1:
for a in list( sorted( set( stInfluenceObjects ) ) ):
if mc.ls( a, typ='joint' ):
mc.treeView( skinTweakTree, e=1, addItem=(a, ''), hideButtons=False )
mc.treeView( skinTweakTree, e=1, bti=( a, 1, '' ), pc=(1, partial( self.skinTweakLockToggle) ) )
lockState = mc.getAttr( a + '.liw' )
if lockState == 0:
mc.treeView( skinTweakTree, e=1, i=( a, 1, 'Lock_OFF_grey.png' ) )
else:
mc.treeView( skinTweakTree, e=1, i=( a, 1, 'Lock_ON.png' ) )
def skinTweakLockToggle( self, buttonName, part ):
global skinTweakTree
attrState = mc.getAttr( buttonName + '.liw' )
if attrState == 1:
mc.setAttr( buttonName + '.liw', 0 )
mc.treeView(skinTweakTree, e=1, i=( buttonName, 1, 'Lock_OFF_grey.png' ) )
else:
mc.setAttr( buttonName + '.liw', 1 )
mc.treeView(skinTweakTree, e=1, i=( buttonName, 1, 'Lock_ON.png' ) )
def changeDockState( self ):
floatState = mc.dockControl( self.skinTweakDock, q=1, fl=1 )
areaState = mc.dockControl( self.skinTweakDock, q=1, area=1 )
mc.optionVar( iv=('STDockState', floatState ) )
mc.optionVar( sv=('STDockArea', areaState ) )
def controllerChanged( self, name, part ):
if name == 'operation':
selOpRadio = mc.radioCollection( self.sTradioOpCollection, q=1, sl=1 )
radioLabel = mc.radioButton(selOpRadio, q=1, l=1 )
if radioLabel == 'Replace':
mc.optionVar( iv=( 'STOption', 1 ) )
elif radioLabel == 'Blend':
mc.optionVar( iv=( 'STOption', 2 ) )
elif name == 'normalize':
normalizeMenu = mc.optionMenu( self.sTnormalizeOM, q=1, sl=1 )
mc.optionVar( iv=( 'STNormalize', normalizeMenu ) )
elif name == 'sort':
selSortRadio = mc.radioCollection( self.sTradioSortCollection, q=1, sl=1 )
radioLabel = mc.radioButton(selSortRadio, q=1, l=1 )
if radioLabel == 'Alphabetically':
mc.optionVar( iv=( 'STSort', 1 ) )
elif radioLabel == 'By Hierarchy':
mc.optionVar( iv=( 'STSort', 2 ) )
self.skinTweakInfluence()
def skinChangeValue( self, mode, val, part ):
global stInfluenceObjects
global stClustrName
global skinTweakTree
try:
self.historyState
except:
self.historyState = -1
skinValue = None
shanceState = None
if mode == 'slider':
sliderValue = mc.floatSlider( self.adjustSlider, q=1, value=1 )
mc.textField( self.sTadjustField, e=1, tx=round( sliderValue, 2 ) )
skinValue = sliderValue
shanceState = 0
if val == 1:
self.historyState = -1
elif val == 0:
if self.historyState == -1:
self.historyState = 1
else:
self.historyState = 0
# print val, self.historyState
elif mode == 'field':
self.historyState = 1
skinValue = mc.textField( self.sTadjustField, q=1, tx=val )
elif mode == 'menu':
self.historyState = 1
mc.textField( self.sTadjustField, e=1, tx=val )
mc.floatSlider( self.adjustSlider, e=1, value=val )
skinValue = val
shanceState = 0
elif mode == 'button':
self.historyState = 1
skinValue = mc.textField( self.ststepField, q=1, tx=1 )
if val == 1:
skinValue = mc.textField( self.ststepField, q=1, tx=1 )
elif val == -1:
skinValue = float( mc.textField( self.ststepField, q=1, tx=1 ) ) * -1
shanceState = 1
normalize = mc.optionMenu( self.sTnormalizeOM, q=1, sl=1 )
selectedItems = []
if stInfluenceObjects:
for s in stInfluenceObjects:
selIremCheck = mc.treeView( skinTweakTree, q=1, isl=s )
if selIremCheck == 1:
selectedItems.append(s)
selRadio = mc.radioCollection( self.sTradioOpCollection, q=1, sl=1 )
radioLabel = mc.radioButton(selRadio, q=1, l=1 )
selComponents = mc.ls( sl=1, typ='float3')
if selectedItems and selComponents:
if self.historyState == 0 or self.historyState == -1:
mc.undoInfo( stateWithoutFlush=0 )
if radioLabel == 'Replace':
for j in selectedItems:
mc.skinPercent( stClustrName, selComponents, nrm=normalize, r=shanceState, tv=[ ( j, float(skinValue) ) ] )
elif radioLabel == 'Blend' and len( selectedItems ) == 2:
if shanceState == 0:
mc.skinPercent( stClustrName, selComponents, nrm=normalize, r=shanceState, tv=[ ( selectedItems[0], float(skinValue) ), (selectedItems[1], 1 - float(skinValue) ) ] )
elif shanceState == 1:
mc.skinPercent( stClustrName, selComponents, nrm=normalize, r=shanceState, tv=[ ( selectedItems[0], float(skinValue) ), (selectedItems[1], float(skinValue) * -1 ) ] )
if self.historyState == 0 or self.historyState == -1:
mc.undoInfo( stateWithoutFlush=1 )
def changeStep( self, controller, val, part ):
if controller == 'menu':
mc.textField( self.ststepField, e=1, tx=val )
mc.optionVar( fv=( 'STStep', float(val) ) )
elif controller == 'button':
mod = mc.getModifiers()
step = 0.01
if mod == 4:
step = 0.1
if val == 1:
getText = mc.textField( self.ststepField, q=1, tx=1 )
mc.textField( self.ststepField, e=1, tx=float( getText ) + step )
mc.optionVar( fv=( 'STStep', float( getText ) + step ) )
elif val == -1:
getText = mc.textField( self.ststepField, q=1, tx=1 )
mc.textField( self.ststepField, e=1, tx=float( getText ) - step )
mc.optionVar( fv=( 'STStep', float( getText ) - step ) )
elif controller == 'field':
stepValue = mc.textField( self.ststepField, q=1, tx=1 )
if float(stepValue)>0 and float(stepValue)<1:
mc.optionVar( fv=( 'STStep', float(stepValue) ) )
def clearFilterName( self ):
global filterName
global filterField
filterName = None
mc.textField( filterField, e=1, tx='' )
self.skinTweakInfluence()
def start():
skinTweakTool().skinTweakUI()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment