Update
This commit is contained in:
229
2023/scripts/rigging_tools/ngskintools2/operations/layers.py
Normal file
229
2023/scripts/rigging_tools/ngskintools2/operations/layers.py
Normal file
@@ -0,0 +1,229 @@
|
||||
import random
|
||||
|
||||
from maya import cmds
|
||||
|
||||
import ngSkinTools2.api
|
||||
from ngSkinTools2 import signal
|
||||
from ngSkinTools2.api import Mirror
|
||||
from ngSkinTools2.api.layers import generate_layer_name
|
||||
from ngSkinTools2.api.log import getLogger
|
||||
from ngSkinTools2.api.pyside import QAction, QtCore
|
||||
from ngSkinTools2.api.session import session, withSession
|
||||
from ngSkinTools2.decorators import undoable
|
||||
from ngSkinTools2.ui import dialogs, qt
|
||||
from ngSkinTools2.ui.action import Action
|
||||
from ngSkinTools2.ui.options import config
|
||||
|
||||
logger = getLogger("layer operations")
|
||||
|
||||
|
||||
@withSession
|
||||
@undoable
|
||||
def initializeLayers(createFirstLayer=True):
|
||||
if session.state.layersAvailable:
|
||||
return # ignore
|
||||
|
||||
target = session.state.selectedSkinCluster
|
||||
|
||||
layers = ngSkinTools2.api.init_layers(target)
|
||||
with ngSkinTools2.api.suspend_updates(target):
|
||||
if createFirstLayer:
|
||||
layer = layers.add("Base weights")
|
||||
layer.set_current()
|
||||
Mirror(target).set_mirror_config(config.mirrorInfluencesDefaults)
|
||||
|
||||
session.events.targetChanged.emitIfChanged()
|
||||
|
||||
if ngSkinTools2.api.is_slow_mode_skin_cluster(target):
|
||||
dialogs.info(
|
||||
"ngSkinTools switched to slow maya API for setting skin cluster weights for this skinCluster, to workaround a Maya bug when skinCluster uses dg nodes as inputs"
|
||||
)
|
||||
|
||||
|
||||
@undoable
|
||||
def addLayer():
|
||||
layers = ngSkinTools2.api.Layers(session.state.selectedSkinCluster)
|
||||
|
||||
def guessParent():
|
||||
currentLayer = layers.current_layer()
|
||||
if currentLayer is None:
|
||||
return None
|
||||
|
||||
# current layer is a parent?
|
||||
if currentLayer.num_children > 0:
|
||||
return currentLayer
|
||||
|
||||
return currentLayer.parent
|
||||
|
||||
with ngSkinTools2.api.suspend_updates(layers.mesh):
|
||||
new_layer = layers.add(generate_layer_name(session.state.all_layers, "New Layer"))
|
||||
new_layer.parent = guessParent()
|
||||
|
||||
session.events.layerListChanged.emitIfChanged()
|
||||
setCurrentLayer(new_layer)
|
||||
|
||||
return new_layer
|
||||
|
||||
|
||||
def build_action_initialize_layers(session, parent):
|
||||
from ngSkinTools2.ui import actions
|
||||
|
||||
from . import import_v1_actions
|
||||
|
||||
def do_initialize():
|
||||
if import_v1_actions.can_import(session):
|
||||
q = (
|
||||
"Skinning layers from previous version of ngSkinTools are present on this mesh. This operation will initialize "
|
||||
"skinning layers from scratch, discarding previous layers information. Do you want to continue?"
|
||||
)
|
||||
if not dialogs.yesNo(q):
|
||||
return
|
||||
|
||||
initializeLayers()
|
||||
|
||||
result = actions.define_action(parent, "Initialize Skinning Layers", callback=do_initialize)
|
||||
|
||||
@signal.on(session.events.nodeSelectionChanged)
|
||||
def update():
|
||||
result.setEnabled(session.state.selectedSkinCluster is not None)
|
||||
|
||||
update()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def buildAction_createLayer(session, parent):
|
||||
from ngSkinTools2.ui import actions
|
||||
|
||||
result = actions.define_action(parent, "Create Layer", callback=addLayer, icon=":/newLayerEmpty.png", shortcut=QtCore.Qt.Key_Insert)
|
||||
|
||||
@signal.on(session.events.targetChanged)
|
||||
def update_to_target():
|
||||
result.setEnabled(session.state.layersAvailable)
|
||||
|
||||
update_to_target()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def buildAction_deleteLayer(session, parent):
|
||||
from ngSkinTools2.ui import actions
|
||||
|
||||
result = actions.define_action(parent, "Delete Layer", callback=deleteSelectedLayers, shortcut=QtCore.Qt.Key_Delete)
|
||||
|
||||
@signal.on(session.context.selected_layers.changed, session.events.targetChanged, qtParent=parent)
|
||||
def update_to_target():
|
||||
result.setEnabled(session.state.layersAvailable and bool(session.context.selected_layers(default=[])))
|
||||
|
||||
update_to_target()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@undoable
|
||||
def setCurrentLayer(layer):
|
||||
"""
|
||||
:type layer: ngSkinTools2.api.layers.Layer
|
||||
"""
|
||||
if not session.active():
|
||||
logger.info("didn't set current layer: no session")
|
||||
|
||||
if not session.state.layersAvailable:
|
||||
logger.info("didn't set current layer: layers not enabled")
|
||||
|
||||
logger.info("setting current layer to %r on %r", layer, session.state.selectedSkinCluster)
|
||||
layer.set_current()
|
||||
session.events.currentLayerChanged.emitIfChanged()
|
||||
|
||||
|
||||
def getCurrentLayer():
|
||||
layers = ngSkinTools2.api.Layers(session.state.selectedSkinCluster)
|
||||
return layers.current_layer()
|
||||
|
||||
|
||||
@undoable
|
||||
def renameLayer(layer, newName):
|
||||
layer.name = newName
|
||||
cmds.evalDeferred(session.events.layerListChanged.emitIfChanged)
|
||||
|
||||
|
||||
@undoable
|
||||
def deleteSelectedLayers():
|
||||
layers = ngSkinTools2.api.Layers(session.state.selectedSkinCluster)
|
||||
for i in session.context.selected_layers(default=[]):
|
||||
layers.delete(i)
|
||||
|
||||
session.events.layerListChanged.emitIfChanged()
|
||||
session.events.currentLayerChanged.emitIfChanged()
|
||||
|
||||
|
||||
class ToggleEnabledAction(Action):
|
||||
name = "Enabled"
|
||||
checkable = True
|
||||
|
||||
def __init__(self, session):
|
||||
Action.__init__(self, session)
|
||||
|
||||
def checked(self):
|
||||
"""
|
||||
return true if most of selected layers are enabled
|
||||
:return:
|
||||
"""
|
||||
layers = session.context.selected_layers(default=[])
|
||||
if not layers:
|
||||
return True
|
||||
|
||||
enabled_disabled_balance = 0
|
||||
for layer in layers:
|
||||
try:
|
||||
# eat up the exception if layer id is invalid
|
||||
enabled_disabled_balance += 1 if layer.enabled else -1
|
||||
except:
|
||||
pass
|
||||
|
||||
return enabled_disabled_balance >= 0
|
||||
|
||||
def run(self):
|
||||
enabled = not self.checked()
|
||||
selected_layers = session.context.selected_layers()
|
||||
if not selected_layers:
|
||||
return
|
||||
|
||||
for i in selected_layers:
|
||||
i.enabled = enabled
|
||||
|
||||
logger.info("layers toggled: %r", selected_layers)
|
||||
|
||||
session.events.layerListChanged.emitIfChanged()
|
||||
|
||||
def enabled(self):
|
||||
return session.state.layersAvailable and bool(session.context.selected_layers(default=[]))
|
||||
|
||||
def update_on_signals(self):
|
||||
return [session.context.selected_layers.changed, session.events.layerListChanged, session.events.targetChanged]
|
||||
|
||||
|
||||
def build_action_randomize_influences_colors(session, parent):
|
||||
"""
|
||||
builds a UI action for randomly choosing new colors for influences
|
||||
:type session: ngSkinTools2.api.session.Session
|
||||
"""
|
||||
|
||||
result = QAction("Randomize colors", parent)
|
||||
result.setToolTip("Choose random colors for each influence, selecting from Maya's pallete of indexed colors")
|
||||
|
||||
def color_filter(c):
|
||||
brightness = c[0] * c[0] + c[1] * c[1] + c[2] * c[2]
|
||||
return brightness > 0.001 and brightness < 0.99 # just a fancy way to skip white and black
|
||||
|
||||
colors = set([tuple(cmds.colorIndex(i, q=True)) for i in range(1, 30)])
|
||||
colors = [c for c in colors if color_filter(c)]
|
||||
|
||||
@qt.on(result.triggered)
|
||||
def triggered():
|
||||
if session.state.selectedSkinCluster is None:
|
||||
return
|
||||
layers = ngSkinTools2.api.Layers(session.state.selectedSkinCluster)
|
||||
layers.config.influence_colors = {i.logicalIndex: random.choice(colors) for i in layers.list_influences()}
|
||||
|
||||
return result
|
||||
Reference in New Issue
Block a user