Automatically Create Redshift ROPs When Starting Houdini

Automatically Create Redshift ROPs When Starting Houdini

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.

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.

Create Redshift ROPs When Starting Houdini
Internal name for Redshift ROP

 

Create Redshift ROPs When Starting Houdini
Internal name for Redshift IPR

 

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.

deep

 

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.

Create Redshift ROPs When Starting Houdini
Display a message using hou.ui.displayMessage()

 

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()

 

Create Redshift ROPs When Starting Houdini
Create Redshift ROPs When Starting Houdini

 

Share:
990adjustments

990adjustments

I am a motion designer & developer based out of South Florida. When not designing or animating pixels, I wrangle some code. If all else fails, I watch Twilight Zone, I Love Lucy, or Three's Company reruns.