Remember the 123 and 456 Python scripts that we talked about extensively here, here and here. Sure you do. Those scripts are quite handy since you can customize Houdini when starting up or when opening a scene. I make great use of them. I know when starting up Houdini I want a camera and a Mantra node so I have the scripts automatically create them for me with some default parameters already set up. However, what if you are one of the cool kids using these new fancy render engines such as Octane, Arnold or Redshift? What if you want to automatically create Redshift ROPs when starting Houdini to impress your friends? Well, this #QuickTip is for you. Start your engines.
Startup Script
We’re going to pick off where we left off in the Python and Houdini Startup Scripts #QuickTip. We’ll just modify the 456.py script to accommodate the creation of a different ROP. In this case, we will create a Redshift ROP along with a Redshift IPR node since they go hand in hand. Yes, I finally jumped on the Redshift train. choo choo!
Let’s take a look at the full Python 456.py script again. It’s really just a matter of adding a few lines of code but I’ll introduce you to a new Python construct to make it more interesting.
#!/usr/bin/env python # Create Camera - 1080 def create_camera(): node = hou.node("/obj").createNode("cam", "cam_1080") node.setParms({"resx": 1920, "resy": 1080}) node.setDisplayFlag(False) # Create Mantra - PBR driver def mantra_driver(): node = hou.node("/out") out = node.createNode("ifd") out.setParms({"vm_renderengine": "pbrraytrace", "override_camerares": True, "camera": "/obj/cam_1080"}) def main(): # Check for camera node nodes = hou.node('/obj').glob('*') cam_exists = False for node in nodes: if node.type().name() == 'cam': cam_exists = True break if not cam_exists: create_camera() # Check for mantra node rops = hou.node('/out').glob('*') rop_exists = False for node in rops: if node.type().name() == 'ifd': rop_exists = True break if not rop_exists: mantra_driver() if __name__ == '__main__': main()
First thing you want to do when creating a script is deciding what are the requirements for your script. This comes down to personal preference and workflow requirements. For this example, do you want to create both a Mantra and Redshift ROPS or just one of them? Maybe you decide you just want a Redshift node. But what happens if Redshift is not installed or something happens that prevents the code from creating the Redshift instance? These are questions you will need to answer for yourself. For this example we will go with Redshift first and if that fails, we will default to a Mantra ROP. You get the best of both worlds.
Redshift ROP Internal Name
In order to create the Redshift ROP we need to find its internal name. This is simple. Recall all we have to do is middle-mouse click the Redshift node to access the info panel and looking at its node type name. It will be the name in parentheses.


Once we have the internal name, it’s just a matter of creating the node by passing in that name to our node creation method. We’ll create a function similar to the one that creates the Mantra ROP.
Creating the Redshift ROP
The function that creates the Redshift ROP driver will also create an instance of the Redshift IPR driver. This is the same as using the Redshift shelf tool. We are just automating it.
def redshift_driver(): node = hou.node('/out') node.createNode('Redshift_ROP').moveToGoodPosition() node.createNode('Redshift_IPR').moveToGoodPosition()
We first create a variable for the object that holds a path to our Out context. Then we create the Redshift ROP using the hou.createNode()
method and pass in the internal name we got from the info panel. The only thing we do differently here from what we do in the Mantra function is chain a call to moveToGoodPosition(relative_to_inputs=True, move_inputs=True, move_outputs=True,move_unconnected=True)
. This method moves a node to a well-spaced position near its inputs or outputs and returns the new position of the node. Notice the method already has default arguments setup so we really just call it without much fuss. We don’t have to do this but if we don’t, then the Redshift nodes will be stacked up on top of each other. This lays them out nicely. UX matters folks.
We have the Redshift function so now we need to use it. Again, Redshift will be our main output so we will call our Redshift function first if no Redshift nodes exist. If that fails, we will create a Mantra node.
Checking for ROP Nodes
We will modify the last section of the main
function in our previous script to check if a Mantra node exists in addition to checking for a Redshift node.
# Check for Mantra or Redshift ROPS rops = hou.node('/out').glob('*') rrop_exists = False mrop_exists = False for node in rops: if node.type().name() == 'ifd': mrop_exists = True if node.type().name() == 'Redshift_ROP': rrop_exists = True
We’re still searching for all the nodes available in the Out context. If you are not familiar with globbing, check the #QuickTip we’re referencing. We add a bool
variable to check if the Redshift ROP exits. In the original code, we broke out of the loop as soon as we found a Mantra ROP. This time, we keep going to see if Redshift ROPs also exist. If any of those two exist, we set our bool
variables to True
.
Once we are done with the loop, we create our ROPS. However, it is possible that Redshift is not available for whatever reason so we need to account for that scenario. Here we’re going to do a very simple check with a commom Python error handling mechanism. Again, your requirements will dictate how elaborate you want to get.
Error Handling
We are going to use a Python construct to make sure that if we encounter any errors while creating a Redshift instance, we don’t choke Houdini. When writing code, you will have syntax errors. You know immediately there is an error because your code will not work. You also have semantic errors where there are no errors in the syntax but the code does not do what you expect it to do. Think about adding 2 + 2. You expect 4 but then get 500. Something is obviously wrong. Then you have run-time errors that occur when the program or script is running. These are bad. These errors detected during execution are called exceptions. I’m sure you have seen that familiar dialogue with the word exception on it. After Effects… (cough, cough).
I’m going to go over this superficially since it’s a deep topic. However, it might be something you want to research since it provides for a much better user experience when developing scripts and apps in general. It can help avoid the program from simply crashing on your users or even worse, losing their data. As an example, if you can catch a run-time error before the program crashes, you can save the user’s data before it crashes and you won’t receive hate mail. Keep in mind that not all run-time errors are fatal. Some run-time errors can be bypassed and just alert the user something went wrong. Again, it’s about requirements and polish.
Python Try Basics
The gist of a try
statement is to provide an alternative path if some error occurs while executing some code. The try statement is composed of several parts. You’ll usually see it being referred to as a try/except
block. The way it works is it first tries executing code within the try
clause. If the code doesn’t spit out any errors, it skips the code in the except
block entirely and continues on with the rest of the program. If something wrong does happen while executing the code within try
, it stops and jumps to the except
clause, this time executing the code within that block. That’s it! A “normal” bare bones try
statement looks something like this:
try: # execute some code that may raise and exception except: # handle the exception raised in the try clause
The try
statement also has an optional else
clause which gets executed if the code within the try
clause succeeds. In other words, if there are no exceptions raised. This could be used if you are writing to a file. If there are no errors, go ahead and save the file for example.
try: # execute some code that may raise and exception except: # handle the exception raised in the try clause else: # since no exception was raised, do this
There is another optional clause which is the finally
statement and this clause gets executed regardless of whether any exceptions are raised or not. It runs no matter what. This is great place to put clean up code such as releasing resources or disconnecting from a database.
try: # Do some file operations except: # Log exception or issue warning due to exception else: # Save file operations finally: # Release resources
In our example we are dealing with all types of exceptions raised but in Python you usually catch specific types of exceptions. This way, the errors are not all handled the same way and you can pin-point the source of the exception. A well formed try
statement looks like the following:
try: result = numerator / denominator except ZeroDivisionError as e: print('An exception occurred of type {0}'.format(e)) else: print('The result is:', result) finally: print('Saving file to disk.')
In our case, we will just use the except
statement alone for simplicity. Let’s have a look at the code and then I’ll go over the details.
try: if not rrop_exists: redshift_driver() except: # catch all exceptions if not mrop_exists: mantra_driver()
So looking at our code, right after the try
statement, we check if the rrop_exists
bool variable is False
, which it would be if we didn’t find any Redshift instances. If it’s False
, then try and execute the redshift_driver()
function. If all goes well, then that’s it, our Redshift instance will be created. Otherwise, if an exception occurs, jump to the code within the except
block and create the Mantra node.
Displaying A Message
How about if we wanted to provide a message if an error occurred while trying to create the Redshift ROP? Remember I said if something wrong happened while executing code within the try
block, jump to the code within the except
block and execute that instead. This is a great spot to place any type of message or maybe write out a debug statement to disk. Usually, you want something within except
that has the least possibility of causing another error.
Here we can use Houdini’s ui
module to display a message to the user. The hou.ui
module contains user interface related functions and the function we want is appropriately named hou.ui.displayMessage()
. This function pops up a small window with a message and one or more buttons. It takes numerous arguments but the only required argument is the actual text message String
.
try: if not rrop_exists: redshift_driver() except: hou.ui.displayMessage("Oops! Something went wrong. Unable to create Redshift ROP.") if not mrop_exists: mantra_driver()
If you were to run this code and assuming the rest of the code is in working order, you will either get a Redshift node created or a message pop up as Houdini is starting up. Try invoking and error by mispelling redshift_driver()
. After the user clicks the OK button, the Mantra node will be created instead.

Final Script
Keep in mind you can structure this differently and really do some heavy duty error checking. As a matter of fact, you can use multiple except
statements and even start nesting try/except
blocks. This is just a basic example to get you started. Adjust to taste. If you are saying “just show me the final script”, this is what the 456.py script looks like with our Python try
statement:
#!/usr/bin/env python # Create Camera - 1080 def create_camera(): node = hou.node('/obj').createNode('cam', 'cam_1080') node.setParms({'resx': 1920, 'resy': 1080}) node.setDisplayFlag(False) # Create Mantra - PBR driver def mantra_driver(): node = hou.node('/out') out = node.createNode('ifd') out.setParms({'vm_renderengine': 'pbrraytrace', 'override_camerares': True, 'camera': '/obj/cam_1080'}) def redshift_driver(): node = hou.node('/out') node.createNode('Redshift_ROP').moveToGoodPosition() node.createNode('Redshift_IPR').moveToGoodPosition() def main(): # Check for camera node nodes = hou.node('/obj').glob('*') cam_exists = False for node in nodes: if node.type().name() == 'cam': cam_exists = True break if not cam_exists: create_camera() # Check for Mantra or Redshift ROPS rops = hou.node('/out').glob('*') rrop_exists = False mrop_exists = False for node in rops: if node.type().name() == 'ifd': mrop_exists = True if node.type().name() == 'Redshift_ROP': rrop_exists = True try: if not rrop_exists: redshift_driver() except: hou.ui.displayMessage('Oops! Something went wrong. Unable to create Redshift ROP.') if not mrop_exists: mantra_driver() if __name__ == '__main__': main()
