def create_ref(file_, namespace, class_=None, force=False): """Create a reference. Args: file_ (str): path to reference namespace (str): reference namespace class_ (type): override FileRef class force (bool): force replace any existing ref Returns: (FileRef): reference """ from psyhive import qt from psyhive import host _file = File(abs_path(file_)) if not _file.exists(): raise OSError("File does not exist: " + _file.path) _class = class_ or FileRef _rng = host.t_range() if _file.extn == 'abc': cmds.loadPlugin('AbcImport', quiet=True) elif _file.extn.lower() == 'fbx': cmds.loadPlugin('fbxmaya', quiet=True) # Test for existing cmds.namespace(set=":") if cmds.namespace(exists=namespace): _ref = find_ref(namespace, catch=True) if _ref: if not force: qt.ok_cancel( 'Replace existing {} reference?'.format(namespace)) _ref.remove(force=True) else: del_namespace(namespace, force=force) # Create the reference _cur_refs = set(cmds.ls(type='reference')) _kwargs = { 'reference': True, 'namespace': namespace, 'options': "v=0;p=17", 'ignoreVersion': True } cmds.file(_file.abs_path(), **_kwargs) # Find new reference node _ref = get_single(set(cmds.ls(type='reference')).difference(_cur_refs)) # Fbx ref seems to update timeline (?) if host.t_range() != _rng: host.set_range(*_rng) return _class(_ref)
def _update_xml_start_frames(n_cloths=None, force=True): """Update start frames in cache xml file. As the cache is run on individual frames, the xml file is regenrated on each frame as a one frame cache. This means the start frame needs to be updated but also the sample rate which is written as zero for one frame caches. Loading a cache with zero sample rate and a frame range will make maya seg fault. Args: n_cloths (NCloth list): nCloth caches to update force (bool): update without confirmation """ _start, _end = host.t_range() _start_tick, _end_tick = int(_start * 240), int(_end * 240) _n_cloths = n_cloths or [ _NCloth(_n_cloth) for _n_cloth in cmds.ls(type='nCloth') ] for _n_cloth in _n_cloths: _xml = _n_cloth.get_cache_xml() print _n_cloth, _xml.path assert _xml.exists() _body = _xml.read() for _str in [ 'Range="{start}-{end}"', 'StartTime="{start}"', 'SamplingRate="{rate}"', ]: _find = _str.format(start=_end_tick, end=_end_tick, rate=0) _replace = _str.format(start=_start_tick, end=_end_tick, rate=240) assert _body.count(_find) == 1 _body = _body.replace(_find, _replace) _xml.write_text(_body, force=force)
def _submit_render(file_=None, layers=None, range_=None, size='Full', force=False): """Submit render. This doesn't handle opening the scene and updating the assets. Args: file_ (str): path to scene to submit layers (list): layers to submit range_ (int tuple): start/end frames size (str): size name (eg. Full, 1/2) force (bool): submit with no confirmation """ _file = file_ or host.cur_scene() _layers = layers or cmds.ls(type='renderLayer') _rng = range_ or host.t_range() print 'SUBMIT RENDER', _file # Build settings _start, _end = _rng _settings = render_settings.RenderSubmitSettings() _settings.render_layers = _layers _settings.render_layer_mode = render_job.RenderLayerMode.CUSTOM _settings.range_start = _start _settings.range_end = _end _settings.frame_source = render_job.FrameSource.FRAME_RANGE _settings.proxy = _map_size_to_pxy(size) print ' - PROXY', _settings.proxy # Build submittable _render_job = render_job.MayaRenderJob(settings=_settings, scene_path=_file) print ' - RENDER JOB', _render_job print ' - LAYERS', _render_job.render_layers print ' - SCENE PATH', _render_job.scene_path print ' - FRAMES', _render_job.frames _submittable = hooks.default_get_render_submittable_hook(_render_job) print ' - SUBMITTABLE', _submittable # Add publishes to make sure appears in output manager _maya_impl = tk2.find_tank_mod('hosts.maya_impl', app='psy_multi_psyqwrapper') _helper = _maya_impl.MayaPipelineRenderSubmitHelper(_submittable) _helper.ensure_can_register_publishes() _submittable.publishes = _helper.register_publishes() print ' - PUBLISHES', _submittable.publishes # Submit if not force: qt.ok_cancel('Submit?') _submitted = hooks.QubeSubmitter().submit(_submittable) if _submitted: print 'Successfully submitted {:d} job{} to the farm.'.format( len(_submitted), get_plural(_submitted))
def set_start(frame): """Set timeline start frame. Args: frame (int): frame to apply """ from psyhive import host _, _end = host.t_range() hou.playbar.setFrameRange(frame, _end)
def set_end(frame): """Set timeline end frame. Args: frame (int): frame to apply """ from psyhive import host _start, _ = host.t_range() hou.playbar.setFrameRange(_start, frame)
def bake_results(chans, simulation=False, range_=None): """Bake anim on the given list of channels. Args: chans (str list): list of channels to bake simulation (bool): bake as simulation (scrub timeline) range_ (tuple): override bake range """ from psyhive import host _range = range_ or host.t_range() cmds.bakeResults(chans, time=_range, simulation=simulation)
def exec_switch_and_key_over_range( self, switch_mode, switch_key=False, selection=True): """Exec switch and key over range. Args: switch_mode (str): fk/ik switch mode switch_key (bool): add keys on switch selection (bool): use timeline selection (otherwise use whole timeline) """ # Read range if selection: _timeline = mel.eval('$tmpVar=$gPlayBackSlider') _start, _end = [ int(_val) for _val in cmds.timeControl( _timeline, query=True, rangeArray=True)] else: _start, _end = host.t_range() print 'TIMELINE RANGE', _start, _end # Get list of keyed frames _frames = {_start, _end} for _attr in self.get_key_attrs(): _crv = get_single( cmds.listConnections(_attr, type='animCurve'), catch=True) if not _crv: continue _ktvs = cmds.getAttr(_crv+'.ktv[*]') or [] _frames = _frames.union([ _frame for _frame, _ in _ktvs if _frame > _start and _frame < _end]) _frames = sorted(_frames) print 'FRAMES', _frames # Key current state _orig_frames = _frames if switch_key: _orig_frames = [_start-1] + _frames + [_end+1] print 'KEYING CURRENT STATE', _orig_frames for _frame in _orig_frames: cmds.currentTime(_frame) cmds.setKeyframe(self.get_key_attrs()) # Key switch print 'KEYING SWITCH', _frames for _frame in _frames: cmds.currentTime(_frame) cmds.refresh() self.exec_switch_and_key( switch_mode=switch_mode, key_mode='Frame', switch_key=False, verbose=0)
def scene_get_frame_range(self): """Check if this scene's meshes match the model meshes.""" host.open_scene(self.path, lazy=True, force=True) return host.t_range(int)
def _cache_yetis(yetis, apply_on_complete=False, samples=3, verbose=0): """Cache a list of yeti nodes. Args: yetis (HFnDependencyNode list): nodes to cache apply_on_complete (bool): apply cache on completion samples (int): samples per frame verbose (int): print process data """ from . import yeti_ui print 'CACHE YETIS', yetis _work = tk2.cur_work() _yetis, _outs, _namespaces = _prepare_yetis_and_outputs( yetis=yetis, work=_work) # Get cache path - if multiple namespace need to cache to tmp _tmp_fmt = abs_path('{}/yetiTmp/<NAME>.%04d.cache'.format( tempfile.gettempdir())) if len(_yetis) > 1: _cache_path = _tmp_fmt _tmp_dir = Dir(os.path.dirname(_tmp_fmt)) _tmp_dir.delete(force=True) _tmp_dir.test_path() else: assert len(_outs) == 1 _cache_path = _outs[0].path print "CACHE PATH", _cache_path # Generate caches dprint('GENERATING CACHES', _cache_path) print ' - SAMPLES', samples for _yeti in _yetis: _yeti.plug('cacheFileName').set_val('') _yeti.plug('fileMode').set_val(0) _yeti.plug('overrideCacheWithInputs').set_val(False) cmds.select(_yetis) cmds.pgYetiCommand( writeCache=_cache_path, range=host.t_range(), samples=samples) dprint('GENERATED CACHES', _cache_path) # Move tmp caches to outputs if len(_yetis) > 1: dprint('MOVING CACHES FROM TMP') for _yeti, _out in safe_zip(_yetis, _outs): print ' - MOVING', _out.path _name = str(_yeti).replace(":", "_") _tmp_seq = Seq(_tmp_fmt.replace('<NAME>', _name)) for _frame, _tmp_path in safe_zip( _tmp_seq.get_frames(), _tmp_seq.get_paths()): lprint(' -', _frame, _tmp_path, verbose=verbose) shutil.move(_tmp_path, _out[_frame]) # Apply cache to yeti nodes if apply_on_complete: dprint('APPLYING CACHES TO YETIS') for _yeti, _cache in safe_zip(_yetis, _outs): apply_cache(cache=_cache, yeti=_yeti) qt.notify( 'Cached {:d} yeti node{}.\n\nSee script editor for details.'.format( len(_yetis), get_plural(_yetis)), title='Cache complete', icon=yeti_ui.ICON, parent=yeti_ui.DIALOG) return _outs
def blast(seq, range_=None, res=None, force=False, cam=None, view=False, verbose=0): """Execute a playblast. Args: seq (Seq): output sequence range_ (tuple): start/end frame res (tuple): override image resolution force (bool): overwrite existing images without confirmation cam (str): override camera view (bool): view blast on complete verbose (int): print process data """ from psyhive import host from maya_psyhive import ui # Get res if res: _width, _height = res cmds.setAttr('defaultResolution.width', _width) cmds.setAttr('defaultResolution.height', _height) else: _width = cmds.getAttr('defaultResolution.width') _height = cmds.getAttr('defaultResolution.height') lprint('RES', _width, _height, verbose=verbose) # Get range _rng = range_ or host.t_range() _start, _end = _rng if cam: _panel = ui.get_active_model_panel() cmds.modelEditor(_panel, edit=True, camera=cam) seq.delete(wording='Replace', force=force) seq.test_dir() # Set image format _fmt_mgr = createImageFormats.ImageFormats() _fmt_mgr.pushRenderGlobalsForDesc({ 'jpg': "JPEG", 'exr': "EXR", }[seq.extn]) _filename = '{}/{}'.format(seq.dir, seq.basename) lprint('BLAST FILENAME', _filename, verbose=verbose) cmds.playblast(startTime=_start, endTime=_end, format='image', filename=_filename, viewer=False, width=_width, height=_height, offScreen=True, percent=100) assert seq.get_frames(force=True) _fmt_mgr.popRenderGlobals() if view: seq.view()