def disable_in_camera_only(palette): """ Args: palette (str): XGen Legacy palette name """ palette = str(palette) for description in list_descriptions(palette): prev = xg.getActive(palette, description, "Previewer") if xg.attrExists("inCameraOnly", palette, description, prev): xg.setAttr("inCameraOnly", "false", palette, description, prev)
def disable_tube_shade(palette): """ Args: palette (str): XGen Legacy palette name """ palette = str(palette) for description in list_descriptions(palette): prim = xg.getActive(palette, description, "Primitive") if xg.attrExists("tubeShade", palette, description, prim): xg.setAttr("tubeShade", "false", palette, description, prim)
def descControlMethod(self, palName, descName): """ Find out what instance method used by description to control primitives, and return type name: 'Guides' 'Attribute' 'Groom' """ # check instance method primitive = xg.getActive(palName, descName, 'Primitive') if xg.getAttr('iMethod', palName, descName, primitive): return 'Guides' else: if xg.getAttr('groom', palName, descName): return 'Groom' else: return 'Attribute'
def description_ctrl_method(description): """ Find out what instance method used by description to control primitives, and return type name: 'Guides' 'Attribute' 'Groom' """ palette = get_palette_by_description(description) primitive = xg.getActive(palette, description, "Primitive") if xg.getAttr("iMethod", palette, description, primitive) == "1": return "Guides" else: # iMethod == "0" if xg.getAttr("groom", palette, description): return "Groom" else: return "Attribute"
def parse_objects(map_attr): """Parse attribute returned from `filePathEditor` into XGen object names (NOTE) Remember to refresh filePathEditor by calling `cmds.filePathEditor(refresh=True)`, or the fxmodule index might not return correctly. >>> cmds.filePathEditor(refresh=True) >>> maps = cmds.filePathEditor(q=1, listFiles="", withAttribute=1) ["descriptionShape.primitive.ClumpingFXModule(1).HeadPoint", ...] >>> parse_objects(maps[0]) ('CY_Mon_Hair', 'description', 'Clumping2', 'pointDir', 0) Args: map_attr (str): An attribute path returned from `cmds.filePathEditor` Returns: tuple: Names of palette, description, object, attr, attr-index """ address = map_attr.split(".") # The description shape name in `map_attr` string is a short name, # and since we only need the description transform short name, it # doesn't matter which shape node we get from `cmds.ls`. desc_shape = cmds.ls(address[0])[0] description = str(cmds.listRelatives(desc_shape, parent=True)[0]) # get short name palette = get_palette_by_description(description) if address[1] == "glRenderer": subtype = "GLRenderer" else: # primitive, generator subtype = xg.getActive(palette, description, str(address[1].capitalize())) if len(address) < 4: # Example: descriptionShape.generator.mask attr = address[2] attr, attr_indx = _parse_attribute(attr, subtype) return palette, description, subtype, attr, attr_indx else: # Example: descriptionShape.primitive.ClumpingFXModule(1).HeadPoint modifier_cls, mod_indx = address[2][:-1].split("(") mod_indx = int(mod_indx) attr = address[3] attr, attr_indx = _parse_attribute(attr, subtype) try: module = xg.fxModules(palette, description)[mod_indx] except IndexError: raise IndexError("Object not found, possible `filePathEditor` " "not refreshed: {}".format(map_attr)) else: if xg.fxModuleType(palette, description, module) == modifier_cls: return palette, description, module, attr, attr_indx raise Exception("Object not found, this is a bug: {}".format(map_attr))
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._path_created = {} 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) 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.makedirs(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.makedirs(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.makedirs(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