Update
This commit is contained in:
parent
ce678534b2
commit
9787a55b24
419
Scripts/Modeling/Manage/Rename.py
Normal file
419
Scripts/Modeling/Manage/Rename.py
Normal file
@ -0,0 +1,419 @@
|
||||
|
||||
'''
|
||||
from importlib import reload
|
||||
import Rename
|
||||
reload(Rename)
|
||||
Rename.UI()
|
||||
'''
|
||||
from Modeling.Manage import Rename
|
||||
# this text can be entered from the script editor and can be made into a button
|
||||
|
||||
import maya.cmds as cmds # type: ignore
|
||||
|
||||
def UI():
|
||||
|
||||
global SelectName
|
||||
global RenameText
|
||||
|
||||
global StartValue
|
||||
global PaddingValue
|
||||
global NumberCheck
|
||||
|
||||
global RemoveFirst
|
||||
global RemoveEnd
|
||||
|
||||
global PrefixText
|
||||
global SuffixText
|
||||
|
||||
global SearchText
|
||||
global ReplaceText
|
||||
global SRCheck
|
||||
|
||||
#UI Width
|
||||
sizeX = 240
|
||||
version = "v1.0"
|
||||
if cmds.window("RenameWin", exists=True):
|
||||
cmds.deleteUI("RenameWin", window=True)
|
||||
|
||||
#Creating UI
|
||||
igEzRenamWin = cmds.window("RenameWin", title="Rename Tool "+version, width=sizeX+6, height=385, mnb = True, mxb = False, sizeable = False)
|
||||
|
||||
#Creating interface elements
|
||||
mainLayout = cmds.columnLayout("mainColumnLayout", width = sizeX, adjustableColumn=False, co = ["both",2])
|
||||
|
||||
#Select All Button
|
||||
cmds.separator(h=5, style = "none", parent = mainLayout)
|
||||
cmds.button(label = "Select All", w=sizeX, h=25, c=SelectAll, ann = "Select ALL objects in scene")
|
||||
cmds.separator(h=5, style = "none", parent = mainLayout)
|
||||
|
||||
#Select by Name
|
||||
cmds.rowColumnLayout( numberOfRows=1, w=sizeX, parent=mainLayout, rowHeight=[(1, 25), (2, 60)], cs = [(5,5), (5,5)])
|
||||
cmds.button(label = "Select by Name", w=sizeX/3, h=25, c=SelectName, align = "Center", ann="Select objects by name")
|
||||
SelectName = cmds.textField(w = sizeX*0.646, ann="Select by Name \n Use * after and/or before the text to select by prefix/suffix \n Example: *_grp")
|
||||
cmds.separator(w = sizeX, h=15, style = "in", parent = mainLayout)
|
||||
|
||||
#Rename and Number
|
||||
cmds.rowColumnLayout( numberOfRows=1, w=sizeX, parent=mainLayout, rowHeight=[(1, 20), (2, 60)])
|
||||
#Rename Field
|
||||
cmds.text(label=" Rename:", font = "boldLabelFont", w = sizeX/4, align="left", ann="Write the name you want to rename the objects selected")
|
||||
RenameText = cmds.textField(w = sizeX*0.75, ann="Write the name you want to rename the objects selected")
|
||||
|
||||
#Start Field
|
||||
cmds.rowColumnLayout( numberOfRows=1, w=sizeX, parent=mainLayout, rowHeight=[(1, 20), (2, 60)])
|
||||
cmds.text(label=" Start:", font = "boldLabelFont", w = sizeX/4, align="left")
|
||||
StartValue = cmds.textField(w = sizeX/4, tx="1", ann="Write the Start value for the sequence")
|
||||
#Padding Field
|
||||
cmds.text(label=" Padding:", font = "boldLabelFont", w = sizeX/4, align="left")
|
||||
PaddingValue = cmds.textField(w = sizeX/4, tx="2", ann="Write the Padding value for the numbers")
|
||||
#Number Letters
|
||||
cmds.rowColumnLayout( numberOfRows=1, w=sizeX, parent=mainLayout, rowHeight=[(1, 20), (2, 60)])
|
||||
cmds.text(label="", font = "boldLabelFont", w = sizeX/4-2, align="left")
|
||||
NumberCheck = cmds.radioButtonGrp(labelArray2=[ 'Numbers', 'Letters'], numberOfRadioButtons=2, w=sizeX, h=20, sl=1, cw = ([1,120]))
|
||||
#ButtonRename and Number
|
||||
cmds.separator(h=5, style = "none", parent = mainLayout)
|
||||
cmds.button(label = "Rename and Number", w=sizeX, h=25, c=RenameNumber, align = "Center", parent = mainLayout)
|
||||
cmds.separator(w = sizeX, h=15, style = "in", parent = mainLayout)
|
||||
|
||||
#RemoveCharacter
|
||||
#Remove First/Last
|
||||
cmds.rowColumnLayout( numberOfRows=1, w=sizeX, parent=mainLayout, rowHeight=[(1, 25), (2, 60)], cs = [(5,5)])
|
||||
cmds.text(label=" Remove:", font = "boldLabelFont", w = sizeX/3-12, align="left")
|
||||
cmds.button(label = "First Char->", w=sizeX/3, h=25, c=lambda *args: Rename.Remove(True), align = "Center")
|
||||
cmds.button(label = "<-Last Char", w=sizeX/3, h=25, c=lambda *args: Rename.Remove(False), align = "Center")
|
||||
cmds.separator(h=5, style = "none", parent = mainLayout)
|
||||
|
||||
#Remove pasted__
|
||||
cmds.rowColumnLayout( numberOfRows=1, w=sizeX, parent=mainLayout, rowHeight=[(1, 25), (2, 60)], cs = [(90,90)])
|
||||
cmds.text(label=" ", font = "boldLabelFont", w = sizeX/3-12, align="left")
|
||||
cmds.button(label = "pasted__", w=sizeX/3, h=25, c=RemovePasted, align = "Center")
|
||||
|
||||
#Remove UI
|
||||
cmds.separator(h=5, style = "none", parent = mainLayout)
|
||||
cmds.rowColumnLayout( numberOfRows=1, w=sizeX, parent=mainLayout, rowHeight=[(1, 25), (2, 60)], cs = [(8.5,8.5)])
|
||||
RemoveFirst = cmds.textField(w = sizeX/5, tx="0", ann="Write the amount of characters you want to delete on text beginning")
|
||||
cmds.button(label = "-", w=25, h=25, c=lambda *args: Rename.RemoveChar('begin'), align = "Center", ann="Delete on text beginning")
|
||||
cmds.button(label = "Remove", w=sizeX/4, h=25, c=lambda *args: Rename.RemoveChar('all'), align = "Center", ann="Delete on text beginning and ending")
|
||||
cmds.button(label = "-", w=25, h=25, c=lambda *args: Rename.RemoveChar('end'), align = "Center", ann="Delete on text ending")
|
||||
RemoveEnd = cmds.textField(w = sizeX/5, tx="3", ann="Write the amount of characters you want to delete on text ending")
|
||||
cmds.separator(w = sizeX, h=15, style = "in", parent = mainLayout)
|
||||
|
||||
#Suffix
|
||||
#Control Suffix
|
||||
cmds.rowColumnLayout( numberOfRows=1, w=sizeX, parent=mainLayout, rowHeight=[(1, 20), (2, 60)], cs = [(5,5)])
|
||||
cmds.text(label=" Prefix:", font = "boldLabelFont", w = sizeX/4-10, align="left", ann="Write the prefix")
|
||||
PrefixText = cmds.textField(w = sizeX/2.5+33, tx="prefix_", ann="Write the prefix")
|
||||
cmds.button(label = "Add", w=sizeX/4-10, h=25, c=lambda *args: Rename.PrefixSuffix(False), align = "Center")
|
||||
cmds.separator(h=5, style = "none", parent = mainLayout)
|
||||
#Group Suffix
|
||||
cmds.rowColumnLayout( numberOfRows=1, w=sizeX, parent=mainLayout, rowHeight=[(1, 20), (2, 60)], cs = [(5,5)])
|
||||
cmds.text(label=" Suffix:", font = "boldLabelFont", w = sizeX/4-10, align="left", ann="Write the suffix")
|
||||
SuffixText = cmds.textField(w = sizeX/2.5+33, tx="_suffix", ann="Write the suffix")
|
||||
cmds.button(label = "Add", w=sizeX/4-10, h=25, c=lambda *args: Rename.PrefixSuffix(True), align = "Center")
|
||||
cmds.separator(w = sizeX, h=15, style = "in", parent = mainLayout)
|
||||
|
||||
#Prefix
|
||||
cmds.rowColumnLayout( numberOfRows=1, w=sizeX, parent=mainLayout, rowHeight=[(1, 20), (2, 60)], cs = [(5,5)])
|
||||
cmds.button(label = "_Grp", w=sizeX/5-4, h=25, c=lambda *args: Rename.Suffix('_Grp'), align = "Center", ann = "Add Grp suffix")
|
||||
cmds.button(label = "_Geo", w=sizeX/5-4, h=25, c=lambda *args: Rename.Suffix('_Geo'), align = "Center", ann = "Add Geo suffix")
|
||||
cmds.button(label = "_Ctrl", w=sizeX/5-4, h=25, c=lambda *args: Rename.Suffix('_Ctrl'), align = "Center", ann = "Add Ctrl suffix")
|
||||
cmds.button(label = "_Jnt", w=sizeX/5-4, h=25, c=lambda *args: Rename.Suffix('_Jnt'), align = "Center", ann = "Add Jnt suffix")
|
||||
cmds.button(label = "_Drv", w=sizeX/5-4, h=25, c=lambda *args: Rename.Suffix('_Drv'), align = "Center", ann = "Add Drv suffix")
|
||||
cmds.separator(w = sizeX, h=15, style = "in", parent = mainLayout)
|
||||
|
||||
#Search and Replace
|
||||
cmds.rowColumnLayout( numberOfRows=1, w=sizeX, parent=mainLayout, rowHeight=[(1, 20), (2, 60)], cs = [(5,5)])
|
||||
cmds.text(label=" Search:", font = "boldLabelFont", w = sizeX/4-10, align="left", ann="Write the text to search")
|
||||
SearchText = cmds.textField(w = sizeX/2+100, ann="Write the text to search")
|
||||
cmds.rowColumnLayout( numberOfRows=1, w=sizeX, parent=mainLayout, rowHeight=[(1, 20), (2, 60)], cs = [(5,5)])
|
||||
cmds.text(label=" Replace:", font = "boldLabelFont", w = sizeX/4-10, align="left", ann="Write the text to replace")
|
||||
ReplaceText = cmds.textField(w = sizeX/2+100, ann="Write the text to replace")
|
||||
cmds.rowColumnLayout( numberOfRows=1, w=sizeX, parent=mainLayout, rowHeight=[(1, 20), (2, 60)], cs = [(5,5)])
|
||||
SRCheck = cmds.radioButtonGrp(labelArray3=[ 'Selected', 'Hierarchy', 'All'], numberOfRadioButtons=3, w=sizeX, h=20, sl=1, cw = ([1,95],[2,95],[3,95]))
|
||||
cmds.button(label = "Apply", w=sizeX, h=25, c=SearchReplace, align = "Center", parent = mainLayout)
|
||||
cmds.separator(h=5, style = "none", parent = mainLayout)
|
||||
|
||||
#Show UI:
|
||||
cmds.showWindow(igEzRenamWin)
|
||||
|
||||
def SelectAll(*args):
|
||||
cmds.select(ado=True, hi = True)
|
||||
selection = cmds.ls(selection=True, sn=True)
|
||||
selectionAdd = []
|
||||
|
||||
#Old select all code version
|
||||
"""for objs in selection:
|
||||
children = cmds.listRelatives(objs, c=True, f =True)
|
||||
print "Children01:", children
|
||||
shapes = cmds.listRelatives(objs, s=True, f = True)
|
||||
print "Shapes:", shapes
|
||||
|
||||
if not children == None:
|
||||
if not shapes == None:
|
||||
for s in shapes:
|
||||
children.remove(s)
|
||||
|
||||
for chi in children:
|
||||
|
||||
children2 = cmds.listRelatives(chi, c=True, f = True)
|
||||
print "CHildren02:", children2
|
||||
|
||||
if not children2 == None:
|
||||
for chi2 in children2:
|
||||
children.append(chi2)
|
||||
|
||||
selectionAdd.append(chi)
|
||||
|
||||
|
||||
|
||||
for objs in selectionAdd:
|
||||
cmds.select(objs, add=True)"""
|
||||
|
||||
def SelectName(*args):
|
||||
cmds.select(cl=True)
|
||||
name = cmds.textField(SelectName, text = 1, q=True)
|
||||
try:
|
||||
selection = cmds.ls(name, l = True)
|
||||
except:
|
||||
cmds.warning("Object Don't Exist")
|
||||
|
||||
for objs in selection:
|
||||
cmds.select(objs, add=True)
|
||||
|
||||
def RenameNumber(*args):
|
||||
|
||||
number = cmds.textField(StartValue, text = 1, q=True)
|
||||
number = int(number)
|
||||
|
||||
padding = cmds.textField(PaddingValue, text = 1, q=True)
|
||||
padding = int(padding)
|
||||
|
||||
NumberLetters = cmds.radioButtonGrp(NumberCheck, q=True, select=True)
|
||||
|
||||
newName = cmds.textField(RenameText, text = 1, q=True)
|
||||
|
||||
selection = cmds.ls(selection=True, sn=True)
|
||||
|
||||
lettersList = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
|
||||
|
||||
#Number suffix
|
||||
y = 0
|
||||
|
||||
for obj in selection:
|
||||
try:
|
||||
#Teste if has duplicate mesh with the same name on the scene and return the name without parents
|
||||
trueName = testDuplicateName(obj)
|
||||
#Save the original name
|
||||
oldName = trueName
|
||||
|
||||
#If true use numbers, else use letters
|
||||
if NumberLetters == 1:
|
||||
zeros = ""
|
||||
for x in range(int(padding)):
|
||||
if len(str(number)) <= x:
|
||||
zeros = zeros+"0"
|
||||
|
||||
#Create the newName and rename
|
||||
name = newName+"_"+"{:0>"+str(padding)+"}"
|
||||
newNameList = name.format(number)
|
||||
cmds.rename(obj, name.format(number))
|
||||
|
||||
else:
|
||||
newNameList = newName+"_"+lettersList[y]
|
||||
cmds.rename(obj, newName+"_"+lettersList[y])
|
||||
if y < len(lettersList)-1:
|
||||
y+=1
|
||||
else:
|
||||
y=0
|
||||
|
||||
#For to rename all the oldNames on list to newNames
|
||||
for x in range(len(selection)):
|
||||
newParentName = selection[x].replace(oldName, newNameList)
|
||||
selection[x] = newParentName
|
||||
except:
|
||||
pass
|
||||
|
||||
number = int(number+1)
|
||||
|
||||
def RemoveChar(Type):
|
||||
|
||||
first = cmds.textField(RemoveFirst, text = 1, q=True)
|
||||
end = cmds.textField(RemoveEnd, text = 1, q=True)
|
||||
|
||||
selection = cmds.ls(selection = True, sn=True)
|
||||
|
||||
for objs in selection:
|
||||
#Teste if has duplicate mesh with the same name on the scene
|
||||
trueName = testDuplicateName(objs)
|
||||
|
||||
#Save the original name
|
||||
oldName = trueName
|
||||
|
||||
if Type == "all":
|
||||
name = trueName[:-int(end)]
|
||||
name = name[int(first):]
|
||||
|
||||
if Type == "begin":
|
||||
name = trueName[int(first):]
|
||||
|
||||
if Type == "end":
|
||||
name = trueName[:-int(end)]
|
||||
|
||||
try:
|
||||
cmds.rename(objs, str(name))
|
||||
except:
|
||||
pass
|
||||
|
||||
#For to rename all the oldNames on list to newNames
|
||||
for x in range(len(selection)):
|
||||
newParentName = selection[x].replace(oldName, name)
|
||||
selection[x] = newParentName
|
||||
|
||||
|
||||
def Remove(Type):
|
||||
|
||||
selection = cmds.ls(selection = True, sn = True)
|
||||
|
||||
for objs in selection:
|
||||
#Teste if has duplicate mesh with the same name on the scene
|
||||
trueName = testDuplicateName(objs)
|
||||
|
||||
#Save the original name
|
||||
oldName = trueName
|
||||
|
||||
if Type:
|
||||
name = trueName[1:]
|
||||
else:
|
||||
name = trueName[:-1]
|
||||
|
||||
try:
|
||||
cmds.rename(objs, name)
|
||||
except:
|
||||
pass
|
||||
|
||||
#For to rename all the oldNames on list to newNames
|
||||
for x in range(len(selection)):
|
||||
newParentName = selection[x].replace(oldName, name)
|
||||
selection[x] = newParentName
|
||||
|
||||
|
||||
|
||||
def RemovePasted(*args):
|
||||
|
||||
selection = cmds.ls("pasted__*", sn = True)
|
||||
|
||||
for objs in selection:
|
||||
#Teste if has duplicate mesh with the same name on the scene
|
||||
trueName = testDuplicateName(objs)
|
||||
|
||||
name = trueName[8:]
|
||||
try:
|
||||
cmds.rename(objs, name)
|
||||
except:
|
||||
cmds.warning("Don't Exist pasted Objects")
|
||||
|
||||
def PrefixSuffix(Suffix):
|
||||
prefix = cmds.textField(PrefixText, text = 1, q=True)
|
||||
suffix = cmds.textField(SuffixText, text = 1, q=True)
|
||||
|
||||
selection = cmds.ls(selection = True, sn = True)
|
||||
|
||||
for objs in selection:
|
||||
|
||||
#Teste if has duplicate mesh with the same name on the scene
|
||||
trueName = testDuplicateName(objs)
|
||||
#Save the original name
|
||||
oldName = trueName
|
||||
|
||||
if Suffix:
|
||||
name = str(trueName)+suffix
|
||||
else:
|
||||
name = prefix+str(trueName)
|
||||
|
||||
try:
|
||||
cmds.rename(objs, name)
|
||||
except:
|
||||
pass
|
||||
|
||||
#For to rename all the oldNames on list to newNames
|
||||
for x in range(len(selection)):
|
||||
newParentName = selection[x].replace(oldName, name)
|
||||
selection[x] = newParentName
|
||||
|
||||
|
||||
def Suffix(Text):
|
||||
|
||||
selection = cmds.ls(selection = True, sn = True)
|
||||
|
||||
for objs in selection:
|
||||
#Test if has duplicate mesh with the same name on the scene
|
||||
trueName = testDuplicateName(objs)
|
||||
|
||||
#Save the original name
|
||||
oldName = trueName
|
||||
|
||||
newName = trueName+Text
|
||||
try:
|
||||
cmds.rename(objs, newName)
|
||||
except:
|
||||
pass
|
||||
|
||||
#For to rename all the oldNames on list to newNames
|
||||
for x in range(len(selection)):
|
||||
newParentName = selection[x].replace(oldName, newName)
|
||||
selection[x] = newParentName
|
||||
|
||||
def SearchReplace(*args):
|
||||
|
||||
search = cmds.textField(SearchText, text = 1, q=True)
|
||||
replace = cmds.textField(ReplaceText, text = 1, q=True)
|
||||
|
||||
SRMethod = cmds.radioButtonGrp(SRCheck, q=True, select=True)
|
||||
|
||||
#Selected search and Replace method
|
||||
if SRMethod == 1:
|
||||
selection = cmds.ls(selection = True, sn = True)
|
||||
|
||||
#Hierarchy search and Replace method
|
||||
if SRMethod == 2:
|
||||
cmds.select(hi = True)
|
||||
selection = cmds.ls(selection = True, sn = False)
|
||||
|
||||
#All search and Replace method
|
||||
if SRMethod == 3:
|
||||
#Select All DagObjects in scene
|
||||
selection = []
|
||||
cmds.select(ado = True, hi = True)
|
||||
selection = cmds.ls(selection = True, sn=False)
|
||||
|
||||
#for to rename the objects
|
||||
for obj in selection:
|
||||
#Teste if has duplicate mesh with the same name on the scene and return the name without parents
|
||||
trueName = testDuplicateName(obj)
|
||||
#Save the original name
|
||||
oldName = trueName
|
||||
#Search and replace to create the new name
|
||||
newName = trueName.replace(search, replace)
|
||||
|
||||
#Rename the object
|
||||
try:
|
||||
cmds.rename(obj, newName)
|
||||
except:
|
||||
pass
|
||||
|
||||
#For to rename all the oldNames on list to newNames
|
||||
for x in range(len(selection)):
|
||||
newParentName = selection[x].replace(oldName, newName)
|
||||
selection[x] = newParentName
|
||||
|
||||
print("Slecao: ", selection)
|
||||
|
||||
|
||||
|
||||
def testDuplicateName(Obj):
|
||||
|
||||
try:
|
||||
trueName = Obj.split("|")
|
||||
return trueName[len(trueName)-1]
|
||||
except:
|
||||
return Obj
|
||||
|
BIN
Scripts/Modeling/Select/EdgeLoopSmartSelect.jpg
Normal file
BIN
Scripts/Modeling/Select/EdgeLoopSmartSelect.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 463 KiB |
431
Scripts/Modeling/Select/EdgeLoopSmartSelect.py
Normal file
431
Scripts/Modeling/Select/EdgeLoopSmartSelect.py
Normal file
@ -0,0 +1,431 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import maya.cmds as cmds
|
||||
import maya.OpenMaya as om
|
||||
import maya.OpenMayaUI as omui
|
||||
from maya.OpenMaya import MGlobal
|
||||
import math
|
||||
import re
|
||||
import maya.mel as mel
|
||||
|
||||
def run():
|
||||
global selInitialGeo
|
||||
global storeAllEdges
|
||||
selInitialGeo = []
|
||||
storeAllEdges = []
|
||||
testAnySel = cmds.ls(sl=1)
|
||||
if testAnySel:
|
||||
checkCurrentSelEdge = cmds.filterExpand(sm=32)
|
||||
checkCurrentSelPoly = cmds.filterExpand(sm=12)
|
||||
checkCurrentSelOther =cmds.filterExpand(sm=(31,34,35) )
|
||||
if checkCurrentSelEdge:
|
||||
checkEdgeLoopGrp = getEdgeRingGroup(checkCurrentSelEdge)
|
||||
if len(checkEdgeLoopGrp) == 1:
|
||||
listAAA = ''
|
||||
try:
|
||||
listAAA = vtxLoopOrder(checkCurrentSelEdge)
|
||||
except:
|
||||
pass
|
||||
if listAAA:
|
||||
storeAllEdges = checkCurrentSelEdge
|
||||
checkCurrentSelPoly = cmds.ls(hl=1)
|
||||
selInitialGeo.append(checkCurrentSelPoly[0])
|
||||
if not cmds.attributeQuery('start', node = selInitialGeo[0], ex=True ):
|
||||
cmds.addAttr(selInitialGeo[0], at = 'long', ln='start')
|
||||
if not cmds.attributeQuery('end', node = selInitialGeo[0], ex=True ):
|
||||
cmds.addAttr(selInitialGeo[0], at = 'long',ln='end')
|
||||
if not cmds.attributeQuery('nearest', node = selInitialGeo[0], ex=True ):
|
||||
cmds.addAttr(selInitialGeo[0], at = 'long',ln='nearest')
|
||||
if not cmds.attributeQuery('closeTo', node = selInitialGeo[0], ex=True ):
|
||||
cmds.addAttr(selInitialGeo[0], at = 'long',ln='closeTo')
|
||||
if not cmds.attributeQuery('firstRun', node = selInitialGeo[0], ex=True ):
|
||||
cmds.addAttr(selInitialGeo[0], at = 'long',ln='firstRun')
|
||||
cmds.setAttr((selInitialGeo[0]+'.firstRun'),0)
|
||||
selShortestLoop()
|
||||
else:
|
||||
cmds.select(checkCurrentSelEdge)
|
||||
else:
|
||||
cmds.select(checkCurrentSelEdge)
|
||||
else:
|
||||
if checkCurrentSelOther:
|
||||
checkCurrentSelPoly = cmds.ls(hl=1)
|
||||
selInitialGeo.append(checkCurrentSelPoly[0])
|
||||
CMD = 'doMenuComponentSelectionExt("' + str(checkCurrentSelPoly[0])+ '", "edge", 0);'
|
||||
mel.eval(CMD)
|
||||
cmds.select(cl=1)
|
||||
cmds.polyCrease((checkCurrentSelPoly[0]+'.e[*]'), value=0)
|
||||
if not cmds.attributeQuery('start', node = selInitialGeo[0], ex=True ):
|
||||
cmds.addAttr(selInitialGeo[0], at = 'long', ln='start')
|
||||
if not cmds.attributeQuery('end', node = selInitialGeo[0], ex=True ):
|
||||
cmds.addAttr(selInitialGeo[0], at = 'long',ln='end')
|
||||
if not cmds.attributeQuery('nearest', node = selInitialGeo[0], ex=True ):
|
||||
cmds.addAttr(selInitialGeo[0], at = 'long',ln='nearest')
|
||||
if not cmds.attributeQuery('closeTo', node = selInitialGeo[0], ex=True ):
|
||||
cmds.addAttr(selInitialGeo[0], at = 'long',ln='closeTo')
|
||||
if not cmds.attributeQuery('firstRun', node = selInitialGeo[0], ex=True ):
|
||||
cmds.addAttr(selInitialGeo[0], at = 'long',ln='firstRun')
|
||||
cmds.setAttr((selInitialGeo[0]+'.firstRun'),0)
|
||||
cmds.scriptJob ( runOnce=True, event = ["SelectionChanged", selShortestLoop])
|
||||
else:
|
||||
print('no selection')
|
||||
|
||||
def selShortestLoop():
|
||||
global ctx
|
||||
global storeAllEdges
|
||||
global selInitialGeo
|
||||
global storeCameraPosition
|
||||
global initialList
|
||||
initialList = []
|
||||
storeAllEdges = cmds.ls(sl=1,fl=1)
|
||||
listVtx = vtxLoopOrder(storeAllEdges)
|
||||
initialList = listVtx
|
||||
startID = listVtx[0].split('[')[-1].split(']')[0]
|
||||
endID = listVtx[-1].split('[')[-1].split(']')[0]
|
||||
cmds.setAttr((selInitialGeo[0]+'.start'),int(startID))
|
||||
cmds.setAttr((selInitialGeo[0]+'.end'),int(endID))
|
||||
view = omui.M3dView.active3dView()
|
||||
cam = om.MDagPath()
|
||||
view.getCamera(cam)
|
||||
camPath = cam.fullPathName()
|
||||
cameraTrans = cmds.listRelatives(camPath,type='transform',p=True)
|
||||
storeCameraPosition = cmds.xform(cameraTrans,q=1,ws=1,rp=1)
|
||||
if cmds.objExists('preSelDisp')==0:
|
||||
cmds.createNode("creaseSet")
|
||||
cmds.rename("preSelDisp")
|
||||
cmds.sets((selInitialGeo[0]+".e[*]"),remove="preSelDisp")
|
||||
cmds.sets(storeAllEdges,forceElement="preSelDisp")
|
||||
cmds.setAttr("preSelDisp.creaseLevel", 1)
|
||||
cmds.polyOptions(dce=1)
|
||||
ctx = 'Click2dTo3dCtx'
|
||||
if cmds.draggerContext(ctx, exists=True):
|
||||
cmds.deleteUI(ctx)
|
||||
cmds.draggerContext(ctx, ppc= liveShortPause ,rc = liveShortPause, dragCommand = liveShortMove, fnz = liveShortStop ,name=ctx, cursor='crossHair',undoMode='step')
|
||||
cmds.setToolTo(ctx)
|
||||
|
||||
|
||||
|
||||
def liveShortMove():
|
||||
global selInitialGeo
|
||||
global ctx
|
||||
global screenX,screenY
|
||||
global storeCameraPosition
|
||||
global storeAllEdges
|
||||
modifiers = cmds.getModifiers()
|
||||
if selInitialGeo:
|
||||
vpX, vpY, _ = cmds.draggerContext(ctx, query=True, dragPoint=True)
|
||||
pos = om.MPoint()
|
||||
dir = om.MVector()
|
||||
hitpoint = om.MFloatPoint()
|
||||
omui.M3dView().active3dView().viewToWorld(int(vpX), int(vpY), pos, dir)
|
||||
pos2 = om.MFloatPoint(pos.x, pos.y, pos.z)
|
||||
checkHit = 0
|
||||
finalMesh = []
|
||||
finalX = 0
|
||||
finalY = 0
|
||||
finalZ = 0
|
||||
shortDistance = 10000000000
|
||||
distanceBetween = 1000000000
|
||||
hitFacePtr = om.MScriptUtil().asIntPtr()
|
||||
hitFace = []
|
||||
for mesh in selInitialGeo:
|
||||
selectionList = om.MSelectionList()
|
||||
selectionList.add(mesh)
|
||||
dagPath = om.MDagPath()
|
||||
selectionList.getDagPath(0, dagPath)
|
||||
fnMesh = om.MFnMesh(dagPath)
|
||||
intersection = fnMesh.closestIntersection(
|
||||
om.MFloatPoint(pos2),
|
||||
om.MFloatVector(dir),
|
||||
None,
|
||||
None,
|
||||
False,
|
||||
om.MSpace.kWorld,
|
||||
99999,
|
||||
False,
|
||||
None,
|
||||
hitpoint,
|
||||
None,
|
||||
hitFacePtr,
|
||||
None,
|
||||
None,
|
||||
None)
|
||||
if intersection:
|
||||
x = hitpoint.x
|
||||
y = hitpoint.y
|
||||
z = hitpoint.z
|
||||
finalX = x
|
||||
finalY = y
|
||||
finalZ = z
|
||||
hitFace = om.MScriptUtil(hitFacePtr).asInt()
|
||||
hitFaceName = (selInitialGeo[0] + '.f[' + str(hitFace) +']')
|
||||
cpX,cpY,cpZ = getPolyFaceCenter(hitFaceName)
|
||||
shortDistanceCheck = 10000
|
||||
checkCVDistance = 10000
|
||||
cvList = (cmds.polyInfo(hitFaceName , fv=True )[0]).split(':')[-1].split(' ')
|
||||
cvListX = [x for x in cvList if x.strip()]
|
||||
|
||||
for v in cvListX:
|
||||
checkNumber = ''.join([n for n in v.split('|')[-1] if n.isdigit()])
|
||||
if len(checkNumber) > 0:
|
||||
cvPoint = (selInitialGeo[0] + '.vtx[' + str(checkNumber) +']')
|
||||
cvPosition = cmds.pointPosition(cvPoint)
|
||||
checkCVDistance = math.sqrt( ((float(cvPosition[0]) - finalX)**2) + ((float(cvPosition[1]) - finalY)**2) + ((float(cvPosition[2]) - finalZ)**2))
|
||||
if checkCVDistance < shortDistanceCheck:
|
||||
shortDistanceCheck = checkCVDistance
|
||||
mostCloseCVPoint = cvPoint
|
||||
mostCloseCVPointPos = cvPosition
|
||||
|
||||
newID = mostCloseCVPoint.split('[')[-1].split(']')[0]
|
||||
cmds.setAttr((selInitialGeo[0]+'.nearest'),int(newID))
|
||||
checkRun = cmds.getAttr(selInitialGeo[0]+'.firstRun')
|
||||
|
||||
if checkRun == 1:
|
||||
checkCloseTo = cmds.getAttr(selInitialGeo[0]+'.nearest')
|
||||
checkStart = cmds.getAttr(selInitialGeo[0]+'.start')
|
||||
checkEnd = cmds.getAttr(selInitialGeo[0]+'.end')
|
||||
|
||||
startPosition = cmds.pointPosition( (selInitialGeo[0] + '.vtx[' + str(checkStart) +']'))
|
||||
endPosition = cmds.pointPosition( (selInitialGeo[0] + '.vtx[' + str(checkEnd) +']'))
|
||||
nearPosition = cmds.pointPosition( (selInitialGeo[0] + '.vtx[' + str(checkCloseTo) +']'))
|
||||
|
||||
distA = math.sqrt( ((float(nearPosition[0]) - startPosition[0])**2) + ((float(nearPosition[1]) - startPosition[1])**2) + ((float(nearPosition[2]) - startPosition[2])**2))
|
||||
distB = math.sqrt( ((float(nearPosition[0]) - endPosition[0])**2) + ((float(nearPosition[1]) - endPosition[1])**2) + ((float(nearPosition[2]) - endPosition[2])**2))
|
||||
if distA > distB:
|
||||
cmds.setAttr((selInitialGeo[0]+'.end'),checkEnd)
|
||||
cmds.setAttr((selInitialGeo[0]+'.start'),checkStart)
|
||||
else:
|
||||
cmds.setAttr((selInitialGeo[0]+'.end'),checkStart)
|
||||
cmds.setAttr((selInitialGeo[0]+'.start'),checkEnd)
|
||||
checkStart = cmds.getAttr(selInitialGeo[0]+'.start')
|
||||
checkEnd = cmds.getAttr(selInitialGeo[0]+'.end')
|
||||
checkNearest = cmds.getAttr(selInitialGeo[0]+'.nearest')
|
||||
#get shortest
|
||||
cmds.select(cl=1)
|
||||
cmds.sets((selInitialGeo[0]+".e[*]"),remove="preSelDisp")
|
||||
sortList = []
|
||||
if modifiers == 4: # "press Ctrl"
|
||||
PA = (selInitialGeo[0] + '.vtx[' + str(checkEnd) +']')
|
||||
PB = (selInitialGeo[0] + '.vtx[' + str(checkNearest) +']')
|
||||
UVA = cmds.polyListComponentConversion(PA,fv =1 ,tuv=1)
|
||||
UVB = cmds.polyListComponentConversion(PB,fv =1 ,tuv=1)
|
||||
startUVID = UVA[0].split('[')[-1].split(']')[0]
|
||||
endUVID = UVB[0].split('[')[-1].split(']')[0]
|
||||
#cmds.polySelect(selInitialGeo[0] , shortestEdgePathUV=(int(startUVID), int(endUVID)))
|
||||
listShort = cmds.polySelect(selInitialGeo[0] ,q=1, shortestEdgePathUV=(int(startUVID), int(endUVID)))
|
||||
if listShort:
|
||||
for l in listShort:
|
||||
sortList.append(selInitialGeo[0]+'.e['+ str(l) +']' )
|
||||
else:
|
||||
#cmds.polySelect(selInitialGeo[0] , shortestEdgePath=(int(checkEnd), int(checkNearest)))
|
||||
#maya run faster without select
|
||||
listShort = cmds.polySelect(selInitialGeo[0] ,q=1, shortestEdgePath=(int(checkEnd), int(checkNearest)))
|
||||
if listShort:
|
||||
for l in listShort:
|
||||
sortList.append(selInitialGeo[0]+'.e['+ str(l) +']' )
|
||||
getC = storeAllEdges + sortList
|
||||
cmds.select(getC)
|
||||
cmds.sets(getC,forceElement="preSelDisp")
|
||||
if modifiers == 1: # "press Shelf"
|
||||
liveList = cmds.sets("preSelDisp",q=1)
|
||||
liveList = cmds.ls(liveList,fl=1)
|
||||
listVtx = vtxLoopOrder(liveList)
|
||||
checkEndID = listVtx[-1].split('[')[-1].split(']')[0]
|
||||
extEdgeA = []
|
||||
extEdgeB = []
|
||||
if int(checkEndID) == checkNearest:
|
||||
extEdgeA = cmds.polyListComponentConversion(listVtx[-1],fv =1 ,te=1)
|
||||
extEdgeB = cmds.polyListComponentConversion(listVtx[-2],fv =1 ,te=1)
|
||||
else:
|
||||
extEdgeA = cmds.polyListComponentConversion(listVtx[0],fv =1 ,te=1)
|
||||
extEdgeB = cmds.polyListComponentConversion(listVtx[1],fv =1 ,te=1)
|
||||
extEdgeA = cmds.ls(extEdgeA,fl=1)
|
||||
extEdgeB = cmds.ls(extEdgeB,fl=1)
|
||||
extEdge = list(set(extEdgeA) - (set(extEdgeA)-set(extEdgeB)))
|
||||
checkExtLoop = cmds.polySelectSp(extEdge,q=1, loop=1)
|
||||
checkExtLoop = cmds.ls(checkExtLoop,fl=1)
|
||||
otherList = list(set(checkExtLoop) - set(liveList))
|
||||
checkEdgeLoopGrp = getEdgeRingGroup(otherList)
|
||||
if checkEdgeLoopGrp:
|
||||
if len(checkEdgeLoopGrp) > 0:
|
||||
if len(checkEdgeLoopGrp) == 1:
|
||||
cmds.sets(otherList,forceElement="preSelDisp")
|
||||
elif len(checkEdgeLoopGrp)> 1:
|
||||
for c in checkEdgeLoopGrp:
|
||||
cvList = cmds.polyListComponentConversion (c,fe=1,tv=1)
|
||||
cvList = cmds.ls(cvList,fl=1)
|
||||
if (selInitialGeo[0]+'.vtx['+ str(checkNearest) +']' ) in cvList:
|
||||
cmds.sets(c,forceElement="preSelDisp")
|
||||
cmds.select("preSelDisp", add=1)
|
||||
cmds.refresh(cv=True,f=True)
|
||||
|
||||
|
||||
def liveShortPause():
|
||||
global storeAllEdges
|
||||
global selInitialGeo
|
||||
global initialList
|
||||
checkRun = cmds.getAttr(selInitialGeo[0]+'.firstRun')
|
||||
if checkRun == 0:
|
||||
cmds.setAttr((selInitialGeo[0]+'.firstRun'),1)
|
||||
else:
|
||||
cmds.setAttr((selInitialGeo[0]+'.firstRun'),2)
|
||||
getEdgeList = cmds.ls(sl=1,fl=1)
|
||||
storeAllEdges = getEdgeList
|
||||
listVtx = vtxLoopOrder(getEdgeList)
|
||||
if len(listVtx)>0:
|
||||
listHead = listVtx[0]
|
||||
listEnd = listVtx[-1]
|
||||
if listHead in initialList:
|
||||
cmds.setAttr((selInitialGeo[0]+'.start'),int(listVtx[0].split('[')[-1].split(']')[0]))
|
||||
cmds.setAttr((selInitialGeo[0]+'.end'),int(listVtx[-1].split('[')[-1].split(']')[0]))
|
||||
|
||||
else:
|
||||
cmds.setAttr((selInitialGeo[0]+'.start'),int(listVtx[-1].split('[')[-1].split(']')[0]))
|
||||
cmds.setAttr((selInitialGeo[0]+'.end'),int(listVtx[0].split('[')[-1].split(']')[0]))
|
||||
else:
|
||||
liveShortStop()
|
||||
|
||||
|
||||
def liveShortStop():
|
||||
cmds.setToolTo("moveSuperContext")
|
||||
cmds.polyOptions(dce=0)
|
||||
if cmds.objExists('preSelDisp'):
|
||||
cmds.setAttr("preSelDisp.creaseLevel", 0)
|
||||
cmds.delete('preSelDisp')
|
||||
|
||||
|
||||
def getPolyFaceCenter(faceName):
|
||||
meshFaceName = faceName.split('.')[0]
|
||||
findVtx = cmds.polyInfo(faceName, fv=1)
|
||||
getNumber = []
|
||||
checkNumber = ((findVtx[0].split(':')[1]).split('\n')[0]).split(' ')
|
||||
for c in checkNumber:
|
||||
findNumber = ''.join([n for n in c.split('|')[-1] if n.isdigit()])
|
||||
if findNumber:
|
||||
getNumber.append(findNumber)
|
||||
centerX = 0
|
||||
centerY = 0
|
||||
centerZ = 0
|
||||
for g in getNumber:
|
||||
x,y,z = cmds.pointPosition((meshFaceName + '.vtx['+g + ']'),w=1)
|
||||
centerX = centerX + x
|
||||
centerY = centerY + y
|
||||
centerZ = centerZ + z
|
||||
|
||||
centerX = centerX/len(getNumber)
|
||||
centerY = centerY/len(getNumber)
|
||||
centerZ = centerZ/len(getNumber)
|
||||
return centerX,centerY,centerZ
|
||||
|
||||
def vtxLoopOrder(edgelist):
|
||||
if edgelist:
|
||||
selEdges = edgelist
|
||||
shapeNode = cmds.listRelatives(selEdges[0], fullPath=True , parent=True )
|
||||
transformNode = cmds.listRelatives(shapeNode[0], fullPath=True , parent=True )
|
||||
edgeNumberList = []
|
||||
for a in selEdges:
|
||||
checkNumber = ((a.split('.')[1]).split('\n')[0]).split(' ')
|
||||
for c in checkNumber:
|
||||
findNumber = ''.join([n for n in c.split('|')[-1] if n.isdigit()])
|
||||
if findNumber:
|
||||
edgeNumberList.append(findNumber)
|
||||
getNumber = []
|
||||
for s in selEdges:
|
||||
evlist = cmds.polyInfo(s,ev=True)
|
||||
checkNumber = ((evlist[0].split(':')[1]).split('\n')[0]).split(' ')
|
||||
for c in checkNumber:
|
||||
findNumber = ''.join([n for n in c.split('|')[-1] if n.isdigit()])
|
||||
if findNumber:
|
||||
getNumber.append(findNumber)
|
||||
dup = set([x for x in getNumber if getNumber.count(x) > 1])
|
||||
getHeadTail = list(set(getNumber) - dup)
|
||||
vftOrder = []
|
||||
finalList = []
|
||||
if len(getHeadTail)>0:
|
||||
vftOrder.append(getHeadTail[0])
|
||||
count = 0
|
||||
while len(dup)> 0 and count < 100:
|
||||
checkVtx = transformNode[0]+'.vtx['+ vftOrder[-1] + ']'
|
||||
velist = cmds.polyInfo(checkVtx,ve=True)
|
||||
getNumber = []
|
||||
checkNumber = ((velist[0].split(':')[1]).split('\n')[0]).split(' ')
|
||||
for c in checkNumber:
|
||||
findNumber = ''.join([n for n in c.split('|')[-1] if n.isdigit()])
|
||||
if findNumber:
|
||||
getNumber.append(findNumber)
|
||||
findNextEdge = []
|
||||
for g in getNumber:
|
||||
if g in edgeNumberList:
|
||||
findNextEdge = g
|
||||
edgeNumberList.remove(findNextEdge)
|
||||
checkVtx = transformNode[0]+'.e['+ findNextEdge + ']'
|
||||
findVtx = cmds.polyInfo(checkVtx,ev=True)
|
||||
getNumber = []
|
||||
checkNumber = ((findVtx[0].split(':')[1]).split('\n')[0]).split(' ')
|
||||
for c in checkNumber:
|
||||
findNumber = ''.join([n for n in c.split('|')[-1] if n.isdigit()])
|
||||
if findNumber:
|
||||
getNumber.append(findNumber)
|
||||
gotNextVtx = []
|
||||
for g in getNumber:
|
||||
if g in dup:
|
||||
gotNextVtx = g
|
||||
if len(gotNextVtx)> 0:
|
||||
dup.remove(gotNextVtx)
|
||||
vftOrder.append(gotNextVtx)
|
||||
count += 1
|
||||
if len(getHeadTail)>1:
|
||||
vftOrder.append(getHeadTail[1])
|
||||
for v in vftOrder:
|
||||
finalList.append(transformNode[0]+'.vtx['+ v + ']' )
|
||||
return finalList
|
||||
|
||||
def getEdgeRingGroup(selEdges):
|
||||
if selEdges:
|
||||
trans = selEdges[0].split(".")[0]
|
||||
e2vInfos = cmds.polyInfo(selEdges, ev=True)
|
||||
e2vDict = {}
|
||||
fEdges = []
|
||||
for info in e2vInfos:
|
||||
evList = [ int(i) for i in re.findall('\\d+', info) ]
|
||||
e2vDict.update(dict([(evList[0], evList[1:])]))
|
||||
while True:
|
||||
try:
|
||||
startEdge, startVtxs = e2vDict.popitem()
|
||||
except:
|
||||
break
|
||||
edgesGrp = [startEdge]
|
||||
num = 0
|
||||
for vtx in startVtxs:
|
||||
curVtx = vtx
|
||||
while True:
|
||||
|
||||
nextEdges = []
|
||||
for k in e2vDict:
|
||||
if curVtx in e2vDict[k]:
|
||||
nextEdges.append(k)
|
||||
if nextEdges:
|
||||
if len(nextEdges) == 1:
|
||||
if num == 0:
|
||||
edgesGrp.append(nextEdges[0])
|
||||
else:
|
||||
edgesGrp.insert(0, nextEdges[0])
|
||||
nextVtxs = e2vDict[nextEdges[0]]
|
||||
curVtx = [ vtx for vtx in nextVtxs if vtx != curVtx ][0]
|
||||
e2vDict.pop(nextEdges[0])
|
||||
else:
|
||||
break
|
||||
else:
|
||||
break
|
||||
num += 1
|
||||
fEdges.append(edgesGrp)
|
||||
retEdges =[]
|
||||
for f in fEdges:
|
||||
collectList=[]
|
||||
for x in f:
|
||||
getCom= (trans +".e["+ str(x) +"]")
|
||||
collectList.append(getCom)
|
||||
retEdges.append(collectList)
|
||||
return retEdges
|
||||
|
||||
run()
|
63
Scripts/Modeling/Select/IntervalSelectEdge.py
Normal file
63
Scripts/Modeling/Select/IntervalSelectEdge.py
Normal file
@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
|
||||
def select_edges():
|
||||
num_edges_selected = cmds.filterExpand(expand=True, selectionMask=32)
|
||||
size_components = len(num_edges_selected) if num_edges_selected else 0
|
||||
|
||||
if size_components == 0:
|
||||
cmds.error("Select at least one edge before running the script.")
|
||||
elif size_components == 1:
|
||||
mel.eval('polySelectEdgesEveryN "edgeRing" 2')
|
||||
print("1 cycle mode selected.")
|
||||
elif size_components == 2:
|
||||
mel.eval('polySelectEdgesEveryN "edgeRing" 4')
|
||||
print("2 cycle modes selected.")
|
||||
elif size_components == 3:
|
||||
mel.eval('polySelectEdgesEveryN "edgeRing" 6')
|
||||
print("3 cycle modes selected.")
|
||||
elif size_components == 4:
|
||||
mel.eval('polySelectEdgesEveryN "edgeRing" 8')
|
||||
print("4 cycle modes selected.")
|
||||
elif size_components == 5:
|
||||
mel.eval('polySelectEdgesEveryN "edgeRing" 10')
|
||||
print("5 cycle modes selected.")
|
||||
elif size_components == 6:
|
||||
mel.eval('polySelectEdgesEveryN "edgeRing" 12')
|
||||
print("6 cycle modes selected.")
|
||||
elif size_components == 7:
|
||||
mel.eval('polySelectEdgesEveryN "edgeRing" 14')
|
||||
print("7 cycle modes selected.")
|
||||
elif size_components == 8:
|
||||
mel.eval('polySelectEdgesEveryN "edgeRing" 16')
|
||||
print("8 cycle modes selected.")
|
||||
elif size_components > 8:
|
||||
cmds.error("Please select 8 or fewer edges.")
|
||||
|
||||
def create_select_edges_window():
|
||||
window_name = "IntervalSelectEdges"
|
||||
if cmds.window(window_name, exists=True):
|
||||
cmds.deleteUI(window_name, window=True)
|
||||
|
||||
window = cmds.window(window_name, title="Interval Select Edges", toolbox=True,
|
||||
widthHeight=(300, 150),
|
||||
sizeable=True,
|
||||
backgroundColor=(0.25, 0.25, 0.25))
|
||||
|
||||
main_layout = cmds.columnLayout(adjustableColumn=True)
|
||||
cmds.text(label="Select edge(s) and click Execute", height=50, width=250, parent=main_layout)
|
||||
cmds.button(label="Select", command=lambda x: select_edges(), width=250, height=30, backgroundColor=(0.53, 0.81, 0.98), parent=main_layout)
|
||||
|
||||
cmds.window(window, edit=True, widthHeight=(300, 150)) # Set the window size again after creating contents
|
||||
cmds.showWindow(window)
|
||||
|
||||
# Add a new function as the entry point for the module
|
||||
def show():
|
||||
create_select_edges_window()
|
||||
|
||||
# If the script is run directly (not imported as a module), show the window
|
||||
if __name__ == "__main__":
|
||||
show()
|
141
Scripts/Modeling/Select/SamePositionSelector.py
Normal file
141
Scripts/Modeling/Select/SamePositionSelector.py
Normal file
@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
|
||||
def save_setting():
|
||||
threshold = cmds.floatSliderGrp(SamePositionSelector_UI_Threshold_FS, q=True, v=True)
|
||||
check_bb = cmds.checkBox(SamePositionSelector_UI_CheckBB_CB, q=True, v=True)
|
||||
unselect = cmds.checkBox(SamePositionSelector_UI_UnselectBB_CB, q=True, v=True)
|
||||
cmds.optionVar(fv=("AriSamePositionS_Threshold", threshold))
|
||||
cmds.optionVar(iv=("AriSamePositionS_CheckBB", check_bb))
|
||||
cmds.optionVar(iv=("AriSamePositionS_Unselect", unselect))
|
||||
|
||||
def vector_much(val_a, val_b, gosa):
|
||||
return (val_a[0] <= val_b[0] + gosa and val_a[0] >= val_b[0] - gosa and
|
||||
val_a[1] <= val_b[1] + gosa and val_a[1] >= val_b[1] - gosa and
|
||||
val_a[2] <= val_b[2] + gosa and val_a[2] >= val_b[2] - gosa)
|
||||
|
||||
def check_bounding_box(object_list_name):
|
||||
gosa = cmds.floatSliderGrp(SamePositionSelector_UI_Threshold_FS, q=True, v=True)
|
||||
object_list_bb_min = [cmds.getAttr(obj + ".boundingBoxMin")[0] for obj in object_list_name]
|
||||
object_list_bb_max = [cmds.getAttr(obj + ".boundingBoxMax")[0] for obj in object_list_name]
|
||||
|
||||
same_obj_list = []
|
||||
for i in range(len(object_list_name)):
|
||||
bb_min_a, bb_max_a = object_list_bb_min[i], object_list_bb_max[i]
|
||||
local_counter = 0
|
||||
for j in range(i + 1, len(object_list_name)):
|
||||
if object_list_name[j] in same_obj_list:
|
||||
continue
|
||||
bb_min_b, bb_max_b = object_list_bb_min[j], object_list_bb_max[j]
|
||||
if vector_much(bb_min_a, bb_min_b, gosa) and vector_much(bb_max_a, bb_max_b, gosa):
|
||||
if local_counter == 0:
|
||||
same_obj_list.append(object_list_name[i])
|
||||
same_obj_list.append(object_list_name[j])
|
||||
local_counter += 1
|
||||
if local_counter != 0:
|
||||
same_obj_list.append(";")
|
||||
return same_obj_list
|
||||
|
||||
def select_list(obj_list):
|
||||
unselect_true = cmds.checkBox(SamePositionSelector_UI_UnselectBB_CB, q=True, v=True)
|
||||
first_true = unselect_true
|
||||
select_list = []
|
||||
for obj in obj_list:
|
||||
if obj != ";":
|
||||
if first_true:
|
||||
first_true = False
|
||||
continue
|
||||
select_list.append(obj)
|
||||
else:
|
||||
if unselect_true:
|
||||
first_true = True
|
||||
cmds.select(select_list)
|
||||
|
||||
def same_position_selector_select(*args):
|
||||
save_setting()
|
||||
bb_true = cmds.checkBox(SamePositionSelector_UI_CheckBB_CB, q=True, v=True)
|
||||
gosa = cmds.floatSliderGrp(SamePositionSelector_UI_Threshold_FS, q=True, v=True)
|
||||
object_list_name = cmds.ls(sl=True, tr=True)
|
||||
object_list_pos = [cmds.xform(obj, q=True, ws=True, piv=True)[:3] for obj in object_list_name]
|
||||
|
||||
same_obj_list = []
|
||||
for i in range(len(object_list_name)):
|
||||
pos_a = object_list_pos[i]
|
||||
local_counter = 0
|
||||
for j in range(i + 1, len(object_list_name)):
|
||||
if object_list_name[j] in same_obj_list:
|
||||
continue
|
||||
pos_b = object_list_pos[j]
|
||||
if vector_much(pos_a, pos_b, gosa):
|
||||
if local_counter == 0:
|
||||
same_obj_list.append(object_list_name[i])
|
||||
same_obj_list.append(object_list_name[j])
|
||||
local_counter += 1
|
||||
if local_counter != 0:
|
||||
same_obj_list.append(";")
|
||||
|
||||
if bb_true:
|
||||
same_bounding_box_list = []
|
||||
pair_list = []
|
||||
for obj in same_obj_list:
|
||||
if obj == ";":
|
||||
same_bounding_box_list.extend(check_bounding_box(pair_list))
|
||||
pair_list = []
|
||||
else:
|
||||
pair_list.append(obj)
|
||||
same_obj_list = same_bounding_box_list
|
||||
|
||||
select_list(same_obj_list)
|
||||
|
||||
def show():
|
||||
global SamePositionSelector_UI_Threshold_FS
|
||||
global SamePositionSelector_UI_CheckBB_CB
|
||||
global SamePositionSelector_UI_UnselectBB_CB
|
||||
|
||||
threshold = 0.01
|
||||
check_bb = True
|
||||
unselect = True
|
||||
|
||||
if cmds.optionVar(exists="AriSamePositionS_Threshold"):
|
||||
threshold = cmds.optionVar(q="AriSamePositionS_Threshold")
|
||||
if cmds.optionVar(exists="AriSamePositionS_CheckBB"):
|
||||
check_bb = cmds.optionVar(q="AriSamePositionS_CheckBB")
|
||||
if cmds.optionVar(exists="AriSamePositionS_Unselect"):
|
||||
unselect = cmds.optionVar(q="AriSamePositionS_Unselect")
|
||||
|
||||
window_name = "SamePositionSelector"
|
||||
if cmds.window(window_name, exists=True):
|
||||
cmds.deleteUI(window_name)
|
||||
|
||||
window = cmds.window(window_name, title="Same Position Selector", tlb=True,
|
||||
widthHeight=(300, 150), backgroundColor=(0.25, 0.25, 0.25),
|
||||
sizeable=True)
|
||||
|
||||
label_threshold = "Threshold"
|
||||
label_check_bb = "Check boundingbox"
|
||||
label_unselect = "Unselect first object"
|
||||
|
||||
main_layout = cmds.columnLayout(adjustableColumn=True)
|
||||
|
||||
cmds.rowLayout(numberOfColumns=2, columnWidth2=(80, 220), adjustableColumn=2, parent=main_layout)
|
||||
cmds.text(label=label_threshold)
|
||||
SamePositionSelector_UI_Threshold_FS = cmds.floatSliderGrp(field=True, minValue=0.0, maxValue=0.1, fieldMinValue=0.0, fieldMaxValue=1000, value=threshold, precision=6)
|
||||
cmds.setParent('..')
|
||||
|
||||
cmds.columnLayout(adjustableColumn=True, parent=main_layout)
|
||||
SamePositionSelector_UI_CheckBB_CB = cmds.checkBox(label=label_check_bb, value=check_bb)
|
||||
SamePositionSelector_UI_UnselectBB_CB = cmds.checkBox(label=label_unselect, value=unselect)
|
||||
cmds.setParent('..')
|
||||
|
||||
cmds.separator(height=10, style='in', parent=main_layout)
|
||||
|
||||
cmds.button(label="Select", command=same_position_selector_select, backgroundColor=(0.53, 0.81, 0.98), height=30, parent=main_layout)
|
||||
|
||||
cmds.window(window, edit=True, widthHeight=(300, 150))
|
||||
cmds.showWindow(window)
|
||||
|
||||
if __name__ == "__main__":
|
||||
show()
|
869
Scripts/Modeling/UV/RizomBridge/RizomUVBridge.py
Normal file
869
Scripts/Modeling/UV/RizomBridge/RizomUVBridge.py
Normal file
@ -0,0 +1,869 @@
|
||||
import os, platform, subprocess, sys
|
||||
|
||||
if sys.version_info.minor < 11:
|
||||
# Maya 2024 and earlier
|
||||
from PySide2 import QtGui
|
||||
from PySide2 import QtWidgets, QtCore
|
||||
from shiboken2 import wrapInstance
|
||||
else:
|
||||
# Maya 2025
|
||||
from PySide6 import QtGui
|
||||
from PySide6 import QtWidgets, QtCore
|
||||
from shiboken6 import wrapInstance
|
||||
|
||||
if sys.version_info.major == 3:
|
||||
# Python 3
|
||||
from . import scriptlist
|
||||
elif sys.version_info.major == 2:
|
||||
# Python 2
|
||||
import scriptlist
|
||||
|
||||
from maya.app.general.mayaMixin import MayaQWidgetDockableMixin
|
||||
|
||||
from maya import OpenMayaUI as omui
|
||||
import maya.OpenMaya as om
|
||||
|
||||
import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
import xml.dom.minidom as xml # For XML settings
|
||||
|
||||
DEBUG = False
|
||||
PRNT_STRING = "<RizomUV Bridge>"
|
||||
|
||||
# om.MGlobal.displayError('ERROR!')
|
||||
|
||||
class Settings():
|
||||
def __init__(self):
|
||||
self.config_path = os.path.join('%s/RizomBridge' % os.getenv('APPDATA'))
|
||||
config_file = 'uisettings.xml'
|
||||
|
||||
# TODO: Create a unique id for the lua script tied to the Maya instance.
|
||||
# rizom_script_path = tempfile.gettempdir() + os.sep + "MayaRizomBridgeScript.lua"
|
||||
rizom_script_path = os.path.join(self.config_path, "MayaRizomBridgeScript.lua")
|
||||
self.rizom_script_path = rizom_script_path.replace('\\', '/')
|
||||
|
||||
self.apppath = None
|
||||
self.config_file_path = os.path.join(self.config_path, config_file)
|
||||
self.check_config_exists(self.config_path)
|
||||
|
||||
try:
|
||||
self.read_settings()
|
||||
except:
|
||||
print("<RizomUV Bridge> Failed to read settings, creating new xml file.")
|
||||
self.set_defaults()
|
||||
self.save_xml()
|
||||
self.read_settings()
|
||||
|
||||
self.reset_export_path()
|
||||
|
||||
def reset_export_path(self):
|
||||
self.exportFile = os.path.join(self.config_path, self.objname)
|
||||
self.exportFile = self.exportFile.replace('\\', '/')
|
||||
|
||||
def read_settings(self):
|
||||
doc = xml.parse(self.config_file_path)
|
||||
|
||||
ui_app = doc.getElementsByTagName("Application")[0]
|
||||
self.apppath = ui_app.getAttribute("apppath")
|
||||
self.objname = ui_app.getAttribute("objname")
|
||||
self.upaxis = ui_app.getAttribute("upaxis")
|
||||
self.loaduvs = self.str_to_bool(ui_app.getAttribute("loaduvs"))
|
||||
self.useuvlink = self.str_to_bool(ui_app.getAttribute("useuvlink"))
|
||||
self.fixuvnames = self.str_to_bool(ui_app.getAttribute("fixuvnames"))
|
||||
self.usecustompath = self.str_to_bool(ui_app.getAttribute("usecustompath"))
|
||||
self.custompath = ui_app.getAttribute("custompath")
|
||||
|
||||
ui_packer = doc.getElementsByTagName("Packer")[0]
|
||||
self.quality = int(ui_packer.getAttribute("quality"))
|
||||
self.mutations = int(ui_packer.getAttribute("mutations"))
|
||||
self.margin = int(ui_packer.getAttribute("margin"))
|
||||
self.spacing = int(ui_packer.getAttribute("spacing"))
|
||||
self.resolution = int(ui_packer.getAttribute("resolution"))
|
||||
self.initscaleavg = self.str_to_bool(ui_packer.getAttribute("initscaleavg"))
|
||||
self.autofit = self.str_to_bool(ui_packer.getAttribute("autofit"))
|
||||
|
||||
def set_defaults(self):
|
||||
self.objname = "MayaRizomExport.fbx"
|
||||
self.upaxis = "Y"
|
||||
self.loaduvs = True
|
||||
self.useuvlink = True
|
||||
self.fixuvnames = False
|
||||
self.usecustompath = False
|
||||
self.custompath = ""
|
||||
|
||||
self.quality = 2
|
||||
self.mutations = 256
|
||||
self.margin = 2
|
||||
self.spacing = 2
|
||||
self.resolution = 1024
|
||||
self.initscaleavg = True
|
||||
self.autofit = True
|
||||
self.apppath = self.findall_rizom_installs()[-1]
|
||||
pass
|
||||
|
||||
def save_xml(self):
|
||||
print(PRNT_STRING, "Saving settings to disk: {}".format(self.config_file_path))
|
||||
doc = xml.Document()
|
||||
root_element = doc.createElement("RizomBridge")
|
||||
|
||||
element_application = doc.createElement("Application")
|
||||
element_application.setAttribute("apppath", str(self.apppath))
|
||||
element_application.setAttribute("objname", str(self.objname))
|
||||
element_application.setAttribute("upaxis", str(self.upaxis))
|
||||
element_application.setAttribute("loaduvs", str(self.loaduvs))
|
||||
element_application.setAttribute("useuvlink", str(self.useuvlink))
|
||||
element_application.setAttribute("fixuvnames", str(self.fixuvnames))
|
||||
element_application.setAttribute("usecustompath", str(self.usecustompath))
|
||||
element_application.setAttribute("custompath", str(self.custompath))
|
||||
|
||||
element_packer = doc.createElement("Packer")
|
||||
element_packer.setAttribute("quality", str(self.quality))
|
||||
element_packer.setAttribute("mutations", str(self.mutations))
|
||||
element_packer.setAttribute("margin", str(self.margin))
|
||||
element_packer.setAttribute("spacing", str(self.spacing))
|
||||
element_packer.setAttribute("resolution", str(self.resolution))
|
||||
element_packer.setAttribute("initscaleavg", str(self.initscaleavg))
|
||||
element_packer.setAttribute("autofit", str(self.autofit))
|
||||
|
||||
doc.appendChild(root_element)
|
||||
root_element.appendChild(element_application)
|
||||
root_element.appendChild(element_packer)
|
||||
doc.writexml(open(self.config_file_path, 'w'), indent=" ", addindent=" ", newl='\n')
|
||||
|
||||
def check_config_exists(self, config_path):
|
||||
print(PRNT_STRING, "Checking for config file:{}".format(self.config_file_path))
|
||||
|
||||
if not os.path.exists(config_path):
|
||||
os.makedirs(config_path)
|
||||
if not os.path.exists(self.config_file_path):
|
||||
print(PRNT_STRING, "Config not found.")
|
||||
self.set_defaults()
|
||||
self.save_xml()
|
||||
else:
|
||||
print(PRNT_STRING, "Config found.")
|
||||
|
||||
def findall_rizom_installs(self):
|
||||
""" Returns list of all rizom.exe in registry that exist on disk """
|
||||
try:
|
||||
import winreg
|
||||
except:
|
||||
self.manual_locate_rizom()
|
||||
return [self.apppath]
|
||||
|
||||
key_path = "SOFTWARE\\Rizom Lab\\"
|
||||
parent_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key_path)
|
||||
installs = []
|
||||
i = 0
|
||||
while i < 1000:
|
||||
try:
|
||||
key = winreg.EnumKey(parent_key, i)
|
||||
try:
|
||||
exe_path = winreg.QueryValue(winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key_path + key),
|
||||
"rizomuv.exe") + ".exe"
|
||||
except FileNotFoundError:
|
||||
exe_path = ""
|
||||
if os.path.exists(exe_path):
|
||||
installs.append(exe_path.replace("\\", "/"))
|
||||
|
||||
except WindowsError:
|
||||
break
|
||||
i += 1
|
||||
print (PRNT_STRING, "Found RizomUV installs in Windows Registry:")
|
||||
for inst in sorted(installs):
|
||||
print(" ..", inst)
|
||||
return sorted(installs)
|
||||
|
||||
def manual_locate_rizom(self):
|
||||
om.MGlobal.displayWarning("Could not locate rizomuv.exe: %s" % self.apppath)
|
||||
fname = QtWidgets.QFileDialog.getOpenFileName(None, 'Locate rizomuv.exe', 'C:/Program Files/Rizom Lab/', "Executable (*.exe)")
|
||||
|
||||
self.apppath = fname[0]
|
||||
self.appver = self.get_version()
|
||||
self.save_xml()
|
||||
|
||||
def get_version(self):
|
||||
""" Return version number as list as read from the folder name, eg. [2022, 2] """
|
||||
return os.path.dirname(self.apppath).split()[-1].split('.')
|
||||
|
||||
def check_lua_path(self):
|
||||
if not os.path.exists(self.rizom_script_path):
|
||||
with open(self.rizom_script_path, 'w') as f:
|
||||
if DEBUG: print(PRNT_STRING, "Creating blank lua file at", self.rizom_script_path)
|
||||
f.write('')
|
||||
|
||||
def str_to_bool(self, s):
|
||||
if s == 'True':
|
||||
return True
|
||||
else:
|
||||
# Return False for everything else, otherwise it might return None which will cause a crash.
|
||||
return False
|
||||
|
||||
|
||||
class RizomUVBridgeWindow(MayaQWidgetDockableMixin, QtWidgets.QDialog):
|
||||
def __init__(self, rootWidget=None, *args, **kwargs):
|
||||
super(RizomUVBridgeWindow, self).__init__()
|
||||
|
||||
"""
|
||||
if not os.path.exists(config_path):
|
||||
reset_config()
|
||||
if DEBUG: print("<RizomUV Bridge>", config_path)
|
||||
Config.read(config_path)
|
||||
"""
|
||||
self.conf = Settings()
|
||||
self.conf.check_lua_path()
|
||||
|
||||
# self.rizomPath = self.conf.apppath
|
||||
print("Rizom Path:", self.conf.apppath)
|
||||
self.setWindowTitle("Bridge")
|
||||
|
||||
self.sj_num_selchange = cmds.scriptJob(parent=self.objectName(), event=['SelectionChanged', self.ui_update_uvchannels])
|
||||
|
||||
# self.setMinimumSize(200, 300)
|
||||
self.resize(250, 300)
|
||||
|
||||
self.create_widgets()
|
||||
self.create_layouts()
|
||||
self.create_connections()
|
||||
self.validate_export_path()
|
||||
self.exported_objects = []
|
||||
self.ui_update_uvchannels()
|
||||
self.cleanse_namespaces()
|
||||
|
||||
if not os.path.exists(self.conf.apppath):
|
||||
self.conf.manual_locate_rizom()
|
||||
v = self.conf.get_version()
|
||||
self.btn_run.setText('Run RizomUV {}.{}'.format(v[0], v[1]))
|
||||
|
||||
rizom_link_path = os.path.dirname(self.conf.apppath) + '/RizomUVLink'
|
||||
self.port = None
|
||||
if rizom_link_path not in sys.path:
|
||||
sys.path.append(os.path.dirname(self.conf.apppath) + '/RizomUVLink')
|
||||
try:
|
||||
from RizomUVLink import CRizomUVLink
|
||||
self.link = CRizomUVLink()
|
||||
except:
|
||||
self.link = None
|
||||
|
||||
|
||||
# noinspection PyAttributeOutsideInit
|
||||
def create_widgets(self):
|
||||
v = ".".join(self.conf.get_version())
|
||||
self.btn_run = QtWidgets.QPushButton('Run RizomUV {}'.format(v), self)
|
||||
self.btn_export = QtWidgets.QPushButton('Export', self)
|
||||
self.btn_import = QtWidgets.QPushButton('Import', self)
|
||||
self.cbx_use_link = QtWidgets.QCheckBox('Attempt to use CRizomUVLink', self)
|
||||
self.cbx_use_link.setChecked(self.conf.useuvlink)
|
||||
self.cbx_fix_set_names = QtWidgets.QCheckBox('Fix UV set names on Import', self)
|
||||
self.cbx_fix_set_names.setChecked(self.conf.fixuvnames)
|
||||
self.cbx_custom_path = QtWidgets.QCheckBox('Use custom path for fbx', self)
|
||||
self.cbx_custom_path.setChecked(self.conf.usecustompath)
|
||||
self.field_custom_path = QtWidgets.QLineEdit("C:/")
|
||||
self.field_custom_path.setText(self.conf.custompath)
|
||||
|
||||
# Export settings widgets
|
||||
self.radioAxisY = QtWidgets.QRadioButton('Y')
|
||||
self.radioAxisZ = QtWidgets.QRadioButton('Z')
|
||||
if self.conf.upaxis == 'Y':
|
||||
self.radioAxisY.setChecked(True)
|
||||
else:
|
||||
self.radioAxisZ.setChecked(True)
|
||||
|
||||
self.cbx_keepuv = QtWidgets.QCheckBox('Load Existing UVs', self)
|
||||
self.cbx_keepuv.setChecked(self.conf.loaduvs)
|
||||
|
||||
self.combo_scripts = QtWidgets.QComboBox(self)
|
||||
self.combo_scripts.addItem("No Script")
|
||||
for s in scriptlist.scripts:
|
||||
self.combo_scripts.addItem(s[1])
|
||||
|
||||
# Utilities widgets
|
||||
self.btn_fix_shell_normals = QtWidgets.QPushButton('Set UV border edges to Hard')
|
||||
self.btn_edit_settings = QtWidgets.QPushButton('Open settings folder')
|
||||
|
||||
self.combo_pack_uvset = QtWidgets.QComboBox(self)
|
||||
#
|
||||
self.btn_pack = QtWidgets.QPushButton('Export and Pack UVs', self)
|
||||
self.combo_pack_quality = QtWidgets.QComboBox(self)
|
||||
self.combo_pack_quality.addItems(['Low', 'Normal', 'High', 'Higher', 'Ultra'])
|
||||
self.combo_pack_quality.setCurrentIndex(self.conf.quality)
|
||||
#
|
||||
self.slider_pack_uvmap = QtWidgets.QSlider(QtCore.Qt.Orientation(1))
|
||||
self.slider_pack_uvmap.setMinimum(0)
|
||||
self.slider_pack_uvmap.setMaximum(5)
|
||||
self.slider_pack_uvmap.setValue(1)
|
||||
|
||||
self.label_uvmap = QtWidgets.QLabel("1")
|
||||
|
||||
self.dspin_pack_mutations = QtWidgets.QSpinBox()
|
||||
self.dspin_pack_mutations.setSingleStep(1)
|
||||
self.dspin_pack_mutations.setRange(1, 1000)
|
||||
self.dspin_pack_mutations.setWrapping(False)
|
||||
self.dspin_pack_mutations.setValue(self.conf.mutations)
|
||||
#
|
||||
self.dspin_pack_resolution = QtWidgets.QSpinBox()
|
||||
self.dspin_pack_resolution.setSingleStep(8)
|
||||
self.dspin_pack_resolution.setRange(8, 8192)
|
||||
self.dspin_pack_resolution.setWrapping(False)
|
||||
self.dspin_pack_resolution.setValue(self.conf.resolution)
|
||||
#
|
||||
self.dspin_pack_margin = QtWidgets.QSpinBox()
|
||||
self.dspin_pack_margin.setSingleStep(1)
|
||||
self.dspin_pack_margin.setWrapping(False)
|
||||
self.dspin_pack_margin.setValue(self.conf.margin)
|
||||
#
|
||||
self.dspin_pack_spacing = QtWidgets.QSpinBox()
|
||||
self.dspin_pack_spacing.setSingleStep(1)
|
||||
self.dspin_pack_spacing.setWrapping(False)
|
||||
self.dspin_pack_spacing.setValue(self.conf.spacing)
|
||||
#
|
||||
self.cbx_initial_scale_avg = QtWidgets.QCheckBox("Use 'Avarage' Initial Scale", self)
|
||||
self.cbx_initial_scale_avg.setChecked(self.conf.initscaleavg)
|
||||
#
|
||||
self.cbx_layout_scaling = QtWidgets.QCheckBox("Layout: Auto Fit", self)
|
||||
self.cbx_layout_scaling.setChecked(self.conf.autofit)
|
||||
|
||||
pass
|
||||
|
||||
# noinspection PyAttributeOutsideInit
|
||||
def create_layouts(self):
|
||||
main_layout = QtWidgets.QVBoxLayout(self)
|
||||
|
||||
grp_layout = QtWidgets.QVBoxLayout()
|
||||
grp_layout.addWidget(self.btn_run)
|
||||
grp_layout.addWidget(self.btn_export)
|
||||
grp_layout.addWidget(self.btn_import)
|
||||
grp_layout.addWidget(self.cbx_use_link)
|
||||
grp_layout.addWidget(self.cbx_fix_set_names)
|
||||
#hor_layout = QtWidgets.QHBoxLayout()
|
||||
grp_layout.addWidget(self.cbx_custom_path)
|
||||
grp_layout.addWidget(self.field_custom_path)
|
||||
#grp_layout.addLayout(hor_layout)
|
||||
|
||||
# grp_layout.addWidget(self.btn_edit)
|
||||
grp = QtWidgets.QGroupBox("UV Operations")
|
||||
grp.setLayout(grp_layout)
|
||||
main_layout.addWidget(grp)
|
||||
|
||||
# Export Settings
|
||||
grp_layout = QtWidgets.QVBoxLayout()
|
||||
grp_layout.addWidget(self.cbx_keepuv)
|
||||
|
||||
hor_layout = QtWidgets.QHBoxLayout()
|
||||
hor_layout.addWidget(QtWidgets.QLabel("Scripts"))
|
||||
hor_layout.addWidget(self.combo_scripts)
|
||||
grp_layout.addLayout(hor_layout)
|
||||
|
||||
hor_layout = QtWidgets.QHBoxLayout()
|
||||
hor_layout.addWidget(QtWidgets.QLabel("Up Axis"))
|
||||
hor_layout.addWidget(self.radioAxisY)
|
||||
hor_layout.addWidget(self.radioAxisZ)
|
||||
grp_layout.addLayout(hor_layout)
|
||||
|
||||
grp = QtWidgets.QGroupBox("Export Settings")
|
||||
grp.setLayout(grp_layout)
|
||||
main_layout.addWidget(grp)
|
||||
|
||||
# Utilites
|
||||
grp_layout = QtWidgets.QVBoxLayout()
|
||||
grp_layout.addWidget(self.btn_fix_shell_normals)
|
||||
grp_layout.addWidget(self.btn_edit_settings)
|
||||
# hor_layout = QtWidgets.QHBoxLayout()
|
||||
# hor_layout.addWidget(self.btn_uvl_edges)
|
||||
# grp_layout.addLayout(hor_layout)
|
||||
|
||||
grp = QtWidgets.QGroupBox("Utilities")
|
||||
grp.setLayout(grp_layout)
|
||||
main_layout.addWidget(grp)
|
||||
|
||||
# UV Packer
|
||||
grp_layout = QtWidgets.QVBoxLayout()
|
||||
grp = QtWidgets.QGroupBox("UV Packer")
|
||||
|
||||
hor_layout = QtWidgets.QHBoxLayout()
|
||||
hor_layout.addWidget(self.btn_pack)
|
||||
grp_layout.addLayout(hor_layout)
|
||||
|
||||
hor_layout = QtWidgets.QHBoxLayout()
|
||||
hor_layout.addWidget(QtWidgets.QLabel("UV Set to pack"))
|
||||
hor_layout.addWidget(self.combo_pack_uvset)
|
||||
grp_layout.addLayout(hor_layout)
|
||||
|
||||
hor_layout = QtWidgets.QHBoxLayout()
|
||||
hor_layout.addWidget(QtWidgets.QLabel("Packing Quality"))
|
||||
hor_layout.addWidget(self.combo_pack_quality)
|
||||
grp_layout.addLayout(hor_layout)
|
||||
|
||||
hor_layout = QtWidgets.QHBoxLayout()
|
||||
hor_layout.addWidget(QtWidgets.QLabel("Mutations"))
|
||||
hor_layout.addWidget(self.dspin_pack_mutations)
|
||||
hor_layout.addWidget(QtWidgets.QLabel("Resolution"))
|
||||
hor_layout.addWidget(self.dspin_pack_resolution)
|
||||
grp_layout.addLayout(hor_layout)
|
||||
|
||||
hor_layout = QtWidgets.QHBoxLayout()
|
||||
hor_layout.addWidget(QtWidgets.QLabel("Margin"))
|
||||
hor_layout.addWidget(self.dspin_pack_margin)
|
||||
hor_layout.addWidget(QtWidgets.QLabel("Spacing"))
|
||||
hor_layout.addWidget(self.dspin_pack_spacing)
|
||||
grp_layout.addLayout(hor_layout)
|
||||
|
||||
hor_layout = QtWidgets.QHBoxLayout()
|
||||
hor_layout.addWidget(self.cbx_initial_scale_avg)
|
||||
grp_layout.addLayout(hor_layout)
|
||||
hor_layout = QtWidgets.QHBoxLayout()
|
||||
hor_layout.addWidget(self.cbx_layout_scaling)
|
||||
grp_layout.addLayout(hor_layout)
|
||||
|
||||
grp_layout.addStretch()
|
||||
grp.setLayout(grp_layout)
|
||||
main_layout.addWidget(grp)
|
||||
pass
|
||||
|
||||
def create_connections(self):
|
||||
self.btn_run.clicked.connect(self.riz_run)
|
||||
self.btn_export.clicked.connect(self.riz_export)
|
||||
self.btn_import.clicked.connect(self.riz_import)
|
||||
self.btn_fix_shell_normals.clicked.connect(fix_shell_border_normals)
|
||||
self.btn_edit_settings.clicked.connect(self.browse_settings_location)
|
||||
self.cbx_custom_path.stateChanged.connect(self.validate_export_path)
|
||||
self.field_custom_path.textEdited.connect(self.validate_export_path)
|
||||
|
||||
self.cbx_keepuv.stateChanged.connect(self.set_config)
|
||||
self.slider_pack_uvmap.valueChanged.connect(self.ui_pack_update_labels)
|
||||
|
||||
self.radioAxisY.clicked.connect(self.set_config)
|
||||
self.radioAxisZ.clicked.connect(self.set_config)
|
||||
# self.combo_scripts.currentIndexChanged.connect(self.ui_toggle_roundtrip_option)
|
||||
|
||||
self.dspin_pack_mutations.valueChanged.connect(self.set_config)
|
||||
self.dspin_pack_resolution.valueChanged.connect(self.set_config)
|
||||
self.dspin_pack_margin.valueChanged.connect(self.set_config)
|
||||
self.dspin_pack_spacing.valueChanged.connect(self.set_config)
|
||||
self.cbx_layout_scaling.stateChanged.connect(self.set_config)
|
||||
self.cbx_use_link.stateChanged.connect(self.set_config)
|
||||
self.cbx_fix_set_names.stateChanged.connect(self.set_config)
|
||||
|
||||
self.btn_pack.clicked.connect(self.riz_pack)
|
||||
return
|
||||
|
||||
def riz_run(self):
|
||||
# Confirm application path
|
||||
if not os.path.exists(self.conf.apppath):
|
||||
self.manual_locate_rizom()
|
||||
|
||||
if self.link and self.cbx_use_link.isChecked():
|
||||
self.port = self.link.RunRizomUV()
|
||||
print(f"{PRNT_STRING} RizomUV {self.link.RizomUVVersion()} link established. Now listening to commands on TCP port: {str(self.port)}")
|
||||
|
||||
# Enable UI relevant only for RizomUV Link
|
||||
# self.btn_uvl_edges.setEnabled(True)
|
||||
# self.btn_uvl_edges.setStyleSheet("background-color: {}; color: white".format("#ef4000"))
|
||||
else:
|
||||
# Use original method if link is not working.
|
||||
print(PRNT_STRING, "RizomUV link not available. Communicating using LUA script file.")
|
||||
cmd = '"' + self.conf.apppath + '" -cf "' + self.conf.rizom_script_path + '"'
|
||||
print(cmd)
|
||||
|
||||
if platform.system() == "Windows":
|
||||
self.sp = subprocess.Popen(cmd, shell=True)
|
||||
else:
|
||||
self.sp = subprocess.Popen(["open", "-a", self.conf.apppath, "-cf", self.conf.rizom_script_path])
|
||||
|
||||
self.btn_export.setEnabled(True)
|
||||
return
|
||||
|
||||
def riz_pack(self):
|
||||
# Export model with no script loaded,
|
||||
# Also tell Rizom not to load the model in the riz_export function
|
||||
# because it sometimes does not have time to load before we overwrite the lua file with these commands.
|
||||
current_uv = self.combo_pack_uvset.currentText()
|
||||
# current_uv_index = self.combo_pack_uvset.currentIndex()
|
||||
|
||||
exported = self.riz_export(False, False)
|
||||
if not exported:
|
||||
return
|
||||
|
||||
# Construct LUA code from GUI options
|
||||
cmd = ''
|
||||
# Common repeated text chunk
|
||||
cmd_properties_prefix = 'ZomIslandGroups({Mode="SetGroupsProperties", WorkingSet="Visible", MergingPolicyString="A_ADD|AIB_ADD_A_VALUE_B|B_CLONE", GroupPaths={ "RootGroup" }, '
|
||||
|
||||
# Load model
|
||||
cmd += 'ZomLoad({File={Path="'+self.conf.exportFile+'", ImportGroups=true, XYZUVW=true, UVWProps=true}})\n'
|
||||
|
||||
# cmd += 'ZomUvset({Mode="SetCurrent", Name="Channel%s"})\n' % str(self.label_uvmap.text())
|
||||
cmd += 'ZomUvset({Mode="SetCurrent", Name="%s"})\n' % current_uv
|
||||
# cmd += 'ZomSet({Path = "Vars.Viewport.ViewportUV.WorkingSet", Value = "Visible&Flat"})\n'
|
||||
|
||||
# cmd += 'ZomSet({Path="Prefs.PackOptions.MapResolution", Value=%i})\n' % self.dspin_pack_resolution.value()
|
||||
cmd += cmd_properties_prefix + 'Properties={Pack={Rotate={Step=90}}}})\n'
|
||||
cmd += cmd_properties_prefix + 'Properties={Pack={Rotate={Mode=0}}}})\n'
|
||||
|
||||
margin = float(self.dspin_pack_margin.value()) / self.dspin_pack_resolution.value()
|
||||
spacing = float(self.dspin_pack_spacing.value()) / self.dspin_pack_resolution.value()
|
||||
cmd += cmd_properties_prefix + 'Properties={Pack={SpacingSize=%f}}})\n' % spacing
|
||||
cmd += cmd_properties_prefix + 'Properties={Pack={MarginSize=%f}}})\n' % margin
|
||||
|
||||
quality = [128, 256, 512, 1024, 2048]
|
||||
cmd += cmd_properties_prefix + 'Properties={Pack={Resolution=%i}}})\n' % quality[self.combo_pack_quality.currentIndex()]
|
||||
cmd += cmd_properties_prefix + 'Properties={Pack={MaxMutations=%i}}})\n' % self.dspin_pack_mutations.value()
|
||||
|
||||
init_scale = 0
|
||||
if self.cbx_initial_scale_avg.isChecked():
|
||||
init_scale = 2
|
||||
|
||||
layout_scale = 0
|
||||
if self.cbx_layout_scaling.isChecked():
|
||||
layout_scale = 2
|
||||
|
||||
cmd += 'ZomSet({Path="Prefs.PackOptions.__ScalingMode", Value=%i})\n' % init_scale
|
||||
cmd += 'ZomSave({File={Path="c:/users/root/appdata/local/temp/MayaRizomExport.fbx", UVWProps=true}, __UpdateUIObjFileName=true})\n'
|
||||
|
||||
cmd += 'ZomIslandGroups({Mode="DistributeInTilesEvenly", WorkingSet="Visible&Flat", MergingPolicyString="A_ADD|AIB_ADD_A_VALUE_B|B_CLONE", UseTileLocks=true, UseIslandLocks=true})\n'
|
||||
cmd += 'ZomPack({RootGroup="RootGroup", WorkingSet="Visible&Flat", ProcessTileSelection=false, RecursionDepth=1, Translate=true, LayoutScalingMode=%i, Scaling={Mode=%i}})\n' % (layout_scale, init_scale)
|
||||
|
||||
if DEBUG:
|
||||
print(cmd)
|
||||
self.write_to_lua_file(cmd)
|
||||
return
|
||||
|
||||
def fbx_export(self):
|
||||
# FBX Export
|
||||
if not cmds.pluginInfo("fbxmaya", loaded=True, query=True):
|
||||
cmds.loadPlugin("fbxmaya")
|
||||
|
||||
cmds.undoInfo(openChunk=True)
|
||||
mel.eval('ConvertInstanceToObject;') # This is the only command that is important to undo.
|
||||
mel.eval('FBXExportSmoothingGroups -v true;')
|
||||
mel.eval('FBXExportTriangulate -v false;')
|
||||
mel.eval('FBXExportSmoothMesh -v false;')
|
||||
mel.eval('FBXExportUpAxis {};'.format(self.conf.upaxis))
|
||||
print('FBXExport -s -f "{}";'.format(self.conf.exportFile))
|
||||
mel.eval('FBXExport -s -f "{}";'.format(self.conf.exportFile))
|
||||
try:
|
||||
cmds.undo()
|
||||
except RuntimeError as RE:
|
||||
# There are no more commands to undo
|
||||
pass
|
||||
|
||||
# End FBX Export
|
||||
return
|
||||
|
||||
def riz_export(self, use_script=True, load_model=True):
|
||||
# displaySmoothness -divisionsU 0
|
||||
self.exported_objects = cmds.ls(selection=True, tr=True)
|
||||
|
||||
# Exit preview smooth, because the FBXExportSmoothMesh option is not always respected by the exporter.
|
||||
cmds.displaySmoothness(du=0, dv=0, pw=4, ps=0, po=1)
|
||||
|
||||
if self.cbx_custom_path.isChecked() and not self.field_custom_path.text() == self.conf.custompath:
|
||||
self.set_config()
|
||||
|
||||
if self.link and self.cbx_use_link.isChecked():
|
||||
print("Rizom Link version", self.link.Version())
|
||||
|
||||
# FBX Export
|
||||
self.fbx_export()
|
||||
if not self.port:
|
||||
self.riz_run()
|
||||
|
||||
params = {
|
||||
"File.Path": self.conf.exportFile,
|
||||
"File.XYZUVW": True, # 3D + UV data loaded (use File.XYZ instead to load 3D data only)
|
||||
"File.UVWProps": True, # UVs properties such as pinning, texel density settings etc... will be loaded
|
||||
"File.ImportGroups": True, # Island group hierarchy will be loaded
|
||||
"__Focus": True, # Focus viewports on the loaded mesh
|
||||
# "Data.UseImportedUVWPolygons": False,
|
||||
}
|
||||
|
||||
self.link.Load(params)
|
||||
|
||||
if DEBUG: print(f"{PRNT_STRING} EXPORTED TO:", self.conf.exportFile)
|
||||
cmds.select(self.exported_objects)
|
||||
|
||||
# Enable import button if it was disabled.
|
||||
self.btn_import.setEnabled(True)
|
||||
else:
|
||||
# Classic Method #
|
||||
print(f"{PRNT_STRING} Exporting model")
|
||||
self.cleanse_namespaces() # Agressive cleanse
|
||||
if not self.exported_objects:
|
||||
return False
|
||||
|
||||
# Delete history in case their are empty groups that would be removed by this action.
|
||||
# Otherwise they would be cleared during import and we have an object count missmatch.
|
||||
cmds.bakePartialHistory()
|
||||
cmd = ''
|
||||
|
||||
# Export Options
|
||||
if load_model:
|
||||
if self.cbx_keepuv.isChecked():
|
||||
cmd += 'ZomLoad({File={Path="'+self.conf.exportFile+'", ImportGroups=true, XYZUVW=true, UVWProps=true}})\n'
|
||||
else:
|
||||
cmd += 'ZomLoad({File={Path="'+self.conf.exportFile+'", ImportGroups=true, XYZ=true}, NormalizeUVW=true})\n'
|
||||
|
||||
# Add scripts
|
||||
if self.combo_scripts.currentIndex() and use_script is True:
|
||||
script_name = scriptlist.scripts[self.combo_scripts.currentIndex()-1][0]
|
||||
script_path = os.path.join(os.path.dirname(__file__), 'lua_scripts/%s' % script_name)
|
||||
with open(script_path, 'r') as lua_script:
|
||||
cmd += lua_script.read()
|
||||
|
||||
if DEBUG: print(f"{PRNT_STRING} {cmd}")
|
||||
|
||||
# FBX Export
|
||||
self.fbx_export()
|
||||
|
||||
if DEBUG: print(f"{PRNT_STRING} EXPORTED TO: {self.conf.exportFile}")
|
||||
cmds.select(self.exported_objects)
|
||||
|
||||
self.write_to_lua_file(cmd)
|
||||
self.btn_import.setEnabled(True)
|
||||
return True
|
||||
|
||||
def riz_import(self):
|
||||
if not os.path.exists(self.conf.exportFile):
|
||||
om.MGlobal.displayError("Could not locate exported file: %s" % self.conf.exportFile)
|
||||
self.btn_import.setEnabled(False)
|
||||
|
||||
if self.cbx_use_link.isChecked():
|
||||
if self.link:
|
||||
try:
|
||||
self.link.Save({"File.Path": self.conf.exportFile})
|
||||
except RuntimeError as RE:
|
||||
cmds.error('Could not send Save command to Rizom over Python Link. Was it enabled when you exported?')
|
||||
|
||||
# FBX Import
|
||||
namespace = ':RIZOMUV'
|
||||
if not cmds.namespace(ex=namespace):
|
||||
cmds.namespace(add=namespace)
|
||||
cmds.namespace(set=namespace)
|
||||
|
||||
mel.eval('FBXImportMode -v add;')
|
||||
mel.eval('FBXImport -f "{}";'.format(self.conf.exportFile))
|
||||
# END FBX Import
|
||||
|
||||
imported_objects = cmds.ls('RIZOMUV:*', long=True, type="transform")
|
||||
original_matches = []
|
||||
for riz_obj in imported_objects:
|
||||
print ("Imported object name", riz_obj)
|
||||
original = riz_obj.replace('RIZOMUV:', '')
|
||||
original_matches.append(original)
|
||||
|
||||
# List UV sets of each item, skip if it has none. This is simply to exclude objects like group nodes.
|
||||
original_uvsets = cmds.polyUVSet(original, allUVSets=True, q=True)
|
||||
if not original_uvsets:
|
||||
print(f"Object {riz_obj} has no UVSets. Will not attempt UV Transfer")
|
||||
continue
|
||||
|
||||
imported_uvsets = cmds.polyUVSet(riz_obj, allUVSets=True, q=True)
|
||||
|
||||
if original_uvsets:
|
||||
# Check names #
|
||||
if self.cbx_fix_set_names.isChecked():
|
||||
for i in range(len(original_uvsets)):
|
||||
try:
|
||||
if not original_uvsets[i] == imported_uvsets[i]:
|
||||
cmds.polyUVSet(riz_obj, rename=True, uvSet=imported_uvsets[i], newUVSet=original_uvsets[i])
|
||||
except IndexError:
|
||||
# This can happen due to a weird Maya bug that I don't understand where the object has more
|
||||
# uvSets listed with the polyUVSet comman, than it has in the UV Set Editor
|
||||
print ("UV Set Index Error. Objects don't seem to have the same amount of UV sets")
|
||||
print("Original UV Sets:", original_uvsets, original)
|
||||
print("Imported UV Sets:", imported_uvsets, riz_obj)
|
||||
pass
|
||||
try:
|
||||
#cmds.polyTransfer(original, ao=riz_obj, ch=False, uv=True)
|
||||
cmds.polyTransfer(original, ao=riz_obj, ch=False, vc=False, v=False, uv=True)
|
||||
except RuntimeError as rt:
|
||||
print ("<RizomUV Bridge> Could not transfer UVs from", riz_obj, "to", original)
|
||||
if DEBUG: print ("<RizomUV Bridge> Transfering UVs from", riz_obj, "to", original)
|
||||
|
||||
cmds.select(original_matches)
|
||||
cmds.bakePartialHistory()
|
||||
cmds.delete(':RIZOMUV:*')
|
||||
cmds.namespace(rm=':RIZOMUV')
|
||||
|
||||
return
|
||||
|
||||
def riz_link(self):
|
||||
"""
|
||||
Establishes link with RizomUV. Even though this is just a single line, I want it in a function to refresh UI.
|
||||
"""
|
||||
pass
|
||||
|
||||
def browse_settings_location(self):
|
||||
os.startfile(os.path.dirname(self.conf.config_file_path))
|
||||
|
||||
def ui_pack_update_labels(self):
|
||||
print("Value changed")
|
||||
self.label_uvmap.setText(str(self.slider_pack_uvmap.value()))
|
||||
|
||||
def ui_update_uvchannels(self):
|
||||
sel_obj = cmds.ls(sl=True, tr=True)
|
||||
if not sel_obj:
|
||||
self.combo_pack_uvset.clear()
|
||||
return
|
||||
|
||||
uvsets = cmds.polyUVSet(sel_obj[0], allUVSets=True, q=True)
|
||||
current_set = cmds.polyUVSet(sel_obj[0], cuv=True, q=True)
|
||||
if uvsets:
|
||||
print (uvsets)
|
||||
self.combo_pack_uvset.clear()
|
||||
self.combo_pack_uvset.addItems(uvsets)
|
||||
self.combo_pack_uvset.setCurrentIndex(uvsets.index(current_set[0]))
|
||||
|
||||
def validate_export_path(self):
|
||||
if self.cbx_custom_path.isChecked():
|
||||
if not os.path.exists(self.field_custom_path.text()):
|
||||
self.btn_import.setEnabled(False)
|
||||
self.btn_export.setEnabled(False)
|
||||
self.field_custom_path.setStyleSheet("color: red")
|
||||
return
|
||||
else:
|
||||
self.conf.exportFile = os.path.join(self.conf.custompath, self.conf.objname)
|
||||
self.btn_import.setEnabled(True)
|
||||
self.btn_export.setEnabled(True)
|
||||
self.field_custom_path.setStyleSheet("color: white")
|
||||
else:
|
||||
self.conf.reset_export_path()
|
||||
self.field_custom_path.setStyleSheet("color: grey")
|
||||
self.btn_import.setEnabled(True)
|
||||
self.btn_export.setEnabled(True)
|
||||
|
||||
print(self.conf.exportFile)
|
||||
|
||||
def cleanse_namespaces(self):
|
||||
""" Step One --
|
||||
Try to delete all existing RIZOMUV namespaces until it fails, this should get rid of stacked instances like
|
||||
RIZOMUV:RIZOMUV:RIZOMUV
|
||||
"""
|
||||
fail = False
|
||||
while(not fail):
|
||||
try:
|
||||
cmds.namespace(rm=':RIZOMUV', mnr=True)
|
||||
except:
|
||||
fail = True
|
||||
|
||||
""" Step Two --
|
||||
In one scene I got the namespaces had gotten renamed to RIZOMUV1, RIZOMUV2, RIZOMUV3 etc
|
||||
so this finds any leftoverrs and deletes them.
|
||||
"""
|
||||
# existing_ns = cmds.namespaceInfo(listNamespace=True, listOnlyNamespaces=True)
|
||||
# for entry in existing_ns:
|
||||
# if 'RIZOMUV' in entry:
|
||||
# cmds.namespace(rm=entry, mnr=True)
|
||||
#
|
||||
# return
|
||||
|
||||
""" Step Two, updated --
|
||||
Let's try to remove other namespaces than simply RIZOM as having others can prevent the import from working
|
||||
"""
|
||||
c = cmds.listRelatives(ad=True)
|
||||
if not c:
|
||||
return
|
||||
|
||||
for obj in c:
|
||||
ns_split = obj.split(':')
|
||||
if len(ns_split)>1:
|
||||
result = cmds.confirmDialog(m="Selected objects have namespaces assigned. \n"
|
||||
"These must go before you can use the tool correctly\n"
|
||||
"Should I delete them for you? (Including on unselected objects)\n\n"
|
||||
"Namespace on object: \n%s" % ns_split[0], button=['Remove', 'Cancel'])
|
||||
if result == 'Remove':
|
||||
cmds.namespace(rm=ns_split[0], mnr=True)
|
||||
else:
|
||||
return
|
||||
return
|
||||
|
||||
def write_to_lua_file(self, command):
|
||||
with open(self.conf.rizom_script_path, 'w') as f:
|
||||
f.write(command)
|
||||
print("<RIZOM> Wrote command to lua file:", self.conf.rizom_script_path)
|
||||
for line in command.split("\n"):
|
||||
print("\t", line)
|
||||
return
|
||||
|
||||
def set_config(self):
|
||||
self.conf.loaduvs = self.cbx_keepuv.isChecked()
|
||||
|
||||
if self.radioAxisY.isChecked():
|
||||
self.conf.upaxis = "Y"
|
||||
else:
|
||||
self.conf.upaxis = "Z"
|
||||
|
||||
self.conf.mutations = self.dspin_pack_mutations.value()
|
||||
self.conf.resolution = self.dspin_pack_resolution.value()
|
||||
self.conf.margin = self.dspin_pack_margin.value()
|
||||
self.conf.spacing = self.dspin_pack_spacing.value()
|
||||
self.conf.autofit = self.cbx_layout_scaling.isChecked()
|
||||
self.conf.fixuvnames = self.cbx_fix_set_names.isChecked()
|
||||
self.conf.useuvlink = self.cbx_use_link.isChecked()
|
||||
self.conf.usecustompath = self.cbx_custom_path.isChecked()
|
||||
self.conf.custompath = self.field_custom_path.text()
|
||||
|
||||
self.conf.save_xml()
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.conf.save_xml()
|
||||
|
||||
|
||||
def GetMayaWidget():
|
||||
"""
|
||||
Return the Maya main window widget as a Python object
|
||||
"""
|
||||
main_window_ptr = omui.MQtUtil.mainWindow()
|
||||
if sys.version_info.major >= 3:
|
||||
return wrapInstance(int(main_window_ptr), QtWidgets.QWidget)
|
||||
else:
|
||||
return wrapInstance(long(main_window_ptr), QtWidgets.QWidget)
|
||||
|
||||
|
||||
def fix_shell_border_normals():
|
||||
obj_list = cmds.ls(sl=True, o=True)
|
||||
all_final_borders = []
|
||||
|
||||
for sub_obj in obj_list:
|
||||
cmds.select(sub_obj, r=True)
|
||||
|
||||
cmds.polyNormalPerVertex(ufn=True)
|
||||
cmds.polySoftEdge(sub_obj, a=180, ch=1)
|
||||
print("Soften all")
|
||||
|
||||
# Select object UVs
|
||||
cmds.select(sub_obj + '.map[*]')
|
||||
mel.eval('polySelectBorderShell 1;')
|
||||
uv_border = cmds.polyListComponentConversion(te=True, internal=True)
|
||||
uv_border = cmds.ls(uv_border, fl=True)
|
||||
final_border = []
|
||||
|
||||
# Magical filter
|
||||
for curEdge in uv_border:
|
||||
edge_uvs = cmds.polyListComponentConversion(curEdge, tuv=True)
|
||||
edge_uvs = cmds.ls(edge_uvs, fl=True)
|
||||
|
||||
if len(edge_uvs) > 2:
|
||||
final_border.append(curEdge)
|
||||
|
||||
cmds.polySoftEdge(final_border, a=0, ch=1)
|
||||
all_final_borders.append(final_border)
|
||||
|
||||
cmds.select(cl=True)
|
||||
for sel_l in all_final_borders:
|
||||
cmds.select(sel_l, add=True)
|
||||
cmds.hilite(obj_list)
|
||||
|
||||
def run():
|
||||
scriptJobs = cmds.scriptJob(listJobs=True)
|
||||
for sj in scriptJobs:
|
||||
if "RizomBridge" in sj:
|
||||
print(PRNT_STRING, "Killing preexisting scriptJob:", sj)
|
||||
cmds.scriptJob(kill=int(sj.split(':')[0]))
|
||||
|
||||
d = RizomUVBridgeWindow()
|
||||
d.show(dockable=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
|
4
Scripts/Modeling/UV/RizomBridge/__init__.py
Normal file
4
Scripts/Modeling/UV/RizomBridge/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import *
|
4
Scripts/Modeling/UV/RizomBridge/lua_scripts/__init__.py
Normal file
4
Scripts/Modeling/UV/RizomBridge/lua_scripts/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import *
|
1
Scripts/Modeling/UV/RizomBridge/lua_scripts/blank.lua
Normal file
1
Scripts/Modeling/UV/RizomBridge/lua_scripts/blank.lua
Normal file
@ -0,0 +1 @@
|
||||
ZomSet({Path="Prefs.FileSuffix", Value=""})
|
@ -0,0 +1,6 @@
|
||||
ZomSelect({PrimType="Edge", WorkingSet="Visible", Select=true, ResetBefore=true, ProtectMapName="Protect", FilterIslandVisible=true, Auto={Box={ActiveEdges={ "XPYP", "XPZP", "XPYM", "XPZM", "YPZP", "YMZP", "YMZM", "YPZM", "XMYP", "XMZP", "XMYM", "XMZM" }}, HandleCutter=true, StoreCoordsUVW=true, FlatteningMode=0, FlatteningUnfoldParams={Iterations=1, BorderIntersections=true, TriangleFlips=true}}})
|
||||
ZomCut({PrimType="Edge", WorkingSet="Visible"})
|
||||
ZomLoad({Data={CoordsUVWInternalPath="Mesh.Tmp.AutoSelect.UVW"}})
|
||||
ZomIslandGroups({Mode="DistributeInTilesByBBox", WorkingSet="Visible", MergingPolicy=8322})
|
||||
ZomIslandGroups({Mode="DistributeInTilesEvenly", WorkingSet="Visible", MergingPolicy=8322, UseTileLocks=true, UseIslandLocks=true})
|
||||
ZomPack({ProcessTileSelection=false, RecursionDepth=1, RootGroup="RootGroup", WorkingSet="Visible", Scaling={Mode=0}, Rotate={}, Translate=true, LayoutScalingMode=2})
|
@ -0,0 +1,10 @@
|
||||
var = ZomGet("Vars.AutoSelect.Mosaic.Developability")
|
||||
|
||||
ZomSet({Path="Prefs.FileSuffix", Value=""})
|
||||
ZomSelect({PrimType="Edge", WorkingSet="Visible", Select=true, ResetBefore=true, ProtectMapName="Protect", FilterIslandVisible=true, Auto={QuasiDevelopable={Developability=var, IslandPolyNBMin=1, FitCones=false, Straighten=true}, HandleCutter=true, StoreCoordsUVW=true, FlatteningMode=0, FlatteningUnfoldParams={Iterations=1, BorderIntersections=true, TriangleFlips=true}}})
|
||||
ZomCut({PrimType="Edge", WorkingSet="Visible"})
|
||||
ZomLoad({Data={CoordsUVWInternalPath="Mesh.Tmp.AutoSelect.UVW"}})
|
||||
ZomIslandGroups({Mode="DistributeInTilesByBBox", WorkingSet="Visible", MergingPolicy=8322})
|
||||
ZomIslandGroups({Mode="DistributeInTilesEvenly", WorkingSet="Visible", MergingPolicy=8322, UseTileLocks=true, UseIslandLocks=true})
|
||||
ZomPack({ProcessTileSelection=false, RecursionDepth=1, RootGroup="RootGroup", WorkingSet="Visible", Scaling={Mode=2}, Rotate={}, Translate=true, LayoutScalingMode=2})
|
||||
|
@ -0,0 +1,11 @@
|
||||
var = ZomGet("Vars.AutoSelect.SharpEdges.Angle")
|
||||
|
||||
ZomSet({Path="Prefs.FileSuffix", Value=""})
|
||||
ZomSet({Path="Vars.EditMode.ElementMode", Value=1})
|
||||
ZomSelect({PrimType="Edge", WorkingSet="Visible", Select=true, All=true})
|
||||
ZomSelect({PrimType="Edge", WorkingSet="Visible", Select=true, ResetBefore=true, ProtectMapName="Protect", FilterIslandVisible=true, Auto={SharpEdges={AngleMin=var}, PipesCutter=false, HandleCutter=true, StoreCoordsUVW=true, FlatteningMode=0, FlatteningUnfoldParams={Iterations=1, BorderIntersections=true, TriangleFlips=true}}})
|
||||
ZomCut({PrimType="Edge", WorkingSet="Visible"})
|
||||
ZomLoad({Data={CoordsUVWInternalPath="Mesh.Tmp.AutoSelect.UVW"}})
|
||||
ZomIslandGroups({Mode="DistributeInTilesByBBox", WorkingSet="Visible", MergingPolicy=8322})
|
||||
ZomIslandGroups({Mode="DistributeInTilesEvenly", WorkingSet="Visible", MergingPolicy=8322, UseTileLocks=true, UseIslandLocks=true})
|
||||
ZomPack({ProcessTileSelection=false, RecursionDepth=1, RootGroup="RootGroup", WorkingSet="Visible", Scaling={Mode=2}, Rotate={}, Translate=true, LayoutScalingMode=2})
|
BIN
Scripts/Modeling/UV/RizomBridge/rizom_icon.png
Normal file
BIN
Scripts/Modeling/UV/RizomBridge/rizom_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 851 B |
2
Scripts/Modeling/UV/RizomBridge/scriptlist.py
Normal file
2
Scripts/Modeling/UV/RizomBridge/scriptlist.py
Normal file
@ -0,0 +1,2 @@
|
||||
# Edit this list when adding new scripts to the lua_script folder
|
||||
scripts = [("box_algorithm.lua", "Box"), ("mosaic_algorithm.lua", "Mosaic"), ("pelt_algorithm.lua", "Pelt"), ("sharp_edge_algorithm.lua", "Sharp Edge")]
|
4
Scripts/Modeling/UV/UVDeluxe/__init__.py
Normal file
4
Scripts/Modeling/UV/UVDeluxe/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import *
|
BIN
Scripts/Modeling/UV/UVDeluxe/config.uvd
Normal file
BIN
Scripts/Modeling/UV/UVDeluxe/config.uvd
Normal file
Binary file not shown.
90
Scripts/Modeling/UV/UVDeluxe/uistates.py
Normal file
90
Scripts/Modeling/UV/UVDeluxe/uistates.py
Normal file
@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pickle
|
||||
import os
|
||||
import maya.cmds as mc
|
||||
|
||||
version = 120
|
||||
|
||||
class UiStates():
|
||||
file = 'config.uvd'
|
||||
filepath = os.path.join(os.path.dirname(__file__), file)
|
||||
|
||||
def __init__(self):
|
||||
self.version = version
|
||||
#Window
|
||||
self.widthHeight = (1150,700)
|
||||
self.collapseFrame0 = False
|
||||
self.collapseFrame1 = True
|
||||
self.collapseFrame2 = True
|
||||
self.collapseFrame3 = True
|
||||
self.collapseFrame4 = True
|
||||
self.collapseFrame5 = True
|
||||
self.collapseFrame6 = True
|
||||
self.collapseFrame7 = True
|
||||
self.collapseFrame8 = True
|
||||
|
||||
#Settings
|
||||
#self.textureSize = (5,5)
|
||||
#self.forgetTextureSize = False
|
||||
self.detectTextureSize = True
|
||||
self.retainCS = mc.texMoveContext('texMoveContext',q=True,scr=True)
|
||||
self.matchDist = 0.05
|
||||
|
||||
#Quicksnap
|
||||
self.snapPath = mc.workspace(q=True,rd=True)
|
||||
|
||||
@staticmethod
|
||||
def pickleDump(uis):
|
||||
with open(UiStates.filepath, 'wb') as datafile:
|
||||
pickle.dump(uis, datafile)
|
||||
|
||||
@staticmethod
|
||||
def pickleLoad():
|
||||
if os.path.exists(UiStates.filepath):
|
||||
print("%s found, loading settings." % UiStates.file)
|
||||
try:
|
||||
with open(UiStates.filepath, 'rb') as datafile:
|
||||
uis = pickle.load(datafile)
|
||||
except EOFError:
|
||||
print("Warning: The file is empty or corrupted.")
|
||||
os.remove(UiStates.filepath)
|
||||
return UiStates()
|
||||
except Exception as e:
|
||||
print(f"Error loading settings: {e}")
|
||||
os.remove(UiStates.filepath)
|
||||
return UiStates()
|
||||
try:
|
||||
pickledVer = uis.version
|
||||
if pickledVer < version:
|
||||
os.remove(UiStates.filepath)
|
||||
return UiStates()
|
||||
except:
|
||||
os.remove(UiStates.filepath)
|
||||
return UiStates()
|
||||
return uis
|
||||
else:
|
||||
return UiStates()
|
||||
|
||||
|
||||
def setUiState(self):
|
||||
#Window
|
||||
self.widthHeight = mc.window('UVDeluxe',query=True,wh=True)
|
||||
self.collapseFrame0 = mc.frameLayout('layout_Settings', query=True, cl=True)
|
||||
self.collapseFrame1 = mc.frameLayout('layout_Mover', query=True, cl=True)
|
||||
self.collapseFrame2 = mc.frameLayout('layout_Scaler', query=True, cl=True)
|
||||
self.collapseFrame3 = mc.frameLayout('layout_Ratio', query=True, cl=True)
|
||||
self.collapseFrame4 = mc.frameLayout('layout_Straighten', query=True, cl=True)
|
||||
self.collapseFrame5 = mc.frameLayout('layout_Align', query=True, cl=True)
|
||||
self.collapseFrame6 = mc.frameLayout('layout_QuickSnap', query=True, cl=True)
|
||||
self.collapseFrame7 = mc.frameLayout('layout_MatchUV', query=True, cl=True)
|
||||
self.collapseFrame8 = mc.frameLayout('layout_SelectionSets',query=True, cl=True)
|
||||
|
||||
self.detectTextureSize = mc.checkBox ('DTR', query=True, v=True)
|
||||
|
||||
self.retainCS = mc.texMoveContext('texMoveContext',q=True,scr=True)
|
||||
#Qucksnap
|
||||
self.snapPath = mc.textField("pathField",query=True,text=True)
|
||||
''' Dump '''
|
||||
UiStates.pickleDump(self)
|
1402
Scripts/Modeling/UV/UVDeluxe/uvdeluxe.py
Normal file
1402
Scripts/Modeling/UV/UVDeluxe/uvdeluxe.py
Normal file
File diff suppressed because it is too large
Load Diff
215
Scripts/Modeling/UV/UVSetEditor.py
Normal file
215
Scripts/Modeling/UV/UVSetEditor.py
Normal file
@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import maya.cmds as cmds
|
||||
|
||||
# Define minimum window width and height
|
||||
MIN_WINDOW_WIDTH = 300 # Increased from 200 to 300
|
||||
MIN_WINDOW_HEIGHT = 300
|
||||
|
||||
# Function: Get and display UV sets
|
||||
def refresh_uv_sets():
|
||||
selection = cmds.ls(selection=True)
|
||||
if not selection:
|
||||
cmds.warning("Please select an object first.")
|
||||
return
|
||||
|
||||
selected_object = selection[0]
|
||||
uv_sets = cmds.polyUVSet(selected_object, query=True, allUVSets=True)
|
||||
cmds.textScrollList('uvList', edit=True, removeAll=True)
|
||||
for uv_set in uv_sets:
|
||||
cmds.textScrollList('uvList', edit=True, append=uv_set)
|
||||
|
||||
# Function: Switch UV set
|
||||
def switch_uv_set(*args):
|
||||
selected_uv_set = cmds.textScrollList('uvList', query=True, selectItem=True)
|
||||
if selected_uv_set:
|
||||
selected_object = cmds.ls(selection=True)
|
||||
if selected_object:
|
||||
selected_object = selected_object[0]
|
||||
# Switch current UV set
|
||||
cmds.polyUVSet(selected_object, currentUVSet=True, uvSet=selected_uv_set[0])
|
||||
print(f"Switched to UV set: {selected_uv_set[0]}")
|
||||
else:
|
||||
cmds.warning("Please select an object.")
|
||||
else:
|
||||
cmds.warning("Please select a UV set.")
|
||||
|
||||
# Function: Delete selected UV set
|
||||
def delete_selected_uv_set():
|
||||
selected_uv_set = cmds.textScrollList('uvList', query=True, selectItem=True)
|
||||
if selected_uv_set:
|
||||
cmds.polyUVSet(delete=True, uvSet=selected_uv_set[0])
|
||||
refresh_uv_sets()
|
||||
|
||||
# Function: Rename selected UV set
|
||||
def rename_selected_uv_set(new_name):
|
||||
selected_uv_set = cmds.textScrollList('uvList', query=True, selectItem=True)
|
||||
if selected_uv_set:
|
||||
if new_name:
|
||||
cmds.polyUVSet(rename=True, newUVSet=new_name, uvSet=selected_uv_set[0])
|
||||
refresh_uv_sets()
|
||||
cmds.textFieldGrp('newNameField', edit=True, text='') # Clear input field content
|
||||
else:
|
||||
cmds.warning("Please enter a new name.")
|
||||
else:
|
||||
cmds.warning("Please select a UV set first.")
|
||||
|
||||
# Function: Create new UV set
|
||||
def create_new_uv_set(new_name):
|
||||
if new_name:
|
||||
cmds.polyUVSet(create=True, uvSet=new_name)
|
||||
refresh_uv_sets()
|
||||
cmds.textFieldGrp('newNameField', edit=True, text='') # Clear input field content
|
||||
else:
|
||||
cmds.warning("Please enter a name for the new UV set.")
|
||||
|
||||
# Function: Set UV set 1 name
|
||||
def set_uv_set1_name(*args):
|
||||
selected_uv_set = cmds.textScrollList('uvList', query=True, selectItem=True)
|
||||
if selected_uv_set:
|
||||
cmds.textFieldGrp("uvSet1", edit=True, text=selected_uv_set[0])
|
||||
else:
|
||||
cmds.warning("Please select a UV set first.")
|
||||
|
||||
# Function: Set UV set 2 name
|
||||
def set_uv_set2_name(*args):
|
||||
selected_uv_set = cmds.textScrollList('uvList', query=True, selectItem=True)
|
||||
if selected_uv_set:
|
||||
cmds.textFieldGrp("uvSet2", edit=True, text=selected_uv_set[0])
|
||||
else:
|
||||
cmds.warning("Please select a UV set first.")
|
||||
|
||||
# Function: UV set swap
|
||||
def UVsetSwap(*args):
|
||||
UVname1 = cmds.textFieldGrp("uvSet1", query=True, text=True)
|
||||
UVname2 = cmds.textFieldGrp("uvSet2", query=True, text=True)
|
||||
cmds.polyUVSet(query=True, allUVSets=True)
|
||||
cmds.polyUVSet(create=True, uvSet='TempUV')
|
||||
cmds.polyUVSet(copy=True, nuv='TempUV', uvSet=UVname1)
|
||||
cmds.polyUVSet(copy=True, nuv=UVname1, uvSet=UVname2)
|
||||
cmds.polyUVSet(copy=True, nuv=UVname2, uvSet='TempUV')
|
||||
cmds.polyUVSet(delete=True, uvSet='TempUV')
|
||||
refresh_uv_sets() # Refresh list after execution
|
||||
|
||||
def UVsetReorder(*args):
|
||||
UVname1 = cmds.textFieldGrp("uvSet1", query=True, text=True)
|
||||
UVname2 = cmds.textFieldGrp("uvSet2", query=True, text=True)
|
||||
print("Reorder object is " + UVname1 + " + " + UVname2)
|
||||
cmds.polyUVSet(reorder=True, uvSet=UVname1, newUVSet=UVname2)
|
||||
UVobj = cmds.ls(sl=True)
|
||||
cmds.select(UVobj)
|
||||
refresh_uv_sets() # Refresh list after execution
|
||||
|
||||
# Function: UV set transfer
|
||||
def get_object_name(*args):
|
||||
# Get currently selected object and fill its name in the text field
|
||||
selected = cmds.ls(sl=True)
|
||||
if selected:
|
||||
cmds.textField('objectNameField', edit=True, text=selected[0])
|
||||
else:
|
||||
cmds.warning("No object selected.")
|
||||
|
||||
def set_uv(*args):
|
||||
# Get source and target objects, perform UV transfer, and clean up history
|
||||
source_object = cmds.textField('objectNameField', query=True, text=True)
|
||||
target_object = cmds.ls(sl=True)
|
||||
if not source_object or not target_object:
|
||||
cmds.warning("Please ensure both source and target objects are selected.")
|
||||
return
|
||||
target_object = target_object[0]
|
||||
sample_space_dict = {'World': 0, 'Local': 1, 'UV': 5, 'Component': 4}
|
||||
sample_space = cmds.radioCollection('sampleSpaceRadio', query=True, select=True)
|
||||
sample_space = cmds.radioButton(sample_space, query=True, label=True)
|
||||
sample_space = sample_space_dict.get(sample_space, 0)
|
||||
cmds.transferAttributes(source_object, target_object, transferPositions=0, transferNormals=0, transferUVs=2, transferColors=0, sampleSpace=sample_space, searchMethod=3)
|
||||
cmds.delete(target_object, constructionHistory=True) # Clean up history
|
||||
|
||||
def on_window_resize(*args):
|
||||
window_name = "UVSetEditor"
|
||||
# Get current window size
|
||||
current_width = cmds.window(window_name, query=True, width=True)
|
||||
current_height = cmds.window(window_name, query=True, height=True)
|
||||
|
||||
# Check and limit window size
|
||||
if current_width < MIN_WINDOW_WIDTH:
|
||||
cmds.window(window_name, edit=True, width=MIN_WINDOW_WIDTH)
|
||||
if current_height < MIN_WINDOW_HEIGHT:
|
||||
cmds.window(window_name, edit=True, height=MIN_WINDOW_HEIGHT)
|
||||
|
||||
def show(*args):
|
||||
window_name = "UVSetEditor"
|
||||
# Check if window exists, if so, delete it
|
||||
if cmds.window(window_name, exists=True):
|
||||
cmds.deleteUI('UV Set Editor', window=True)
|
||||
# Window
|
||||
# Create a new window and set its title and initial size
|
||||
window = cmds.window(window_name, title=" UV Set Editor", widthHeight=(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT), sizeable=True, tlb=True) # tlb=True
|
||||
|
||||
cmds.frameLayout(label='UV-Set')
|
||||
cmds.columnLayout(adjustableColumn=True)
|
||||
# Create a textScrollList control and set the selection change command
|
||||
cmds.textScrollList('uvList', numberOfRows=8, allowMultiSelection=False, width=280, selectCommand=switch_uv_set)
|
||||
cmds.textFieldGrp('newNameField', placeholderText=' Enter new name, then click Re to rename', width=280, columnAlign=[1, 'center'] ,columnWidth=[1,280])
|
||||
cmds.rowLayout(numberOfColumns=4,
|
||||
columnWidth4=(65, 65, 65, 65),
|
||||
columnAttach4=('both', 'both', 'both', 'both'))
|
||||
cmds.button( label='Get', height=32, command=lambda x: refresh_uv_sets(),backgroundColor=(0.53, 0.81, 0.98))
|
||||
cmds.button( label='Del', height=32, command=lambda x: delete_selected_uv_set())
|
||||
cmds.button( label='New', height=32, command=lambda x: create_new_uv_set(cmds.textFieldGrp('newNameField', query=True, text=True)))
|
||||
cmds.button( label='Re', height=32, command=lambda x: rename_selected_uv_set(cmds.textFieldGrp('newNameField', query=True, text=True)))
|
||||
cmds.setParent( '..' )
|
||||
|
||||
cmds.setParent('..') # End current form layout
|
||||
|
||||
cmds.frameLayout(label='UV-Swap')
|
||||
cmds.columnLayout(adjustableColumn=True, width=280)
|
||||
cmds.text(l='Enter UV set names in "uv1" and "uv2"', h=15)
|
||||
cmds.text(l=' UV swap or reorder swap. ', h=15)
|
||||
cmds.text(l='', h=5)
|
||||
cmds.rowLayout(numberOfColumns=3, columnWidth3=(65, 65, 130), columnAttach3=('both', 'both', 'both'))
|
||||
cmds.button(label='Get', height=25, command=set_uv_set1_name, backgroundColor=(0.53, 0.81, 0.98))
|
||||
cmds.textFieldGrp("uvSet1", placeholderText='uv1', editable=True, width=200)
|
||||
cmds.setParent('..')
|
||||
cmds.rowLayout(numberOfColumns=3, columnWidth3=(65, 65, 130), columnAttach3=('both', 'both', 'both'))
|
||||
cmds.button(label='Get', height=25, command=set_uv_set2_name, backgroundColor=(0.53, 0.81, 0.98))
|
||||
cmds.textFieldGrp("uvSet2", placeholderText='uv2', editable=True, width=200)
|
||||
cmds.setParent('..')
|
||||
cmds.rowColumnLayout(numberOfColumns=2, columnWidth=[(1, 135), (2, 135)])
|
||||
cmds.button(label='UV Swap', command=UVsetSwap, backgroundColor=(0.53, 0.81, 0.98))
|
||||
cmds.button(label='Reorder Swap', command=UVsetReorder, backgroundColor=(0.53, 0.81, 0.98))
|
||||
|
||||
UVname1 = cmds.textFieldGrp("uvSet1", query=True, text=True)
|
||||
UVname2 = cmds.textFieldGrp("uvSet2", query=True, text=True)
|
||||
print("Now we have UVset = {}, {}".format(UVname1, UVname2))
|
||||
|
||||
cmds.setParent('..') # End current form layout
|
||||
|
||||
# Separator
|
||||
cmds.separator(height=20, style='in')
|
||||
|
||||
# Create a column layout, all child elements will be vertically arranged
|
||||
cmds.frameLayout(label='UV-Transfer')
|
||||
cmds.columnLayout(adjustableColumn=True, width=230, height=130)
|
||||
cmds.rowLayout(numberOfColumns=3, columnWidth3=(50, 100, 50))
|
||||
cmds.button(label='Get', command=get_object_name, backgroundColor=(0.53, 0.81, 0.98), width=45) # Create a button that calls get_object_name function when clicked
|
||||
cmds.textField('objectNameField', enable=False, width=120) # Create a text field to display the name of the selected object
|
||||
cmds.button(label='Set', command=set_uv, backgroundColor=(0.53, 0.81, 0.98), width=45) # Create a button that calls set_uv function when clicked
|
||||
cmds.setParent('..') # End current form layout
|
||||
|
||||
# cmds.frameLayout(label='Sample Space')
|
||||
cmds.text(l='Sample Space:', h=20, align='left')
|
||||
form = cmds.formLayout()
|
||||
|
||||
cmds.radioCollection('sampleSpaceRadio') # Create a radio button group
|
||||
rb1 = cmds.radioButton(label='World', select=True) # Create a radio button
|
||||
rb2 = cmds.radioButton(label='Local')
|
||||
rb3 = cmds.radioButton(label='UV')
|
||||
rb4 = cmds.radioButton(label='Component')
|
||||
# Set form layout parameters to keep radio buttons horizontally aligned and centered when window size changes
|
||||
cmds.formLayout(form, edit=True, attachForm=[(rb1, 'left', 10), (rb4, 'right', 10)], attachControl=[(rb2, 'left', 5, rb1), (rb3, 'left', 5, rb2), (rb4, 'left', 5, rb3)])
|
||||
cmds.setParent('..') # End current form layout
|
||||
|
||||
cmds.scriptJob(event=["idle", on_window_resize], parent=window) # Listen for window resize events
|
||||
|
||||
cmds.showWindow(window) # Show window
|
Loading…
Reference in New Issue
Block a user