def lcObj_exportObjs(*args, **kwargs): ''' Export .obj files from selected geometry, either as one combined file or as individual files per object. Will recognize and convert poly smooth preview to geometry for export ''' global prefix path = pm.textField(prefix+'_textField_export_path', query=True, text=True) objPrefix = pm.textField(prefix+'_textField_prefix', query=True, text=True) if objPrefix: objPrefix+='_' if path: sel = pm.ls(sl=True) if sel: sel = geometry.filterForGeometry(sel) print sel #undo is the easiest way to work on geometry temporarily pm.undoInfo(openChunk=True) if pm.checkBox(prefix+'_checkBox_use_smooth', query=True, v=True): for obj in sel: pm.select(obj) #find the objects currently displayed as smooth and create converted poly copies if pm.displaySmoothness(q=True, polygonObject=True)[0] == 3: pm.mel.performSmoothMeshPreviewToPolygon() if pm.checkBox(prefix+'_checkBox_export_indi', query=True, v=True): #export objects individually for obj in sel: pm.select(obj) name = str(obj) exportString = path+'/'+objPrefix+name+'.obj' pm.exportSelected(exportString, force=True, options='groups=1;ptgroups=1;materials=0;smoothing=1;normals=1', type='OBJexport', pr=True, es=True) else: #export as one object pm.select(sel) name = '' while name == '': dialog = pm.promptDialog(title='OBJ Name', message='Enter Name:', button=['OK', 'Cancel'], defaultButton='OK', cancelButton='Cancel', dismissString='Cancel') if dialog == 'OK': name = pm.promptDialog(query=True, text=True) if name: exportString = path+'/'+objPrefix+name+'.obj' pm.exportSelected(exportString, force=True, options='groups=1;ptgroups=1;materials=0;smoothing=1;normals=1', type='OBJexport', pr=True, es=True) else: pm.warning("You didn't type a name for your obj") if dialog == 'Cancel': break pm.undoInfo(closeChunk=True) pm.undo() pm.select(clear=True) else: pm.warning('Did you specify a path?')
def testChunkUndo(self): @chunk_undo def spam(): pmc.joint(), pmc.joint() spam() self.assertEqual(len(pmc.ls(type='joint')), 2) pmc.undo() self.assertFalse(pmc.ls(type='joint'))
def safeRename(objs, newNames): ''' Safely renames the given PyNodes to the given names. First validates the names, then renames each node to a name that will not conflict with any new name. If an error is encountered, the original name is restored. ''' objPairs = zip(objs, newNames) # Validate names skipPairs = set([]) for objPair in objPairs: obj, name = objPair # Don't try to rename nodes to the same names. if name == obj.nodeName(stripNamespace=True): skipPairs.add(objPair) elif not pm.mel.isValidObjectName(name): raise InvalidNameError( 'Cannot rename "%s" to "%s"' % (obj.nodeName(), name)) try: with gat.internal.UndoChunk(): # Rename objects to something that I hope doesn't already exist, # so that we don't run into issues trying to rename an object in # our list to the name of an object that hasn't yet been # renamed. for objPair in objPairs: if objPair in skipPairs: continue obj, name = objPair try: obj.rename('_' * 80) except RuntimeError: print 'Failed to rename %s to %s. Skipping node.' % (obj, name) skipPairs.add(objPair) # Rename things for real for objPair in objPairs: if objPair not in skipPairs: obj, name = objPair obj.rename(name) except RuntimeError as err: # Undo bad renames and show error pm.undo() raise RenameError('Failed while renaming %s to %s: %s' % (obj, name, err.message))
def move_Up(self): cur_item = self.ui.attr_listView.selectedItems()[0].text() cur_index = self.attr_List.index(cur_item) self.attr_List[cur_index] = self.attr_List[cur_index - 1] self.attr_List[cur_index - 1] = cur_item self.ui.attr_listView.clear() for each in self.attr_List: lock = pm.getAttr(self.ui.object_name.text() +'.'+ each, l = True) pm.setAttr(self.ui.object_name.text() +'.'+ each, l = False) pm.deleteAttr(self.ui.object_name.text() +'.'+ each) pm.undo() pm.setAttr(self.ui.object_name.text() +'.'+ each, l = lock) self.ui.attr_listView.addItems(self.attr_List) self.ui.attr_listView.setCurrentRow( cur_index - 1 )
def export(self): output_path = self.Output_Path.text() if not os.path.exists(output_path): self.Output_Path.setText("") msg = u"路径不存在" QtWidgets.QMessageBox.warning(self, u"警告", msg) return base_name = os.path.basename(output_path) sel_list = pm.ls(sl=1) if not sel_list: msg = u"请选择一个物体" QtWidgets.QMessageBox.warning(self, u"警告", msg) return for sel in sel_list: pm.undoInfo(ock=1) pm.parent(sel, w=1) # NOTE 居中轴心 pm.xform(sel, cp=1) pm.mel.BakeCustomPivot() sel.t.set(0, 0, 0) sel.r.set(0, 0, 0) x, _, z = pm.xform(sel, q=1, rp=1) bbox = pm.exactWorldBoundingBox(sel) pm.xform(sel, piv=[x, bbox[1], z]) sel.t.set(0, -bbox[1], 0) pm.makeIdentity(apply=1, t=1, r=1, s=1, n=0, pn=0) index = 1 path = os.path.join(output_path, "%s_%s.ma" % (base_name, str(index).zfill(2))) while os.path.exists(path): index += 1 path = os.path.join( output_path, "%s_%s.ma" % (base_name, str(index).zfill(2))) path = path.replace('\\', '/') print(path) # commnad = 'FBXExport -f "%s.fbx" -s ' % path.replace('\\','/') # NOTE 导出 ma 文件 pm.mel.file(path, f=1, options="v=0;", typ="mayaAscii", pr=1, es=1) pm.undoInfo(cck=1) pm.undo()
def findLengthFromParam(crv, param): ''' MFnNurbsCurve has findParamFromLength, but not the other way! workaround is to cut the curve at param, then get the whole length of the new curve ''' firstCrv, secondCrv, node = pm.detachCurve(crv.u[param], ch=True, rpo=False) try: length = firstCrv.length() pm.undo() return length except RuntimeError as e: print e print 'param may be 0' pm.undo() return 0
def Down_Right(self, ui): listIndex = ui.TargetList.currentIndex() itemName = str(listIndex.data()) selected = pm.select(itemName) joint = pm.ls(sl=True)[0] pm.undo() temp = targetTree[listIndex.row()] targetTree[listIndex.row()] = targetTree[listIndex.row() + 1] targetTree[listIndex.row() + 1] = temp tempIndex = targetIndex[listIndex.row()] targetIndex[listIndex.row()] = targetIndex[listIndex.row() + 1] targetIndex[listIndex.row() + 1] = tempIndex self.updateTargetList(ui, targetTree)
def __init__(self): super(DockableWindow, self).__init__() self.shown = False # Build our *.ui files into qt/resources, so the subclass can load its layout. qt_helpers.compile_all_layouts() # How do we make our window handle global hotkeys? undo = Qt.QAction('Undo', self) undo.setShortcut(Qt.Qt.CTRL + Qt.Qt.Key_Z) undo.triggered.connect(lambda: pm.undo()) self.addAction(undo) redo = Qt.QAction('Redo', self) redo.setShortcut(Qt.Qt.CTRL + Qt.Qt.Key_Y) redo.triggered.connect(lambda: pm.redo(redo=True)) self.addAction(redo) style = '' # Maya's checkbox style makes the checkbox invisible when it's deselected, # which makes it impossible to tell that there's even a checkbox there to # click. Adjust the background color to fix this. style += 'QTreeView::indicator:unchecked { background-color: #000; }' # Make tree and list view items slightly larger by default. style += 'QTreeView::item { height: 20px; }' style += 'QListView::item { height: 26px; }' self.setStyleSheet(self.styleSheet() + style)
def up_down_attribute(up=False, down=False): """ Args: up: Set the selected attribute go up 1 index in the main channel box down: Set the selected attribute go down 1 index in the main channel box Returns: Relocation of selected attribute in main channel box """ selections = pm.ls(sl=True) if len(selections) != 1: return om.MGlobal.displayError("This function only work with one object per time") selection = selections[0] selected_attr = pm.channelBox("mainChannelBox", query=True, selectedMainAttributes=True) list_attr = pm.listAttr(selection, userDefined=True, locked=True) if len(list_attr) > 0: for attr in list_attr: pm.setAttr("{0}.{1}".format(selection, attr), lock=False) if down: if len(selected_attr) > 1: selected_attr.reverse() sort = selected_attr if len(selected_attr) == 1: sort = selected_attr for i in sort: attr_list = pm.listAttr(selection, userDefined=True) attr_list_size = len(attr_list) attr_position = attr_list.index(i) pm.deleteAttr(selection, attribute=attr_list[attr_position]) pm.undo() for x in range(attr_position + 2, attr_list_size, 1): pm.deleteAttr(selection, attribute=attr_list[x]) pm.undo() if up: for i in selected_attr: attr_list = pm.listAttr(selection, userDefined=True) attr_list_size = len(attr_list) attr_position = attr_list.index(i) if attr_list[attr_position - 1]: pm.deleteAttr(selection, attribute=attr_list[attr_position - 1]) pm.undo() for x in range(attr_position + 1, attr_list_size, 1): pm.deleteAttr(selection, attribute=attr_list[x]) pm.undo() if len(list_attr) > 0: for attr in list_attr: pm.setAttr("{0}.{1}".format(selection, attr), lock=True) sys.stdout.write("Complete.\n")
def undo_chunk(auto_undo=False, exc_callback=None): ''' Undo chunk context manager... ''' try: pm.undoInfo(openChunk=True) yield except Exception as e: pm.undoInfo(closeChunk=True) if auto_undo: pm.undo() if exc_callback: exc_callback(e) raise else: pm.undoInfo(closeChunk=True)
def inner(*args, **kwargs): err = None pmc.undoInfo(openChunk=True) try: res = func(*args, **kwargs) except Exception as err: raise finally: pmc.undoInfo(closeChunk=True) # Close undo! if err: # Did we error out? pmc.undo() e_type, e_name, e_trace = sys.exc_info() # Last error pmc.confirmDialog( t="Uh oh... %s" % e_type.__name__, m=str(e_name) ) return res
def deleteAttr(up=False, tmp=False): objs = pm.ls(sl=True) attrs = pm.channelBox("mainChannelBox", q=True, sma=True) sl_attrs = copy.deepcopy(attrs) for obj in objs: if up: attrs = pm.listAttr(obj, ud=True) for attr in sl_attrs: attrs.remove(attr) for attr in attrs: try: pm.deleteAttr (obj, at=attr) if tmp: pm.undo() except: pass
def R_Down(self, ui): index = ui.TargetList.currentIndex() itemText = str(index.data()) selected = pm.select(itemText) selectedJoint = pm.ls(sl=True)[0] pm.undo() temp = targetTree[index.row()] targetTree[index.row()] = targetTree[index.row() + 1] targetTree[index.row() + 1] = temp tempIndex = targetIndex[index.row()] targetIndex[index.row()] = targetIndex[index.row() + 1] targetIndex[index.row() + 1] = tempIndex self.updateTargetList(ui, targetTree)
def amcveProfile(cvSrc, trim): """ """ cvSrc = pm.ls(cvSrc)[0] tiLen = [] if trim: tiLen.append(pm.playbackOptions(q= 1, min= 1)) tiLen.append(pm.playbackOptions(q= 1, max= 1)) pm.undoInfo(ock= 1) pm.setKeyframe(cvSrc, insert= 1, t= tiLen, f= tiLen) pm.undoInfo(cck= 1) cvBaseMod = { 'cvTyp' : pm.objectType(cvSrc), 'prInf' : cvSrc.getPreInfinityType().key, 'poInf' : cvSrc.getPostInfinityType().key, 'weedT' : pm.keyTangent(cvSrc, q= 1, weightedTangents= 1), 'breaD' : pm.keyframe(cvSrc, q= 1, breakdown= 1) } cvPortray = { 'Frame' : pm.keyframe(cvSrc, q= 1, timeChange= 1), 'Float' : pm.keyframe(cvSrc, q= 1, floatChange= 1), 'Value' : pm.keyframe(cvSrc, q= 1, valueChange= 1) } cvFeature = { 'TLock' : pm.keyTangent(cvSrc, q= 1, lock= 1), 'WLock' : pm.keyTangent(cvSrc, q= 1, weightLock= 1), 'InTyp' : pm.keyTangent(cvSrc, q= 1, inTangentType= 1), 'OuTyp' : pm.keyTangent(cvSrc, q= 1, outTangentType= 1), 'InWet' : pm.keyTangent(cvSrc, q= 1, inWeight= 1), 'OuWet' : pm.keyTangent(cvSrc, q= 1, outWeight= 1), 'InAng' : pm.keyTangent(cvSrc, q= 1, inAngle= 1), 'OuAng' : pm.keyTangent(cvSrc, q= 1, outAngle= 1) } cvSrcProfile = { 'cvTrimmed' : tiLen, 'cvBaseMod' : cvBaseMod, 'cvPortray' : cvPortray, 'cvFeature' : cvFeature } if trim: pm.undo() return cvSrcProfile
def exportAssetAssembly(name, rigTopNode, meshTopNode, path, postScript=None): if pm.ls(rigTopNode): rigTopNode = pm.PyNode(rigTopNode) else: pm.displayError( "{} doesn't exist or duplicated. Please check your " "scene".format(rigTopNode)) return if pm.ls(meshTopNode): meshTopNode = pm.PyNode(meshTopNode) else: pm.displayError( "{} doesn't exist or duplicated. Please check " "your scene".format(meshTopNode)) return # check the folder and script # if the target name exist abort and request another name deformer_jnts = rigTopNode.rigGroups[3].connections()[0].members() if not deformer_jnts: pm.displayError( "{} is empty. The tool can't find any joint".format(meshTopNode)) # export connections and cut joint connections # cut al possible remaining connection and adjust hierarchy # pot script if postScript: try: execfile(postScript) except Exception as ex: template = "An exception of type {0} occured. Arguments:\n{1!r}" message = template.format(type(ex).__name__, ex.args) pm.displayError(message) cont = pm.confirmBox("FAIL: Script Fail", "Do you want to export anyway?" + "\n\n" + message + "\n\n" + traceback.format_exc(), "Continue", "Cancel") if not cont: pm.undo() return
def exportRig(path=None): """ Exports a rig from the current scene. This command relies on our static root joint existing in the scene. Args: path(str): A destination fbx file path. Returns: str: The exported file path. """ # path = path or saveFbxDialog('Export Rig Dialog') path = path or os.path.join(getSceneCharacterAssetDirectory(), 'skeleton.fbx') # Find the root and bounding box root = getRootJoint() if root is None: raise RootJointException('Export rig failed, could not find a root joint in the scene.') box = getBoundingBox() try: pmc.undoInfo(openChunk=True) if root.getParent() is not None: pmc.parent(root, world=True) if box.getParent() is not None: pmc.parent(box, world=True) # Disconnect all connections and constraints for joint in [root] + getBindSkeleton(): joint.message.disconnect(outputs=True) constraints = joint.getChildren(type='constraint') if len(constraints) > 0: pmc.delete(constraints) exportFbx([root, box], path, animation=False) finally: pmc.undoInfo(closeChunk=True) if not pmc.undoInfo(uqe=True, q=True): pmc.undo() # Convert to hkx ckcmd.importrig(path, os.path.dirname(path))
def randomizer_createUserInterface(): """-------------------------------------------------------------------------- Create User Interface Procedure --------------------------------------------------------------------------""" pm.window('randomizer_window', s=0, rtf=0, t="randomizer", wh=(300, 700)) # Create UI elements pm.columnLayout('mainColumnLayout', h=900, w=248, columnAlign="center", adjustableColumn=1) pm.separator('selectedTransformObjectsSeparator', h=10, w=240, st="none") pm.text('selectedTransformObjectsText', fn="boldLabelFont", h=24, l="selected transform Objects", w=240, al="center") pm.textScrollList('selectedTransformObjectsTextScrollList', h=80, w=240) pm.button('loadObjectsButton', h=28, c=lambda *args: randomizer_loadSelection(0), l="load transform Objects", w=240) pm.separator('selectedMaterialsSeparator', h=10, w=240, st="none") pm.text('selectedMaterialsText', fn="boldLabelFont", h=24, l="selected Materials", w=240, al="center") pm.textScrollList('selectedMaterialsTextScrollList', h=80, w=240) pm.button('loadMaterialsButton', h=28, c=lambda *args: randomizer_loadSelection(1), l="load Materials", w=240) pm.separator('transformAttributesSeparator', h=10, w=240, st="none") pm.text('randomizeAttributesText', fn="boldLabelFont", h=24, l="randomize Attributes", w=240, al="center") pm.checkBoxGrp('randomizeAttributesCheckBoxGrp', h=24, l4="Material", l2="Rotate", l3="Scale", w=240, l1="Translate", ncb=4, cw=[(1, 67), (2, 57), (3, 50), (4, 57)]) pm.separator('translateAttributesSeparator', h=10, w=240, st="none") pm.text('translateText', fn="boldLabelFont", h=24, l="Translate", w=240, al="center") pm.floatFieldGrp('minMaxXtranslateFloatFieldGrp', pre=3, el="max X", bgc=(0.25, 0, 0), h=24, l="min X", nf=2, v1=0, v2=0, w=240, cw=[(1, 60), (2, 60), (3, 60), (4, 60)]) pm.floatFieldGrp('minMaxYtranslateFloatFieldGrp', pre=3, el="max Y", bgc=(0, 0.25, 0), h=24, l="min Y", nf=2, v1=0, v2=0, w=240, cw=[(1, 60), (2, 60), (3, 60), (4, 60)]) pm.floatFieldGrp('minMaxZtranslateFloatFieldGrp', pre=3, el="max Z", bgc=(0, 0, 0.25), h=24, l="min Z", nf=2, v1=0, v2=0, w=240, cw=[(1, 60), (2, 60), (3, 60), (4, 60)]) pm.separator('rotateAttributesSeparator', h=10, w=240, st="none") pm.text('rotateText', fn="boldLabelFont", h=24, l="Rotate", w=240, al="center") pm.floatFieldGrp('minMaxXrotateFloatFieldGrp', pre=3, el="max X", bgc=(0.25, 0, 0), h=24, l="min X", nf=2, v1=0, v2=0, w=240, cw=[(1, 60), (2, 60), (3, 60), (4, 60)]) pm.floatFieldGrp('minMaxYrotateFloatFieldGrp', pre=3, el="max Y", bgc=(0, 0.25, 0), h=24, l="min Y", nf=2, v1=0, v2=0, w=240, cw=[(1, 60), (2, 60), (3, 60), (4, 60)]) pm.floatFieldGrp('minMaxZrotateFloatFieldGrp', pre=3, el="max Z", bgc=(0, 0, 0.25), h=24, l="min Z", nf=2, v1=0, v2=0, w=240, cw=[(1, 60), (2, 60), (3, 60), (4, 60)]) pm.separator('scaleAttributesSeparator', h=10, w=240, st="none") pm.text('scaleText', fn="boldLabelFont", h=24, l="Scale", w=240, al="center") pm.floatFieldGrp('minMaxXscaleFloatFieldGrp', pre=3, el="max X", bgc=(0.25, 0, 0), h=24, l="min X", nf=2, v1=1, v2=1, w=240, cw=[(1, 60), (2, 60), (3, 60), (4, 60)]) pm.floatFieldGrp('minMaxYscaleFloatFieldGrp', pre=3, el="max Y", bgc=(0, 0.25, 0), h=24, l="min Y", nf=2, v1=1, v2=1, w=240, cw=[(1, 60), (2, 60), (3, 60), (4, 60)]) pm.floatFieldGrp('minMaxZscaleFloatFieldGrp', pre=3, el="max Z", bgc=(0, 0, 0.25), h=24, l="min Z", nf=2, v1=1, v2=1, w=240, cw=[(1, 60), (2, 60), (3, 60), (4, 60)]) pm.separator('randomizeSelectionSeparator', h=10, w=240, st="none") pm.button('randomizeAbsoluteButton', h=28, c=lambda *args: randomizer_randomizeSelection(), l="randomize Abolute", w=240) pm.button('randomizeRelativeButton', h=28, c=lambda *args: randomizer_randomizeSelection(relative=True), l="randomize Relative", w=240) pm.separator('timeAttributesSeparator', h=10, w=240, st="none") pm.text('timeText', fn="boldLabelFont", h=24, l="Time", w=240, al="center") pm.intFieldGrp('minMaxTimeIntFieldGrp', el="max", bgc=(0, 0, 0), h=24, l="min", nf=2, v1=-1, v2=1, w=240, cw=[(1, 60), (2, 60), (3, 60), (4, 60)]) pm.button('setUniformKeyframe', h=28, c=lambda *args: rand_Keyframe(objects=None, attribute="all", axis=["X", "Y", "Z"], uniform=True, min=-10, max=10, step=1), l="Set Keyframes uniform", w=240) pm.button('setRandomKeyframe', h=28, c=lambda *args: rand_Keyframe(objects=None, attribute="all", axis=["X", "Y", "Z"], uniform=False, min=-10, max=10, step=1), l="Set Keyframes random", w=240) pm.separator('undoSeparator', h=10, w=240, st="none") pm.button('undoButton', h=28, c=lambda *args: pm.undo(), l="undo", w=240) pm.iconTextButton('staschiIconTextButton', h=28, c=lambda *args: randomizer_loadHelpWebsite(), l="www.staschi.com", w=240, st="textOnly") pm.setParent('..') pm.setParent('..') # Display UI pm.showWindow('randomizer_window')
def main(): sel_list = pm.ls(sl=1) if not sel_list: return sel = sel_list[0] pm.undoInfo(ock=1) pm.parent(sel,w=1) # NOTE 居中轴心 pm.xform(sel,cp=1) pm.mel.BakeCustomPivot() sel.t.set(0,0,0) sel.r.set(0,0,0) x,_,z = pm.xform(sel,q=1,rp=1) bbox = pm.exactWorldBoundingBox(sel) pm.xform(sel,piv=[x,bbox[1],z]) pm.mel.BakeCustomPivot() pm.xform(sel,ws=1,t=[0,0,0]) index = 1 path = os.path.join(output_path,"%s_%s.ma" % (base_name,str(index).zfill(2))) while os.path.exists(path): index += 1 path = os.path.join(output_path,"%s_%s.ma" % (base_name,str(index).zfill(2))) path = path.replace('\\','/') print(path) # commnad = 'FBXExport -f "%s.fbx" -s ' % path.replace('\\','/') # NOTE 导出 ma 文件 pm.mel.file(path,f=1,options="v=0;",typ="mayaAscii",pr=1,es=1) pm.undoInfo(cck=1) pm.undo()
def exportAssetAssembly(name, rigTopNode, meshTopNode, path, postScript=None): """Export the asset assembly. Model, rig and connections dict. Args: name (str): Name of the asset rigTopNode (str): Name of the rig top node meshTopNode (str): Name of the model top node path (str): Pestination directory postScript (path, optional): Script to run before export Returns: None: None """ if pm.ls(rigTopNode): rigTopNode = pm.PyNode(rigTopNode) else: pm.displayError( "{} doesn't exist or duplicated. Please check your " "scene".format(rigTopNode)) return if pm.ls(meshTopNode): meshTopNode = pm.PyNode(meshTopNode) else: pm.displayError( "{} doesn't exist or duplicated. Please check " "your scene".format(meshTopNode)) return # check the folder and script # if the target name exist abort and request another name deformer_jnts = rigTopNode.rigGroups[3].connections()[0].members() if not deformer_jnts: pm.displayError( "{} is empty. The tool can't find any joint".format(meshTopNode)) # export connections and cut joint connections file_path = os.path.join(path, name + ".jmm") dm_nodes = exportConnections(source=deformer_jnts, filePath=file_path, disc=True) # cut al possible remaining connection and adjust hierarchy # joint or visibility jnt_org = pm.PyNode("jnt_org") pm.disconnectAttr(rigTopNode.jnt_vis, jnt_org.visibility) # restructure model model = pm.createNode("transform", n="model", p=None, ss=True) pm.addAttr(model, ln="rigGroups", at='message', m=1) pm.parent(meshTopNode, jnt_org, model) # disconnect jnt set sets = rigTopNode.listConnections(type="objectSet") deformersGrp = None for oSet in sets: if "deformers_grp" in oSet.name(): deformersGrp = oSet if deformersGrp: for cnx in deformersGrp.message.listConnections(p=True): pm.disconnectAttr(deformersGrp.message, cnx) pm.connectAttr(deformersGrp.message, model.attr("rigGroups[0]")) # disconnect bindPoses dg_poses = rigTopNode.message.listConnections(type="dagPose", p=True) for dgp in dg_poses: if dgp.node().name().startswith("bindPose"): pm.disconnectAttr(rigTopNode.message, dgp) # post script if postScript: try: execfile(postScript) except Exception as ex: template = "An exception of type {0} occured. Arguments:\n{1!r}" message = template.format(type(ex).__name__, ex.args) pm.displayError(message) cont = pm.confirmBox("FAIL: Script Fail", "Do you want to export anyway?" + "\n\n" + message + "\n\n" + traceback.format_exc(), "Continue", "Cancel") if not cont: pm.undo() return # export rig model pm.select(dm_nodes, r=True) pm.select(rigTopNode, add=True) file_path = os.path.join(path, name + "_rig.ma") exp = pm.exportSelected(file_path, f=True, type="mayaAscii") pm.displayInfo(exp) # export mesh and joints pm.select(model, r=True) file_path = os.path.join(path, name + "_model.ma") exp = pm.exportSelected(file_path, f=True, type="mayaAscii") pm.displayInfo(exp)
def __exit__(self, exc_type, exc_val, exc_tb): pmc.undoInfo(closeChunk=True) # Undo in case of an exception being raised if exc_val is not None: pmc.undo()
def exportFullPackage(self, palName, version, bake= False, anim= False): """ Export Palettes, Descriptions, Grooming, Guides, all together, even bake modifiers befoer export if needed. """ self.clearPreview() # bake modifiers generator = {} if bake: for desc in xg.descriptions(palName): # bake Noise modifiers # fxModules evals from bottom to top clumpModLast = '' for fxm in xg.fxModules(palName, desc): if xg.fxModuleType(palName, desc, fxm) == 'ClumpingFXModule': # set the top clumpingMod cvAttr to True, for anim modifiers which needs clump if clumpModLast: xg.setAttr('cvAttr', 'false', palName, desc, clumpModLast) xg.setAttr('cvAttr', 'true', palName, desc, fxm) clumpModLast = fxm if xg.fxModuleType(palName, desc, fxm) == 'NoiseFXModule': # temporarily turn off lod so we dont bake it in lod = xg.getAttr('lodFlag', palName, desc) xg.setAttr('lodFlag', 'false', palName, desc) # change mode for bake xg.setAttr('mode', '2', palName, desc, fxm) # bake the noise pm.mel.xgmNullRender(pb= desc) # restore xg.setAttr('lodFlag', lod, palName, desc) # change mode to baked xg.setAttr('mode', '1', palName, desc, fxm) # bake groom modifiers fxm = xg.addFXModule(palName, desc, 'BakedGroomManagerFXModule') xg.setAttr('active', 'true', palName, desc, fxm) xg.bakedGroomManagerBake(palName, desc) # set Generator to XPD generator[desc] = xg.getActive(palName, desc, 'Generator') xg.setActive(palName, desc, 'FileGenerator') # change to export version path and keep current workPath = xg.getAttr('xgDataPath', palName) workProj = xg.getAttr('xgProjectPath', palName) xg.setAttr('xgDataPath', self.paletteVerDir(palName, version, raw= True), palName) xg.setAttr('xgProjectPath', self.projPath, palName) # get resolved repo path dataPath = self.paletteVerDir(palName, version) # set [xgDogTag] attr for ANIM record branchName if anim: xg.setAttr('xgDogTag', version, palName) # export descriptions for desc in xg.descriptions(palName): dstDescDir = xg.expandFilepath('${DESC}', desc, True, True) expPath = dstDescDir + desc + '.xdsc' xg.exportDescription(palName, desc, expPath) # copy map files srcDescVar = workPath.replace('${PROJECT}', workProj) + '/${DESC}' srcDescDir = xg.expandFilepath(srcDescVar, desc) for mapDir in os.listdir(srcDescDir): srcMap = os.path.join(srcDescDir, mapDir) dstMap = os.path.join(dstDescDir, mapDir) if os.path.isdir(srcMap): dir_util.copy_tree(srcMap, dstMap) # export palettes expPath = dataPath + '/' + palName + '.xgen' xg.exportPalette(palName, expPath) # export grooming for desc in xg.descriptions(palName): igdesc = xg.getAttr('groom', palName, desc) if igdesc: expPath = xg.expandFilepath('${DESC}/groom', desc, True, True) tpu = 5 sampling = 1 igDescr = xg.igDescription(desc) # export Attribute Map try: pm.waitCursor(state= True) # may have .ptx file handle lock issue pm.mel.iGroom(exportMaps= expPath, texelsPerUnit= tpu, instanceMethod= sampling, description= igDescr) finally: pm.waitCursor(state= False) # export Mask try: pm.waitCursor(state= True) # may have .ptx file handle lock issue pm.mel.iGroom(exportMask= expPath, texelsPerUnit= tpu, description= igDescr) finally: pm.waitCursor(state= False) # export Region try: pm.waitCursor(state= True) # may have .ptx file handle lock issue pm.mel.iGroom(exportRegion= expPath, texelsPerUnit= tpu, description= igDescr) finally: pm.waitCursor(state= False) # export Settings jsonPath = expPath + 'groomSettings.json' groomSettings = {}.fromkeys(['density', 'length', 'width']) for key in groomSettings: groomSettings[key] = pm.getAttr(igdesc + '.' + key) with open(jsonPath, 'w') as jsonFile: json.dump(groomSettings, jsonFile, indent=4) # export guides with undoable('exportGuides'): for desc in xg.descriptions(palName): # listGuides guides = xg.descriptionGuides(desc) if not guides: continue expPath = xg.expandFilepath('${DESC}', desc) pm.select(guides, r= 1) # guides to curves curves = pm.mel.xgmCreateCurvesFromGuides(0, True) # export as alembic if not pm.pluginInfo('AbcExport', q= 1, l= 1): pm.loadPlugin('AbcExport') abcCmds = '-frameRange 1 1 -uvWrite -worldSpace -dataFormat ogawa ' abcRoot = '-root ' + ' -root '.join([cur.longName() for cur in pm.ls(curves)]) abcPath = expPath + 'curves.abc' pm.mel.AbcExport(j= abcCmds + abcRoot + ' -file ' + abcPath) pm.undo() if anim: # save out hairSystem preset presetMel = [] for nodeType in ['nucleus', 'hairSystem', 'nRigid']: presetDict = self.ioAttrPreset(nodeType, True) presetMel.extend(presetDict.values()) # move preset file to version repo presetRepo = self.nDynPresetPath(palName, version) if not os.path.exists(presetRepo): os.mkdir(presetRepo) for prs in presetMel: dstPath = '/'.join([presetRepo, os.path.basename(prs)]) shutil.move(prs, dstPath) # create empty _shot_ folder shotDir = self.paletteDeltaDir(palName, version, '') if not os.path.exists(shotDir): os.mkdir(shotDir) # export snapshot for i in range(5): tmpPath = self.snapshotTmp % (i+1) if os.path.isfile(tmpPath): imgPath = self.snapshotImgPath(palName, version, str(i+1)) if not os.path.exists(os.path.dirname(imgPath)): os.mkdir(os.path.dirname(imgPath)) shutil.move(tmpPath, imgPath) # restore dataPath xg.setAttr('xgDataPath', workPath, palName) xg.setAttr('xgProjectPath', workProj, palName) # restore modifiers if bake: for desc in xg.descriptions(palName): # bake Noise modifiers for fxm in xg.fxModules(palName, desc): if xg.fxModuleType(palName, desc, fxm) == 'NoiseFXModule': # restore to live mode xg.setAttr('mode', '0', palName, desc, fxm) # remove bake groom modifiers for fxm in xg.fxModules(palName, desc): if xg.fxModuleType(palName, desc, fxm) == 'BakedGroomManagerFXModule': xg.removeFXModule(palName, desc, fxm) # restore Generator xg.setActive(palName, desc, generator[desc]) self.refresh('Full') self.notifyMsg('Collection Export Complete !', 0) return True
def exportSkin(meshes=None, path=None): """ Exports the given mesh nodes as a skyrim skin fbx. If no meshes are given the current selected meshes will be used. If no meshes are selected all meshes skinned to the root skeleton will be used. Args: meshes(list): A list of meshes to export. path(str): The destination fbx path. Returns: str: The exported file path. """ path = path or saveFbxDialog('Save Skin Dialog', dir=getSceneCharacterAssetDirectory()) # Get the root skeleton root = getRootJoint() if root is None: raise RootJointException('Export rig failed, could not find a root joint in the scene.') rootSkeleton = [root] + root.listRelatives(ad=True, type='joint') def getSkinnedMeshes(): clusters = set() for joint in rootSkeleton: for cluster in pmc.ls(pmc.listConnections(joint), type='skinCluster'): clusters.add(cluster) return [pmc.skinCluster(cluster, geometry=True, q=True)[0] for cluster in clusters] meshes = meshes or pmc.selected() or getSkinnedMeshes() meshes = getMeshes(meshes) if len(meshes) > 1: raise NotImplementedError('Multiple meshes selected for export. Currently we only support one mesh per skin.') # Check max influences for mesh in meshes: if not _checkMaxInfluences(mesh): raise MaxInfluenceException('Failed to export "%s". Skinning contains more than 4 influences.' % mesh) try: pmc.undoInfo(openChunk=True) # Set vertex colors to white for mesh in meshes: pmc.polyColorPerVertex(mesh, colorRGB=[1, 1, 1], a=1) # To fix certain issues with skinning we need to mess with the normals for mesh in meshes: pmc.bakePartialHistory(mesh, prePostDeformers=True) # Delete Non-deformer history pmc.polyNormalPerVertex(mesh, unFreezeNormal=True) # Unlock the normals pmc.polySoftEdge(mesh, a=180) # Soften the normals pmc.bakePartialHistory(mesh, prePostDeformers=True) # Delete Non-deformer history pmc.polyNormalPerVertex(mesh, freezeNormal=True) # Lock the normals pmc.polySoftEdge(mesh, a=0) # Harden the normals pmc.bakePartialHistory(mesh, prePostDeformers=True) # Delete Non-deformer history # Remove all joint constraints constraints = root.listRelatives(ad=True, type='constraint') if len(constraints) > 0: pmc.delete(constraints) # Disconnect message connections for joint in rootSkeleton: joint.message.disconnect() if not joint.hasAttr(MATCH_ATTR_NAME): continue for input in joint.attr(MATCH_ATTR_NAME).inputs(plugs=True): input.disconnect(joint.attr(MATCH_ATTR_NAME)) exportFbx(rootSkeleton + [mesh.getParent() for mesh in meshes], path=path) finally: pmc.undoInfo(closeChunk=True) pmc.undo() # Export nif ckcmd.importskin(path, os.path.dirname(path))
def testUndoChunk(self): with undo_chunk(): pmc.joint(), pmc.joint() self.assertEqual(len(pmc.ls(type='joint')), 2) pmc.undo() self.assertFalse(pmc.ls(type='joint'))
def subDelAttr(obj, string): pm.deleteAttr(obj, at=string) pm.undo()
def lcObj_exportObjs(*args, **kwargs): ''' Export .obj files from selected geometry, either as one combined file or as individual files per object. Will recognize and convert poly smooth preview to geometry for export ''' global prefix path = pm.textField(prefix + '_textField_export_path', query=True, text=True) objPrefix = pm.textField(prefix + '_textField_prefix', query=True, text=True) if objPrefix: objPrefix += '_' if path: sel = pm.ls(sl=True) if sel: sel = geometry.filterForGeometry(sel) print sel #undo is the easiest way to work on geometry temporarily pm.undoInfo(openChunk=True) if pm.checkBox(prefix + '_checkBox_use_smooth', query=True, v=True): for obj in sel: pm.select(obj) #find the objects currently displayed as smooth and create converted poly copies if pm.displaySmoothness(q=True, polygonObject=True)[0] == 3: pm.mel.performSmoothMeshPreviewToPolygon() if pm.checkBox(prefix + '_checkBox_export_indi', query=True, v=True): #export objects individually for obj in sel: pm.select(obj) name = str(obj) exportString = path + '/' + objPrefix + name + '.obj' pm.exportSelected( exportString, force=True, options= 'groups=1;ptgroups=1;materials=0;smoothing=1;normals=1', type='OBJexport', pr=True, es=True) else: #export as one object pm.select(sel) name = '' while name == '': dialog = pm.promptDialog(title='OBJ Name', message='Enter Name:', button=['OK', 'Cancel'], defaultButton='OK', cancelButton='Cancel', dismissString='Cancel') if dialog == 'OK': name = pm.promptDialog(query=True, text=True) if name: exportString = path + '/' + objPrefix + name + '.obj' pm.exportSelected( exportString, force=True, options= 'groups=1;ptgroups=1;materials=0;smoothing=1;normals=1', type='OBJexport', pr=True, es=True) else: pm.warning("You didn't type a name for your obj") if dialog == 'Cancel': break pm.undoInfo(closeChunk=True) pm.undo() pm.select(clear=True) else: pm.warning('Did you specify a path?')
def export_anim(root): # Select Root pymel.select(root) scene_name = str(pymel.sceneName().basename().split('.')[0]) path = os.path.join(siteCustomize.ROOT_DIR, 'animations', 'export', scene_name) path = path.replace('\\', '/') pymel.mel.eval('FBXResetExport()') pymel.mel.eval('FBXExportInAscii -v true') # EXPORT pymel.mel.eval('FBXExport -f "{0}" -s'.format(path)) if __name__ == '__main__': # # ctrl = pymel.selected()[0] # # export_pose(ctrl.region, pose_name='test') with pymel.UndoChunk(): main = pymel.PyNode('Main_Net') root = main.jnts[0] bake_anim(root) export_anim(root) pymel.undo()
def lcObj_exportObjs(*args, **kwargs): ''' Export .obj files from selected geometry, either as one combined file or as individual files per object. Will recognize and convert poly smooth preview to geometry for export ''' global lct_cfg global prefix global defaultPath path = pm.textField(prefix+'_textField_export_path', query=True, text=True) objPrefix = pm.textField(prefix+'_textField_prefix', query=True, text=True) if objPrefix: objPrefix+='_' if path and path != defaultPath: sel = pm.ls(sl=True) if sel: sel = lcGeometry.Geometry.filterForGeometry(sel) #undo is the easiest way to work on geometry temporarily pm.undoInfo(openChunk=True) if sel: if pm.checkBox(prefix+'_checkBox_use_smooth', query=True, v=True): for obj in sel: pm.select(obj) #find the objects currently displayed as smooth and create converted poly copies if pm.displaySmoothness(q=True, polygonObject=True)[0] == 3: pm.mel.performSmoothMeshPreviewToPolygon() if pm.checkBox(prefix+'_checkBox_export_indi', query=True, v=True): #export objects individually for obj in sel: pm.select(obj) nameSplit = str(obj).split('|') if len(nameSplit) > 1: name = nameSplit[-1] else: name = nameSplit[0] exportString = os.path.normpath(os.path.join(path,str(objPrefix+name+'.obj'))) try: pm.exportSelected(exportString, force=True, options='groups=1;ptgroups=1;materials=0;smoothing=1;normals=1', type='OBJexport', pr=True, es=True) lcUtility.Utility.lc_print('Exporting: {0}'.format(exportString)) except: lcUtility.Utility.lc_print_exception('Failed to export: {0}'.format(exportString)) #undo export individually pm.undoInfo(closeChunk=True) pm.undo() else: #export as one object pm.select(sel) name = '' while name == '': dialog = pm.promptDialog(title='OBJ Name', message='Enter Name:', button=['OK', 'Cancel'], defaultButton='OK', cancelButton='Cancel', dismissString='Cancel') if dialog == 'OK': name = pm.promptDialog(query=True, text=True) if name: exportString = os.path.normpath(os.path.join(path,str(objPrefix+name+'.obj'))) try: pm.exportSelected(exportString, force=True, options='groups=1;ptgroups=1;materials=0;smoothing=1;normals=1', type='OBJexport', pr=True, es=True) pm.undoInfo(closeChunk=True) pm.undo() lcUtility.Utility.lc_print('Exporting: {0}'.format(exportString)) except: pm.undoInfo(closeChunk=True) pm.undo() lcUtility.Utility.lc_print('Failed to export: {0}'.format(exportString), mode='warning') else: pm.undoInfo(closeChunk=True) pm.undo() lcUtility.Utility.lc_print("You didn't type a name for your obj", mode='warning') if dialog == 'Cancel': pm.undoInfo(closeChunk=True) pm.undo() break pm.select(sel) else: lcUtility.Utility.lc_print('Select a mesh first', mode='warning') else: lcUtility.Utility.lc_print('Select a mesh first', mode='warning') else: lcUtility.Utility.lc_print('Did you set a path?', mode='warning')
# save out presets presetDict = {} for node in pm.ls(type= nodeType): presetName = node.name() if save: pm.nodePreset(save= [node, presetName]) else: pm.nodePreset(load= [node, presetName]) presetDict[node.name()] = presetVar % (nodeType, presetName) return presetDict @contextmanager def undoable(name): pm.undoInfo(ock=True, cn=name) try: yield name except Exception, e: import traceback pm.warning('[XGen Hub] : Error while running undoable <%s> : %s' % (name, e)) traceback.print_exc() finally: pm.undoInfo(cck=True) try: pm.undo() except RuntimeError as e: pm.warning(str(e))
def __exit__(self, exc_type, exc_val, exc_tb): pmc.undoInfo(closeChunk=True) if exc_val is not None: pmc.undo()
def __init__(self): super(KeyingWindow, self).__init__() # How do we make our window handle global hotkeys? undo = Qt.QAction('Undo', self) undo.setShortcut(Qt.Qt.CTRL + Qt.Qt.Key_Z) undo.triggered.connect(lambda: pm.undo()) self.addAction(undo) redo = Qt.QAction('Redo', self) redo.setShortcut(Qt.Qt.CTRL + Qt.Qt.Key_Y) redo.triggered.connect(lambda: pm.redo(redo=True)) self.addAction(redo) self.weight_node = None self.shown = False self.callback_ids = om.MCallbackIdArray() self._currently_refreshing = False style = r''' /* Maya's checkbox style makes the checkbox invisible when it's deselected, * which makes it impossible to tell that there's even a checkbox there to * click. Adjust the background color to fix this. */ QTreeView::indicator:unchecked { background-color: #000; } ''' self.setStyleSheet(style) self.time_change_listener = maya_helpers.TimeChangeListener(self._time_changed, pause_during_playback=False) # Make sure zMouthController has been generated. qt_helpers.compile_all_layouts() from zMayaTools.qt_widgets import draggable_progress_bar reload(draggable_progress_bar) from zMayaTools.qt_generated import zMouthController reload(zMouthController) self.ui = zMouthController.Ui_zMouthController() self.ui.setupUi(self) self.ui.selectionBar.setMinimum(0) self.ui.selectionBar.setMaximum(1000) self.ui.mainWeightBar.setMinimum(0) self.ui.mainWeightBar.setMaximum(1000) self.ui.selectNodeButton.clicked.connect(self.select_current_node) self.ui.shapeSelection1.currentIndexChanged.connect(self.shape1Changed) self.ui.shapeSelection2.currentIndexChanged.connect(self.shape2Changed) self.ui.selectedNodeDropdown.currentIndexChanged.connect(self.selectedNodeChanged) self.ui.setKeyShape1.clicked.connect(self.clicked_key_shape_1) self.ui.setKeyShape2.clicked.connect(self.clicked_key_shape_2) self.ui.keySelection.clicked.connect(self.clicked_key_selection) self.ui.keyMainWeight.clicked.connect(self.clicked_key_main_weight) self.ui.soloShape1.clicked.connect(self.solo_shape1) self.ui.soloShape2.clicked.connect(self.solo_shape2) self.ui.selectionBar.mouse_movement.connect(self.set_selection_bar_value) self.ui.mainWeightBar.mouse_movement.connect(self.set_main_weight) self.ui.selectionBar.set_undo_chunk_around_dragging('Dragging selection') self.ui.mainWeightBar.set_undo_chunk_around_dragging('Dragging weight') # This will call selectedNodeChanged, and trigger the rest of the refresh. self.refresh_weight_node_list()