216 lines
8.0 KiB
Python
216 lines
8.0 KiB
Python
from ngSkinTools2 import signal
|
|
from ngSkinTools2.api import Mirror, MirrorOptions, VertexTransferMode
|
|
from ngSkinTools2.api.log import getLogger
|
|
from ngSkinTools2.api.mirror import set_reference_mesh_from_selection
|
|
from ngSkinTools2.api.pyside import QtWidgets
|
|
from ngSkinTools2.api.session import session
|
|
from ngSkinTools2.ui import qt
|
|
from ngSkinTools2.ui.layout import TabSetup, createTitledRow
|
|
from ngSkinTools2.ui.options import bind_checkbox, config
|
|
from ngSkinTools2.ui.widgets import NumberSliderGroup
|
|
|
|
log = getLogger("tab paint")
|
|
|
|
|
|
def build_ui(parent_window):
|
|
def build_mirroring_options_group():
|
|
def get_mirror_direction():
|
|
mirror_direction = QtWidgets.QComboBox()
|
|
mirror_direction.addItem("Guess from stroke", MirrorOptions.directionGuess)
|
|
mirror_direction.addItem("Positive to negative", MirrorOptions.directionPositiveToNegative)
|
|
mirror_direction.addItem("Negative to positive", MirrorOptions.directionNegativeToPositive)
|
|
mirror_direction.addItem("Flip", MirrorOptions.directionFlip)
|
|
mirror_direction.setMinimumWidth(1)
|
|
qt.select_data(mirror_direction, config.mirror_direction())
|
|
|
|
@qt.on(mirror_direction.currentIndexChanged)
|
|
def value_changed():
|
|
config.mirror_direction.set(mirror_direction.currentData())
|
|
|
|
return mirror_direction
|
|
|
|
def axis():
|
|
mirror_axis = QtWidgets.QComboBox()
|
|
mirror_axis.addItem("X", 'x')
|
|
mirror_axis.addItem("Y", 'y')
|
|
mirror_axis.addItem("Z", 'z')
|
|
|
|
@qt.on(mirror_axis.currentIndexChanged)
|
|
def value_changed():
|
|
session.state.mirror().axis = mirror_axis.currentData()
|
|
|
|
@signal.on(session.events.targetChanged)
|
|
def target_changed():
|
|
if session.state.layersAvailable:
|
|
qt.select_data(mirror_axis, session.state.mirror().axis)
|
|
|
|
target_changed()
|
|
|
|
return mirror_axis
|
|
|
|
def mirror_seam_width():
|
|
seam_width_ctrl = NumberSliderGroup(max_value=100)
|
|
|
|
@signal.on(seam_width_ctrl.valueChanged)
|
|
def value_changed():
|
|
session.state.mirror().seam_width = seam_width_ctrl.value()
|
|
|
|
@signal.on(session.events.targetChanged)
|
|
def update_values():
|
|
if session.state.layersAvailable:
|
|
seam_width_ctrl.set_value(session.state.mirror().seam_width)
|
|
|
|
update_values()
|
|
|
|
return seam_width_ctrl.layout()
|
|
|
|
def elements():
|
|
influences = bind_checkbox(QtWidgets.QCheckBox("Influence weights"), config.mirror_weights)
|
|
mask = bind_checkbox(QtWidgets.QCheckBox("Layer mask"), config.mirror_mask)
|
|
dq = bind_checkbox(QtWidgets.QCheckBox("Dual quaternion weights"), config.mirror_dq)
|
|
|
|
return influences, mask, dq
|
|
|
|
result = QtWidgets.QGroupBox("Mirroring options")
|
|
layout = QtWidgets.QVBoxLayout()
|
|
result.setLayout(layout)
|
|
layout.addLayout(createTitledRow("Axis:", axis()))
|
|
layout.addLayout(createTitledRow("Direction:", get_mirror_direction()))
|
|
layout.addLayout(createTitledRow("Seam width:", mirror_seam_width()))
|
|
layout.addLayout(createTitledRow("Elements to mirror:", *elements()))
|
|
|
|
return result
|
|
|
|
def vertex_mapping_group():
|
|
# noinspection PyShadowingNames
|
|
def mirror_mesh_group():
|
|
mesh_name_edit = QtWidgets.QLineEdit("mesh1")
|
|
mesh_name_edit.setReadOnly(True)
|
|
select_button = QtWidgets.QPushButton("Select")
|
|
create_button = QtWidgets.QPushButton("Create")
|
|
set_button = QtWidgets.QPushButton("Set")
|
|
set_button.setToolTip("Select symmetry mesh and a skinned target first")
|
|
|
|
layout = QtWidgets.QHBoxLayout()
|
|
layout.addWidget(mesh_name_edit)
|
|
layout.addWidget(create_button)
|
|
layout.addWidget(select_button)
|
|
layout.addWidget(set_button)
|
|
|
|
@signal.on(session.events.targetChanged, qtParent=tab.tabContents)
|
|
def update_ui():
|
|
if not session.state.layersAvailable:
|
|
return
|
|
|
|
mesh = Mirror(session.state.selectedSkinCluster).get_reference_mesh()
|
|
mesh_name_edit.setText(mesh or "")
|
|
|
|
def select_mesh(m):
|
|
if m is None:
|
|
return
|
|
|
|
from maya import cmds
|
|
|
|
cmds.setToolTo("moveSuperContext")
|
|
cmds.selectMode(component=True)
|
|
cmds.select(m + ".vtx[*]", r=True)
|
|
cmds.hilite(m, replace=True)
|
|
cmds.viewFit()
|
|
|
|
@qt.on(select_button.clicked)
|
|
def select_handler():
|
|
select_mesh(Mirror(session.state.selectedSkinCluster).get_reference_mesh())
|
|
|
|
@qt.on(create_button.clicked)
|
|
def create():
|
|
if not session.state.layersAvailable:
|
|
return
|
|
|
|
m = Mirror(session.state.selectedSkinCluster)
|
|
mesh = m.get_reference_mesh()
|
|
if mesh is None:
|
|
mesh = m.build_reference_mesh()
|
|
|
|
update_ui()
|
|
select_mesh(mesh)
|
|
|
|
@qt.on(set_button.clicked)
|
|
def set_clicked():
|
|
set_reference_mesh_from_selection()
|
|
update_ui()
|
|
|
|
update_ui()
|
|
|
|
return layout
|
|
|
|
vertex_mapping_mode = QtWidgets.QComboBox()
|
|
vertex_mapping_mode.addItem("Closest point on surface", VertexTransferMode.closestPoint)
|
|
vertex_mapping_mode.addItem("UV space", VertexTransferMode.uvSpace)
|
|
|
|
result = QtWidgets.QGroupBox("Vertex Mapping")
|
|
layout = QtWidgets.QVBoxLayout()
|
|
layout.addLayout(createTitledRow("Mapping mode:", vertex_mapping_mode))
|
|
layout.addLayout(createTitledRow("Symmetry mesh:", mirror_mesh_group()))
|
|
result.setLayout(layout)
|
|
|
|
@qt.on(vertex_mapping_mode.currentIndexChanged)
|
|
def value_changed():
|
|
session.state.mirror().vertex_transfer_mode = vertex_mapping_mode.currentData()
|
|
|
|
@signal.on(session.events.targetChanged)
|
|
def target_changed():
|
|
if session.state.layersAvailable:
|
|
qt.select_data(vertex_mapping_mode, session.state.mirror().vertex_transfer_mode)
|
|
|
|
return result
|
|
|
|
def influence_mapping_group():
|
|
def edit_mapping():
|
|
mapping = QtWidgets.QPushButton("Preview and edit mapping")
|
|
|
|
single_window_policy = qt.SingleWindowPolicy()
|
|
|
|
@qt.on(mapping.clicked)
|
|
def edit():
|
|
from ngSkinTools2.ui import influenceMappingUI
|
|
|
|
window = influenceMappingUI.open_ui_for_mesh(parent_window, session.state.selectedSkinCluster)
|
|
single_window_policy.setCurrent(window)
|
|
|
|
return mapping
|
|
|
|
layout = QtWidgets.QVBoxLayout()
|
|
layout.addWidget(edit_mapping())
|
|
|
|
result = QtWidgets.QGroupBox("Influences mapping")
|
|
result.setLayout(layout)
|
|
return result
|
|
|
|
tab = TabSetup()
|
|
tab.innerLayout.addWidget(build_mirroring_options_group())
|
|
tab.innerLayout.addWidget(vertex_mapping_group())
|
|
tab.innerLayout.addWidget(influence_mapping_group())
|
|
tab.innerLayout.addStretch()
|
|
|
|
btn_mirror = QtWidgets.QPushButton("Mirror")
|
|
tab.lowerButtonsRow.addWidget(btn_mirror)
|
|
|
|
@qt.on(btn_mirror.clicked)
|
|
def mirror_clicked():
|
|
if session.state.currentLayer.layer:
|
|
mirror_options = MirrorOptions()
|
|
mirror_options.direction = config.mirror_direction()
|
|
mirror_options.mirrorDq = config.mirror_dq()
|
|
mirror_options.mirrorMask = config.mirror_mask()
|
|
mirror_options.mirrorWeights = config.mirror_weights()
|
|
|
|
session.state.mirror().mirror(mirror_options)
|
|
|
|
@signal.on(session.events.targetChanged, qtParent=tab.tabContents)
|
|
def update_ui():
|
|
tab.tabContents.setEnabled(session.state.layersAvailable)
|
|
|
|
update_ui()
|
|
|
|
return tab.tabContents
|