If the scenes get more and more complicated, material selection gets time-consuming, too. To speedup the selecting and navigating networks, I’ve build a shelf tool, that lets you jump directly to the corresponding material of an object. Please have look at my video. I’m explaining the installation and functionality. Hopefully that makes your navigation, during the shading process more comfortable.
#Import Modules import toolutils import hou #Set Variables selected_node = "" #Define type arrays MAT_Detect = ["redshift::Material","redshift_vopnet","principledshader::2.0","materialbuilder","arnold::standard_surface", "arnold_materialbuilder"] Sel_Detect = ["geo","instance"] #Get the Selected Nodes selected = hou.selectedNodes() #Check if there is something selected if selected: #Compare first selected objects type with the valid object types if selected.type().name() in Sel_Detect: #Set the selected node. Just the fist is valid selected_node = selected #Force the user to select an object, if the current doesn't match the selection type else: #Clear the selection hou.clearAllSelected() #Promt the user to select an new object prompt = toolutils.selectionPrompt(hou.objNodeTypeCategory()) scene_viewer = toolutils.sceneViewer() selected_objects = scene_viewer.selectObjects(prompt) #Check if an object is selected if selected_objects: #Set the first selected node to variable selected_node = selected_objects else: #Output an Error hou.ui.displayMessage("Nothing Selected") #Force the user to select an object, because nothing is selected else: #Promt the user to select an new object prompt = toolutils.selectionPrompt(hou.objNodeTypeCategory()) scene_viewer = toolutils.sceneViewer() selected_objects = scene_viewer.selectObjects(prompt) #Check if an object is selected if selected_objects: #Set the first selected node to variable selected_node = selected_objects else: #Output an Error hou.ui.displayMessage("Nothing Selected") #Check if the selected_node variable is not empty if selected_node: #Compare selected_node's type with the valid object types if selected_node.type().name() not in MAT_Detect : #Convert Releative Pathes to Absolute Pathes matPath = selected_node.parm("shop_materialpath").eval() #Set the targetpath to the node variable node = selected_node.node(matPath) #Check if node is valid if node: #Look for child Objects if node.children(): #If there are children, replace node with the fist child node = node.children() else: #Output an Error hou.ui.displayMessage("Empty material path") else: node = selected_node #Look for child Objects if node.children(): node = node.children() #Check if the material node exists if node: #Set some Variables pane = "" index = 0 #Loop over the active panes while pane is not None: #Search for the first network editor pane = hou.ui.paneTabOfType(hou.paneTabType.NetworkEditor, index) #Loop over the panes if pane is not None: #Get the current state ID = pane.linkGroup() #Looking for Linkgroup1 if str(ID) == "paneLinkType.Group1": targetPane = pane switchorselect = 1 #Looking for FollowSelection if str(ID) == "paneLinkType.FollowSelection": targetPane = pane switchorselect = 0 #Looking for Pinned if str(ID) == "paneLinkType.Pinned": targetPane = pane switchorselect = 2 index += 1 #If there is a PaneType Group1 if switchorselect == 1: #Set the current Node targetPane.setCurrentNode(node) #If the PaneTypeState is set to Follow selection if switchorselect == 0: #Selet the material node.setSelected(True, clear_all_selected=True) #If the PaneTypeState is set to Pinned if switchorselect == 2: #Retun an errror hou.ui.displayMessage("The PaneType is set to Pinned")
Everyone who is coming from a Maya/Softimage background is wondering why the Houdini ChannelList has this strange scoping behavior. It loads by default all parameters with auto-add into the ChannelList.
To get only the animated ones there is an option:
I have prepared a script, if you want to stay with the default behavior (Add Parameters With Auto-Add to Channel List flag), but want the option to load the Animation Editor with just the animated parms.
First select the Nodes with the animation you want to edit. Then run the script. You’ll notice the script scopes/unscopes the channels, and leave you with a clean animation editor.
The script was a nice finger exercise 🙂
import hou if hou.selectedItems(): oSel = hou.selectedItems() for oObj in oSel: for parm in oObj.parms(): if parm.isTimeDependent(): parm.setScope(1) else: parm.setScope(0) try: if str(parm.expression()) == "linear()": parm.setScope(1) if str(parm.expression()) == "bezier()": parm.setScope(1) if str(parm.expression()) == "constant()": parm.setScope(1) except: parm.setScope(0) else: print "nothing selected" animationEditor = hou.ui.curDesktop().createFloatingPanel(hou.paneTabType.ChannelEditor) animationEditor.setName("Animation Editor - Selection")
Hey here is my function/expression of the week. In production scenarios we get our layers mostly with framepadding. This padzero helps to load and to offset them.
Here is an production example:
Hey here is a python function that returns all unused materials of a scene. After a while Houdini scenes tend to have more and more materials that are not needed. This function helps to find all stuff that has no dependency in the scene. I’ve added a searchContext List that defines all the types of materials we were working with. So if you are working with other renderes (like vray or renderman), it is needed to add this type of materials to the list. If you don’t know your type of material, you can use the function in the third line. Simply put this into the python source editor, select your material and hit apply. The console should give you informations over the type.
import hou #debug Line if you want to add new searchContexts #print hou.selectedItems().type() #findUnUsedMaterails function #returns a tupple of materialpathes def findUnUsedMaterials(): #define an empty list that will returned in the end outList =  #set the search Contexts searchContext = [["mat", "principledshader::2.0"],\ ["mat", "redshift_vopnet"],\ ["mat", "redshift::Material"], \ ["mat", "materialbuilder"],\ ["mat", "arnold_materialbuilder"],\ ["shop", "RS_Material"],\ ["shop", "vopsurface"],\ ["shop", "redshift_vopnet"],\ ["shop", "arnold_vopnet"]] #loop over the searchContext variable for inContext in searchContext: #define the node Context Type, mat or shop if inContext == "mat": node_type = hou.nodeType(hou.vopNodeTypeCategory(), inContext) if inContext == "shop": node_type = hou.nodeType(hou.shopNodeTypeCategory(), inContext) #get all Instances of the Mat type Mats = node_type.instances() for Mat in Mats: #set a checker variable for adding materials to the outList checker = 0 #get all dependencies of the current material instance allDepents = Mat.dependents() #check if there are dependencies if allDepents: #loop over all dependencies of the material instance for currDepents in allDepents: #if there is an dependency set the checker to 1 if (currDepents.type().name() != inContext): checker = 1 #if the checker is still == 0, meaning that there is no dependency append the material path to the outList if(checker == 0): outList.append(str(Mat.path())) else: #if there is no dependency append the material paht the outList outList.append(str(Mat.path())) #return the list of unused materaials return outList print findUnUsedMaterials()
PS: If you are a tough guy, loop over the returned list and delete the nodes 😀
unusedMats = findUnUsedMaterials() for unusedMat in unusedMats: hou.node(unusedMat).destroy()