Paul Ambrosiussen shared an article on a little trick in Houdini you should not try at home.
A silly thing using Houdini’s event callbacks you should definitely not try at home!
Hi, In this tutorial I want to show you a cool little trick you definitely should not attempt to try yourself. No really, definitely do not try this either at home or at work to prank your colleagues.
One night Stephan Walsch sent a gif on Discord that showed a kitty turning off the template flag on a node that already had the display flag set. And if you have watched any of my tutorials you will know that I have a habit of ticking both the display and template flag on the current node I am working on. I don’t know when or why I have obtained this terrible habit, but I felt personally attacked. Is this a bad thing to do? Not really. It just annoys people when they see someone doing that. It was a bit of a bummer that the gif Stephan sent was just an edit made in a video editing software and not a real thing. So I started thinking… How would I be able to make it a reality to get kitty to unlearn my undesired behavior? Two hours later it was working.
So before we look at the script itself, I want to quickly cover some essential knowledge which you will need to not implement this yourself.
The Network Editor & Nodes
The network editor is where you create all your nodes in Houdini. It’s what makes Houdini Houdini. By creating a network of nodes, a user is able to express a set of operations that need to run in a visual way. Houdini has many different types of nodes, but for this tutorial we will just skip those and only focus on “surface operators” or “sops”. Nodes have many different properties, which once again we will not cover in this tutorial. All we need to know is that these nodes have a couple of “flags” a user can toggle on and off. And the ones we are interested in are the display and template flags. The display flag is the blue colored extent of the node, which controls the visibility of data in the viewport. Move your display flag around to different nodes and you will see different things in the viewport. The template flag is the pink one. It serves the purpose of showing a “templated” or wireframe version of the data you would normally see if you have the display flag set on a node. (Unless you know of the secret trick and use the template flag as a second display flag)
Houdini has a ton of events that you can hook into when you do any type of action in the application. Do you want to change the node color when you create it? You can do that. Do you want to create a fully functional game using the node editor? You can do that.
I stumbled across this page that describes various events that you can hook into by attaching an event callback on a node. One of those events was the hou.nodeEventType.FlagChanged. The description read “Runs after one of the node’s flags was turned on or off.” Bingo! I can just add a callback that runs whenever a user changes one of these flags, and then do a simple check if both display and template flags are turned on.
Houdini allows users to create startup scripts, which will be run during various phases of the startup process of the full application. An example of one such script is the scripts/123.py script, which will get run when Houdini is started without a scene (.hip) file. The docs state that this is useful for customizing the empty scene, for example, if you want to start every scene with a default lighting rig. Sounds useful to me, but not for the reasons mentioned. I just want to use this functionality to create a safe little sandbox where kitty will get to live. I ended up using scripts/456.py because that one gets run whenever a scene file is loaded.
*shiver*. Scary. This is a topic I do not want to explain myself in detail since it can get quite complex. I recommend you read this link instead.
But since most people TLDR;... Here is an excerpt from that webpage.
“Think of threading as having two (or more) different processors running on your program, each one doing an independent task at the same time. That’s almost right. The threads may be running on different processors, but they will only be running one at a time.”
The only part that we will need to know about this is that if we were to have Houdini update the image we will be using as a flipbook in the main process, Houdini would just freeze the UI for the duration of the flipbook and not show us anything. So as a workaround to Houdini only supporting static images in the network editor, I decided to use the threading module to spin up a separate thread that will update the image for us. That way the editor stays nice and interactive, but we also get to see the kitty in action. Disclaimer: This can be, and probably is very dangerous to do.
Network images are a way to annotate and organize your node networks in Houdini. They can basically be used to store some references inside the network editor, store notes, or even as annotations. Labs recently released the “Sticker Placer” tool, which makes the process of creating and setting these images a lot easier. Important to note is that it only supports images of a certain type and no GIFs or videos of any kind! This will become important later.
If you just want to see the full script and skip the explanation (it is documented. Experienced deeners who know python should be OK), scroll to the bottom.
First, we need to import a bunch of modules. Time allows us to track the time and make the computer wait for a specified amount of time. Os will be used to format some paths, threading will be used for threading, and hou is the API SideFX offers to do cool Houdini work in python with.
You might be wondering why I jumped to line 68-70 right after 1-4, but that is simply because I am showing you the code in the order it will be executed. The lines in between the two snippets only contain functions that get called by the callback we create on line 70.
On line 69 we are creating a variable called GEO, which will be holding a reference to the object level geometry container. This is that whitebox I mentioned earlier. I create it by telling hou to create a node of type “geo” on the object level. Inside there is where the kitty will live. The node it creates will have the name “WARNING_CONTAINS_KITTIES” since that is what I told the second argument of the function it should be. See.
On line 70, we are adding an event callback of type “ChildCreated” to this node. This means that whenever a user will create a node inside that geometry container we created on line 69, the function called “add_flag_watcher” (which we will get to) gets called.
“Add_flag_watcher” is a function I created myself, and its sole purpose is to attach a callback to the sop node that got created inside of the geometry container early. We now have a node that will attach some sort of event to every node that gets created inside of it. Perfect. This means that if I for example create a null node, it will have an event callback already attached to it! And that callback happens to be the “FlagChanged” callback we looked at earlier in the tutorial. It will get run every time the user changes the node flags on the created sop node.
As we can see in the image above showing line 66, “flag_changed” gets called whenever a node flag gets changed. It runs when the display flag changes, it runs when the template flag changes, etc. So the first thing we need to do is check if the relevant node has both its display and template flag set. If so, trigger kitty.
We then need to figure out what network editor pane is open. And I do that using some simple list comprehension as seen on line 18. It's essentially a more compact form of writing a for loop with an if statement inside. The result of this line is a list containing one or more references to network editors open. If none is found, no kitty will appear :( If we have one or multiple, just store it as a reference in “_networkeditor”.
Before we look at the most interesting bits of the code, we need to define some variables that control our kitty animation. We need to store where the sequence of images lives, the extension, the number of frames, when to disable the template flag, the framerate, and the scale of the flipbook in case it needs to be bigger or smaller relative to the node.
I then define a local function that contains a simple for loop that will function as a “flipbook”. Since Houdini only supports static images, we need to go old-school and just change the frame of our manual “video” ourselves. So the first thing we do is create a network image on line 30. We then enter the for loop, which is set to the number of frames in our sequence defined earlier as a user variable. Each iteration of the loop can be considered as the things we need to do for each frame.
These are the flipbook frames we will be using. They are created by Stephan Walsch.
First, we set the image to be used for this frame. This will of course be based on the directory and extension we specified. We then calculate the bounds of the relevant node and scale it up twice. (Since we need our flipbook to be a little bigger than the node). Next up we need to inform the network editor that we have made changes to the background images by calling “setBackGroundImages()” on the reference of the editor we got earlier.
The next bit is the most important, considering we intend kitty to disable the template flag for us. So we do a quick check if the current iteration of the “flipbook” for loop is the frame where the template flag needs to be disabled. If it is, turn the template flag off.
Next up, we just tell the script to “sleep”, which is essentially just waiting for a specified amount of time before continuing. If we didn't do this, our flipbook of for example 60 frames would just happen in an instant, since the computer would be able to run this loop within milliseconds. Important: If you were to do this as is in Houdini, it would freeze the UI until the processing is done. So that's why we are going to abuse threading. (explained earlier in the tutorial) Once the flipbook is done playing, we just tell the network editor we no longer need that image we created, so it gets deleted on line 57. Notice that the indentation of that line is one less tab than the for loop above. This means it will happen once the loop is complete.
This is the feared threading I mentioned earlier. All we do is create a new thread and tell it to run that “flipbook_image” function we defined above these lines. Note I said defined, not ran! The “flipbook_image” function has never run. It just “existed” until this point in the script. By calling “_thread.start()” we start the thread and the kitty will do its thing.
The full script! Place this script in $HOUDINI_USER_PREFERENCES/scripts. Download Kitty_Flipbook.zip and extract it somewhere. Then on line 7 of the 456.py script, change the directory to wherever you extracted the flipbook images. That’s it! It will now work after a reboot of Houdini.