Houdini: Animation Editor with just animated channels


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():
                    if str(parm.expression()) == "linear()":
                    if str(parm.expression()) == "bezier()":
                    if str(parm.expression()) == "constant()":
    print "nothing selected"

animationEditor = hou.ui.curDesktop().createFloatingPanel(hou.paneTabType.ChannelEditor)
animationEditor.setName("Animation Editor - Selection")

Houdini: find all unused materials

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()[0].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[0] == "mat":
            node_type = hou.nodeType(hou.vopNodeTypeCategory(), inContext[1])
        if inContext[0] == "shop":
            node_type = hou.nodeType(hou.shopNodeTypeCategory(), inContext[1])
        #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[1]):
                        checker = 1 
                #if the checker is still == 0, meaning that there is no dependency append the material path to the outList
                if(checker == 0):
                #if there is no dependency append the material paht the outList
    #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:

Function of the Week: sample_direction_cone



today I’ll establish my personal Node/Function of the week. This week it’s the vex function “sample_direction_cone”.


The help says: “Returns a unit vector, i.e. a vector of length 1, based on u. Given uniform random u pairs of values in [0,1), the returned unit vectors will be uniform random and continuous with respect to u on the surface of the unit sphere, in the area within maxangle of the direction indicated by center.”


So what to use this for? My usual cases are randomization of velocity vectors, ray cast operations or additive spread-transforms of scattered pieces. XSI operators will know this kind of function from the ICE function “randomize vector by cone” – This is the equal Houdini function.

Here is an point wrangle example, that demonstrates the function in combination with an raycast function.

v@dir = sample_direction_cone(chv("initVector"),ch("Angle") ,set(ch("spreadU")*rand(@ptnum*20), ch("spreadV")*rand(@ptnum)));
vector pos;
vector uvw;
int prim = intersect(1, @P, @dir*20, pos, uvw);
@P = primuv(1, "P", prim, uvw);

moving the privot of packed primitives

Today I had to move all pivots of an packed primitive object for an rbd simulation. If the centroid, center of mass or origin doesn’t fit your needs, maybe this could be interesting.

// move the pivot of all packed primitives

vector oMoveIntrinsicPivot = chv("MoveIntrinsicPivot");
@P += oMoveIntrinsicPivot;
setprimintrinsic(0, "pivot",@primnum,oMoveIntrinsicPivot,"add");       

Creating bgeo files from selected objects

After importing FBX files, hip files are getting very large. To avoid saving all geometry for every scene it makes sense to save the data to disk. For 3-4 objects it’s no big deal to do this by hand, but when dealing with hundreds of objects, this is getting annoying. Here is a small snipped, that reads the current houdini selection and exports bgeo.sc files to $HIP/geo/`opname(“..”)`/`opname(“..”)`.bgeo.sc. This is really the basic approach without any versioning, it gives you a good starting point how to set this up.

import hou  
oSelection = hou.selectedItems()

if oSelection == 0:
    print "nothing is selected"
    for oSelectedNode in oSelection:
        print oSelectedNode.name()
        c = oSelectedNode.children()
        for n in c:
            p = n.path()
            node = hou.node(p)
            type = hou.nodeFlag.Render
            flag = node.isGenericFlagSet(type)
            if flag == 1:
                oFlaggedNode = n
                #print (p + " Render Flag is " + str(flag))
        oNewROPNode = oSelectedNode.createNode("rop_geometry")
        oNewROPNode.setInput(0, oFlaggedNode )
        oNewFileNode = oSelectedNode.createNode("file")
        c = oSelectedNode.children()
        for n in c:
            p = n.path()
            node = hou.node(p)
            type = hou.nodeFlag.Render
            flag = node.isGenericFlagSet(type)
            if flag == 0:

Select objects with this material

Like the “Assign Material to Selection” function, all Softimage/Maya Guys know the “Select objects with his martial” button. I know this is already an option under the material palette. But who uses this? So here is the code to get the same functionality in Houdini. Just copy/paste the code into this file: C:\Users\USER\Documents\houdini17.0\OPmenu.xml And you are done. On the next houdini restart it should pop up on the right mouse button menu.


<?xml version="1.0" encoding="UTF-8"?>
        <scriptItem id="TM_Util_SelectObjectsWithThisMaterial">
            <label>TM Tools: Select Objects with this Material</label>
import hou
oselectedNodes = hou.selectedNodes()
oShaderTypes = ["redshift::Material", "principledshader::2.0", "redshift_vopnet", "material" ]

for mats in oselectedNodes:
    oShaderCheck = 0
    oShaderType = str(mats.type().name())
    for item in oShaderTypes:
        if oShaderType in item:
                oShaderCheck = 1
    #print mats.name()
    if oShaderCheck == 1:
        oNodes = mats.dependents()
        for oNode in oNodes:
            if str(oNode.type().name()) == "geo":
                #print oNode.path()



Assign Material to Selection

All Maya and Softimage Guys know the option “Assign to Selection”. Here is the Houdini equivalent ;). Just copy/paste this code into the this file: C:\Users\USER\Documents\houdini17.0\OPmenu.xml

Node: if there is no file yet, just create one. Houdini should pick it up on the next startup. And as you see, currently it works exclusively for redshift materials and the standard principed shader. If you want to use other shader types add them to the oShaderTypes variable.

<?xml version="1.0" encoding="UTF-8"?>
        <scriptItem id="Util_AssignMaterialToSelection">
            <label>Tools: Assign Material to Selection</label>
import hou
shader = kwargs.get("node", None)
oselectedNodes = hou.selectedNodes()
oShaderCheck = 0
oShaderTypes = ["redshift::Material", "principledshader::2.0", "redshift_vopnet", "material" ]
oShaderType = str(shader.type().name())

for item in oShaderTypes:
    if oShaderType in item:
        oShaderCheck = 1

if oShaderCheck == 1:
    for oNode in oselectedNodes:
        if str(oNode.type().name()) == "geo":
        	#print "assign" + str(shader.path()) + " to " + str(oNode.path())