def importDescription(self, palName, descName, version, binding=False): """ XGen description will imported without validator. When importing baked description, @binding set to False should be fine. """ xdscFileName = descName + '.xdsc' xdscFile = '/'.join( [self.paletteVerDir(palName, version), descName, xdscFileName]) if not os.path.isfile(xdscFile): pm.error('[XGen Hub] : .xdsc file is not exists. -> ' + xdscFile) return None self.clearPreview() # check if descriptions exists in current scene if descName in xg.descriptions(palName): # delete current description folder descDir = xg.expandFilepath('${DESC}', descName) if os.path.isdir(descDir): try: dir_util.remove_tree(descDir) except: pm.warning('[XGen Hub] : Dir may not remove. -> ' + descDir) # delete current description xg.deleteDescription(palName, descName) # IMPORT DESCRIPTION desc = base.importDescription(palName, xdscFile) # create imported descriptions folder dataPath = xg.getAttr('xgDataPath', palName) paletteRoot = xg.expandFilepath(dataPath, '') msxgApi.setupDescriptionFolder(paletteRoot, palName, desc) # wrap into maya nodes pm.mel.xgmWrapXGen(pal=palName, d=desc, gi=binding) # bind to selected geometry if binding: igdesc = xg.getAttr('groom', palName, desc) xg.modifyFaceBinding(palName, desc, 'Append', '', False, len(igdesc)) if igdesc: # set groom density and sampling method pm.setAttr(igdesc + '.density', 1) pm.setAttr(igdesc + '.interpStyle', 1) # import grooming as well self.importGrooming(palName, descName, version) # import guides as well self.importGuides(palName, descName, version) self.notifyMsg('Description Import Complete !', 0) return desc
def current_data_paths(palette, expand=False): paths = list() for path in xg.getAttr("xgDataPath", palette).split(";"): if expand: path = xg.expandFilepath(str(path), "") path = os.path.normpath(path).replace("\\", "/") paths.append(path) return paths
def importGuides(self, palName, descName= None, version= None): """ """ self.clearPreview() if descName: descs = [descName] else: descs = xg.descriptions(palName) # copy groom dir from versionRepo if @version has given if version: # check exists guidesDesc = {} hasMissing = False for desc in descs: if self.descControlMethod(palName, desc) == 'Guides': abcPath = '/'.join([self.paletteVerDir(palName, version), desc, 'curves.abc']) if os.path.isfile(abcPath): guidesDesc[desc] = abcPath else: hasMissing = True msg = '[XGen Hub] : palette [%s] description [%s] version [%s] NOT exists. -> %s' pm.warning(msg % (palName, desc, version, abcPath)) # copy file if no missing if not hasMissing: for desc in guidesDesc: src = guidesDesc[desc] dst = '/'.join([self.paletteWipDir(palName), desc, 'curves.abc']) if os.path.isdir(dst): os.remove(dst) shutil.copyfile(src, dst) else: pm.error('[XGen Hub] : Some .abc missing, Check ScriptEditor. guides import stopped.') return None # IMPORT GUIDES for desc in descs: # import alembic if not pm.pluginInfo('AbcImport', q= 1, l= 1): pm.loadPlugin('AbcImport') abcPath = xg.expandFilepath('${DESC}', desc) + 'curves.abc' if os.path.isfile(abcPath): pool = pm.group(em= 1, n= 'curvesToGuide_processPoll') pm.mel.AbcImport(abcPath, mode= 'import', rpr= pool) # select curves curves = pm.listRelatives(pool, c= 1) pm.select(curves, r= 1) # curvesToGuides pm.mel.xgmCurveToGuide(d= desc, tsp= 1.0, tsa= 0.0, deleteCurve= True) self.notifyMsg('Guides Import Complete !', 0) return True
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
def importGrooming(self, palName, descName= None, version= None): """ """ self.clearPreview() if descName: descs = [descName] else: descs = xg.descriptions(palName) # copy groom dir from versionRepo if @version has given if version: # check exists groomDesc = {} hasMissing = False for desc in descs: if xg.getAttr('groom', palName, desc): groomSource = '/'.join([self.paletteVerDir(palName, version), desc, 'groom']) if os.path.exists(groomSource): groomDesc[desc] = groomSource else: hasMissing = True msg = '[XGen Hub] : palette [%s] description [%s] version [%s] NOT exists. -> %s' pm.warning(msg % (palName, desc, version, groomSource)) # copy file if no missing if not hasMissing: for desc in groomDesc: src = groomDesc[desc] dst = '/'.join([self.paletteWipDir(palName), desc, 'groom']) if os.path.isdir(dst): try: dir_util.remove_tree(dst) except: pm.warning('[XGen Hub] : Dir may not remove. -> ' + dst) dir_util._path_created = {} dir_util.copy_tree(src, dst) else: pm.error('[XGen Hub] : Some data missing, Check ScriptEditor. grooming import stopped.') return None self.refresh() # IMPORT GROOMING # clear out autoExport path for preventing grooming auto export xg.setOptionVarString('igAutoExportFolder', '') for desc in descs: if xg.getAttr('groom', palName, desc): importPath = xg.expandFilepath('${DESC}/groom', desc) igDescr = xg.igDescription(desc) # import Attribute Map try: pm.waitCursor(state= True) pm.mel.iGroom(im= importPath, d= igDescr) finally: pm.waitCursor(state= False) # import Mask try: pm.waitCursor(state= True) pm.mel.iGroom(ik= importPath, d= igDescr) finally: pm.waitCursor(state= False) # import Region try: pm.waitCursor(state= True) pm.mel.iGroom(ir= importPath, d= igDescr) finally: pm.waitCursor(state= False) # restore default autoExport path xg.setOptionVarString('igAutoExportFolder', '${DESC}/groom') # IMPORT GROOM SETTINGS """ Currently only grab [density] setting, ['length', 'width'] will messed up imported grooming's map attribute """ for desc in descs: igdesc = xg.getAttr('groom', palName, desc) jsonPath = xg.expandFilepath('${DESC}/groom', desc) + 'groomSettings.json' if igdesc and os.path.isfile(jsonPath): groomSettings = {} with open(jsonPath) as jsonFile: groomSettings = json.load(jsonFile) for key in groomSettings: # grab [density] setting only if key == 'density': pm.setAttr(igdesc + '.' + key, groomSettings[key]) self.notifyMsg('Grooming Import Complete !', 0) return True
def importPalette(self, palName, version, binding= False, anim= False, asDelta= False, delta= []): """ ** NOT SUPPORT NAMESPACE ** XGen palette will imported without validator. [!!!] When importing [BAKED] palette, @binding set to False should be fine. """ xgenFileName = palName + '.xgen' xgenFile = str('/'.join([self.paletteVerDir(palName, version), xgenFileName])) if not os.path.isfile(xgenFile): self.notifyMsg('.xgen file is not exists.', 2) pm.error('[XGen Hub] : .xgen file is not exists. -> ' + xgenFile) return None if asDelta and not pm.sceneName(): self.notifyMsg('Please save the scene.', 2) return None self.clearPreview() # check if palette exists in current scene if palName in xg.palettes(): # delete current palette folder palDir = xg.expandFilepath(xg.getAttr('xgDataPath', palName), '') if os.path.isdir(palDir): try: dir_util.remove_tree(palDir) except: pm.warning('[XGen Hub] : Dir may not remove. -> ' + palDir) # delete current palette # this action might cry about 'None type object has no attr "previewer"' # when there is no xgen ui panel xg.deletePalette(palName) # IMPORT PALETTE palName = base.importPalette(xgenFile, delta, '') # update the palette with the current project xg.setAttr('xgProjectPath', str(pm.workspace(q= 1, rd= 1)), palName) dataPath = xg.paletteRootVar() + '/' + palName xg.setAttr('xgDataPath', dataPath, palName) # create imported palette folder paletteRoot = xg.expandFilepath(dataPath, '', True, True) # create all imported descriptions folder msxgApi.setupDescriptionFolder(paletteRoot, palName) # wrap into maya nodes palName = str(pm.mel.xgmWrapXGen(pal= palName, wp= binding, wlg= binding, gi= binding)) # copy maps from source descNames = xg.descriptions(palName) msxgApi.setupImportedMap(xgenFile, palName, descNames, self.projPath) # bind grooming descriptions to geometry if binding: for desc in descNames: igdesc = xg.getAttr('groom', palName, desc) if igdesc: # get groom dag node igdesc = xg.igActivateDescription(desc) # bind groom to geo pm.mel.igBindFromXGen(desc) # set groom density and sampling method pm.setAttr(igdesc + '.density', 1) pm.setAttr(igdesc + '.interpStyle', 1) # set all groom visible on xg.igSetDescriptionVisibility(True) # sync primitives tab attritube map path with auto export path xg.igSyncMaps(desc) # import grooming as well self.importGrooming(palName) # import as anim, build hairSystem if anim: # build hairSystem self.linkHairSystem(palName) # check preset dir exists presetLocalDir = str(pm.internalVar(userPresetsDir= 1)) presetRepo = self.nDynPresetPath(palName, version) if os.path.exists(presetRepo): # copy preset for prs in os.listdir(presetRepo): dstPath = presetLocalDir + prs prs = '/'.join([presetRepo, prs]) shutil.copyfile(prs, dstPath) # load preset # [note] nucleus preset will not be loaded during current devlope presetMel = [] for nodeType in ['hairSystem', 'nRigid']: presetDict = self.ioAttrPreset(nodeType, False) presetMel.extend(presetDict.values()) # dump preset for prs in presetMel: if os.path.isfile(prs): os.remove(prs) else: pm.warning('[XGen Hub] : nDynamic attribute presets folder not found.') if asDelta: dataPath = xg.getAttr('xgDataPath', palName) dataPath = dataPath + ';' + self.paletteVerDir(palName, version, raw= True) xg.setAttr('xgDataPath', dataPath, palName) # save scenes pm.saveFile(f= 1) # set export delta pm.setAttr(palName + '.xgExportAsDelta', 1) pm.warning('[XGen Hub] : Collection Import Complete !') self.notifyMsg('Collection Import Complete !', 0) return palName