The other day I ran into a seemingly simple problem. I was trying to add a new blendshape to my rig but for some reason I wasn't able to get some verts to behave properly. To make a long story short, I wrote this:
(Shelf Button)
If you're like me and ever ran into this issue, you might have noticed that Maya's input window doesn't always solve the problem like you might expect. This tool is meant to provide an alternative.
At the moment I'm still testing things out with just about every
rig I can find to see if I run across any bugs. Currently the only deformers this tool supports are tweaks, blendshapes, and skinClusters (since that's all I needed at the time) but I plan on adding more features if it makes creating blendshapes and reordering deformers overall, easier.
If anyone's interested in looking at the code or using the tool yourself, below is the script written in Python. To throw this thing on your shelf you can use the following three lines. Let me know if this tool becomes of use to anyone and any comments or suggestions would be great too!
Download the script here:
http://bit.ly/1I315zV
Download the script here:
http://bit.ly/1I315zV
# =====================================
# Force Deformation Order - BETA v.1.0
# =====================================
import maya.cmds as mc
# ==============
# Window
# ==============
# If window already exists, it will be replaced by new window
FDOName = "forceDOrder_UI"
if mc.window("forceDOrder_UI", exists=True):
mc.deleteUI("forceDOrder_UI", window=True)
def FDO_UI():
# QuiCam UI
FDOWin = mc.window(FDOName, title="Force Deformation Order", menuBar=True)
parentLayout = mc.columnLayout(adj=True)
instructionMenu = mc.menu(label="Instructions")
mc.menuItem(label="Open Instruction Window", parent=instructionMenu, command="forceDeformationOrder.instructionsWindow()")
mc.setParent("..")
mc.separator(parent=parentLayout, height=10, style="in")
mc.button(parent=parentLayout, label="Load List", width=100, height=30, command="forceDeformationOrder.loadList()")
mc.separator(parent=parentLayout, height=10, style="in")
childLayout = mc.rowLayout(parent=parentLayout, numberOfColumns=2, adjustableColumn=True)
mc.textScrollList("textBox")
mc.columnLayout(parent=childLayout, adj=True)
mc.button(label="Move Up", width=100, height=40, command="forceDeformationOrder.moveUp()")
mc.button(label="Move Down", width=100, height=40, command="forceDeformationOrder.moveDown()")
mc.columnLayout(parent=parentLayout, adj=True)
mc.separator(height=10, style="in")
mc.button(label="Remove All", width=100, height=30, command="forceDeformationOrder.removeAllList()")
mc.separator(height=10, style="in")
mc.separator(height=10, style="in")
mc.button(label="Force Deformation Order", width=100, height=30, backgroundColor=[1, 0.2, 0.2], command="forceDeformationOrder.forceOrder()")
mc.showWindow(FDOWin)
# Instructions Window
def instructionsWindow():
# If window already exists, it will be replaced by new window
instructionsName = "instructWin_UI"
if mc.window("instructWin_UI", exists=True):
mc.deleteUI("instructWin_UI", window=True)
# Instructions
instructionsWin = mc.window(instructionsName, title=" FDO - Instructions")
mc.columnLayout(adj=True, width=500)
mc.text(wordWrap=True, al="center", label="1.) Select one piece of geometry to rearrange your object's deformation order.")
mc.text(wordWrap=True, al="center", label="2.) When you have made your selection, load your list and specify the order of your inputs.")
mc.text(wordWrap=True, al="center", label="3.) Once you are satisfied with the order of your list, click 'Force Deformation Order'.")
mc.text(wordWrap=True, al="center", font="boldLabelFont", label="Note: Make sure your geometry is selected before running any commands.")
mc.separator(height=10, style="in")
mc.separator(height=10, style="in")
mc.text(wordWrap=True, al="center", font="boldLabelFont", backgroundColor=[0.8, 0.35, 0.35], label="Suggestions or Comments - http://b-animated.blogspot.com/")
mc.showWindow(instructionsWin)
# ==========
# Commands
# ==========
# Load List
def loadList():
# Store geo variable for selection...
selectedGeo = mc.ls(sl=True)
# Query geometry - obtain deformer inputs
queryGeo = mc.deformer(query=True, geometry=True)
for i in queryGeo:
geoShape = i
listDeforms = mc.listSets(type=2, object=geoShape)
mc.select(listDeforms, replace=True, noExpand=True) # needs 'noExpand' for sets
masterList = []
# Check for "skinCluster" nodes...
for everySkin in listDeforms:
listConnects = mc.listConnections(everySkin, type="skinCluster")
masterList.append(listConnects)
# Check for "blendShape" nodes...
for everyBS in listDeforms:
listConnects = mc.listConnections(everyBS, type="blendShape")
masterList.append(listConnects)
# Check for "tweak" nodes...
for everyTweak in listDeforms:
listConnects = mc.listConnections(everyTweak, type="tweak")
masterList.append(listConnects)
# Delete "None" objects..
for everyNone in masterList:
masterList.remove(None) # ... run twice to make sure
masterList.remove(None)
# Add to list
mc.textScrollList("textBox", query=True, allItems=True)
for everyInput in masterList:
mc.textScrollList("textBox", edit=True, append=everyInput)
listCount = len(masterList)
mc.select(selectedGeo, replace=True) # select geo before spitting warning
mc.warning(listCount, " Deformer(s) Added To List.")
# Remove all from list
def removeAllList():
mc.textScrollList("textBox", query=True, allItems=True)
mc.textScrollList("textBox", edit=True, removeAll=True)
mc.warning("All Items Removed From List.")
# List Control
def moveUp():
# Set up index to move item up
currentIndex = mc.textScrollList("textBox", query=True, selectIndexedItem=True) # current index
selInt = currentIndex.pop() - 1 # pop 'list' out of brackets - now 'int'
# Set up string to specify which item to move up
selStr = mc.textScrollList("textBox", query=True, selectItem=True) # shape node for selected item
moveItem = [selInt] + selStr # new list
# Move item up
mc.textScrollList("textBox", edit=True, appendPosition=moveItem) # ...requires one integer value and one string
# Delete selected item to aviod duplicates
removeDup = mc.textScrollList("textBox", query=True, selectIndexedItem=True) # produce index
mc.textScrollList("textBox", edit=True, removeIndexedItem=removeDup) # remove duplicate from list
mc.textScrollList("textBox", edit=True, selectIndexedItem=selInt) # select new list item
def moveDown():
# Set up index to move item up
currentIndex = mc.textScrollList("textBox", query=True, selectIndexedItem=True) # current index
selInt = currentIndex.pop() + 2 # pop 'list' out of brackets - now 'int'
# Set up string to specify which item to move up
selStr = mc.textScrollList("textBox", query=True, selectItem=True) # shape node for selected item
moveItem = [selInt] + selStr # new list
# Move item up
mc.textScrollList("textBox", edit=True, appendPosition=moveItem) # ...requires one integer value and one string
# Delete selected item to aviod duplicates
removeDup = mc.textScrollList("textBox", query=True, selectIndexedItem=True) # produce index
mc.textScrollList("textBox", edit=True, removeIndexedItem=removeDup) # remove duplicate from list
mc.textScrollList("textBox", edit=True, selectIndexedItem=selInt -1) # select new list item
# Force order based on list
def forceOrder():
# Store geo variable for selection...
selectedGeo = mc.ls(sl=True, long=True) # GEO (long name)
# Compare new list to old defomation order
listShapes = mc.textScrollList("textBox", query=True, allItems=True) # LIST
# Convert shape nodes to transform nodes
listAll = [] # empty list
for everyItem in listShapes:
wrapQuotes = everyItem.__str__() # wrap in quotes
listAll.append(wrapQuotes) # toss everything into empty list
# Slice itemsi in 'listAll' so we are only dealing with two items at a time (needed for reorderDeformers)
splitTwo = -2 # set to -2 to set up sliceCount
for i in listAll:
splitTwo += 1 # add 1 for every iteration
sliceCount = listAll.__getslice__(splitTwo, splitTwo +2) # slice tuple
sliceTotal = len(sliceCount) # gather length
if sliceTotal == 2: # if there are 2 values returned... move forward
RDList = sliceCount.__getslice__(0,2) # isolate deformer's list - shape nodes
RDFinals = RDList[0], RDList[1], selectedGeo[0].__str__() # convert...
# *** For every tuple, run reorderDeformers command ***
RDMaster = map(str, RDFinals) # covert type tuple to list...
mc.reorderDeformers(RDMaster[0], RDMaster[1], RDMaster[2]) # * REORDER DEFORMERS *
# three values (Dform1, Dform2, geo affected) - Dform2 placed over 1
# Once order has been changed, we'll reselect geo to refresh input list
mc.select(clear=True)
mc.select(selectedGeo, replace=True)
mc.warning("Deformation Order has been rearranged.") # final warning
# Script by Bryan Godoy
# http://b-animated.blogspot.com/
# https://twitter.com/b_animates
No comments:
Post a Comment