230 lines
6.9 KiB
Python
230 lines
6.9 KiB
Python
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(
|
||
"切换为设置皮肤集群权重,以解决 Maya皮肤集群使用装点作为输入时的错误。"
|
||
)
|
||
|
||
|
||
@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 = (
|
||
"来自旧版 ngSkinTools的皮肤层存在于此网格上。此操作将初始化"
|
||
"从头开始剥离图层,丢弃之前的图层信息。您要继续吗?"
|
||
)
|
||
if not dialogs.yesNo(q):
|
||
return
|
||
|
||
initializeLayers()
|
||
|
||
result = actions.define_action(parent, "初始化蒙皮层", 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, "创建图层", 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, "删除图层", 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("未设置当前图层:没有会话")
|
||
|
||
if not session.state.layersAvailable:
|
||
logger.info("未设置当前图层:图层未启用")
|
||
|
||
logger.info("将当前图层设置为 %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("图层已切换: %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("随机颜色", parent)
|
||
result.setToolTip("为每个影响选择随机颜色,从Maya的索引色板中选择。")
|
||
|
||
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
|