def cur_work(): """Get current workfile. Returns: (FrasierWork): current work """ return FrasierWork(host.cur_scene())
def build_shot_from_template(shot, template, force=False): """Build a scene from the given template. Args: shot (str): name of shot to update to (eg. rnd0080) template (str): path to template work file force (bool): force save new scene with no confirmation """ _shot = tk2.find_shot(shot) _tmpl_work = tk2.get_work(template) if host.cur_scene() != _tmpl_work.path: _tmpl_work.load(force=force) # Make sure we're on default render layer cmds.editRenderLayerGlobals(currentRenderLayer='defaultRenderLayer') _update_assets() _update_abcs(shot=shot) # Update frame range _rng = _shot.get_frame_range() print 'RANGE', _rng if _rng and _rng != (None, None): host.set_range(*_rng) else: print 'FAILED TO UPDATE TIMELINE' # Save scene _shot_work = _tmpl_work.map_to(Shot=_shot.name, Sequence=_shot.sequence).find_next() print 'SHOT WORK', _shot_work if not force: qt.ok_cancel("Save new work file?\n\n" + _shot_work.path) _shot_work.save(comment='Scene built by shot_builder')
def open_scene(file_, force=False, prompt=False, lazy=False, load_refs=True): """Open the given scene. Args: file_ (str): file to open force (bool): lose unsaved changes without confirmation prompt (bool): show missing reference dialogs lazy (bool): abandon load if scene is already open load_refs (bool): load references """ from psyhive import host _file = get_path(file_) if lazy and host.cur_scene() == _file: return if not force: host.handle_unsaved_changes() if File(_file).extn == 'fbx': load_plugin('fbxmaya') _kwargs = {} if not load_refs: _kwargs['loadReferenceDepth'] = 'none' cmds.file(_file, open=True, force=True, prompt=prompt, ignoreVersion=True, **_kwargs)
def export_hsl_fbx_from_cur_scene(fbx, force=False): """Export HSL format fbx from the current scene. This uses the MocapTools library. Args: fbx (str): path to export to force (bool): overwrite existing files without confirmation """ cmds.loadPlugin('fbxmaya', quiet=True) install_mocap_tools() from MocapTools.Scripts import PsyopMocapTools _fbx = File(fbx) if _fbx.exists(): _fbx.delete(wording='Overwrite', force=force) _tmp_fbx = File('{}/MocapTools/Anim/Export/{}_SK_Tier1_Male.fbx'.format( KEALEYE_TOOLS_ROOT, File(host.cur_scene()).basename)) print ' - TMP FBX', _tmp_fbx.path _setup = PsyopMocapTools.mocapSetupTools() _tmp_fbx.delete(force=True) assert not _tmp_fbx.exists() _setup.exportAnim(PsyopMocapTools.config.animFBX) assert _tmp_fbx.exists() # Move from tmp dir _fbx.test_dir() shutil.move(_tmp_fbx.path, _fbx.path) print ' - SAVED FBX', nice_size(_fbx.path), _fbx.path
def update_output_paths(self, catch=False): """Update current scene output paths to match this work file. Args: catch (bool): no error if update output file paths fails """ from psyhive import tk if os.environ.get('PSYHIVE_DISABLE_UPDATE_OUTPUT_PATHS'): print 'UPDATE OUTPUT PATHS DISABLED' return # Make sure outputpaths app is loaded _engine = tank.platform.current_engine() _tk = tank.Sgtk(self.path) _ctx = _tk.context_from_path(self.path) try: _engine.change_context(_ctx) except tank.TankError as _exc: if not catch: raise _exc print 'FAILED TO APPLY CONTEXT', _ctx return # Apply output paths _outputpaths = tk.find_tank_app('outputpaths') _no_workspace = not host.cur_scene() try: _outputpaths.update_output_paths(scene_path=self.path, no_workspace=_no_workspace) except AttributeError as _exc: if not catch: raise _exc print 'FAILED TO UPDATE OUTPUT PATHS'
def init_ui(self): """Init ui elements.""" self.ui.splitter.setSizes([314, 453]) self._redraw__Character() _path = self._trg_path or host.cur_scene() if _path: self.jump_to(_path)
def _get_scene_name(): """Get current scene name hud text. Returns: (str): scene name hud text """ _cur_scene = host.cur_scene() return 'file: {}'.format(File(_cur_scene).filename if _cur_scene else '')
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 save_inc(self, comment, safe=True): """Save increment file. Args: comment (str): comment safe (bool): error if we are saving over an existing scene file without incrementing """ _fileops = find_tank_app('psy-multi-fileops') if not host.cur_scene() == self.path: if safe: print 'CUR', host.cur_scene() print 'TRG', self.path raise ValueError host.save_as(self.path, revert_filename=False) _fileops.init_app() _fileops.save_increment_file(comment=comment)
def _revert_scene_fn(*args, **kwargs): _cur_file = host.cur_scene() _tmp_file = abs_path('{}/_psyhive_tmp.mb'.format( tempfile.gettempdir())) host.save_as(_tmp_file, force=True) _result = func(*args, **kwargs) host.open_scene(_tmp_file, force=True) if _cur_file: cmds.file(rename=_cur_file) return _result
def obtain_cur_work(): """Get cacheable version of the current work file. Returns: (_CTTWorkFileBase): work file """ _scene = host.cur_scene() if not _scene: return None return obtain_work(_scene)
def load(self, force=True, lazy=False): """Load this work file. Args: force (bool): open with no scene modified warning lazy (bool): abandon load if file is already open """ if lazy and host.cur_scene() == self.path: print "SCENE ALREADY OPEN", self.path return _fileops = find_tank_app('psy-multi-fileops') _fileops.open_file(self.path, force=force)
def generate(self): """Generate mov in current nuke session.""" if not host.cur_scene() == _REVIEW_MOV_EXPORT_NK: host.open_scene(_REVIEW_MOV_EXPORT_NK, force=True) for _idx, _mov in enumerate(self.input_movs): _node = nuke.toNode('Read{:d}'.format(_idx+1)) _node['file'].fromUserText(_mov.path) _last = _node['last'].value() print 'LAST', _last nuke.toNode('Write1')['file'].setValue(self.path) nuke.render('Write1', 1, _last)
def cur_work(class_=None): """Get work file object associated with the current file. Args: class_ (type): force workfile type Returns: (TTWorkFileBase): work file """ _cur_scene = host.cur_scene() if not _cur_scene: return None return get_work(_cur_scene, class_=class_, catch=True)
def __init__(self, path=None): """Constructor. Args: path (str): jump interface to path """ self._asset_roots = tk2.obtain_assets() self._work_files = [] super(_HiveBro, self).__init__(ui_file=UI_FILE) _path = path or host.cur_scene() if _path: self.jump_to(_path)
def load_vendor_ma(path, fix_hik_issues=False, force=False, lazy=False): """Load vendor ma file. The file is loaded and then the bad rig reference is updated. Args: path (str): vendor ma file fix_hik_issues (bool): check if hik is still driving the motion burner skeleton and disable it if it is force (bool): lose unsaved changes with no warning lazy (bool): don't open scene if it's already open """ # Load scene if not lazy or host.cur_scene() != path: if not force: host.handle_unsaved_changes() # Load the scene try: pause_viewports_on_exec(cmds.file)(path, open=True, prompt=False, force=True) except RuntimeError as _exc: if "has no '.ai_translator' attribute" in _exc.message: pass else: print '######################' print _exc.message print '######################' raise RuntimeError('Error on loading scene ' + path) assert host.get_fps() == 30 _fix_cr_namespaces() # Update rig _ref = ref.find_ref(filter_='-camera -cemera') if not _ref.path == MOBURN_RIG: _ref.swap_to(MOBURN_RIG) _ref = _fix_nested_namespace(_ref) if not _ref.namespace == 'SK_Tier1_Male_CR': _ref.rename('SK_Tier1_Male_CR') # Test for hik issues if fix_hik_issues: _test_for_hik_issues(_ref)
def summary(self): """Get error summary for email/ticket. Returns: (str): error summary """ return '\n'.join([ 'HOST: {}'.format(host.NAME), 'PROJECT: {}'.format(pipe.cur_project().name), 'SCENE: {}'.format(host.cur_scene()), 'PWD: {}'.format(abs_path(os.getcwd())), 'PLATFORM: {}'.format(sys.platform), '', 'TRACEBACK:', '```', self.traceback.clean_text, '```'])
def _generate_fbx(work, load_scene=True, lazy=True, force=False): """Generate fbx for a work file. Args: work (FrasierWork): work file to generate for load_scene (bool): load scene before export (for debugging) lazy (bool): don't load file if it's already open force (bool): overwrite existing files without confirmation """ print 'EXPORT FBX' if load_scene: if not lazy or host.cur_scene() != work.path: print ' - LOADING SCENE FOR FBX EXPORT' host.open_scene(work.path, force=True) work.export_fbx(force=force)
def cur_work(class_=None): """Get work file object associated with the current file. Args: class_ (type): force workfile type Returns: (TTWork): work file """ _cur_scene = host.cur_scene() if not _cur_scene: return None _class = class_ or TTWork try: return _class(_cur_scene) except ValueError: return None
def _find_ref_issues(ref_): """Find any issues with the given reference. Args: ref_ (FileRef): reference to check Returns: (str list): issues with reference """ _file = File(host.cur_scene()) _issues = [] # Check namespace _issues += _find_ref_namespace_issues(ref_) if not ref_.namespace: return _issues # Check top node _top_node_issues, _junk = _find_ref_top_node_issues(ref_) _issues += _top_node_issues if _junk: return _issues # Check ref file path _ref_file = File(ref_.path) print ' - FILE', _ref_file.path _local_file = File('{}/{}'.format(_file.dir, _ref_file.filename)) if ingest.is_vendor_file(_ref_file): _vendor_file = ingest.VendorFile(_ref_file) print ' - VENDOR FILE' if _vendor_file.step != 'rig': _issues.append("Reference {} is not a rig".format(ref_.namespace)) elif ingest.is_psy_asset(_ref_file): _psy_file = ingest.PsyAsset(_ref_file) print ' - PSYOP FILE' if _psy_file.step != 'rig': _issues.append("Psyop reference {} is not a rig".format( ref_.namespace)) elif not _local_file.exists(): print ' - OFF-PIPELINE FILE' _issues.append("Reference {} has an off-pipline file {} which isn't " "provided in the current directory {}".format( ref_.namespace, _ref_file.filename, _file.dir)) return _issues
def has_ik_legs(self, force=False, verbose=0): """Test if this work file ik legs. Args: force (bool): force reread data verbose (int): print process data Returns: (bool): whether legs have been update to ik """ if not host.cur_scene() == self.path: raise CacheMissing for _ctrl in ['SK_Tier1_Male:FKIKLeg_R', 'SK_Tier1_Male:FKIKLeg_L']: _attr = _ctrl + '.FKIKBlend' lprint("CHECKING", _attr, cmds.getAttr(_attr), verbose=verbose) if not cmds.getAttr(_attr) == 10: return False return True
def rerender_work_file(work_file, passes, range_): """Rerender a work file. Assets are updated to the latest version and then the workfile is versioned up. Args: work_file (TTWorkFileBase): work file to rerender passes (str list): list of passes to rerender range_ (int tuple): start/end frames Returns: (tuple): layers which were missing from the scene """ _work = work_file.find_latest() _layers = [_layer_from_pass(_pass) for _pass in passes] print 'RERENDERING', _work if not host.cur_scene() == _work.path: _work.load(force=True) print ' - SCENE IS LOADED' # Check for missing layers _missing_layers = [] for _layer in copy.copy(_layers): if not cmds.objExists(_layer): _missing_layers.append(_layer) _layers.remove(_layer) if _missing_layers: print 'MISSING LAYERS', _missing_layers if not _layers: raise RuntimeError("No layers were found to render") print ' - FOUND LAYERS TO RENDER', _layers _update_outputs_to_latest() _next_work = _work.find_next() _next_work.save(comment="Version up for batch rerender") _submit_render(file_=_next_work.path, layers=_layers, force=True, range_=range_) return _missing_layers
def _callback__Work(self): """Update work elements.""" _work = get_single(self.ui.Work.selected_data(), catch=True) _c_work = self.c_works.get(_work) _cur_scene = host.cur_scene() _cur_work = tk2.cur_work() if _work: _cur_work_selected = (_cur_work.ver_fmt == _work.ver_fmt if _cur_work else False) _work_orig = _work.map_to(version=1) self.ui.WorkPath.setText(_work.path) self.ui.VendorMa.setText(_work_orig.get_vendor_file()) # Set label _rng = _work_orig.get_range() if _rng: _start, _end = [int(round(_val)) for _val in _rng] _label = 'Range: {:d} - {:d}'.format(_start, _end) else: _label = 'Cache missing' self.ui.WorkLabel.setText(_label) self.ui.Load.setEnabled(True) self.ui.VersionUp.setEnabled(_cur_work_selected) self.ui.ExportFbx.setEnabled(_cur_work_selected) self.ui.WorkBrowser.setEnabled(True) self.ui.PlaySeq.setEnabled(bool(_c_work.find_outputs())) else: self.ui.WorkPath.setText('') self.ui.VendorMa.setText('') self.ui.Load.setEnabled(False) self.ui.VersionUp.setEnabled(False) self.ui.ExportFbx.setEnabled(False) self.ui.WorkBrowser.setEnabled(False) self.ui.PlaySeq.setEnabled(False)
def _callback__WorkJumpTo(self): _file = host.cur_scene() self.jump_to(_file)
def _blast_work(work, seq=None, build_cam_func=None, view=False, force=False, blast_=True, verbose=0): """Blast the given work file. Args: work (FrasierWork): work file to blast seq (TTOutputFileSeq): output image sequence build_cam_func (fn): function to build blast cam view (bool): view images on blast force (bool): force overwrite existing images blast_ (bool): execute blast verbose (int): print process data """ _seq = seq or work.blast if cmds.ogs(query=True, pause=True): cmds.ogs(pause=True) assert not cmds.ogs(query=True, pause=True) print 'BLAST', _seq print ' - FRAMES', _seq.find_range() if not force and _seq.exists(verbose=1): print ' - ALREADY EXISTS' return if not host.cur_scene() == work.path: cmds.file(work.path, open=True, prompt=False, force=force) _build_cam_func = build_cam_func or _build_blast_cam _cam = _build_cam_func() print ' - CAM', _cam, type(_cam) # Look through cam _panel = ui.get_active_model_panel() _editor = ui.get_active_model_panel(as_editor=True) cmds.modelPanel(_panel, edit=True, camera=_cam) cmds.refresh() _cur_cam = cmds.modelPanel(_panel, query=True, camera=True) print ' - CUR CAM', _cur_cam assert _cur_cam == _cam # Apply blast settings cmds.modelEditor(_editor, edit=True, grid=False, locators=False, cameras=False, nurbsCurves=False, dimensions=False, joints=False) cmds.camera(_cam, edit=True, displayFilmGate=False, displayResolution=False, overscan=1) pm.PyNode("hardwareRenderingGlobals").multiSampleEnable.set(True) cmds.setAttr(_cam.shp + '.nearClipPlane', 0.5) # Execute blast if not blast_: return blast(seq=_seq, res=(1280, 720), verbose=verbose) if view: _seq.view() print ' - BLASTED', _seq
def check_current_scene(show_dialog=True, verbose=1): """Check current scene for ingestion issues. Args: show_dialog (bool): show status dialog on completion verbose (int): print process data Returns: (str list): list of issues with current file """ _file = File(host.cur_scene()) _issues = [] lprint('FILE', _file, verbose=verbose) lprint(' - BASENAME', _file.basename, verbose=verbose) # Check current scene filename _issues += _find_scene_name_issues(_file) # Check maya version _ver = int(cmds.about(version=True)) if _ver != 2018: _issues.append('Bad maya version {:d}'.format(_ver)) # Check for unwanted node types for _type in ['displayLayer', 'renderLayer']: _lyrs = [ _lyr for _lyr in cmds.ls(type=_type) if _lyr not in DEFAULT_NODES if not cmds.referenceQuery(_lyr, isNodeReferenced=True) ] if _lyrs: _issues.append('Scene has {} layers: {}'.format( _type.replace("Layer", ""), ', '.join(_lyrs))) for _type in ['unknown']: _nodes = [ _node for _node in cmds.ls(type=_type) if _node not in DEFAULT_NODES if not cmds.referenceQuery(_node, isNodeReferenced=True) ] if _nodes: _issues.append('Scene has {} nodes: {}'.format( _type, ', '.join(_nodes))) # Check references _refs = ref.find_refs(unloaded=False) lprint('CHECKING {:d} REFS'.format(len(_refs)), verbose=verbose) for _ref in _refs: lprint(' - CHECKING', _ref, verbose=verbose) _issues += _find_ref_issues(_ref) # Print summary if verbose: print '\nSUMMARY: FOUND {:d} ISSUE{}'.format( len(_issues), get_plural(_issues).upper()) for _idx, _issue in enumerate(_issues): print ' {:5} {}'.format('[{:d}]'.format(_idx + 1), _issue) print if not show_dialog: pass elif not _issues: qt.notify('No issues found.\n\nFile is read to send to psyop.', verbose=0) else: qt.notify_warning( 'This file has {:d} issue{}.\n\nCheck the script editor for ' 'details.'.format(len(_issues), get_plural(_issues)), verbose=0) return _issues
def _callback__Magnet(self): _cur_scene = host.cur_scene() self.jump_to(_cur_scene)