This commit is contained in:
Jeffreytsai1004 2025-01-14 02:12:52 +08:00
parent ce678534b2
commit 9787a55b24
19 changed files with 3672 additions and 0 deletions

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 KiB

View 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()

View 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()

View 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()

View 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()

View File

@ -0,0 +1,4 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from . import *

View File

@ -0,0 +1,4 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from . import *

View File

@ -0,0 +1 @@
ZomSet({Path="Prefs.FileSuffix", Value=""})

View File

@ -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})

View File

@ -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})

View File

@ -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})

Binary file not shown.

After

Width:  |  Height:  |  Size: 851 B

View 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")]

View File

@ -0,0 +1,4 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from . import *

Binary file not shown.

View 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)

File diff suppressed because it is too large Load Diff

View 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