splitUVCmd.py
import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
import sys
import polyModifier
def statusError(message):
fullMsg = "Status failed: %s\n" % message
sys.stderr.write(fullMsg)
OpenMaya.MGlobal.displayError(fullMsg)
raise
kPluginCmdName = "spSplitUV"
kPluginNodeTypeName = "spSplitUVNode"
kPluginNodeId = OpenMaya.MTypeId(0x87013)
class splitUV(polyModifier.polyModifierCmd):
def __init__(self):
polyModifier.polyModifierCmd.__init__(self)
self.__fComponentList = OpenMaya.MObject()
self.__fSelUVs = OpenMaya.MIntArray()
self.__fSplitUVFactory = splitUVFty()
def isUndoable(self):
return True
def doIt(self, args):
"""
implements the scripted splitUV command.
Arguments:
args - the argument list that was passes to the command from MEL
"""
selList = OpenMaya.MSelectionList()
OpenMaya.MGlobal.getActiveSelectionList(selList)
selListIter = OpenMaya.MItSelectionList(selList)
compListFn = OpenMaya.MFnComponentListData()
compListFn.create()
found = False
foundMultiple = False
while not selListIter.isDone():
dagPath = OpenMaya.MDagPath()
component = OpenMaya.MObject()
itemMatches = True
selListIter.getDagPath(dagPath, component)
if itemMatches and (component.apiType() == OpenMaya.MFn.kMeshMapComponent):
if not found:
compListFn.add(component)
self.__fComponentList = compListFn.object()
compFn = OpenMaya.MFnSingleIndexedComponent(component)
compFn.getElements(self.__fSelUVs)
dagPath.extendToShape()
self._setMeshNode(dagPath)
found = True
else:
foundMultiple = True
break
selListIter.next()
if foundMultiple:
self.displayWarning("Found more than one object with selected UVs - Only operating on first found object.")
self._setModifierNodeType(kPluginNodeId)
if found:
if self.__validateUVs():
try:
self._doModifyPoly()
except:
self.displayError("splitUV command failed!")
raise
else:
self.setResult("splitUV command succeeded!")
else:
self.displayError("splitUV command failed: Selected UVs are not splittable")
else:
self.displayError("splitUV command failed: Unable to find selected UVs")
def redoIt(self):
"""
Implements redo for the scripted splitUV command.
This method is called when the user has undone a command of this type
and then redoes it. No arguments are passed in as all of the necessary
information is cached by the doIt method.
"""
try:
self._redoModifyPoly()
self.setResult("splitUV command succeeded!")
except:
self.displayError("splitUV command failed!")
raise
def undoIt(self):
"""
implements undo for the scripted splitUV command.
This method is called to undo a previous command of this type. The
system should be returned to the exact state that it was it previous
to this command being executed. That includes the selection state.
"""
try:
self._undoModifyPoly()
self.setResult("splitUV undo succeeded!")
except:
self.displayError("splitUV undo failed!")
raise
def _initModifierNode(self, modifierNode):
depNodeFn = OpenMaya.MFnDependencyNode(modifierNode)
uvListAttr = depNodeFn.attribute("inputComponents")
uvListPlug = OpenMaya.MPlug(modifierNode, uvListAttr)
uvListPlug.setMObject(self.__fComponentList)
def _directModifier(self, mesh):
self.__fSplitUVFactory.setMesh(mesh)
self.__fSplitUVFactory.setUVIds(self.__fSelUVs)
self.__fSplitUVFactory.doIt()
def __validateUVs(self):
"""
Validate the UVs for the splitUV operation. UVs are valid only if they are shared
by more than one face. While the splitUVNode is smart enough to not process the
split if a UV is not splittable, a splitUV node is still created by the polyModifierCmd.
So call this method to validate the UVs before calling _doModifyPoly().
validateUVs() will return true so long as there is at least one valid UV. It will
also prune out any invalid UVs from both the component list and UVId array.
"""
dagPath = self._getMeshNode()
mesh = dagPath.node()
meshFn = OpenMaya.MFnMesh(mesh)
polyIter = OpenMaya.MItMeshPolygon(mesh)
selUVFaceCountArray = OpenMaya.MIntArray()
indexParam = OpenMaya.MScriptUtil()
indexParam.createFromInt(0)
indexPtr = indexParam.asIntPtr()
count = 0
selUVsCount = self.__fSelUVs.length()
for i in range(selUVsCount):
while not polyIter.isDone():
if polyIter.hasUVs():
polyVertCount = polyIter.polygonVertexCount()
for j in range(polyVertCount):
polyIter.getUVIndex(j, indexPtr)
UVIndex = OpenMaya.MScriptUtil(indexPtr).asInt()
if UVIndex == self.__fSelUVs[i]:
count += 1
break
polyIter.next()
selUVFaceCountArray.append(count)
isValid = False
validUVIndices = OpenMaya.MIntArray()
for i in range(selUVsCount):
if selUVFaceCountArray[i] > 1:
isValid = True
validUVIndices.append(i)
if isValid:
self.__pruneUVs(validUVIndices)
return isValid
def __pruneUVs(self, validUVIndices):
"""
This method will remove any invalid UVIds from the component list and UVId array.
The benefit of this is to reduce the amount of extra processing that the node would
have to perform. It will result in less iterations through the mesh as there are
less UVs to search for.
"""
validUVIds = OpenMaya.MIntArray()
for i in range(validUVIndices.length()):
uvIndex = validUVIndices[i]
validUVIds.append(self.__fSelUVs[uvIndex])
self.__fSelUVs.clear()
self.__fSelUVs = validUVIds
compFn = OpenMaya.MFnSingleIndexedComponent()
try:
compFn.create(OpenMaya.MFn.kMeshMapComponent)
except:
statusError("compFn.create( MFn::kMeshMapComponent )")
try:
compFn.addElements(validUVIds)
except:
statusError("compFn.addElements( validUVIds )")
component = compFn.object()
compListFn = OpenMaya.MFnComponentListData()
compListFn.create()
try:
compListFn.add(component)
except:
statusError("compListFn.add( component )")
self.__fComponentList = compListFn.object()
class splitUVFty(polyModifier.polyModifierFty):
def __init__(self):
polyModifier.polyModifierFty.__init__(self)
self.__fMesh = OpenMaya.MObject()
self.__fSelUVs = OpenMaya.MIntArray()
self.__fSelUVs.clear()
def setMesh(self, mesh):
self.__fMesh = mesh
def setUVIds(self, uvIds):
self.__fSelUVs = uvIds
def doIt(self):
"""
Performs the actual splitUV operation on the given object and UVs
"""
selUVFaceIdMap = OpenMaya.MIntArray()
selUVFaceOffsetMap = OpenMaya.MIntArray()
selUVLocalVertIdMap = OpenMaya.MIntArray()
meshFn = OpenMaya.MFnMesh(self.__fMesh)
selUVSet = meshFn.currentUVSetName()
indexParam = OpenMaya.MScriptUtil()
indexParam.createFromInt(0)
indexPtr = indexParam.asIntPtr()
offset = 0
selUVsCount = self.__fSelUVs.length()
polyIter = OpenMaya.MItMeshPolygon(self.__fMesh)
for i in range(selUVsCount):
selUVFaceOffsetMap.append(offset)
polyIter.reset()
while not polyIter.isDone():
if polyIter.hasUVs():
polyVertCount = polyIter.polygonVertexCount()
for j in range(polyVertCount):
polyIter.getUVIndex(j, indexPtr)
UVIndex = OpenMaya.MScriptUtil(indexPtr).asInt()
if UVIndex == self.__fSelUVs[i]:
selUVFaceIdMap.append(polyIter.index())
selUVLocalVertIdMap.append(j)
offset += 1
break
polyIter.next()
selUVFaceOffsetMap.append(offset)
currentUVCount = meshFn.numUVs(selUVSet)
for i in range(selUVsCount):
offset = selUVFaceOffsetMap[i]
uvId = self.__fSelUVs[i]
uParam = OpenMaya.MScriptUtil()
uParam.createFromDouble(0.0)
uPtr = uParam.asFloatPtr()
vParam = OpenMaya.MScriptUtil()
vParam.createFromDouble(0.0)
vPtr = vParam.asFloatPtr()
meshFn.getUV(uvId, uPtr, vPtr, selUVSet)
u = OpenMaya.MScriptUtil(uPtr).asFloat()
v = OpenMaya.MScriptUtil(vPtr).asFloat()
faceCount = selUVFaceOffsetMap[i + 1] - selUVFaceOffsetMap[i]
for j in range(faceCount-1):
meshFn.setUV(currentUVCount, u, v, selUVSet)
localVertId = selUVLocalVertIdMap[offset]
faceId = selUVFaceIdMap[offset]
meshFn.assignUV(faceId, localVertId, currentUVCount, selUVSet)
currentUVCount += 1
offset += 1
class splitUVNode(polyModifier.polyModifierNode):
uvList = OpenMaya.MObject()
def __init__(self):
polyModifier.polyModifierNode.__init__(self)
self.fSplitUVFactory = splitUVFty()
def compute(self, plug, data):
"""
Description:
This method computes the value of the given output plug based
on the values of the input attributes.
Arguments:
plug - the plug to compute
data - object that provides access to the attributes for this node
"""
stateData = 0
state = OpenMayaMPx.cvar.MPxNode_state
try:
stateData = data.outputValue(state)
except:
statusError("ERROR getting state")
if stateData.asShort() == 1:
try:
inputData = data.inputValue(splitUVNode.inMesh)
except:
statusError("ERROR getting inMesh")
try:
outputData = data.outputValue(splitUVNode.outMesh)
except:
statusError("ERROR getting outMesh")
outputData.setMObject(inputData.asMesh())
else:
if plug == splitUVNode.outMesh:
try:
inputData = data.inputValue(splitUVNode.inMesh)
except:
statusError("ERROR getting inMesh")
try:
outputData = data.outputValue(splitUVNode.outMesh)
except:
statusError("ERROR getting outMesh")
try:
inputUVs = data.inputValue(splitUVNode.uvList)
except:
statusError("ERROR getting uvList")
outputData.setMObject(inputData.asMesh())
mesh = outputData.asMesh()
compList = inputUVs.data()
compListFn = OpenMaya.MFnComponentListData(compList)
uvIds = OpenMaya.MIntArray()
for i in range(compListFn.length()):
comp = compListFn[i]
if comp.apiType() == OpenMaya.MFn.kMeshMapComponent:
uvComp = OpenMaya.MFnSingleIndexedComponent(comp)
for j in range(uvComp.elementCount()):
uvId = uvComp.element(j)
uvIds.append(uvId)
self.fSplitUVFactory.setMesh(mesh)
self.fSplitUVFactory.setUVIds(uvIds)
try:
self.fSplitUVFactory.doIt()
except:
statusError("ERROR in splitUVFty.doIt()")
outputData.setClean()
else:
return OpenMaya.MStatus.kUnknownParameter
return OpenMaya.MStatus.kSuccess
def cmdCreator():
return OpenMayaMPx.asMPxPtr(splitUV())
def nodeCreator():
return OpenMayaMPx.asMPxPtr(splitUVNode())
def nodeInitializer():
attrFn = OpenMaya.MFnTypedAttribute()
splitUVNode.uvList = attrFn.create("inputComponents", "ics", OpenMaya.MFnComponentListData.kComponentList)
attrFn.setStorable(True)
splitUVNode.inMesh = attrFn.create("inMesh", "im", OpenMaya.MFnMeshData.kMesh)
attrFn.setStorable(True)
splitUVNode.outMesh = attrFn.create("outMesh", "om", OpenMaya.MFnMeshData.kMesh)
attrFn.setStorable(False)
attrFn.setWritable(False)
splitUVNode.addAttribute(splitUVNode.uvList)
splitUVNode.addAttribute(splitUVNode.inMesh)
splitUVNode.addAttribute(splitUVNode.outMesh)
splitUVNode.attributeAffects(splitUVNode.inMesh, splitUVNode.outMesh)
splitUVNode.attributeAffects(splitUVNode.uvList, splitUVNode.outMesh)
def initializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject, "Autodesk", "1.0", "Any")
try:
mplugin.registerCommand(kPluginCmdName, cmdCreator)
except:
sys.stderr.write( "Failed to register command: %s\n" % kPluginCmdName)
raise
try:
mplugin.registerNode(kPluginNodeTypeName, kPluginNodeId, nodeCreator, nodeInitializer)
except:
sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName)
raise
def uninitializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject)
try:
mplugin.deregisterCommand(kPluginCmdName)
except:
sys.stderr.write("Failed to unregister command: %s\n" % kPluginCmdName)
raise
try:
mplugin.deregisterNode(kPluginNodeId)
except:
sys.stderr.write("Failed to deregister node: %s" % kPluginNodeTypeName)
raise