def __init__(self, parent, **kwargs): """ Construction """ # call base init super(HoudiniSessionCollector, self).__init__(parent, **kwargs) # cache the workfiles app self.__workfiles_app = self.parent.engine.apps.get( "tk-multi-workfiles2") self.houdini_sgtk_outputs = { # rops hou.ropNodeTypeCategory(): { "alembic": "filename", # alembic cache "ifd": "vm_picture", # mantra render node }, } self.houdini_native_outputs = { # rops hou.ropNodeTypeCategory(): { "alembic": "filename", # alembic cache "comp": "copoutput", # composite "ifd": "vm_picture", # mantra render node "opengl": "picture", # opengl render "wren": "wr_picture", # wren wireframe }, }
def __init__(self, parent, **kwargs): """ Construction """ # call base init super(DDHoudiniSessionCollector, self).__init__(parent, **kwargs) self.houdini_sgtk_outputs[ hou.ropNodeTypeCategory()]["geometry"] = "sopoutput" self.houdini_native_outputs[ hou.ropNodeTypeCategory()]["geometry"] = "sopoutput"
def findNodeByType(context, pattern): import fnmatch nodeTypeCategories = {} nodeTypeCategories['Object'] = hou.objNodeTypeCategory() nodeTypeCategories['Sop'] = hou.sopNodeTypeCategory() nodeTypeCategories['Vop'] = hou.vopNodeTypeCategory() nodeTypeCategories['Dop'] = hou.dopNodeTypeCategory() nodeTypeCategories['Cop2'] = hou.cop2NodeTypeCategory() nodeTypeCategories['Chop'] = hou.chopNodeTypeCategory() nodeTypeCategories['Shop'] = hou.shopNodeTypeCategory() nodeTypeCategories['Driver'] = hou.ropNodeTypeCategory() nodeTypeCategories['Top'] = hou.topNodeTypeCategory() nodeTypeCategories['Lop'] = hou.lopNodeTypeCategory() category = nodeTypeCategories[context] nodes = [ nodetype for nodetypename, nodetype in category.nodeTypes().items() if fnmatch.fnmatch(nodetypename, pattern) ] if nodes: return nodes[0] else: return None
def _get_exported_alembic_items(self): """Scan the file for tk alembic nodes with already exported caches.""" app = self.parent # see if the alembicnode app is installed alembic_app = app.engine.apps.get("tk-houdini-alembicnode", None) if not alembic_app: app.log_info( "Will not attempt to scan for alembic caches." "The 'tk-houdini-alembicnode' app is not installed." ) return [] # get all the tk alembic nodes in the scene tk_alembic_nodes = hou.nodeType(hou.ropNodeTypeCategory(), "sgtk_alembic").instances() alembic_items = [] # for each tk alembic node, see if the output file has been # created on disk. The node will have already evaluated the # all th fields, so current version should be correct. for tk_alembic_node in tk_alembic_nodes: out_path_parm = tk_alembic_node.parm("filename") out_path = out_path_parm.menuLabels()[out_path_parm.eval()] if os.path.exists(out_path): alembic_items.append({ "type": "alembic_cache", "name": tk_alembic_node.name(), "other_params": {'path': out_path}, }) return alembic_items
def _setParmInROPChain(rop, parm_name, vals): """Set the values for the given parameters in each node of the ROP chain. `rop` is the last node in the chain. `parm_name` is the name of the parameter or parameter tuple to be set. `val` is the parameter values. """ import hou rop_stack = [ rop, ] visited_rops = [] while len(rop_stack) > 0: cur_rop = rop_stack.pop() if type(vals) == type([]) or type(vals) == type(()): parm = cur_rop.parmTuple(parm_name) else: parm = cur_rop.parm(parm_name) # Set the parameter if it exists. if parm is not None: _setParm(parm, vals) visited_rops.append(cur_rop) # Examine inputs. for input_node in cur_rop.inputs(): if input_node is None: continue if input_node.type().category() == hou.ropNodeTypeCategory() \ and input_node not in visited_rops: rop_stack.append(input_node)
def create_rop_in_active_pane(node_type, error_list_obj=None): """ Creates the specified ROP type in the current network pane and moves it to a convenient location Args: node_type (str): Name of the node type to create. E.g. "ifd" error_list_obj (RopErrorList): An instance of RopErrorList class to store any errors or warnings Returns: hou.RopNode: The new node, or None if failed. """ with ErrorList(error_list_obj) as error_list_obj: network_pane = get_network_pane() cwd = network_pane.pwd() if cwd.childTypeCategory() != hou.ropNodeTypeCategory(): error_list_obj.add( ErrorMessage("Cannot create ROP node in:\n" + cwd.path())) return None rop_node = cwd.createNode(node_type, exact_type_name=True) rop_node.setSelected(True, True) rop_node.moveToGoodPosition() return rop_node
def high_repair(is_full=False): preprocess() # High Frequency Pass matcher = nodesearch.Name(HDA_name) for node in matcher.nodes(hou.node("/obj/"), recursive=True): if hou.node(node.path() + "/hf_prepare_3d"): node_3d = hou.node(node.path() + "/hf_prepare_3d") if hou.node(node.path() + "/hf_optimize_3d"): node_op_3d = hou.node(node.path() + "/hf_optimize_3d") if hou.node(node.path() + "/hf_prepare_2d"): node_2d = hou.node(node.path() + "/hf_prepare_2d") ''' 1. Choose 3D Context Region ''' node_3d.bypass(False) ''' 2-4. 3D Context Region Optimization ''' node_op_3d.bypass(False) ''' 5. Generate 2D Render ''' num_images = len( glob.glob(hou.hipFile.name().split(".")[0] + "/*_opening.png")) mark_for_destroy = [] image_paths = [] cameras = hou.nodeType(hou.objNodeTypeCategory(), "cam").instances() for camera in cameras: camera_name = camera.name() if "oz_camera_" in camera_name and int(filter( str.isdigit, camera_name)) > num_images: mark_for_destroy.append(camera) renders = hou.nodeType(hou.ropNodeTypeCategory(), "ifd").instances() for render in renders: render_name = render.name() if "oz_render_" in render_name: if int(filter(str.isdigit, render_name)) <= num_images: image_paths.append(render.parm("vm_picture").eval()) render.render() else: mark_for_destroy.append(render) ''' 6. Map 3D Region -> 2D Render 7. 2D Repair ''' #render_then_map(image_paths, node_2d) render_map_thread = Thread(target=render_then_map, args=( image_paths, node_2d, is_full, )) render_map_thread.start() ''' *. Clean-Up ''' for node in mark_for_destroy: node.destroy() reset_camera_info()
def get_all_tk_arnold_nodes(cls): """ Returns a list of all tk-houdini-arnoldnode instances in the current session. """ # get all instances of tk arnold nodes tk_node_type = TkArnoldNodeHandler.TK_ARNOLD_NODE_TYPE return hou.nodeType(hou.ropNodeTypeCategory(), tk_node_type).instances()
def get_all_tk_mantra_nodes(cls): """ Returns a list of all tk-houdini-mantranode instances in the current session. """ # get all instances of tk mantra nodes tk_node_type = TkMantraNodeHandler.TK_MANTRA_NODE_TYPE return hou.nodeType(hou.ropNodeTypeCategory(), tk_node_type).instances()
def get_all_tk_geometry_nodes(cls): """ Returns a list of all tk-houdini-geometrynode instances in the current session. """ tk_node_type = TkGeometryNodeHandler.TK_GEOMETRY_NODE_TYPE return hou.nodeType(hou.ropNodeTypeCategory(), tk_node_type).instances()
def get_all_tk_file_nodes(cls): """ Returns a list of all tk-houdini-filenode instances in the current session. """ tk_node_type = TkFileNodeHandler.TK_FILE_NODE_TYPE return hou.nodeType(hou.ropNodeTypeCategory(), tk_node_type).instances()
def process(self, context): node_type = hou.nodeType(hou.ropNodeTypeCategory(), 'alembic') abc_nodes = node_type.instances() for node in list(abc_nodes): instance = context.create_instance(name=node.name()) instance.set_data('family', value='cache') instance.set_data('path', value=node.path()) instance.add(node)
def get_nodes(): """ Returns a list of all SGTK Mantra nodes. :returns: All SGTK Mantra nodes. :rtype: List """ node_class = ToolkitMantraNodeHandler.SG_NODE_CLASS rop_nodes = hou.nodeType(hou.ropNodeTypeCategory(), node_class).instances() return rop_nodes
def ExistingRenderers(self): # add some existing renderers renderers = ["ifd"] # plugin_renderers = ["Redshift_ROP", "ris::22", "arnold","opengl"] plugin_renderers = ["arnold", "ris::22"] for node_type in hou.ropNodeTypeCategory().nodeTypes().values(): for renderer in plugin_renderers: if renderer in node_type.name(): renderers.append(renderer) return renderers
def get_nodes(self, class_=None): """ Returns a list of sgtk nodes """ node_class = ToolkitGeometryNodeHandler.SG_NODE_CLASS sop = True if not class_ or class_ == 'sop' else False rop = True if not class_ or class_ == 'rop' else False nodes = [] if sop: nodes += hou.nodeType(hou.sopNodeTypeCategory(), node_class).instances() if rop: nodes += hou.nodeType(hou.ropNodeTypeCategory(), node_class).instances() return nodes
def _get_alembic_items(self): """Scan the file for tk alembic nodes to potentially publish.""" app = self.parent # see if the alembicnode app is installed alembic_app = app.engine.apps.get("tk-houdini-alembicnode", None) if not alembic_app: app.log_info( "Will not attempt to scan for alembic caches." "The 'tk-houdini-alembicnode' app is not installed." ) return [] # get all the tk alembic nodes in the scene tk_alembic_nodes = hou.nodeType(hou.ropNodeTypeCategory(), "sgtk_alembic").instances() alembic_items = [] # add all tk alembic nodes to the list of secondary publish items. for tk_alembic_node in tk_alembic_nodes: is_bypassed = tk_alembic_node.isBypassed() out_path_parm = tk_alembic_node.parm("filename") out_path = out_path_parm.menuLabels()[out_path_parm.eval()] # normalize the path out_path = os.path.normpath(out_path) # only select the item if the path exists and the node is not # bypassed should_select = out_path and os.path.exists(out_path) and \ not is_bypassed alembic_items.append({ "name": tk_alembic_node.name(), "type": "alembic_cache", "description": "Full Path: %s" % (tk_alembic_node.path(),), "selected": should_select, "other_params": { "path": out_path, "node": tk_alembic_node, }, }) return alembic_items
def get_all_tk_alembic_nodes(cls): """ Returns a list of all tk-houdini-alembicnode instances in the current session. """ tk_node_type = TkAlembicNodeHandler.TK_ALEMBIC_NODE_TYPE # get all instances of tk alembic rop/sop nodes tk_alembic_nodes = [] tk_alembic_nodes.extend( hou.nodeType(hou.sopNodeTypeCategory(), tk_node_type).instances()) tk_alembic_nodes.extend( hou.nodeType(hou.ropNodeTypeCategory(), tk_node_type).instances()) return tk_alembic_nodes
def get_all_tk_geometry_nodes(cls): """ Returns a list of all tk-houdini-geometrynode instances in the current session. """ tk_node_type = ToolkitGeometryNodeHandler.SG_NODE_CLASS # get all instances of tk geometry rop/sop nodes tk_geometry_nodes = [] tk_geometry_nodes.extend( hou.nodeType(hou.sopNodeTypeCategory(), tk_node_type).instances()) tk_geometry_nodes.extend( hou.nodeType(hou.ropNodeTypeCategory(), tk_node_type).instances()) return tk_geometry_nodes
def display_caching_nodes(self): self.listModel.clear() self.opening_file() # Get instances type for caching out_render = hou.nodeType(hou.ropNodeTypeCategory(), "geometry") rendering_node = out_render.instances() # Get SOP filecache node sop_render = hou.nodeType(hou.sopNodeTypeCategory(), "rop_geometry") geometry_node = sop_render.instances() # Create empty dictionnary containing the render nodes and add the nodes self._add_dic(rendering_node, "ROP", self.rendering_nodes) self._add_dic(geometry_node, "SOP", self.rendering_nodes) # Update QComboBox i = 0 self.nodeType.clear() for key, value in self.rendering_nodes.items(): self.nodeType.insertItem(i, key) i += 1 self._update_list()
def convert_to_regular_file_nodes(cls, app): """Convert Toolkit file nodes to regular file nodes. :param app: The calling Toolkit Application """ tk_node_type = TkFileNodeHandler.TK_FILE_NODE_TYPE # determine the surface operator type for this class of node sop_types = hou.sopNodeTypeCategory().nodeTypes() sop_type = sop_types[tk_node_type] # determine the render operator type for this class of node rop_types = hou.ropNodeTypeCategory().nodeTypes() rop_type = rop_types[tk_node_type] # get all instances of tk file rop/sop nodes tk_file_nodes = [] tk_file_nodes.extend( hou.nodeType(hou.sopNodeTypeCategory(), tk_node_type).instances()) tk_file_nodes.extend( hou.nodeType(hou.ropNodeTypeCategory(), tk_node_type).instances()) if not tk_file_nodes: app.log_debug("No Toolkit file Nodes found for conversion.") return # iterate over all the tk file nodes and attempt to convert them for tk_file_node in tk_file_nodes: # determine the corresponding, built-in operator type if tk_file_node.type() == sop_type: file_operator = cls.HOU_SOP_GEOMETRY_TYPE else: app.log_warning("Unknown type for node '%s': %s'" % (tk_file_node.name(), tk_file_node.type())) continue # create a new, regular file node file_node = tk_file_node.parent().createNode(file_operator) # copy the file parms value to the new node filename = _get_output_menu_label( tk_file_node.parm(cls.NODE_OUTPUT_PATH_PARM)) file_node.parm(cls.NODE_OUTPUT_PATH_PARM).set(filename) # copy across knob values _copy_parm_values(tk_file_node, file_node, excludes=[cls.NODE_OUTPUT_PATH_PARM]) # store the file output profile name in the user data so that we # can retrieve it later. output_profile_parm = tk_file_node.parm(cls.TK_OUTPUT_PROFILE_PARM) # copy the inputs and move the outputs _copy_inputs(tk_file_node, file_node) if file_operator == cls.HOU_SOP_GEOMETRY_TYPE: _save_outputs_to_user_data(tk_file_node, file_node) # make the new node the same color file_node.setColor(tk_file_node.color()) # remember the name and position of the original tk file node tk_file_node_name = tk_file_node.name() tk_file_node_pos = tk_file_node.position() # destroy the original tk file node tk_file_node.destroy() # name and reposition the new, regular file node to match the # original file_node.setName(tk_file_node_name) file_node.setPosition(tk_file_node_pos) app.log_debug("Converted: Tk file node '%s' to file node." % (tk_file_node_name, ))
def convert_back_to_tk_alembic_nodes(cls, app): """Convert Alembic nodes back to Toolkit Alembic nodes. :param app: The calling Toolkit Application Note: only converts nodes that had previously been Toolkit Alembic nodes. """ # get all rop/sop alembic nodes in the session alembic_nodes = [] alembic_nodes.extend(hou.nodeType(hou.sopNodeTypeCategory(), cls.HOU_SOP_ALEMBIC_TYPE).instances()) alembic_nodes.extend(hou.nodeType(hou.ropNodeTypeCategory(), cls.HOU_ROP_ALEMBIC_TYPE).instances()) if not alembic_nodes: app.log_debug("No Alembic Nodes found for conversion.") return # the tk node type we'll be converting to tk_node_type = TkAlembicNodeHandler.TK_ALEMBIC_NODE_TYPE # iterate over all the alembic nodes and attempt to convert them for alembic_node in alembic_nodes: # get the user data dictionary stored on the node user_dict = alembic_node.userDataDict() # get the output_profile from the dictionary tk_output_profile_name = user_dict.get( cls.TK_OUTPUT_PROFILE_NAME_KEY) if not tk_output_profile_name: app.log_warning( "Almbic node '%s' does not have an output profile name. " "Can't convert to Tk Alembic node. Continuing." % (alembic_node.name(),) ) continue # create a new, Toolkit Alembic node: tk_alembic_node = alembic_node.parent().createNode(tk_node_type) # find the index of the stored name on the new tk alembic node # and set that item in the menu. try: output_profile_parm = tk_alembic_node.parm( TkAlembicNodeHandler.TK_OUTPUT_PROFILE_PARM) output_profile_index = output_profile_parm.menuLabels().index( tk_output_profile_name) output_profile_parm.set(output_profile_index) except ValueError: app.log_warning("No output profile found named: %s" % (tk_output_profile_name,)) # copy over all parameter values except the output path _copy_parm_values(alembic_node, tk_alembic_node, excludes=[cls.NODE_OUTPUT_PATH_PARM]) # copy the inputs and move the outputs _copy_inputs(alembic_node, tk_alembic_node) # determine the built-in operator type if alembic_node.type().name() == cls.HOU_SOP_ALEMBIC_TYPE: _restore_outputs_from_user_data(alembic_node, tk_alembic_node) elif alembic_node.type().name() == cls.HOU_ROP_ALEMBIC_TYPE: _move_outputs(alembic_node, tk_alembic_node) # make the new node the same color. the profile will set a color, # but do this just in case the user changed the color manually # prior to the conversion. tk_alembic_node.setColor(alembic_node.color()) # remember the name and position of the original alembic node alembic_node_name = alembic_node.name() alembic_node_pos = alembic_node.position() # destroy the original alembic node alembic_node.destroy() # name and reposition the new, regular alembic node to match the # original tk_alembic_node.setName(alembic_node_name) tk_alembic_node.setPosition(alembic_node_pos) app.log_debug("Converted: Alembic node '%s' to TK Alembic node." % (alembic_node_name,))
# This work is provided "AS IS" and subject to the Shotgun Pipeline Toolkit # Source Code License included in this distribution package. See LICENSE. # By accessing, using, copying or modifying this work you indicate your # agreement to the Shotgun Pipeline Toolkit Source Code License. All rights # not expressly granted therein are reserved by Shotgun Software Inc. import os import hou import sgtk HookBaseClass = sgtk.get_hook_baseclass() # A dict of dicts organized by category, type and output file parm _HOUDINI_OUTPUTS = { # rops hou.ropNodeTypeCategory(): { "alembic": "filename", # alembic cache "comp": "copoutput", # composite "ifd": "vm_picture", # mantra render node "opengl": "picture", # opengl render "wren": "wr_picture", # wren wireframe }, } class HoudiniSessionCollector(HookBaseClass): """ Collector that operates on the current houdini session. Should inherit from the basic collector hook. """
def convert_geometry_to_sg_nodes(self): """ Utility function to convert all Geometry nodes to Shotgun Geometry nodes (only converts Geometry nodes that were previously Shotgun Geometry nodes) # Example use: import sgtk eng = sgtk.platform.current_engine() app = eng.apps["tk-houdini-geometrynode"] # Convert previously converted Geometry nodes back to # Shotgun Geometry nodes: app.convert_from_geometry_nodes() """ # get geometry nodes: sop_nodes = hou.nodeType(hou.sopNodeTypeCategory(), 'rop_geometry').instances() rop_nodes = hou.nodeType(hou.ropNodeTypeCategory(), 'geometry').instances() nodes = sop_nodes + rop_nodes for n in nodes: try: user_dict = n.userDataDict() profile = user_dict.get('tk_profile_name') if not profile: # can't convert to a Shotgun Geometry Node # as we have missing parameters! continue # set as selected: # wn.setSelected(True) node_name = n.name() node_pos = n.position() self._app.log_debug('Converting node: {0}'.format(n.name())) self._app.log_debug('path: {0}'.format(n.path())) # create new Shotgun Geometry node: node_class = ToolkitGeometryNodeHandler.SG_NODE_CLASS new_sg_n = n.parent().createNode(node_class) # set the profile try: parm = new_sg_n.parm( ToolkitGeometryNodeHandler.PARM_CONFIG) index = parm.menuLabels().index(profile) parm.set(index) except ValueError: pass # copy across and knob values from the internal geometry node. exclude = ['sopoutput'] self.__copy_parm_values(n, new_sg_n, exclude) # Copy inputs and move outputs self.__copy_inputs_to_node(n, new_sg_n) self.__move_outputs_to_node(n, new_sg_n) self.__move_outputs_from_user_data_to_node(n, new_sg_n) self.__copy_color(n, new_sg_n) # delete original node: n.destroy() # rename new node: new_sg_n.setName(node_name) new_sg_n.setPosition(node_pos) except Exception as err: self._app.log_warning(err) msg = 'Problems converting node: {0}'.format(n.path()) self._app.log_warning(msg)
def isActive(): return hou.nodeType(hou.ropNodeTypeCategory(), "arnold") is not None
def convert_alembic_to_sg_nodes(self): """ Utility function to convert all Alembic nodes to Shotgun Alembic nodes (only converts Alembic nodes that were previously Shotgun Alembic nodes) # Example use: import sgtk eng = sgtk.platform.current_engine() app = eng.apps["tk-houdini-alembicnode"] # Convert previously converted Alembic nodes back to # Shotgun Alembic nodes: app.convert_from_alembic_nodes() """ # get alembic nodes: sop_nodes = hou.nodeType(hou.sopNodeTypeCategory(), 'rop_alembic').instances() rop_nodes = hou.nodeType(hou.ropNodeTypeCategory(), 'alembic').instances() nodes = sop_nodes + rop_nodes for n in nodes: user_dict = n.userDataDict() profile = user_dict.get('tk_profile_name') if not profile: # can't convert to a Shotgun Alembic Node # as we have missing parameters! continue # set as selected: # wn.setSelected(True) node_name = n.name() node_pos = n.position() # create new Shotgun Alembic node: node_class = ToolkitAlembicNodeHandler.SG_NODE_CLASS new_sg_n = n.parent().createNode(node_class) # set the profile try: parm = new_sg_n.parm(ToolkitAlembicNodeHandler.PARM_CONFIG) index = parm.menuLabels().index(profile) parm.set(index) except ValueError: pass # copy across and knob values from the internal write node. exclude = ['filename'] self.__copy_parm_values(n, new_sg_n, exclude) # Copy inputs and move outputs self.__copy_inputs_to_node(n, new_sg_n) self.__move_outputs_to_node(n, new_sg_n) self.__copy_color(n, new_sg_n) # delete original node: n.destroy() # rename new node: new_sg_n.setName(node_name) new_sg_n.setPosition(node_pos)
def _all_job_nodes(): return hou.nodeType( hou.ropNodeTypeCategory(), "conductor::job::0.1").instances()
def _get_rendered_image_items(self): """Scan the file for tk mantra nodes to potentially publish.""" app = self.parent # see if the mantranode app is installed mantra_app = app.engine.apps.get("tk-houdini-mantranode", None) if not mantra_app: app.log_info( "Will not attempt to scan for rendered images." "The 'tk-houdini-mantranode' app is not installed." ) return [] # find all the tk mantra nodes tk_mantra_nodes = hou.nodeType(hou.ropNodeTypeCategory(), "sgtk_mantra").instances() render_items = [] # get the current version from the work file work_template = mantra_app.get_template("work_file_template") scene_name = str(hou.hipFile.name()) scene_path = os.path.abspath(scene_name) fields = work_template.get_fields(scene_path) cur_version = fields["version"] fields["SEQ"] = "FORMAT: %d" # get the output_profiles for the app. More efficient to do this here # than to repeat this logic per item in the secondary publish hook. output_profiles = {} for output_profile in mantra_app.get_setting("output_profiles"): name = output_profile["name"] output_profiles[name] = output_profile # for each mantra node, see which output profile is selected. # get the template for the selected profile. the validation hook will # check see if there are any images on disk matching the pattern for tk_mantra_node in tk_mantra_nodes: output_profile_parm = tk_mantra_node.parm("sgtk_output_profile") output_profile_name = \ output_profile_parm.menuLabels()[output_profile_parm.eval()] output_profile = output_profiles[output_profile_name] output_template = mantra_app.get_template_by_name( output_profile["output_render_template"]) is_bypassed = tk_mantra_node.isBypassed() paths = mantra_app.engine.tank.abstract_paths_from_template( output_template, fields) # normalize the paths paths = [os.path.normpath(p) for p in paths] # only select the item if the output path exists and the node is # not bypassed. should_select = len(paths) == 1 and not is_bypassed render_items.append({ "type": "rendered_image", "name": tk_mantra_node.name(), "description": "Full Path: %s" % (tk_mantra_node.path(),), "selected": should_select, "other_params": { "paths": paths, "node": tk_mantra_node, }, }) return render_items
def convert_back_to_tk_mantra_nodes(cls, app): """Convert Mantra nodes back to Toolkit Mantra nodes. :param app: The calling Toolkit Application Note: only converts nodes that had previously been Toolkit Mantra nodes. """ # get all instances of the built-in mantra nodes mantra_nodes = hou.nodeType(hou.ropNodeTypeCategory(), cls.HOU_MANTRA_NODE_TYPE).instances() if not mantra_nodes: app.log_debug("No Mantra Nodes found for conversion.") return # iterate over all the mantra nodes and attempt to convert them for mantra_node in mantra_nodes: # get the user data dictionary stored on the node user_dict = mantra_node.userDataDict() # get the output_profile from the dictionary tk_output_profile_name = user_dict.get( cls.TK_OUTPUT_PROFILE_NAME_KEY) if not tk_output_profile_name: app.log_warning( "Mantra node '%s' does not have an output profile name. " "Can't convert to Tk Mantra node. Continuing." % (mantra_node.name(), )) continue # create new Shotgun Write node: tk_node_type = TkMantraNodeHandler.TK_MANTRA_NODE_TYPE tk_mantra_node = mantra_node.parent().createNode(tk_node_type) # find the index of the stored name on the new tk mantra node # and set that item in the menu. try: output_profile_parm = tk_mantra_node.parm( TkMantraNodeHandler.TK_OUTPUT_PROFILE_PARM) output_profile_index = output_profile_parm.menuLabels().index( tk_output_profile_name) output_profile_parm.set(output_profile_index) except ValueError: app.log_warning("No output profile found named: %s" % (tk_output_profile_name, )) # copy over all parameter values except the output path _copy_parm_values(mantra_node, tk_mantra_node, excludes=[]) # explicitly copy AOV settings to the new tk mantra node plane_numbers = _get_extra_plane_numbers(mantra_node) for plane_number in plane_numbers: plane_parm_name = cls.TK_EXTRA_PLANES_NAME % (plane_number, ) aov_name = user_dict.get(plane_parm_name) tk_mantra_node.parm(plane_parm_name).set(aov_name) # copy the inputs and move the outputs _copy_inputs(mantra_node, tk_mantra_node) _move_outputs(mantra_node, tk_mantra_node) # make the new node the same color. the profile will set a color, # but do this just in case the user changed the color manually # prior to the conversion. tk_mantra_node.setColor(mantra_node.color()) # remember the name and position of the original mantra node mantra_node_name = mantra_node.name() mantra_node_pos = mantra_node.position() # destroy the original mantra node mantra_node.destroy() # name and reposition the new, regular mantra node to match the # original tk_mantra_node.setName(mantra_node_name) tk_mantra_node.setPosition(mantra_node_pos) app.log_debug("Converted: Mantra node '%s' to TK Mantra node." % (mantra_node_name, ))
def _all_submitter_nodes(): return hou.nodeType( hou.ropNodeTypeCategory(), "conductor::submitter::0.1").instances()
def convert_back_to_tk_alembic_nodes(cls, app): """Convert Alembic nodes back to Toolkit Alembic nodes. :param app: The calling Toolkit Application Note: only converts nodes that had previously been Toolkit Alembic nodes. """ # get all rop/sop alembic nodes in the session alembic_nodes = [] alembic_nodes.extend( hou.nodeType(hou.sopNodeTypeCategory(), cls.HOU_SOP_ALEMBIC_TYPE).instances()) alembic_nodes.extend( hou.nodeType(hou.ropNodeTypeCategory(), cls.HOU_ROP_ALEMBIC_TYPE).instances()) if not alembic_nodes: app.log_debug("No Alembic Nodes found for conversion.") return # the tk node type we'll be converting to tk_node_type = TkAlembicNodeHandler.TK_ALEMBIC_NODE_TYPE # iterate over all the alembic nodes and attempt to convert them for alembic_node in alembic_nodes: # get the user data dictionary stored on the node user_dict = alembic_node.userDataDict() # get the output_profile from the dictionary tk_output_profile_name = user_dict.get( cls.TK_OUTPUT_PROFILE_NAME_KEY) if not tk_output_profile_name: app.log_warning( "Almbic node '%s' does not have an output profile name. " "Can't convert to Tk Alembic node. Continuing." % (alembic_node.name(), )) continue # create a new, Toolkit Alembic node: tk_alembic_node = alembic_node.parent().createNode(tk_node_type) # find the index of the stored name on the new tk alembic node # and set that item in the menu. try: output_profile_parm = tk_alembic_node.parm( TkAlembicNodeHandler.TK_OUTPUT_PROFILE_PARM) output_profile_index = output_profile_parm.menuLabels().index( tk_output_profile_name) output_profile_parm.set(output_profile_index) except ValueError: app.log_warning("No output profile found named: %s" % (tk_output_profile_name, )) # copy over all parameter values except the output path _copy_parm_values(alembic_node, tk_alembic_node, excludes=[cls.NODE_OUTPUT_PATH_PARM]) # copy the inputs and move the outputs _copy_inputs(alembic_node, tk_alembic_node) # determine the built-in operator type if alembic_node.type().name() == cls.HOU_SOP_ALEMBIC_TYPE: _restore_outputs_from_user_data(alembic_node, tk_alembic_node) elif alembic_node.type().name() == cls.HOU_ROP_ALEMBIC_TYPE: _move_outputs(alembic_node, tk_alembic_node) # make the new node the same color. the profile will set a color, # but do this just in case the user changed the color manually # prior to the conversion. tk_alembic_node.setColor(alembic_node.color()) # remember the name and position of the original alembic node alembic_node_name = alembic_node.name() alembic_node_pos = alembic_node.position() # destroy the original alembic node alembic_node.destroy() # name and reposition the new, regular alembic node to match the # original tk_alembic_node.setName(alembic_node_name) tk_alembic_node.setPosition(alembic_node_pos) app.log_debug("Converted: Alembic node '%s' to TK Alembic node." % (alembic_node_name, ))
def convert_sg_to_alembic_nodes(self): """ Utility function to convert all Shotgun Alembic nodes to regular Alembic nodes. # Example use: import sgtk eng = sgtk.platform.current_engine() app = eng.apps["tk-houdini-alembicnode"] # Convert Shotgun Alembic nodes to Alembic nodes: app.convert_to_alembic_nodes() """ # get sgtk alembic nodes: sg_nodes = self.get_nodes() for sg_n in sg_nodes: sop_types = hou.sopNodeTypeCategory().nodeTypes() sop_type = sop_types[ToolkitAlembicNodeHandler.SG_NODE_CLASS] rop_types = hou.ropNodeTypeCategory().nodeTypes() rop_type = rop_types[ToolkitAlembicNodeHandler.SG_NODE_CLASS] is_sop = sg_n.type() == sop_type is_rop = sg_n.type() == rop_type # set as selected: node_name = sg_n.name() node_pos = sg_n.position() # create new regular Alembic node: if is_sop: alembic_operator = 'rop_alembic' elif is_rop: alembic_operator = 'alembic' else: continue new_n = sg_n.parent().createNode(alembic_operator) # copy across file parms: filename = self.__get_menu_label(sg_n.parm('filename')) new_n.parm('filename').set(filename) # copy across any knob values from the internal alembic node. # parmTuples exclude = ['filename'] self.__copy_parm_values(sg_n, new_n, exclude) # Store Toolkit specific information on write node # so that we can reverse this process later # Profile Name new_n.setUserData('tk_profile_name', self.get_node_profile_name(sg_n)) # Copy inputs and move outputs self.__copy_color(sg_n, new_n) self.__copy_inputs_to_node(sg_n, new_n) if is_rop: self.__move_outputs_to_node(sg_n, new_n) elif is_sop: self.__move_outputs_from_node_to_user_data(sg_n, new_n) # delete original node: sg_n.destroy() # rename new node: new_n.setName(node_name) new_n.setPosition(node_pos)
def renderIfdSubmit(self, me, background=True, rrControl=True): # get input nodes nodes = me.inputAncestors() paths = [] # get parameters from the node mem = me.evalParm("mem") priority = me.evalParm("priority") maxClients = me.evalParm("maxClients") rrSubmitter = me.evalParm("rrSubmitter") dry = me.evalParm("dry") # keep only mantra nodes nodesNew = [] for node in nodes: if node.type() == hou.nodeType(hou.ropNodeTypeCategory(), "ifd"): nodesNew.append(node) nodes = nodesNew # enable IFD saving parameter, derive ifd path from image path and save path to list for node in nodes: try: pathImg = node.parm("vm_picture").unexpandedString() #pathImg = pathImg.split("/") ##pathImg.insert(len(pathImg)-1, "ifd") #pathImg[-2] = pathImg[-2] + "_ifd" #pathImg = "/".join(pathImg) #pathImg = pathImg.split(".") #pathImg[-1] = "ifd" #pathImg = ".".join(pathImg) pathImg = ifdPath(pathImg) node.parm("soho_diskfile").set(pathImg) except: #node.parm("soho_diskfile").setExpression("hou.session.hpipe.idPath(hou.node(\"" + oldPath + "\"), \"deep\", src=\"ifd\" )", language=hou.exprLanguage.Python) pass node.parm("soho_outputmode").set(1) firstFrame = node.evalParm("f1") pathCurrent = node.parm("soho_diskfile").evalAtFrame(firstFrame) paths.append(pathCurrent) # enable and set post render script if background: script = self.submitToRR(file=pathCurrent, mem=mem, priority=priority, maxClients=maxClients, rrSubmitter=False, dry=True) script = "unix \'" + script.replace( "\\", "/" ) + " >>& //bigfoot/jellyfish/00_pipeline/houdini/renderfarm.log\'" node.setParms({ "tpostrender": 1, "lpostrender": "hscript", "postrender": script }) # execute in background / normal if not dry: if background: hou.hipFile.save() for node in nodes: node.parm("executebackground").pressButton() else: for node in nodes: node.render() # disable IFD generation parameter and send to RR if not background for i, node in enumerate(nodes): node.parm("soho_outputmode").set(0) if not background: self.submitToRR(file=paths[i], mem=mem, priority=priority, maxClients=maxClients, rrSubmitter=rrSubmitter, dry=dry, log=True) else: node.setParms({"tpostrender": 0}) # run rrControl if rrControl: subprocess.Popen(self.rr_root + "rrControl.exe " + self.rr_ui[1])
def process(self, context): # Find nodes by class. nodes = [] node_type = hou.nodeType("Driver/ifd") nodes.extend(node_type.instances()) node_type = hou.nodeType(hou.ropNodeTypeCategory(), "alembic") nodes.extend(node_type.instances()) node_type = hou.nodeType(hou.ropNodeTypeCategory(), "dop") nodes.extend(node_type.instances()) node_type = hou.nodeType(hou.ropNodeTypeCategory(), 'geometry') nodes.extend(node_type.instances()) # Categorize nodes based on whether they are in a network box starting # with "remote". nodes_local = list(nodes) for box in hou.node("out").networkBoxes(): if box.name().lower().startswith("remote"): for node in box.nodes(): if node in nodes_local: nodes_local.remove(node) # Creating instances per node. for node in nodes: # Haven't figured out distributed simulation yet, so ignoring it as # a special case. if node.type().name() == "dop" and node not in nodes_local: continue instance = context.create_instance(name=node.name()) instance.data["publish"] = not node.isBypassed() instance.add(node) # Determine node type specifics. node_type = "" category = "" output_parm = "" if node.type().name() == "ifd": node_type = "mantra" category = "img" output_parm = "vm_picture" # Rendering *.ifd files. if node.parm("soho_outputmode").eval(): category = "render" output_parm = "soho_diskfile" if node.type().name() == "alembic": node_type = "alembic" category = "cache" output_parm = "filename" if node.type().name() == "dop": node_type = "dynamics" category = "cache" output_parm = "dopoutput" if node.type().name() == "geometry": node_type = "geometry" category = "cache" output_parm = "sopoutput" # Get expected output files. files = [] if node.parm("trange").eval() == 0: frame = int(hou.frame()) files.append(node.parm(output_parm).evalAtFrame(frame)) else: start = node.parm("f1").eval() end = node.parm("f2").eval() step = node.parm("f3").eval() for frame in range(int(start), int(end) + 1, int(step)): files.append(node.parm(output_parm).evalAtFrame(frame)) # Except for alembic output that only ever outputs to a single file if node_type == "alembic": files = [files[0]] # Get extension ext = os.path.splitext(files[0])[1] # Special case for *.bgeo.sc files since it was two "extensions". if files[0].endswith(".bgeo.sc"): ext = ".bgeo.sc" # Create output collection. collections = clique.assemble(files, minimum_items=1)[0] collection = None for col in collections: if col.format("{tail}") == ext: collection = col instance.data["collection"] = collection # Assigning families. families = [node_type, category, ext[1:]] label = node.name() + " - " + category if node in nodes_local: families += ["local"] instance.data["label"] = label + " - local" else: families += ["remote"] instance.data["label"] = label + " - remote" instance.data["families"] = families instance.data["family"] = category
# This work is provided "AS IS" and subject to the Shotgun Pipeline Toolkit # Source Code License included in this distribution package. See LICENSE. # By accessing, using, copying or modifying this work you indicate your # agreement to the Shotgun Pipeline Toolkit Source Code License. All rights # not expressly granted therein are reserved by Shotgun Software Inc. import os import hou import sgtk HookBaseClass = sgtk.get_hook_baseclass() # A dict of dicts organized by category, type and output file parm _HOUDINI_OUTPUTS = { # rops hou.ropNodeTypeCategory(): { "alembic": "filename", # alembic cache "comp": "copoutput", # composite "ifd": "vm_picture", # mantra render node "opengl": "picture", # opengl render "wren": "wr_picture", # wren wireframe }, } class HoudiniSessionCollector(HookBaseClass): """ Collector that operates on the current houdini session. Should inherit from the basic collector hook. """ @property
def convert_sg_to_geometry_nodes(self): """ Utility function to convert all Shotgun Geometry nodes to regular Geometry nodes. # Example use: import sgtk eng = sgtk.platform.current_engine() app = eng.apps["tk-houdini-geometrynode"] # Convert Shotgun Geometry nodes to Geometry nodes: app.convert_to_geometry_nodes() """ # get sgtk geometry nodes: sg_nodes = self.get_nodes() for sg_n in sg_nodes: try: sop_types = hou.sopNodeTypeCategory().nodeTypes() sop_type = sop_types[ToolkitGeometryNodeHandler.SG_NODE_CLASS] rop_types = hou.ropNodeTypeCategory().nodeTypes() rop_type = rop_types[ToolkitGeometryNodeHandler.SG_NODE_CLASS] is_sop = sg_n.type() == sop_type is_rop = sg_n.type() == rop_type # set as selected: node_name = sg_n.name() node_pos = sg_n.position() self._app.log_debug('Converting node: {0}'.format(sg_n.name())) self._app.log_debug('path: {0}'.format(sg_n.path())) # create new regular Geometry node: if is_sop: geometry_operator = 'rop_geometry' elif is_rop: geometry_operator = 'geometry' else: continue new_n = sg_n.parent().createNode(geometry_operator) # copy across file parms: filename = self.__get_menu_label(sg_n.parm('sopoutput')) new_n.parm('sopoutput').set(filename) # copy across any knob values from the internal geometry node. # parmTuples exclude = ['sopoutput'] self.__copy_parm_values(sg_n, new_n, exclude) # Store Toolkit specific information on geometry node # so that we can reverse this process later # Profile Name new_n.setUserData('tk_profile_name', self.get_node_profile_name(sg_n)) # Copy inputs and move outputs self.__copy_inputs_to_node(sg_n, new_n) if is_rop: self.__move_outputs_to_node(sg_n, new_n) elif is_sop: self.__move_outputs_from_node_to_user_data(sg_n, new_n) self.__copy_color(sg_n, new_n) # delete original node: sg_n.destroy() # rename new node: new_n.setName(node_name) new_n.setPosition(node_pos) except Exception as err: self._app.log_warning(err) msg = 'Problems converting node: {0}'.format(sg_n.path()) self._app.log_warning(msg)
def convert_to_regular_alembic_nodes(cls, app): """Convert Toolkit Alembic nodes to regular Alembic nodes. :param app: The calling Toolkit Application """ tk_node_type = TkAlembicNodeHandler.TK_ALEMBIC_NODE_TYPE # determine the surface operator type for this class of node sop_types = hou.sopNodeTypeCategory().nodeTypes() sop_type = sop_types[tk_node_type] # determine the render operator type for this class of node rop_types = hou.ropNodeTypeCategory().nodeTypes() rop_type = rop_types[tk_node_type] # get all instances of tk alembic rop/sop nodes tk_alembic_nodes = [] tk_alembic_nodes.extend( hou.nodeType(hou.sopNodeTypeCategory(), tk_node_type).instances()) tk_alembic_nodes.extend( hou.nodeType(hou.ropNodeTypeCategory(), tk_node_type).instances()) if not tk_alembic_nodes: app.log_debug("No Toolkit Alembic Nodes found for conversion.") return # iterate over all the tk alembic nodes and attempt to convert them for tk_alembic_node in tk_alembic_nodes: # determine the corresponding, built-in operator type if tk_alembic_node.type() == sop_type: alembic_operator = cls.HOU_SOP_ALEMBIC_TYPE elif tk_alembic_node.type() == rop_type: alembic_operator = cls.HOU_ROP_ALEMBIC_TYPE else: app.log_warning("Unknown type for node '%s': %s'" % (tk_alembic_node.name(), tk_alembic_node.type())) continue # create a new, regular Alembic node alembic_node = tk_alembic_node.parent().createNode(alembic_operator) # copy the file parms value to the new node filename = _get_output_menu_label( tk_alembic_node.parm(cls.NODE_OUTPUT_PATH_PARM)) alembic_node.parm(cls.NODE_OUTPUT_PATH_PARM).set(filename) # copy across knob values _copy_parm_values(tk_alembic_node, alembic_node, excludes=[cls.NODE_OUTPUT_PATH_PARM]) # store the alembic output profile name in the user data so that we # can retrieve it later. output_profile_parm = tk_alembic_node.parm( cls.TK_OUTPUT_PROFILE_PARM) tk_output_profile_name = \ output_profile_parm.menuLabels()[output_profile_parm.eval()] alembic_node.setUserData(cls.TK_OUTPUT_PROFILE_NAME_KEY, tk_output_profile_name) # copy the inputs and move the outputs _copy_inputs(tk_alembic_node, alembic_node) if alembic_operator == cls.HOU_SOP_ALEMBIC_TYPE: _save_outputs_to_user_data(tk_alembic_node, alembic_node) elif alembic_operator == cls.HOU_ROP_ALEMBIC_TYPE: _move_outputs(tk_alembic_node, alembic_node) # make the new node the same color alembic_node.setColor(tk_alembic_node.color()) # remember the name and position of the original tk alembic node tk_alembic_node_name = tk_alembic_node.name() tk_alembic_node_pos = tk_alembic_node.position() # destroy the original tk alembic node tk_alembic_node.destroy() # name and reposition the new, regular alembic node to match the # original alembic_node.setName(tk_alembic_node_name) alembic_node.setPosition(tk_alembic_node_pos) app.log_debug("Converted: Tk Alembic node '%s' to Alembic node." % (tk_alembic_node_name,))
def isActive(): return hou.nodeType(hou.ropNodeTypeCategory(), "Redshift_ROP")
def convert_mantra_to_sg_nodes(self): """ Utility function to convert all Mantra nodes to Shotgun Mantra nodes (only converts Mantra nodes that were previously Shotgun Mantra nodes) # Example use: import sgtk eng = sgtk.platform.current_engine() app = eng.apps["tk-houdini-mantranode"] # Convert previously converted Mantra nodes back to # Shotgun Mantra nodes: app.convert_from_write_nodes() """ # get write nodes: nodes = hou.nodeType(hou.ropNodeTypeCategory(), 'ifd').instances() for n in nodes: user_dict = n.userDataDict() profile = user_dict.get('tk_profile_name') if not profile: # can't convert to a Shotgun Mantra Node # as we have missing parameters! continue node_name = n.name() node_pos = n.position() # create new Shotgun Write node: node_class = ToolkitMantraNodeHandler.SG_NODE_CLASS new_sg_n = n.parent().createNode(node_class) # set the profile try: parm = new_sg_n.parm(ToolkitMantraNodeHandler.PARM_CONFIG) index = parm.menuLabels().index(profile) parm.set(index) except ValueError: pass # copy across and knob values from the internal write node. exclude = [] self.__copy_parm_values(n, new_sg_n, exclude) # explicitly copy some settings to the new Shotgun Mantra Node: # AOV Names nums = self.__get_all_extra_plane_numbers(n) for num in nums: parm_name = 'sgtk__aov_name{0}'.format(num) user_data_name = 'tk_aov_name{0}'.format(num) aov_name = user_dict.get(user_data_name) new_sg_n.parm(parm_name).set(aov_name) # Copy inputs and move outputs self.__copy_inputs_to_node(n, new_sg_n) self.__move_outputs_to_node(n, new_sg_n) self.__copy_color(n, new_sg_n) # delete original node: n.destroy() # rename new node: new_sg_n.setName(node_name) new_sg_n.setPosition(node_pos)