def execute(self, operation, file_path, **kwargs): """ Main hook entry point :operation: String Scene operation to perform :file_path: String File path to use if the operation requires it (e.g. open) :returns: Depends on operation: 'current_path' - Return the current scene file path as a String all others - None """ if operation == "current_path": # return the current scene path return FarmAPI.GetKatanaFileName() elif operation == "open": # do new scene as Maya doesn't like opening # the scene it currently has open! KatanaFile.Load(file_path) elif operation == "save": current_file = FarmAPI.GetKatanaFileName() # save the current scene: KatanaFile.Save(current_file)
def _OpenDialog(nodeScope=None, fileLocation=None): from Katana import UI4 import AssetAPI enabled = FarmAPI.IsSceneValid(nodeScope=nodeScope, unwantedSymbols=['_']) errorText = FarmAPI.GetErrorMessages() if len(errorText) > 0: UI4.Widgets.MessageBox.Warning('Error', ' '.join(errorText)) return if fileLocation is None: fileLocation = '' xmlFile = UI4.Util.AssetId.BrowseForAsset( fileLocation, 'Specify a filename', True, { 'fileTypes': 'xml', 'acceptDir': False, 'context': AssetAPI.kAssetContextFarm }) if not xmlFile: return nodeList = FarmAPI.GetNodeList() if not nodeList: UI4.Widgets.MessageBox.Warning('Error', 'No nodes found!') _GenerateFarmFile(nodeList, xmlFile)
def GetAllDependencyNames(renderNode): # Get the names of all unique nodes renderNode is dependent on renderSettingsNodes = FarmAPI.GetSortedDependencies(renderNode) dependencies = renderSettingsNodes[ len(renderSettingsNodes) - 1].dependencies # The last index of GetSortedDependencies() contains the dependencies directly corresponding to the current node return list(set(dependencies))
def __tank_on_scene_event_callback(**kwargs): """ Callback that fires every time a file is saved or loaded. Carefully manage exceptions here so that a bug in Tank never interrupts the normal workflows in Katana. """ # get the new file name file_name = FarmAPI.GetKatanaFileName() if not file_name: # New scene return try: # this file could be in another project altogether, so create a new Tank # API instance. try: tk = tank.tank_from_path(file_name) except tank.TankError, e: __create_tank_disabled_menu(e) return # try to get current ctx and inherit its values if possible curr_ctx = None if tank.platform.current_engine(): curr_ctx = tank.platform.current_engine().context # and now extract a new context based on the file new_ctx = tk.context_from_path(file_name, curr_ctx) # now restart the engine with the new context __engine_refresh(tk, new_ctx)
def kanana_rendernodes(self, task_json): katana_scene = FarmAPI.GetKatanaFileName() render_info_dict = {} render_node_info_dict = {} render_nodes = NodegraphAPI.GetAllNodesByType("Render") if len(render_nodes) != 0: for render_node in render_nodes: render_output_dict = {} render_frame_dict = {} render_names = render_node.getName() render_name = render_names scene_name = os.path.basename(os.path.basename(katana_scene)) print ("the render node name is %s" % render_name) num_re = re.compile(r"(\d+_\d+)[\D]*", re.I) try: render_node.getParameter("lock").setValue(0, 0) # render_node_info=Nodes3DAPI.RenderNodeUtil.GetRenderNodeInfo(render_node,graphState) render_node_info = Nodes3DAPI.RenderNodeUtil.GetRenderNodeInfo(render_node) for i in xrange(render_node_info.getNumberOfOutputs()): outputInfo = render_node_info.getOutputInfoByIndex(i, forceLocal=False) render_output_name = outputInfo['name'] render_output = outputInfo["outputFile"] # print render_output_name,render_output if render_output.find('Temp') > 0: print ("the %s output is %s ,it is tmp ,dont copy" % (render_output_name, render_output)) else: render_output_dict[render_output_name] = render_output render_start = render_node.getParameter('farmSettings.activeFrameRange.start').getValue(0) render_end = render_node.getParameter('farmSettings.activeFrameRange.end').getValue(0) render_frame_dict["start"] = render_start render_frame_dict["end"] = render_end render_info_dict[render_name] = {} render_info_dict[render_name]["aov"] = {} render_info_dict[render_name]["aov"] = render_output_dict try: render_TimeRange = render_node.getParameter('farmSettings.TimeRange').getValue(0) render_info_dict[render_name]["frames"] = "%s[%s]" % (render_TimeRange, 1) except: render_info_dict[render_name]["frames"] = "%s-%s[%s]" % (int(render_start), int(render_end), 1) render_info_dict[render_name]["denoise"] = "0" render_info_dict[render_name]["renderable"] = "1" except Exception as err: print (err) print ("the bad render node name is %s" % render_name) pass render_node_info_dict["rendernodes"] = render_info_dict self.write_json_info(task_json, "scene_info", render_node_info_dict)
def _session_path(): """ Return the path to the current session :return: """ path = FarmAPI.GetKatanaFileName() if isinstance(path, unicode): path = path.encode("utf-8") return path
def _save_as(): project_path = os.path.dirname(FarmAPI.GetKatanaFileName()) path = UI4.Util.AssetId.BrowseForAsset(path, 'Select Katana File', False, {'fileTypes': 'katana'}) # make sure not using unicode! if isinstance(path, unicode): path = path.encode("utf-8") if path: KatanaFile.Save(path)
def execute(self, **kwargs): """ Main hook entry point :returns: A list of any items that were found to be published. Each item in the list should be a dictionary containing the following keys: { type: String This should match a scene_item_type defined in one of the outputs in the configuration and is used to determine the outputs that should be published for the item name: String Name to use for the item in the UI description: String Description of the item to use in the UI selected: Bool Initial selected state of item in the UI. Items are selected by default. required: Bool Required state of item in the UI. If True then item will not be deselectable. Items are not required by default. other_params: Dictionary Optional dictionary that will be passed to the pre-publish and publish hooks } """ items = [] # get the main scene: scene_name = FarmAPI.GetKatanaFileName() if not scene_name: raise TankError("Please Save your file before Publishing") scene_path = os.path.abspath(scene_name) name = os.path.basename(scene_path) # create the primary item - this will match the primary output 'scene_item_type': items.append({"type": "work_file", "name": name}) # # if there is any geometry in the scene (poly meshes or nurbs patches), then # # add a geometry item to the list: # if cmds.ls(geometry=True, noIntermediate=True): # items.append({"type":"geometry", "name":"All Scene Geometry"}) return items
def add_new_cp_uv(): node=cku.get_lgt_shot_maker_node() if cku.get_node_children_by_name(node,'CopyUv_\d*$') or \ cku.get_node_children_by_name(node,'CopyUV_\d*$'): return old_cp=cku.get_node_children_by_name(node,'CopyUv_Ani_Srf_\d*',operation=lambda x:x.setBypassed(True)) if old_cp: new_cp_op=cku.replace_me_with(old_cp[0], new_node='CopyUV_Lc', bypass_old_node=True) if new_cp_op: print '\n\nAdd new copy uv op node to fix srf v000 transfering uv bug.\n\n' new_cp_op.setName('CopyUV_') KatanaFile.Save(FarmAPI.GetKatanaFileName())
def checkFileNaming(): # check file naming correctness file_path = FarmAPI.GetKatanaFileName() file_base, file_name = os.path.split(file_path) # LGT katana file lgt_naming_pattern = '([a-z][0-9]*)(\.[a-z]*)(\.[a-z]*)(\.v[0-9]*)\.katana' result = re.match(lgt_naming_pattern, file_name) if result == None: return -1 elif file_name.split('.')[2] != 'lighting': return -1 else: return 0
def execute(self, work_template, primary_task, secondary_tasks, progress_cb, **kwargs): """ Main hook entry point :param work_template: template This is the template defined in the config that represents the current work file :param primary_task: The primary task that was published by the primary publish hook. Passed in here for reference. :param secondary_tasks: The list of secondary tasks that were published by the secondary publish hook. Passed in here for reference. :param progress_cb: Function A progress callback to log progress during pre-publish. Call: progress_cb(percentage, msg) to report progress to the UI :returns: None :raises: Raise a TankError to notify the user of a problem """ # get the engine name from the parent object (app/engine/etc.) engine_name = self.parent.engine.name progress_cb(0, "Versioning up the scene file") # get the current scene path: scene_path = os.path.abspath(FarmAPI.GetKatanaFileName()) # increment version and construct new file name: progress_cb(25, "Finding next version number") fields = work_template.get_fields(scene_path) next_version = self._get_next_work_file_version(work_template, fields) fields["version"] = next_version new_scene_path = work_template.apply_fields(fields) # log info self.parent.log_debug("Version up work file %s --> %s..." % (scene_path, new_scene_path)) # rename and save the file progress_cb(50, "Saving the scene file") KatanaFile.Save(new_scene_path) progress_cb(100)
def submit_to_farm(self): sg = Connection('get_project_info').get_sg() file_path = FarmAPI.GetKatanaFileName() file_name = os.path.basename(file_path) userdata = getUserFullFromDB() muster_connection = MusterSubmit(userdata) shot_name = file_name.split('.')[0] listOfJobsToSubmit = [] #~ this map would write the render node which one need to render single frame with frame number dowm! aSingleFrameNodeMap = {} # copy tmp file base_dir = os.path.dirname(file_path).replace('/work/', '/projcache/') user_tmp = os.path.join(base_dir, getpass.getuser() + '_tmp') try: #katanafile='/mnt/work/home/wangbin/Wb2015/CodeWork/lgtsmp/test.katana' self.passedLgtShotSimplifyNode() except Exception, e: print e
def _render(self): import os file_name = FarmAPI.GetKatanaFileName() #tmp_file = os.path.join("/tmp",file_name.split("/")[-1]) #KatanaFile.Save(tmp_file) if os.environ['REZ_KATANA_VERSION'] == "3.1v2": command = [ 'mate-terminal', '-x', 'rez-env', 'katana-3.1v2', 'renderman-22', 'usd-19.03', "yeti", '--', 'katana' ] else: command = [ 'mate-terminal', '-x', 'rez-env', 'katana-2.6v4', 'renderman-21.8', 'usd-19.03', 'yeti-2.2.9', '--', 'katana' ] temp_file = self._get_temp_file(str(file_name)) if not os.path.exists(os.path.dirname(temp_file)): os.makedirs(os.path.dirname(temp_file)) status = shutil.copyfile(file_name, temp_file) for node in self.selected_nodes: command.append("--batch") command.append("--katana-file=%s" % temp_file) command.append("--render-node=%s" % node.getName()) command.append( str('--t=%s-%s' % (self.ui.start_frame.text(), self.ui.end_frame.text()))) print command subprocess.Popen(command) self.close() return
def onCheckLgtShotStatus(): from shotgun_connection import Connection file_path = FarmAPI.GetKatanaFileName() file_name = os.path.basename(file_path) shot = file_name.split(".")[0] job_filters = [ ['project', 'name_is', 'cat'], ['entity', 'type_is', 'Shot'], ['entity.Shot.code', 'is', str(shot)], ['step', 'name_is', 'lgt'] ] job_fields = [ 'entity.Shot.code', 'step', 'sg_status_list' ] sg = Connection('get_project_info').get_sg() task = sg.find_one("Task", job_filters, job_fields) Status = task['sg_status_list'] if Status in ['ip','aaa','rtk']: return True else: return False
def onStartup(**kwargs): # Add menu options FarmAPI.AddFarmMenuOption(_GenerateXMLForSelectedNodeLabel, _InitDialogSelected) FarmAPI.AddFarmMenuOption(_GenerateXMLForAllNodesLabel, _InitDialogAll) # Add popup menu options FarmAPI.AddFarmPopupMenuOption(_GenerateXMLForCurrentNodeLabel, _InitDialogCurrent) FarmAPI.AddFarmPopupMenuOption(_GenerateXMLForSelectedNodeLabel, _InitDialogSelected) FarmAPI.AddFarmPopupMenuOption(_GenerateXMLForAllNodesLabel, _InitDialogAll) # Add custom farm settings FarmAPI.AddFarmSettingNumber("threadable", 1, hints={ 'widget': 'checkBox', 'constant': 'True' }) FarmAPI.AddFarmSettingString("farmFileName")
def _GenerateFarmFile(nodeList, fileName): sortedDependencies = FarmAPI.GetSortedDependencies(nodeList) katanaFile = FarmAPI.GetKatanaFileName() # Generate XML _GenerateXML(fileName, sortedDependencies, katanaFile)
def _get_version(self): file_name = FarmAPI.GetKatanaFileName() return int(filter(str.isdigit, re.search("v\d+", file_name).group()))
def _render_to_farm(self): import tractor.api.author as author start_frame = int(self.ui.start_frame.text()) end_frame = int(self.ui.end_frame.text()) file_name = FarmAPI.GetKatanaFileName() temp_file = self._get_temp_file(str(file_name)) if not os.path.exists(os.path.dirname(temp_file)): os.makedirs(os.path.dirname(temp_file)) status = shutil.copyfile(file_name, temp_file) for node in self.selected_nodes: job = author.Job() #job.title = '[Katana]' + file_name.split(".")[0].split("/") job.service = "Linux64" job.priority = 50 file_title = file_name.split(".")[0].split("/")[-1] project_name = self._app.context.project['name'] user_name = self._app.context.user['name'] user_id = os.environ['USER'] select_node = str(node.getName()) temp = "] [" title = [] title.append(user_name) title.append(project_name) title.append(file_title) title.append(select_node) title.append("%d - %d" % (start_frame, end_frame)) title = temp.join(title) title = "[" + title + "]" job.title = str(title) for frame in range(start_frame, end_frame + 1): task = author.Task(title=str(frame)) if os.environ['REZ_KATANA_VERSION'] == "3.1v2": command = [ 'rez-env', 'katana-3.1v2', 'renderman-22', 'usd-19.03', 'yeti', '--', 'katana' ] else: command = [ 'rez-env', 'katana-2.6v4', 'renderman-21.8', 'usd-19.03', 'yeti-2.2.9', '--', 'katana' ] command.append("--batch") command.append("--katana-file=%s" % temp_file) command.append("--render-node=%s" % node.getName()) command.append(str("--t=%d-%d" % (frame, frame))) command = author.Command(argv=command) task.addCommand(command) job.addChild(task) job.spool(hostname="10.0.20.82", owner=user_id) self.close() return
def execute(self, task, work_template, comment, thumbnail_path, sg_task, progress_cb, **kwargs): """ Main hook entry point :param task: Primary task to be published. This is a dictionary containing the following keys: { item: Dictionary This is the item returned by the scan hook { name: String description: String type: String other_params: Dictionary } output: Dictionary This is the output as defined in the configuration - the primary output will always be named 'primary' { name: String publish_template: template tank_type: String } } :param work_template: template This is the template defined in the config that represents the current work file :param comment: String The comment provided for the publish :param thumbnail: Path string The default thumbnail provided for the publish :param sg_task: Dictionary (shotgun entity description) The shotgun task to use for the publish :param progress_cb: Function A progress callback to log progress during pre-publish. Call: progress_cb(percentage, msg) to report progress to the UI :returns: Path String Hook should return the path of the primary publish so that it can be passed as a dependency to all secondary publishes :raises: Hook should raise a TankError if publish of the primary task fails """ # TODO: This may not be the best choice of function, as it returns an Asset ID. # When using the default Asset manager (file path) it'll work, though. scene_path = FarmAPI.GetKatanaFileName() # Find dependendies (TODO) dependencies = [] # This should be a list of file paths, I think # use templates to convert to publish path: output = task["output"] fields = work_template.get_fields(scene_path) fields["TankType"] = output["tank_type"] publish_template = output["publish_template"] publish_path = publish_template.apply_fields(fields) if os.path.exists(publish_path): raise TankError("The published file named '%s' already exists!" % publish_path) # save the scene: progress_cb(10.0, "Saving the scene") self.parent.log_debug("Saving the scene...") KatanaFile.Save(scene_path) # copy the file: progress_cb(50.0, "Copying the file") try: publish_folder = os.path.dirname(publish_path) self.parent.ensure_folder_exists(publish_folder) self.parent.log_debug("Copying %s --> %s..." % (scene_path, publish_path)) self.parent.copy_file(scene_path, publish_path, task) except Exception, e: raise TankError("Failed to copy file from %s to %s - %s" % (scene_path, publish_path, e))
def collect_current_katana_session(self, settings, parent_item): """ Creates an item that represents the current maya session. :param parent_item: Parent Item instance :returns: Item of type maya.session """ publisher = self.parent # get the path to the current file path = FarmAPI.GetKatanaFileName() # determine the display name for the item if path: file_info = publisher.util.get_file_path_components(path) display_name = file_info["filename"] else: display_name = "Current Katana Session" # create the session item for the publish hierarchy session_item = parent_item.create_item( "katana.session", "Katana Session", display_name ) # get the icon path to display for this item icon_path = os.path.join( self.disk_location, os.pardir, "icons", "maya.png" ) session_item.set_icon_from_path(icon_path) # discover the project root which helps in discovery of other # publishable items project_root = os.path.dirname(FarmAPI.GetKatanaFileName()) session_item.properties["project_root"] = project_root # if a work template is defined, add it to the item properties so # that it can be used by attached publish plugins work_template_setting = settings.get("Work Template") if work_template_setting: work_template = publisher.engine.get_template_by_name( work_template_setting.value) # store the template on the item for use by publish plugins. we # can't evaluate the fields here because there's no guarantee the # current session path won't change once the item has been created. # the attached publish plugins will need to resolve the fields at # execution time. session_item.properties["work_template"] = work_template self.logger.debug("Work template defined for Maya collection.") self.logger.info("Collected current Maya scene") return session_item
def PopulateSubmitter(gui): """ This function populates an instance of DeadlineTab with the UI controls that make up the submission dialog. This tab is instantiated by Katana every time the user selects "Tabs -> Thinkbox -> Submit to Deadline" from the menu bar in Katana. Essentially, this function serves as a deferred __init__ implementation for the tab class that can be easily updated via the Deadline repository. :param gui: An instance of DeadlineTab from the Client folder. The instance gets created upon selecting the "Deadline" tab option in Katana. The tab class itself is defined in the Client file (deployed to localappdata/.../katanasubmitter/tabs directory) and is a skeleton class that invokes this function to populate the tab with UI controls and assign them to attributes of the tab instance. """ global submissionInfo print("Grabbing submitter info...") try: stringSubInfo = CallDeadlineCommand([ "-prettyJSON", "-GetSubmissionInfo", "Pools", "Groups", "MaxPriority", "UserHomeDir", "RepoDir:submission/Katana/Main", "RepoDir:submission/Integration/Main", ], useDeadlineBg=True) output = json.loads(stringSubInfo, encoding="utf-8") except: print("Unable to get submitter info from Deadline:\n\n" + traceback.format_exc()) raise if output["ok"]: submissionInfo = output["result"] else: print( "DeadlineCommand returned a bad result and was unable to grab the submitter info.\n\n" + output["result"]) raise ValueError(output["result"]) # Create a widget with a vertical box layout as a container for widgets to include in the tab scrollWidget = QWidget() scrollLayout = QGridLayout(scrollWidget) scrollLayout.setSpacing(4) scrollLayout.setContentsMargins(4, 4, 4, 4) buttonLayout = QHBoxLayout() # First layout: General options scrollLayout.addWidget(CreateSeparator("Job Description"), 0, 0, 1, 3) jobNameLabel = QLabel("Job Name") jobNameLabel.setToolTip( "The name of your job. This is optional, and if left blank, it will default to 'Untitled'." ) scrollLayout.addWidget(jobNameLabel, 1, 0) gui.jobNameWidget = QLineEdit( os.path.basename(FarmAPI.GetKatanaFileName()).split('.')[0]) scrollLayout.addWidget(gui.jobNameWidget, 1, 1, 1, 1) commentLabel = QLabel("Comment") commentLabel.setToolTip( "A simple description of your job. This is optional and can be left blank." ) scrollLayout.addWidget(commentLabel, 2, 0) gui.commentWidget = QLineEdit("") scrollLayout.addWidget(gui.commentWidget, 2, 1, 1, 1) departmentLabel = QLabel("Department") departmentLabel.setToolTip( "The department you belong to. This is optional and can be left blank." ) scrollLayout.addWidget(departmentLabel, 3, 0) gui.departmentWidget = QLineEdit("") scrollLayout.addWidget(gui.departmentWidget, 3, 1, 1, 1) # Second layout: Job options scrollLayout.addWidget(CreateSeparator("Job Options"), 4, 0, 1, 3) pools = submissionInfo["Pools"] poolLabel = QLabel("Pool") poolLabel.setToolTip("The pool that your job will be submitted to.") scrollLayout.addWidget(poolLabel, 5, 0) gui.poolsWidget = QComboBox() gui.poolsWidget.addItems(pools) scrollLayout.addWidget(gui.poolsWidget, 5, 1) secondPoolLabel = QLabel("Secondary Pool") secondPoolLabel.setToolTip( "The secondary pool lets you specify a pool to use if the primary pool does not have any available Slaves." ) scrollLayout.addWidget(secondPoolLabel, 6, 0) gui.secondPoolsWidget = QComboBox() gui.secondPoolsWidget.addItems(pools) scrollLayout.addWidget(gui.secondPoolsWidget, 6, 1) groups = submissionInfo["Groups"] groupLabel = QLabel("Group") groupLabel.setToolTip("The group that your job will be submitted to.") scrollLayout.addWidget(groupLabel, 7, 0) gui.groupWidget = QComboBox() gui.groupWidget.addItems(groups) scrollLayout.addWidget(gui.groupWidget, 7, 1) priorityLabel = QLabel("Priority") priorityLabel.setToolTip( "A job can have a numeric priority from 0 to 100, where 0 is the lowest priority and 100 is the highest." ) scrollLayout.addWidget(priorityLabel, 8, 0) maxPriority = submissionInfo["MaxPriority"] gui.priorityBox = QSpinBox() gui.priorityBox.setMinimum(0) gui.priorityBox.setMaximum(maxPriority) scrollLayout.addWidget(gui.priorityBox, 8, 1) taskTimeoutLabel = QLabel("Task Timeout") taskTimeoutLabel.setToolTip( "The number of minutes a Slave has to render a task for this job before it requeues it. Specify 0 for no limit." ) scrollLayout.addWidget(taskTimeoutLabel, 9, 0) gui.taskTimeoutBox = QSpinBox() gui.taskTimeoutBox.setMinimum(0) gui.taskTimeoutBox.setMaximum(10000) scrollLayout.addWidget(gui.taskTimeoutBox, 9, 1) concurrentTasksLabel = QLabel("Concurrent Tasks") concurrentTasksLabel.setToolTip( "The number of tasks that can render concurrently on a single Slave. This is useful if the rendering application only uses one thread to render and your Slaves have multiple CPUs." ) scrollLayout.addWidget(concurrentTasksLabel, 10, 0) gui.concurrentTasksWidget = QSpinBox() scrollLayout.addWidget(gui.concurrentTasksWidget, 10, 1) gui.concurrentTasksWidget.setMinimum(1) gui.concurrentTasksWidget.setMaximum(16) gui.limitTasksSlaveLimit = QCheckBox("Limit Tasks To Slave's Task Limit") gui.limitTasksSlaveLimit.setToolTip( "If you limit the tasks to a Slave's task limit, then by default, the Slave won't dequeue more tasks then it has CPUs. This task limit can be overridden for individual Slaves by an administrator." ) scrollLayout.addWidget(gui.limitTasksSlaveLimit, 10, 2) machineLimitLabel = QLabel("Machine Limit") machineLimitLabel.setToolTip( "Use the Machine Limit to specify the maximum number of machines that can render your job at one time. Specify 0 for no limit." ) scrollLayout.addWidget(machineLimitLabel, 11, 0) gui.machineLimitWidget = QSpinBox() scrollLayout.addWidget(gui.machineLimitWidget, 11, 1) gui.isBlackListWidget = QCheckBox("Machine List Is Blacklist") gui.isBlackListWidget.setToolTip( "You can force the job to render on specific machines by using a whitelist, or you can avoid specific machines by using a blacklist." ) scrollLayout.addWidget(gui.isBlackListWidget, 11, 2) machineListLabel = QLabel("Machine List") machineListLabel.setToolTip( "The whitelisted or blacklisted list of machines.") scrollLayout.addWidget(machineListLabel, 12, 0) machineListLayout = QHBoxLayout() gui.machineListWidget = QLineEdit("") machineListLayout.addWidget(gui.machineListWidget) getMachineListWidget = QPushButton("...") getMachineListWidget.pressed.connect( lambda: BrowseMachineList(gui.machineListWidget)) machineListLayout.addWidget(getMachineListWidget) scrollLayout.addLayout(machineListLayout, 12, 1, 1, 2) limitsLabel = QLabel("Limits") limitsLabel.setToolTip("The Limits that your job requires.") scrollLayout.addWidget(limitsLabel, 13, 0) limitsLayout = QHBoxLayout() gui.limitsWidget = QLineEdit("") limitsLayout.addWidget(gui.limitsWidget) getLimitsWidget = QPushButton("...") getLimitsWidget.pressed.connect(lambda: BrowseLimitList(gui.limitsWidget)) limitsLayout.addWidget(getLimitsWidget) scrollLayout.addLayout(limitsLayout, 13, 1, 1, 2) dependenciesLabel = QLabel("Dependencies") dependenciesLabel.setToolTip( "Specify existing jobs that this job will be dependent on. This job will not start until the specified dependencies finish rendering." ) scrollLayout.addWidget(dependenciesLabel, 14, 0) dependenciesLayout = QHBoxLayout() gui.dependenciesWidget = QLineEdit("") dependenciesLayout.addWidget(gui.dependenciesWidget) getDependenciesWidget = QPushButton("...") getDependenciesWidget.pressed.connect( lambda: BrowseDependencyList(gui.dependenciesWidget)) dependenciesLayout.addWidget(getDependenciesWidget) scrollLayout.addLayout(dependenciesLayout, 14, 1, 1, 2) onJobCompleteLabel = QLabel("On Job Complete") onJobCompleteLabel.setToolTip( "If desired, you can automatically archive or delete the job when it completes." ) scrollLayout.addWidget(onJobCompleteLabel, 15, 0) gui.onJobCompleteWidget = QComboBox() gui.onJobCompleteWidget.addItems(["Nothing", "Archive", "Delete"]) scrollLayout.addWidget(gui.onJobCompleteWidget, 15, 1) gui.submitSuspendedWidget = QCheckBox("Submit Job as Suspended") gui.submitSuspendedWidget.setToolTip( "If enabled, the job will submit in the suspended state. This is useful if you don't want the job to start rendering right away. Just resume it from the Monitor when you want it to render." ) scrollLayout.addWidget(gui.submitSuspendedWidget, 15, 2) # Third layout: Katana options scrollLayout.addWidget(CreateSeparator("Katana Options"), 16, 0, 1, 3) frameRangeLabel = QLabel("Frame Range") frameRangeLabel.setToolTip("The list of frames to render.") scrollLayout.addWidget(frameRangeLabel, 17, 0) gui.frameRangeWidget = QLineEdit("") # Populate based on frame range scrollLayout.addWidget(gui.frameRangeWidget, 17, 1, 1, 1) frameRange = FarmAPI.GetSceneFrameRange() gui.frameRangeWidget.setText( str(frameRange['start']) + "-" + str(frameRange['end'])) gui.submitSceneBox = QCheckBox("Submit Katana Scene File") gui.submitSceneBox.setToolTip( "If this option is enabled, the scene file will be submitted with the job, and then copied locally to the Slave machine during rendering." ) scrollLayout.addWidget(gui.submitSceneBox, 17, 2) framesPerTaskLabel = QLabel("Frames Per Task") framesPerTaskLabel.setToolTip( "This is the number of frames that will be rendered at a time for each job task." ) scrollLayout.addWidget(framesPerTaskLabel, 18, 0) gui.framesPerTaskWidget = QSpinBox() gui.framesPerTaskWidget.setMinimum(1) scrollLayout.addWidget(gui.framesPerTaskWidget, 18, 1, 1, 1) gui.useWorkingDirectory = QCheckBox("Use Working Directory") gui.useWorkingDirectory.setToolTip( "If enabled, the current working directory will be used during rendering. This is required if your Katana project file contains relative paths." ) gui.useWorkingDirectory.setChecked(True) scrollLayout.addWidget(gui.useWorkingDirectory, 18, 2) renderNodeSelectLabel = QLabel("Render Node Submission") renderNodeSelectLabel.setToolTip( "Choose to render the whole scene, render all nodes as separate jobs, or render separate nodes" ) scrollLayout.addWidget(renderNodeSelectLabel, 19, 0) gui.renderSelectBox = QComboBox() gui.renderSelectBox.addItems( ["Submit All Render Nodes As Separate Jobs", "Select Render Node"]) scrollLayout.addWidget(gui.renderSelectBox, 19, 1) gui.includeImageWrite = QCheckBox("Include ImageWrite Nodes") gui.includeImageWrite.setToolTip( "If enabled, ImageWrite nodes will be included for submission.") scrollLayout.addWidget(gui.includeImageWrite, 19, 2) renderNodeLabel = QLabel("Render Node") renderNodeLabel.setToolTip( "Set the render node to render with, or leave blank to use the node already set." ) scrollLayout.addWidget(renderNodeLabel, 20, 0) gui.frameDependent = QCheckBox("Submit Jobs As Frame Dependent") gui.frameDependent.setToolTip( "If enabled, the Katana Job(s) will have Frame Dependencies. If your scene contains static content, do not use!" ) scrollLayout.addWidget(gui.frameDependent, 20, 2) gui.renderNodeBox = QComboBox() gui.renderSelectBox.currentIndexChanged.connect( lambda: RenderSelectionChanged(gui.renderSelectBox, gui.renderNodeBox)) scrollLayout.addWidget(gui.renderNodeBox, 20, 1) gui.renderNodeBox.setDisabled(True) # Submit button buttonLayoutSpacer = QSpacerItem(0, 0, QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) buttonLayout.addItem(buttonLayoutSpacer) gui.pipelineToolStatusLabel = QLabel("No Pipeline Tools Set") gui.pipelineToolStatusLabel.setAlignment(QtCore.Qt.AlignCenter) buttonLayout.addWidget(gui.pipelineToolStatusLabel) pipelineToolsButton = QPushButton("Pipeline Tools") pipelineToolsButton.pressed.connect(lambda: PipelineToolsClicked(gui)) buttonLayout.addWidget(pipelineToolsButton) submitButton = QPushButton("Submit") submitButton.pressed.connect(lambda: SubmitPressed(gui)) buttonLayout.addWidget(submitButton) scrollLayout.addLayout(buttonLayout, 21, 0, 1, 3) verticalStretchLayout = QVBoxLayout() verticalStretchLayout.addStretch() scrollLayout.addLayout(verticalStretchLayout, 22, 0) scrollArea = QScrollArea() scrollArea.setWidget(scrollWidget) scrollArea.setWidgetResizable(True) scrollArea.setFrameStyle(QFrame.NoFrame + QFrame.Plain) vLayout = QVBoxLayout() vLayout.setObjectName('vLayout') vLayout.addWidget(scrollArea) gui.setLayout(vLayout) LoadStickySettings(gui) try: pipelineToolStatusMessage = RetrievePipelineToolStatus( raiseOnExitCode=True) except subprocess.CalledProcessError as e: pipelineToolStatusMessage = HandlePipelineToolsCalledProcessError(e) UpdatePipelineToolStatusLabel(gui, pipelineToolStatusMessage) # Populate the render node drop down based on the effective check state # of the "Include ImageWrite Nodes" checkbox after sticky settings are applied PopulateRenderNodeDropDown(gui.includeImageWrite.isChecked(), gui.renderNodeBox) # We delay wiring up this signal handler until after the sticky settings are applied to avoid # rebuilding the drop-down list multiple times unnecessarily gui.includeImageWrite.stateChanged.connect( lambda checked: PopulateRenderNodeDropDown(checked, gui.renderNodeBox)) # Check if this tab is part of a pane in the main window, or if it is contained in a floating pane if gui.window() != UI4.App.MainWindow.CurrentMainWindow(): # Resize the floating pane's window to accommodate the tab's widgets requiredSize = scrollWidget.sizeHint() gui.window().resize(max(requiredSize.width() + 20, 200), min(requiredSize.height() + 40, 1000))
def _save_as(): scene_path = FarmAPI.GetKatanaFileName() KatanaFile.Save( scene_path )
def onStartup(**kwargs): # add Menu Option # FarmAPI.AddFarmMenuOption('rrSubmitter', initAssExport) FarmAPI.AddFarmPopupMenuOption('rrSubmitter (local)', localExport) FarmAPI.AddFarmPopupMenuOption('rrSubmitter (farm)', farmExport) FarmAPI.AddFarmSettingString('fileName') FarmAPI.AddFarmSettingString('outputFolder', hints={ 'widget': 'assetIdInput', 'dirsOnly': 'true', 'acceptDir': 'true' }) # .setHintString("{'widget':'assetIdInput', 'dirsOnly':'true', 'acceptDir':'true'}") FarmAPI.AddFarmSettingNumber('stepSize', 1) FarmAPI.AddFarmSettingNumber('useThreads', 2) FarmAPI.AddFarmSettingNumber('packageSize', 10) FarmAPI.AddFarmSettingNumber('useRendermanDenoiserPostScript', hints={'widget': 'checkBox'}) FarmAPI.AddFarmSettingNumber('useYetiLic', hints={'widget': 'checkBox'}) FarmAPI.AddFarmSettingNumber('useComment', hints={'widget': 'checkBox'}) FarmAPI.AddFarmSettingString('comment') # Denoise FarmAPI.AddFarmSettingNumber('useRendermanDenoiserPostScript', hints={'widget': 'checkBox'}) FarmAPI.AddFarmSettingString('denoiseFilter', hints={ 'widget': 'popup', 'options': [ 'default.filter.json', 'sigmaAlphaOnly.filter.json', 'volume.filter.json', ] }) FarmAPI.AddFarmSettingNumber('useFilterOverride', hints={'widget': 'checkBox'}) FarmAPI.AddFarmSettingStringArray( 'denoiseFilterOverride', hints={ 'widget': 'dynamicArray', 'isDynamicArray': 'true', #'panelWidget': 'popup', # 'options': 'filterLayersIndependently.filteroverride.json|fireflyKiller.filteroverride.json|linearWarp.filteroverride.json|nearestWarp.filteroverride.json|noAlbedoDivide.filteroverride.json|noDepth.filteroverride.json|noFireflyKiller.filteroverride.json|nonsplitVariances.filteroverride.json|noUnpremultiplyColor.filteroverride.json|splitVariances.filteroverride.json|unpremultiplyColor.filteroverride.json|unpremultiplyFeatures.filteroverride.json', # 'options': [ # 'filterLayersIndependently.filteroverride.json', # 'fireflyKiller.filteroverride.json', # 'linearWarp.filteroverride.json', # 'nearestWarp.filteroverride.json', # 'noAlbedoDivide.filteroverride.json', # 'noDepth.filteroverride.json', # 'noFireflyKiller.filteroverride.json', # 'nonsplitVariances.filteroverride.json', # 'noUnpremultiply:wColor.filteroverride.json', # 'splitVariances.filteroverride.json', # 'unpremultiplyColor.filteroverride.json', # 'unpremultiplyFeatures.filteroverride.json' # ] })
def setup_ui(self): l_nodes_raw = NodegraphAPI.GetAllNodesByType('Render') l_nodes = [] for n in l_nodes_raw: np = n.getInputPortByIndex(0) if np.getNumConnectedPorts(): l_nodes.append(n) l_renders = FarmAPI.GetSortedDependencyList(l_nodes) l_aovs = [] for render_node in l_renders: if len(render_node['outputs']) > 0: for aov in render_node['outputs']: l_aovs.append([render_node['name'], aov[ 'name'], aov['outputLocation']]) # setting output directory to display in label if len(l_renders) > 0: if len(l_renders[0]['outputs']) > 1: output_location_of_some_layer = l_renders[ 0]['outputs'][1]['outputLocation'] self.output_directory, layer = os.path.split( output_location_of_some_layer) self.ui.label_5.setText(self.output_directory) else: self.ui.label_5.setText("Output path not found. Contact TD.") checkboxList = [] nodes_L, nodes_R = [], [] for item in l_aovs: title = item[0] checkboxList.append(title) checkboxList = sorted(list(set(checkboxList))) for i in range(len(checkboxList)): name = checkboxList[i] if name[len(name) - 1] == "L": nodes_L.append(name) else: nodes_R.append(name) # Add to list showing L nodes self.ui.tableWidget.setRowCount(len(nodes_L)) for i in range(len(nodes_L)): name = nodes_L[i] item = QtGui.QTableWidgetItem('%s' % name) check = Qt.Checked item.setCheckState(check) self.ui.tableWidget.setItem(i, 0, item) sf_mode = QTableWidgetItem(u"*双击编辑") check = Qt.Unchecked sf_mode.setCheckState(check) self.ui.tableWidget.setItem(i, 1, sf_mode) # Add to list showing R and other nodes self.ui.tableWidget_2.setRowCount(len(nodes_R)) for i in range(len(nodes_R)): name = nodes_R[i] item = QtGui.QTableWidgetItem('%s' % name) check = Qt.Checked item.setCheckState(check) self.ui.tableWidget_2.setItem(i, 0, item) sf_mode = QTableWidgetItem(u"*双击编辑") check = Qt.Unchecked sf_mode.setCheckState(check) self.ui.tableWidget_2.setItem(i, 1, sf_mode) f_range = FarmAPI.GetSceneFrameRange() self.ui.lineEdit.setText(str(f_range['start'])) self.ui.lineEdit_2.setText(str(f_range['end'])) return
def initExport(option): dependencyList = FarmAPI.GetSortedDependencyList()[0] filepath = FarmAPI.GetKatanaFileName() # TODO - validity check saved = FarmAPI.IsSceneValid(FarmAPI.NODES_ALL) if not saved: # errormsg = FarmAPI.GetErrorMessages() result = UI4.Widgets.MessageBox.Warning('Unsaved Changes', 'Save your file', acceptText='Save', cancelText='Cancel') if result == 0: # Save KatanaFile.Save(filepath) else: # cancel return # TODO - Get Katana version katanaVersion = "2.54" rendererVersion = "21.4" # get renderservice renderer = dependencyList['service'] requ_lics = '' if renderer == 'arnold': rendererVersion = RenderingAPI.RendererInfo.GetPlugin( 'ArnoldRendererInfo').getRegisteredRendererVersion() extension = '.ass' requ_lics += 'Arnold;' elif renderer == 'prman': rendererVersion = RenderingAPI.RendererInfo.GetPlugin( 'PRManRendererInfo').getRegisteredRendererVersion() renderer = 'RenderMan' extension = '.rib' requ_lics += 'RenderMan;' else: UI4.Widgets.MessageBox.Warning('Unsupported Renderer', 'Unknown Renderer') return use_yeti = dependencyList['useYetiLic'] if use_yeti: requ_lics += "Yeti" software = 'Katana' software = 'Katana' if option == 'local': software = renderer # print 'dependency list ', dependencyList fileDir = dependencyList['outputFolder'] # print 'FILEDDIR ', fileDir fileName = dependencyList['fileName'] if fileName == '': UI4.Widgets.MessageBox.Warning('Warning', 'Add a name parameter') return # tmp name for xml and katana farm file xmlFileName = getNewTempFileName(fileDir, fileName) tmpFile = open(xmlFileName, 'w') dst = tmpFile.name[:-4] + '.katana' comment_file = tmpFile.name[:-4] + '_comment.txt' comment = '' use_comment = dependencyList['useComment'] if use_comment: comment = dependencyList['comment'] with open(comment_file, 'w') as f: f.write(comment) if (option == 'local'): # check file/dir if not os.path.isdir(fileDir): if UI4.Widgets.MessageBox.Warning('Warning', 'Directory does not exist.\n' + fileDir + '\n\nCreate it?', acceptText='Yes', cancelText='No'): return else: os.mkdir(fileDir) sceneName = os.path.join(fileDir, fileName) + '_<FN4>' + extension else: sceneName = dst # sceneName = FarmAPI.GetKatanaFileName() # check framerange framerange = dependencyList['range'] if framerange is None: UI4.Widgets.MessageBox.Warning('Warning', 'Add a valid framerange') return startframe = int(framerange[0]) endframe = int(framerange[1]) if endframe <= startframe: UI4.Widgets.MessageBox.Warning('Warning', 'Add a valid framerange') return # distribution check threadCount = int(dependencyList['useThreads']) if threadCount <= 0: UI4.Widgets.MessageBox.Warning('Warning', 'You must use at least one thread') return availableThreads = multiprocessing.cpu_count() if (threadCount > availableThreads) and (option == 'local'): UI4.Widgets.MessageBox.Warning( 'Warning', 'Your machine is restricted to max.' + str(availableThreads)) return packageSize = int(dependencyList['packageSize']) if packageSize <= 0: UI4.Widgets.MessageBox.Warning('Warning', 'Add a valid packageSize') return # denoiser post script flags if int(dependencyList['useRendermanDenoiserPostScript']) == 1: filter = dependencyList['denoiseFilter'] filter_cmd = 'denoise -v variance -f {}'.format(filter) if dependencyList['useFilterOverride']: filter_override = dependencyList['denoiseFilterOverride'] for override in filter_override: filter_cmd += '+{}'.format(override) # create job newJob = rrJob() if (option == 'local'): newJob.version = rendererVersion else: newJob.version = katanaVersion newJob.rendererVersionName = renderer newJob.rendererVersion = rendererVersion newJob.software = software newJob.renderer = renderer newJob.RequiredLicenses = requ_lics #"Yeti" # TODO newJob.sceneName = sceneName newJob.sceneDatabaseDir = "" newJob.seqStart = startframe newJob.seqEnd = endframe newJob.seqStep = dependencyList['stepSize'] # TODO - get dynamic newJob.seqFileOffset = 0 newJob.seqFrameSet = "" newJob.imageWidth = 99 # TODO - get dynamic newJob.imageHeight = 99 newJob.imageDir = fileDir newJob.imageFileName = fileName + '_####_variance.exr' newJob.imageFramePadding = 4 # TODO - get dynamic newJob.imageExtension = "" # ".exr" # TODO get dynamic newJob.imagePreNumberLetter = "" newJob.imageSingleOutput = False newJob.imageStereoR = "" newJob.imageStereoL = "" newJob.sceneOS = getOSString() # TODO - get dynamic newJob.camera = "" newJob.layer = dependencyList['name'] newJob.channel = "" newJob.maxChannels = 0 newJob.channelFileName = [] newJob.channelExtension = [] newJob.isActive = False newJob.sendAppBit = "" newJob.preID = "" newJob.waitForPreID = "" if dependencyList['useRendermanDenoiserPostScript']: newJob.CustomA = filter_cmd else: newJob.CustomA = "" newJob.CustomB = "comment: {}".format(comment) newJob.CustomC = "" newJob.LocalTexturesFile = "" newJob.rrSubmitVersion = "%rrVersion%" newJob.packageSize = packageSize newJob.threadCount = threadCount newJob.renderNode = dependencyList['name'] # write xml file root = newJob.writeToXMLstart(None) job = newJob.writeToXMLJob(root) newJob.writeToXMLEnd(tmpFile, root) # copy katanna recipie shutil.copy(filepath, dst) # submit job if option == 'local': # start control session for local conversion scriptDir = os.path.dirname(os.path.realpath(__file__)) sessionScript = os.path.join(scriptDir, 'session/ControlSessions.py') subp = subprocess.Popen(['python', sessionScript, tmpFile.name, dst], close_fds=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) elif option == 'farm': os.system(getRRSubmitterPath() + " \"" + xmlFileName + "\"")
def after_call(self): from Katana import FarmAPI import production.functiming as functiming self.func_file = FarmAPI.GetKatanaFileName() functiming.ShotgunTimerEnv.after_call(self)
def kanana_rendernodes(self, task_json): katana_scene = FarmAPI.GetKatanaFileName() render_info_dict = {} render_node_info_dict = {} render_nodes = NodegraphAPI.GetAllNodesByType("Render") #graphState = NodegraphAPI.GetCurrentGraphState() #render_node = NodegraphAPI.GetNode("825_100_r1_envir_Din_Apt_Curtain_BTY") if len(render_nodes) != 0: for render_node in render_nodes: render_output_dict = {} render_frame_dict = {} render_names = render_node.getName() render_name = render_names #print render_node.getParameters().getXML() scene_name = os.path.basename(os.path.basename(katana_scene)) print("the render node name is %s" % render_name) num_re = re.compile(r"(\d+_\d+)[\D]*", re.I) if num_re.findall(scene_name): scene_num = num_re.findall(scene_name)[0] if scene_num in render_name and not render_node.isBypassed( ) and not render_name.endswith( "_pass") and not render_name.endswith("1"): try: render_node.getParameter("lock").setValue(0, 0) #render_node_info=Nodes3DAPI.RenderNodeUtil.GetRenderNodeInfo(render_node,graphState) render_node_info = Nodes3DAPI.RenderNodeUtil.GetRenderNodeInfo( render_node) for i in xrange( render_node_info.getNumberOfOutputs()): outputInfo = render_node_info.getOutputInfoByIndex( i, forceLocal=False) render_output_name = outputInfo['name'] render_output = outputInfo["outputFile"] #print render_output_name,render_output if render_output.find('Temp') > 0: print( "the %s output is %s ,it is tmp ,dont copy" % (render_output_name, render_output)) else: render_output_dict[ render_output_name] = render_output #print render_output_dict #if render_node.getParameter('farmSettings.setActiveFrameRange').getValue(0)=="Yes": render_start = render_node.getParameter( 'farmSettings.activeFrameRange.start' ).getValue(0) render_end = render_node.getParameter( 'farmSettings.activeFrameRange.end').getValue( 0) #print range(0,Nodes3DAPI.RenderNodeUtil.GetNumRenderOutputs(render_node)) #print Nodes3DAPI.RenderNodeUtil.GetDefaultIncludedOutputs(render_node).keys() render_frame_dict["start"] = render_start render_frame_dict["end"] = render_end #print render_start,render_end #print render_frame_dict render_info_dict[render_name] = {} render_info_dict[render_name]["aov"] = {} render_info_dict[render_name][ "aov"] = render_output_dict try: render_TimeRange = render_node.getParameter( 'farmSettings.TimeRange').getValue(0) render_info_dict[render_name][ "frames"] = "%s[%s]" % (render_TimeRange, 1) except: render_info_dict[render_name][ "frames"] = "%s-%s[%s]" % ( int(render_start), int(render_end), 1) render_info_dict[render_name]["denoise"] = "0" render_info_dict[render_name]["renderable"] = "1" #render_info_dict[render_name]["frames"]=render_frame_dict except Exception as err: print(err) print("the bad render node name is %s" % render_name) pass render_node_info_dict["rendernodes"] = render_info_dict self.write_json_info(task_json, "scene_info", render_node_info_dict)
def passedLgtShotSimplifyNode(self): lgtsimplifynode=NodegraphAPI.GetNode('LgtShotSimplify_') if lgtsimplifynode: lgtsimplifynode.setBypassed(True) KatanaFile.Save(FarmAPI.GetKatanaFileName()) print "setBypassed ok"
def _GetExistingFileLocation(): primaryNode = FarmAPI.GetCurrentNode() farmFileNameParam = primaryNode.getParameter('farmSettings.farmFileName') if farmFileNameParam: return farmFileNameParam.getValue(0) return ''