def set_abs_path(self, xgen_dir): if not xgg.Maya: return # palette is collection, use palettes to get collections first. palettes = xgen.palettes() for palette in palettes: # Use descriptions to get description of each collection descriptions = xgen.descriptions(palette) for description in descriptions: commaon_objs = xgen.objects(palette, description, True) fx_objs = xgen.fxModules(palette, description) objs = commaon_objs + fx_objs # Get active objs,e.g. SplinePrimtives for obj in objs: attrs = xgen.allAttrs(palette, description, obj) for attr in attrs: value = xgen.getAttr(attr, palette, description, obj) if "${DESC}" in value: print palette, description, obj, attr description_dir = os.path.join(xgen_dir, "collections", palette, description).replace("\\", "/") new_value = value.replace("${DESC}", description_dir) xgen.setAttr(attr, new_value, palette, description, obj) de = xgg.DescriptionEditor de.refresh("Full")
def xgseedOnCreateDescription(param): logger.debug("xgenseed xgseedOnCreateDescription called") params = str(param).split(',') if len(params) == 2: xg.setAttr("renderer", "appleseed", params[1], params[0], "RendermanRenderer")
def exportCurves(descName, fxmName): # setup value = xg.getAttr("exportDir", palette, descName, fxmName) xg.setAttr("exportDir", str(value), palette, descName, fxmName) xg.setAttr("exportCurves", "true", palette, descName, fxmName) # Need to fill in the export faces to correct value xg.setAttr("exportFaces", "", palette, descName, fxmName) # export clumpCurves.mel pmc.mel.xgmNullRender(descName, percent=0) # get clumpCurves.mel file path curvesMelPath = xg.getAttr("_fullExportDir", palette, descName, fxmName) # Remove clumpCurves.mel's last cmd : "xgmMakeCurvesDynamic;" print("Reading curves mel. -> %s" % curvesMelPath) with open(curvesMelPath, "r") as mel_script: curvesMel = mel_script.readlines() cmdIndex = curvesMel.index("xgmMakeCurvesDynamic;\n") curvesMel[cmdIndex] = "" # execute it, and we will run our MakeCurvesDynamic later pmc.mel.eval("".join(curvesMel)) # restore xg.setAttr("exportCurves", "false", palette, descName, fxmName) xg.setAttr("exportFaces", "", palette, descName, fxmName)
def fix_invalid(cls, instance): import xgenm as xg invalid = cls.get_invalid(instance) for description in invalid: palette = xg.palette(description) xg.setAttr("percent", "100.0", palette, description, "GLRenderer")
def exportAnimPackage(self, palName, shotName): """doc""" # get version info from [xgDogTag] version = self.getAnimBranch(palName) if not version: pm.error('[XGen Hub] : Couldn\'t get ANIM branch name. Export process stop.') return None self.clearPreview() # add shotName attribute to xgen and save in xgen delta later if not xg.attrExists(self.xgShotAttr, palName): xg.addCustomAttr(self.xgShotAttr, palName) xg.setAttr(self.xgShotAttr, shotName, palName) # add nucleus startFrame attribute to xgen and save in xgen delta later if not xg.attrExists(self.xgRefFrame, palName): xg.addCustomAttr(self.xgRefFrame, palName) xg.setAttr(self.xgRefFrame, str(int(pm.PyNode('nucleus1').startFrame.get())), palName) # get resolved repo shotName path deltaPath = self.paletteDeltaDir(palName, version, shotName) if not os.path.exists(deltaPath): os.mkdir(deltaPath) deltaFile = '/'.join([deltaPath, palName + '.xgd']) # export delta xg.createDelta(palName, deltaFile) # get curves and export for desc in xg.descriptions(palName): curvesGrp = pm.ls(desc + '_hairSystemOutputCurves', type= 'transform') if curvesGrp and curvesGrp[0].listRelatives(): curves = curvesGrp[0].listRelatives() # cache curves, export as alembic if not pm.pluginInfo('AbcExport', q= 1, l= 1): pm.loadPlugin('AbcExport') start, end = self.getTimeSliderMinMax() abcCmds = '-frameRange %d %d -uvWrite -worldSpace -dataFormat ogawa ' % (start, end) abcRoot = '-root ' + ' -root '.join([cur.longName() for cur in pm.ls(curves)]) abcPath = '/'.join([deltaPath, desc + '.abc']) pm.mel.AbcExport(j= abcCmds + abcRoot + ' -file ' + abcPath) # 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), shotName) if not os.path.exists(os.path.dirname(imgPath)): os.mkdir(os.path.dirname(imgPath)) shutil.move(tmpPath, imgPath) self.refresh('Full') self.notifyMsg('Anim Result Export Complete !', 0) return True
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 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 xgOutputSettings(self, palName): """doc""" for desc in xg.descriptions(palName): # set renderer xg.setAttr( 'renderer', 'VRay', palName, desc, 'RendermanRenderer') # auto set primitive Bound value = xgcmds.autoSetPrimitiveBound(palName, desc) #xg.setAttr('primitiveBound', value, palName, desc, 'RendermanRenderer') self.refresh('Full')
def renderableButtonToggledSlot(self, checked): if checked: self.renderableButton.setIcon(self.disRenderableIcon) xg.setAttr("percent", xge.prepForAttribute(str(0)), self.collection, self.description, "RendermanRenderer") else: self.renderableButton.setIcon(self.renderableIcon) xg.setAttr("percent", xge.prepForAttribute(str(100)), self.collection, self.description, "RendermanRenderer") self.de.refresh('Description')
def setDefaultSettings(self): xg.setAttr("inCameraOnly", xge.prepForAttribute(str(False)), self.collection, self.description, "GLRenderer") xg.setAttr("splineSegments", xge.prepForAttribute(str(1)), self.collection, self.description, "GLRenderer") xg.setAttr("renderer", xge.prepForAttribute('Arnold Renderer'), self.collection, self.description, "RendermanRenderer") xg.setAttr("custom__arnold_rendermode", xge.prepForAttribute(str(1)), self.collection, self.description, "RendermanRenderer") xg.setAttr("custom__arnold_minPixelWidth", xge.prepForAttribute(str(0.5)), self.collection, self.description, "RendermanRenderer")
def importAnimResult(self, palName, version, shotName): """ """ self.clearPreview() # get delta .xgd file deltaPath = self.paletteDeltaDir(palName, version, shotName) deltaFile = '/'.join([deltaPath, palName + '.xgd']) # import if os.path.isfile(deltaFile): if not self.importPalette(palName, version, False, False, True, [deltaFile]): return None else: pm.error('[XGen Hub] : .xgd file not exists. Import stopped. -> ' + deltaFile) return None # get wires.abc wiresAbc = {} for abc in os.listdir(deltaPath): abcPath = '/'.join([deltaPath, abc]) if os.path.isfile(abcPath): descName = abc.split('.')[0] wiresAbc[descName] = str(abcPath) # animWire turn off live mode to read .abc for desc in [ desc for desc in wiresAbc if desc in xg.descriptions(palName) ]: for fxm in [ fxm for fxm in xg.fxModules(palName, desc) if xg.fxModuleType( palName, desc, fxm) == 'AnimWiresFXModule' ]: if xg.getAttr('active', palName, desc, fxm) == 'true': xg.setAttr('liveMode', 'false', palName, desc, fxm) xg.setAttr('wiresFile', wiresAbc[desc], palName, desc, fxm) # set ref frame self.setRefWiresFrame(xg.getAttr(self.xgRefFrame, palName)) # assign shaders # render settings self.xgOutputSettings(palName) self.refresh('Full') self.notifyMsg('Anim Result Import Complete !', 0) return True
def setRefWiresFrame(self, refWiresFrame= None): """doc""" if not refWiresFrame: refWiresFrame = str(int(pm.PyNode('nucleus1').startFrame.get())) else: if pm.objExists('nucleus1'): pm.PyNode('nucleus1').startFrame.set(int(refWiresFrame)) for palName in xg.palettes(): for desc in xg.descriptions(palName): for fxm in xg.fxModules(palName, desc): if xg.fxModuleType(palName, desc, fxm) == 'AnimWiresFXModule': xg.setAttr('refWiresFrame', refWiresFrame, palName, desc, fxm) self.refresh('Full')
def setPreviewInCam(self, palName, valueDict= None): """doc""" if valueDict: # restore value for desc in xg.descriptions(palName): xg.setAttr('inCameraOnly', valueDict[desc], palName, desc, 'GLRenderer') return None else: # set to false if no value in valueDict = {} for desc in xg.descriptions(palName): valueDict[desc] = xg.getAttr('inCameraOnly', palName, desc, 'GLRenderer') xg.setAttr('inCameraOnly', 'false', palName, desc, 'GLRenderer') return valueDict
def _do_import(self): """ Imports the groom into the scene """ # todo: query if is it the last version import_folder = self.ui.groom_package_txf.text() self.character = self.ui.import_character_cbx.currentText() if not import_folder: raise ValueError("Import path must be specified") # build scene mc.loadPlugin('xgenToolkit.mll') import_path_folder = import_folder.replace('.zip', '') _, groom_asset = os.path.split(import_path_folder) xgen_file = [f for f in os.listdir(import_path_folder) if f.endswith('.xgen')][-1] xgen_file = os.path.join(import_path_folder, xgen_file).replace('\\', '/') map_folder = [os.path.join(import_path_folder, d) for d in os.listdir(import_path_folder) if os.path.isdir(os.path.join(import_path_folder, d))][0] # import maya scenes mc.file(os.path.join(import_folder, 'scalps.ma'), i=True, type="mayaAscii", ignoreVersion=True, mergeNamespacesOnClash=False, gl=True, namespace=self.character, options="v=0", groupReference=False) # load mapping in_data = dict() with open(os.path.join(import_path_folder, 'mapping.json'), 'r') as fp: in_data = json.load(fp) # import xgen try: xg.importPalette(fileName=str(xgen_file), deltas=[], nameSpace=str(self.character)) except Exception: LOGGER.warning('Not found maps folder') # set path to xgen xg.setAttr('xgDataPath', str(map_folder), xg.palettes()[0]) # todo: remember shader is not imported, it will be imported by the shader import tool # Get the description editor first. # Changes in the groom itself, guides, and so on de = xgg.DescriptionEditor # # # # # Do a full UI refresh de.refresh("Full")
def switch_data_path(palette, data_path): """Switch xgDataPath context Args: palette (str): XGen Legacy palette name data_path (str): xgDataPath """ origin = xg.getAttr("xgDataPath", palette) data_path = data_path.replace("\\", "/") try: xg.setAttr("xgDataPath", data_path, palette) yield finally: xg.setAttr("xgDataPath", origin, palette)
def set_refWires_frame(refWiresFrame, palette): """Setup refWireFrame to the descriptions that has animWire modifier Args: refWiresFrame (int, float): refWireFrame value palette (str): XGen Legacy palette name """ refWiresFrame = str(int(refWiresFrame)) palette = str(palette) for desc in xg.descriptions(palette): for fxm in xg.fxModules(palette, desc): if xg.fxModuleType(palette, desc, fxm) != "AnimWiresFXModule": continue xg.setAttr("refWiresFrame", refWiresFrame, palette, desc, fxm)
def xgen_preview_all(palette): """Preview all XGen Legacy primitives instead of in view only Args: palette (str): XGen Legacy palette name """ origin_value = {} for desc in xg.descriptions(palette): origin_value[desc] = xg.getAttr("inCameraOnly", palette, desc, "GLRenderer") xg.setAttr("inCameraOnly", "false", palette, desc, "GLRenderer") try: yield finally: # restore value for desc in xg.descriptions(palette): xg.setAttr("inCameraOnly", origin_value[desc], palette, desc, "GLRenderer")
def exportCurvesMel(palName, descName, fxmName): """doc""" # setup value = xg.getAttr('exportDir', palName, descName, fxmName) xg.setAttr('exportDir', str(value), palName, descName, fxmName) xg.setAttr('exportCurves', 'true', palName, descName, fxmName) # # Need to fill in the export faces to correct value # xg.setAttr('exportFaces', '', palName, descName, fxmName) # export clumpCurves.mel pm.mel.xgmNullRender(descName, percent=0) # get clumpCurves.mel file path curvesMelPath = xg.getAttr('_fullExportDir', palName, descName, fxmName) # remove clumpCurves.mel's last cmd : "xgmMakeCurvesDynamic;" print 'Reading curves mel. -> ' + curvesMelPath curvesMel = open(curvesMelPath, 'r').readlines() cmdIndex = curvesMel.index('xgmMakeCurvesDynamic;\n') curvesMel[cmdIndex] = '' # execute it, and we will run our MakeCurvesDynamic later pm.mel.eval(''.join(curvesMel)) # restore xg.setAttr('exportCurves', 'false', palName, descName, fxmName) xg.setAttr('exportFaces', '', palName, descName, fxmName)
def import_xgen_cache(): palettes = xgen.palettes() if not palettes: return for palette in palettes: asset_name = palette.split("_")[0] descriptions = xgen.descriptions(palette) if not descriptions: continue cache_dir = get_cache_dir() for description in descriptions: cache_file_name = "%s/%s/hair/%s.abc" % (cache_dir, asset_name, description) if not os.path.isfile(cache_file_name): continue xgen.setAttr("useCache", "true", palette, description, "SplinePrimitive") xgen.setAttr("liveMode", "false", palette, description, "SplinePrimitive") xgen.setAttr("cacheFileName", cache_file_name, palette, description, "SplinePrimitive") de = xgg.DescriptionEditor de.refresh("Full")
cmds.select(cl= 1) for geo in geoCollection.keys(): cmds.select(cmds.ls('*' + geo, r= 1)[0], add= 1) moGeoCache.importGeoCache('assassin_' + cutId + '_geoCache_v01', 1, 'assassin') # import collections for geo in geoCollection.keys(): cmds.select(cmds.ls('*' + geo, r= 1)[0], r= 1) cmds.setAttr(cmds.ls(sl= 1)[0] + '.v', 0) xg.importPalette( geoCollection[geo], [], '' ) # get abc for disc in hairCacheDisc: xg.setAttr( 'cacheFileName', str(hairSimRoot + cutId + '/' + disc + '.abc'), hairColl, disc, 'SplinePrimitive') xg.setAttr( 'useCache', 'true', hairColl, disc, 'SplinePrimitive') xg.setAttr( 'liveMode', 'false', hairColl, disc, 'SplinePrimitive') # set renderer for collection in xg.palettes(): for disc in xg.descriptions(collection): xg.setAttr( 'renderer', 'VRay', collection, disc, 'RendermanRenderer') # update ui de = xgg.DescriptionEditor de.refresh('Full') # assign shader hairGrp = ['hairA3', 'hairA4', 'hairA5', 'hairA6', 'hairA14', 'assassin1', 'assassin2'] browlashGrp = ['lash1', 'lash2', 'lash3', 'lashBottom1']
# import geoCache cmds.select(cl=1) for geo in geoCollection.keys(): cmds.select(cmds.ls('*' + geo, r=1)[0], add=1) moGeoCache.importGeoCache('assassin_' + cutId + '_geoCache_v01', 1, 'assassin') # import collections for geo in geoCollection.keys(): cmds.select(cmds.ls('*' + geo, r=1)[0], r=1) cmds.setAttr(cmds.ls(sl=1)[0] + '.v', 0) xg.importPalette(geoCollection[geo], [], '') # get abc for disc in hairCacheDisc: xg.setAttr('cacheFileName', str(hairSimRoot + cutId + '/' + disc + '.abc'), hairColl, disc, 'SplinePrimitive') xg.setAttr('useCache', 'true', hairColl, disc, 'SplinePrimitive') xg.setAttr('liveMode', 'false', hairColl, disc, 'SplinePrimitive') # set renderer for collection in xg.palettes(): for disc in xg.descriptions(collection): xg.setAttr('renderer', 'VRay', collection, disc, 'RendermanRenderer') # update ui de = xgg.DescriptionEditor de.refresh('Full') # assign shader hairGrp = [ 'hairA3', 'hairA4', 'hairA5', 'hairA6', 'hairA14', 'assassin1', 'assassin2'
def setDensity(self, val): xg.setAttr("density", xge.prepForAttribute(str(val)), self.collection, self.description, "RandomGenerator") pm.mel.eval('xgmPreview -progress {"%s"};' % self.description) self.de.refresh('Description')
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
def bake_modules(palette, description): """Bake description's modifiers which data needs to be baked This bakes NoiseFXModule and MeshCutFXModule, also set ClumpingFXModule attribute 'cvAttr' to True for AnimModifiers. Args: palette (str): XGen Legacy palette name description (str): XGen Legacy description name """ fxmod_typ = (lambda fxm: xg.fxModuleType(palette, description, fxm)) fx_modules = xg.fxModules(palette, description) previous_clump = None # (NOTE) fxModules iterate from bottom to top for fxm in fx_modules: if fxmod_typ(fxm) == "ClumpingFXModule": # set the top clumpingMod cvAttr to True, for AnimModifiers # which needs clump if previous_clump: xg.setAttr("cvAttr", "false", palette, description, previous_clump) xg.setAttr("cvAttr", "true", palette, description, fxm) previous_clump = fxm if fxmod_typ(fxm) in ("NoiseFXModule", "MeshCutFXModule"): # temporarily turn off lod so we dont bake it in lod = xg.getAttr("lodFlag", palette, description) xg.setAttr("lodFlag", "false", palette, description) # change mode for bake xg.setAttr("mode", "2", palette, description, fxm) # bake the noise cmds.xgmNullRender(description, progress=True) # restore xg.setAttr("lodFlag", lod, palette, description) # change mode to baked xg.setAttr("mode", "1", palette, description, fxm)
def set_data_path(palette, data_path): data_path = data_path.replace("\\", "/") xg.setAttr("xgDataPath", str(data_path), str(palette))
def commit(self): xg.setAttr(self.id, xg.prepForAttribute(self.value), self.collection, self.description, self.object) # Refresh the ui. xg.xgGlobal.DescriptionEditor.refresh('Full')
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