Python Rop: Part 5 — Inner Workings

There a handy Rop for TDs and pipeline folks called “Shell,” It’s pretty great and allows calling to the shell to run systems commands… but we are not going to use it, well not so much as intended, but going to take advantage of a peculiar feature.

In the Network Graph, while still inside our working subnet, drop a Shell node. When you look at the Parm Pane you will see options for running Unix/Shell command. Leave this alone. What is interesting is when left blank it still executes the pre and post commands.

Parm Editor Pane for Shell Rop on Script Tab

In the Parm Editor, click the Scripts Tab for the shell node. This is the place of interest. We are going to leverage the preframe and prerender parms to run our python. (It could also be the post equivalents, as it before and after running nothing essentially.)

  • Change the Pre-Render and Pre-Frame Script Languages to Python.
  • Switch toggles on the left to off.

**NOTE Next is parm linking and working with both our working Python Rop subnet and the interior shell Rop parms. I often find this easiest with 2 Parm Panes open. If using the Build desktop, a new tab can be created over the network pane, and both pinned (or linked depending on settings) or you may choose to have floating Parm Panes or dive in and out of the Network. However for clarity I will be showing these panes side by side.

Parm Panes Side By Side For Python Rop and Shell Rop Highlighting Fields to Link

The left Python Rop, the right will be the Shell Rop.

The content of the Python Code Field needs to be accessible to prerender and preframe parms on the Shell Rop. This is easily done with a channel reference. It will be referenced in both places as they are mutually exclusive and we want to be able to easily switch between them on the Python Rop UI.

RMB on Python Code Label on the Python Rop Working Subnet, (where we had dragged from on the Python Sop), RMB → Copy Parameter. Then on the Shell Rop, first in the Pre-Render Script field, enable the field and RMB→Paste Relative References. Do the same for the Pre-Frame Script.

**NOTE We can also see the sensible boiler plate we added earlier now appears in the Python Code field.

Parm Panes Side By Side For Python Rop and Shell Rop Highlighting Toggle and Pulldown to Link

The integer menu added earlier, is going to control the selection of Pre-Render or Pre-Frame. On the Execute When Label, previously created on the Python Rop, RMB→ Copy Parameter.

If you recall the 1 Value is for “One Per Frame.” 1 implies on and can be used to enable the Pre-Frame Script Field. On the Shell Rop parms, Pre-Frame togglebox, RMB→Paste Relative Reference. Make sure to do this on the togglebox and not the adjacent label. It will highlight green, and if you have both Parm Panes open you can change the int menu to turn on and off the Pre-Frame Script execution on the Shell Rop.

The inverse is needed for the Pre-Render Script. The int was value 0 for “Once Per Render”, which would disable it when chosen, as it did for Pre-Frame Script. Lets get the same starting point by RMB→ Paste Relative Reference on the togglebox for Pre-Render Script.

Expression Editor Showing Parm Expression on Shell Rop Toggle fo Pre-Render Script Enable

To invert it. RMB again on the toggle box and select Expression→Edit Expression. The expression editor will open. Simply Prefixing this chanref with 1 will create the opposite effect as before. This should be fairly obvious as 1-1=0 and 1-0=1.
Press Accept.

You should now be able to change the menu on the Python Rop and see these alternate fields on the Shell Rop enable in a mutually exclusive fashion keeping to the menu selection.

In the Network Graph, select the Python Rop and RMB→ Save Node Type
Changes are now committed to this new HDA. Time to test. Select the Python Rop and in the Python Code Field enter

print hou.pwd()

Parm Pane for Python Rop and Py Shell Side by Side Showing Unexpected Output

Open a Python Shell and Press Render Button on the Python Rop. If all is well there will be output in the python shell. Success!… or is it?

Something has happened. It is printing ‘shell1’, the interior node name to the Python Shell. That is because it is where the script is actually executing. Unfortunately, unlike some other nodes there is no easy way to set the execution path. Since this is not obvious, it is best to go back to our default boiler plate grab the correct node so its obvious and easy to use.

  • In network Graph, on Python Rop, RMB → Type Properties
  • In middle Existing Parameters column select Python Code.
  • On Right Parameter Description column make select the Channel Tab
  • In first field ALT+E to get to our default editor or type in the field directly (add a carriage return ie \n if you do).

Notepad Showing Updated Boiler Plate Defult for Python Rop Python Code Field

Add this bellow previous boiler plate comment:

node = hou.pwd().parent()

Save and Close your text editor. This will now have boiler plate where the typical node variable points to the expected place, hopefully to clear up any confusion, since it isn’t obvious.

On Type Properties Dialog, Press Apply.

**NOTE If the script in the Python Rop’s Python Code field did not update to new boiler plate. On Python Code Label RMB→ revert to defaults

Parm Pane for Python Rop and Py Shell Side by Side Showing Expected Output

Enter on the python Rop Python Code field, beneath the boiler plate add”

print node.path()

Press Render.

Success! You should now see the proper path to the Python Rop.

Some Finishing Touches. Its best to have descriptive errors. Currently we may see an error like “there was an error on shell1” – this isn’t very useful. It is best to have these errors “bubble up” to out top HDA to be easily seen.

Edit Type Properties Node Tab Messaging Nodes Highlighted

  • Type Properties Dialog should still be open, if  not, then open it from Python Rop.
  • Go To the Node Tab
  • Click to browse button to right of Message Nodes, and select shell1 and accept.
  • On Type Properties Dialog, Press Apply.

For some extra polishing, I downloaded a python logo SVG (with proper usage rights) and embedded it into the operator, via the Node Tab of the Type Properties Dialog.

That about it. Hopefully this was useful as a HDA building tutorial or for some tricks for advanced users. Head over to downloads to grab a copy of the finished HDA

Happy CG’ing
(|:-D>

Python Rop: Part 4 — Cleanup

While the Parameter Interface in the works, we have very little of use, as the Python Sop will error out without an input. We actually don’t need it, all the ‘heavy lifting’ will be done in the land of Rops. We need to clean up and then flesh out something that can actually cook in Rops.

As mentioned there’s no actual need the python sop. We took a copy of it’s Python Code Field and now no longer need it. Go inside the subnet, select the sopnet  previously created and DELETE it. Now we can turn attentions back to the Type Properties Dialog.

Type Properties Editor on Python Rop Showing Menu Tab and Fields to Cleanup.

In the Middle Existing Parameter column, select Python Code Parameter. On the right Parameter Description Column select the Channels Tab. The highlighted fields shown need to be changed.

First make sure the 2nd icon for linking is not depressed, then delete the entry in Linked Channels  sub-columns. This is garbage pointing to the now nonexistent python sop.

This can be edited directly or if you have a text editor set up, click inside the field and ALT+E to open it. On Windows this defaults to notepad.

Note Pad Showing Not Functional DEfault For Python Code Field Left by Py Sop

On the left the is a default. This default is from the Python Sop and no longer appropriate as Rops does not have geometry to deal with directly.

Notepad Showing Python Rop Python Code Field New Default Comment

In my case I didn’t want any boiler plate code.. so simply deleted it all and replace with

# Clever Python Code Goes Here…

Save and closed notepad and the results populated the Field.

Notepad Showing Python Rop Python Code Field Menu Cleanup

Again on the far right Parameter Description column, select the Menu Tab. This area can be populated similarly with our text editor or directly in the field. The purpose is essentially Presets.’ The left field is a python snippet and the right field a Label. The small pull-down to the right of the Python Code field, displays the label and when selected, populates the Python Code with the snippet. You can add your own commonly used Python Snippets here later. However, the current preset is for a Sop and not of use, so simply delete the contents of both sub-columns.

On Type Properties Dialog, Press Accept.
Allow the dialog to close.

Most of the work in the next section will be in the Parmameter Editor Pane.

Python Rop: Part 3 — Parameter Interface Build

Now to start on the UI. In the Edit Type Dialog got to “Parameters” Tab. In the left column make sure “Create Parameters” tab it on “By Type.”

Add Int Parm in Type Properties

First we want to create a quick pull down that will return a 0 or 1. We will then use this to control a toggle to run the python node once per render or once per frame.

Find and highlight “integer” on the left By Type column, and then LMB+DRAG it to the center Existing Parameters section on to “root”. This should place an integer parameter beneath the two existing. If it was created, but not in the right spot, drag to reorder the parameters in the center column until it resembles image above.

In the far right column, make sure you are on the Parameter Tab. Enter for name frameorrender and Execute When for the label.

Add Int Parm Menu Edit in Type Properties

On the far right Parameter Description column, got to Menu Tab and toggle on “use menu.” Make sure you are on the Menu Items radio Tab. Enter the following two menu items that will display text and return an int:

For the first, set Token to 0 and Label to Once Per Render.
For the Second set Token to 1 and Label to Once Per Frame.

Press Apply.

Parm Editor With In PulldownThe Parm Pane should look similar to above image.

The Python Code Editor. We want a python editor in the Parm Pane similar to the python sop. But what is this editor? It doesn’t appear in the Parms By Type list — or does it? … well kind of.

The Python Code editor is a special look/feel for a string field with some tags and setup. This can be created with python or in the Type Properties editor from scratch — but we are not going to do that. If there is significant interest I can make a followup post on how, but there is no reason other than Geek Points. Geek Points are cool, but time is more valuable and same place can be gotten to faster. We already know we want the familiar python sop interface we know and love, so we are simply going to start there.

Netwrok Pane With Sopnet Inside Rop Subnet

Press ENTER to Dive inside the subnet we are working on. Place a sopnet.

Netwrok Pane With Py Sop in Sopnet Inside Rop Subnet

Press ENTER to dive inside the sopnet and place python sop.

Now there are 2 options. The first is preferred as it gets us there faster.

Parm Pan For Python Sop Python Code Label Highlighted

Option 1: If you have Type Properties on top and the Parm Pane visible, Click on the label “Python Code” (highlighted in image) and LMB+DRAG it to the root , on the center Existing Parameters Column of the Type Properties Editor.

Edit TYpe Properties Parms From Node Py Sop Python Code Selected

Option 2: If not all panes are visible or if you are on Linux and your Window manager configuration doesn’t particularly like the pane dragging.

  • Change the far left column Create Parameters to the From Nodes Tab.
  • Navigate the tree to inside python sop.
  • LMB+DRAG The “Python Code” Label to the Middle Exiting Parameters Column on to root.

Either method should now add “Python Code” immediately below our previously created menu. As before, if not in the correct order, drag to reorder.

Press Apply.

The sops Python Code Field will turn green indicating its channel referenced to the top HDA’s UI, this is fine for now. Click in the network editor and press u key twice to return to out working HDA, highlight it and the Parm Pane should now look similar to above.

Python Rop Parm Pane Showing Python Code Field

Great! We have an interface and are well on the way.
Lets bring everything together and make it do work in the next section.

Python Rop: part 2 — Create Bare HDA

First create empty HDA. Its simpler to not rely on the hip file at all and work from the start in an HDA.

Go to a ropnet or /out and drop a subnetwork, then highlight RMB→ Create Digital Asset. There are lots of options when creating and HDA, but only going to touch on those meaningful to this series of posts.

Name the HDA something meaningful. Standard naming would be to name the file with Context_mytool_name.hda (or otl or hdanc or otlnc depending on your prefs and license). The tool is in snake as my_tool and the Title to be similar and in title case My Tool. The dialog does a pretty good job of getting you most the way there but may require some hand editing depending on the order of fields edited. Use ROP_python.hda for the file python for the name and Python for the Label.

Then Press Accept.

Type Properties Editor Basic Tab

This Will open the edit Type Properties Dialog (see below). On the Basic Tab, change “Max Inputs” to one. There will be need to use this node at the top or middle of a Rop chain. Press Apply.

Leave this open for now and place it in an area where the network graph and parm editor wont be obstructed. If using Build desktop, try placing it over the viewport, as it wont be used right now, or find another good place.

**NOTE we want to keep this dialog on top, depending on your window manager and settings, Linux users may need to force this via the Houdini preferences or via the window manager – typically RMB on the dialog title bar and the popup or a submenu will have the option to force to top.

In the next section we will start on the parameter interface build.

Python Rop: part 1 — Intro

This post will be a short tutorial with multiple purposes. Its a solid intro to HDA building for beginners that will yield something actually useful. For more advanced users it might contain some useful tricks, and serves as a quick tutorial on how to build the node which will likely take under an hour.

Why?

Convenience. We often talk about creating conveniences. It usually implies something that does not add any new feature or functionality; it simply enables a user in a more familiar or intuitive way. A python Rop simply provides the familiar python interface available in other context to Rops.

While the pre and post scripts exist on many the included Rops, many third-party Rops, especially those for render engines, may not. This allows having that additional functionality without altering the shipped Rops or having to maintain wrapper otls – just to encapsulate multiple nodes elevating their interfaces to a single one – per node.

A third use is for altering the network during evaluation at render generation time. There could be any specific needs that would require render time evaluation of the graph or require adhoc alterations. Having a python sop couldbe valuable for prototyping, debugging, and adhoc one-offs where no real development resources are necessary.

This is a cool little node and when we are done walking though the tutorial will have a useful tool in our Houdini arsenal. I am working in non-com and have made the Rop available for download for those that want it to dissect along with the tutorial or to skip the tutorial all together. I will try to make a normal HDA available in the near future. I would appreciate it if you like the HDA and want to share it, you send them to the blog so I can see interest in various projects I make available to plan future posts.

With that said, lets get to building.

Take and takes: part 2 — Where and about.

end thoughts …
All appears to work reasonably well in h11.1.xxx –Although, I have yet to test it in any  harsh or production environment. So, anyone who does, feel free to email me some feedback, it’d be appreciated.

There’s some conveniences I ran across in hscript docs that I might like in python. As mentioned in part 1, I wanted to keep the module clean, but I may implement a companion module, if I find myself really wanting it. I also made a fair attempt to add docstrings tha’tll show up in the help popups in Houdini and to keep it generally looking the same as the rest, but some finer ui things like dragging a take into the py shell and expecting the object aren’t working

There are some methods of Take object in particular that are best guess where assumptions had to be made as they were necessary features but have some error potential going forward. There are some places where there was no sense in implementing a feature and still others that are necessary ‘hacks’. This is all noted below.

what is available for download
This scripts are available in takes.py in the script downloads section as well as incorporated into eyevexTools py modules also available for download

basic use
import eyevexTools.takes

# use for creating a new take….
mytake = eyevexTools.takes.Take(‘mytake’)

# it is recommended to use find or a listing function instead of the wrapper directly
mytake = eyevexTools.takes.findTake(‘mytake’)
curenttake = eyevexTools.takes.curTake()
roottake = eyevexTools.takes.rootTake()
alltakes = eyevexTools.takes.allTakes()

caveats

  • unable to implent the XML export as the format can be arbitrary
  • although it is impossible to know is the path would be returned in the presented format, It was needed for this implementation but may not be compatable
  • It is not clear if insertTakeAbove and moveUnderTake will be returning parent or child. I assume it to be child.
  • EYEVEX_TAKE_PREFIX is a hscript env used to store the take prefix (when not default), as hscript provided no facility to retrieve it after being set
  • allAllParmsOfNode method in the docs is assumed a typo/error and that it is method addAllParmsOfNode -which is how it appears in this implementation, but can be a risky assumption.
  • asCode method doesn’t include the code for wrapping the take

(|;-D>

Take and takes: part 1 — What and Why.

Takes in Houdini are an extremely powerful and flexible way to nondestructively try different parameter values in the same session, create render passes for lighting, and create and compare variations. In the series of posts on FauxLiner, we looked at reasons and ways to combine and wrap hscript with hython.  The takes libraries is more elaborate but is done in a similar fashion and for similar reasons.

The takes system is currently accessible from hscript but not hython.  As takes is so powerful and versatile, it is often needed from python, particularly as larger pipeline and tool scripts move to hython. This often results in wrapping hscript take commands in similar looking python code. For example,we can  look at a simple take related command, takename  This can easily be wrapped in pyton, making an equivalent accessible in HOM for take renaming.

Docs Usage example shows:
takename take new_name

# this can easily be python wrapped as
def takename(take, new_name):

hscript_cmd = ‘takename ‘ + take + ‘ ‘ + new_name
hou.hscript(hscript_cmd)

return None

And this is done and done often. It is very common to redevelope or rebuild similar scripts and tool utilities again and again at different jobs or in different projects. Wouldn’t it be easier to have all these common wrapped Houdini take related commands available in a python library while awaiting the official hython takes release ? — the presented python modules attempt to do just that.

This is a ‘stop-gap solution’. Lets briefly go over what is typically meant by this. In short, there is a time lag or a ‘gap’ between what is needed (in this case python access to Takes) and what is available (the official hython release by sidefx is not in current builds). We need to ‘stop’ the gap with an implementation or ‘solution’. Stop-gap solutions aren’t usually elegant and often rely on brute force (we could have this library pull from the HDK C++ libraries which would be more efficient and flexible, but sidefx should eventually be distributing this, so we avoid al ot of extra work by taking a efficiency hit by wrapping hscript). Stop-gaps are intended to be temporary measures and come in two basic varieties: The first is a branch of a tool, project or pipeline that “does the job” and when the gap is passed will be completely discarded as the proper released solution moves into the main fork. The second type moves inline with the tool, pipe, or project and is intended “to transition” to the final solution, which then in itself will be transitioned to from the stop-gap solution. The second variety tends to get employed when the time frame for the final solution is long, unknown, or of unknown stability/compatibility. The Takes solution presented in these posts is of the latter variety.

The first decision that was needed is whether or not to present the wrapped hscript takes commands in a similar 1:1 fashion as shown with takename above. For those who already know hscript, it would be very easy to guess the py equivalent. But wait… When looking in the Houdini docs it would appear there are already some indications on how this may be implemented, if we look at hou.takes and hou.Take. These two docs have what appear a fairly complete list of functions to deal with takes, what methods the Take object will eventually employ, and what kind of values we can expect to be returned by the functions and class methods. Although the docs lack any real description of use, some assumptions can be made by drawing parallels with what is already known about the hscript implementation. The function naming is also descriptive and provide insights. i.e. It can be assumed that…

hou.Take.addParm(self, node)

…will eventually add a parameter to the take that this instance of hou.Take represents. Because we have access to the mentioned information on the possible eventual sidefx implentation, this library models itself after it, and NOT a 1:1 hscript wrapper. This provides additional advantages…

  • forward compatibility (easy upgrade path): by keeping the function names and return values in sync with what we expect the official hython release to be we ease upgrading. Ideally it would be as simple as finding all “eyevex.takes.Take” and replacing them with “hou.Take”, but in reality its not likely going to be THAT easy.  We can avoid introducing additional problems by resisting the temptation to ‘improve’ on the functions and args presented in the docs with changes, and keeping such enhancements in a separate module which can continue to be used, even after the official release.
  • full advantage of pythons object oriented features: when the rest to tools using the library are taking advantage of hython OOP features it could be awkward to deal with the separate procedural style of straight python wrapped hscript
  • reduced breaking changes if the ‘gap’ lasts longer than anticipated: since it is unknown when the official implementation will arrive, there remains the possibility this could fall into long term or indefinite use. Especially considering the library will be distributed, by keeping the function names and return as close as possible with the docs, all the function bodies in between can change. The initial inefficiencies in a quick stop-gap solution that are acceptable may become cumbersome in long term use. This allows the function bodies to be rewritten for greater efficiency or even pull form HDK level (if for some reason this became worth while) without having to alter any code utilizing the modules.

Continue to the next section for download information, as well as potential differences between the presented modules and what will eventually ship in the hou module with Houdini.

FauxLiner: part 4 — Now What.

end thoughts …
In these posts we looked at how to make a tool to help transition new artists to Houdini and allowed a different accessible way to select nodes at different levels. We talked about various hiccups that one might run into when developing such a tool including mixing languages, issues with documentations and reversing in script what was previously done in the GUI.

There are some areas that could be far more compact but for the sake of instruction readability is favored over compactness. A python floating tab could have been used as well, but keeping it in hscript allowed us an easy way to devise the script in steps and allow the title to display cleanly in the floater.  The technique of returning a python ref to a preexisting FauxLiner helped keeps the function simple in addition to making sense since having multiple floaters would not offer anything additional.

what is available for download
This script is available in floaters.py in the script downloads section as well as incorporated into eyevexTools py module also available for download.

In addition to FauxLiner, floaters.py in both cases also contains “Quick Bundler’ (floaters.quickBundler() ). This is a floating panel with a bundlelist pane paired with the FauxLiner.  This is made specifically with rapid bundle creation and editing in mind. I assign “add to selected bundle” in the hotkey editor to CTRL+” Then with the Quick Bundler open, you can rapid bundle by:

  • activate/create bundle on the left
  • select node from any/all levels via the FauxLiner on the right
  • just move pointer over left side and press your hotkey
  • repeat …

caveats

  • currently with the quick bundler, there cannot be any other floating bundle lists open. This is a known issue.
  • after opening either floater, you may go to list mode in the node graph for the next network you create. It seems to only do this once. Press ‘t’ over the node graph to toggle it off list mode

FauxLiner: part 3 — How.

So, now we have a good idea of what we want in the end floater, why we need to implement it, and that it does currently exist in some form accessible from the GUI, although there are a few issues to overcome. We want the end result to be a python function, where we can easily grab a ref to the floater for future manipulation and for easier integration with other python scripts and parts of the GUI.

Unfortunately, after looking through the docs and experimenting, there is the realization this can not be done exclusively with python.  The floating pane can be created and some of the unneeded UI elements hidden — but thats where the fun stops. List mode can be toggled on but List Order can not be, neither can a lot of the other subtle changes we tried out in the GUI in part 2. There is also the issue of pane linking we will get to a little later. So we need to figure out the initial implementation in hscript and move forward from there.  We saved our ‘scrap’ desktop in part 2 which has our preconfigured floater saved with it, so that seems like a good place to start investigating.

Navigate to the desktop file in your Houdini directory and open in your favorite text editor:

  • go to your home directory
  • look for houdiniXX.x (where XX.x is the ver number)
  • inside houdiniXX.x find ‘desktop’ folder and go inside
  • you should see scrap.desk, this is our saved desktop from part 2
  • open it in your text editor

we want to find a floater of neteditor pane type, so find ‘neteditor’, there may more than one, but the line of the one we want ends in ‘FloatingPanel’ — we know this because — well it was a floater. Copy that line into a new document. It should look something like this:

neteditor -G 0.75 -T 0.375 -K 0.3 -C 0.55 -p 0 -c 0 -o 0 -n 1 -s 3 -x 0 -w 0 -k 0 -I 0 -B 1 -D 0 -L 1 -S tree -t comments subnet none -g 0 -a 0 -y 0.5 -m e -r 2 1 -N 1 -H 0.22 -V 0.22 FloatingPanel

related to this floater you should also see immediately below it:
netviewdep -l 0 -c 0 -C 0 -e 0 -E 0 -b 0 -S 0 -s 3 FloatingPanel

and several line similar to:
netcolumns -c display,xray,select,origin,capture,bone -n OBJ FloatingPanel

if we look in our hscript reference we can see what these commands do. In short, the first ‘netviewdep’ configures options for the network graph which is irrelevant since we are not using it. The calls to ‘netcolumns’ configure what columns to toggle node flags are available for what node and network types. We will be deemphasizing this portion of the list view since our focus is selection and to a lesser degree navigation, so its fine to leave at defaults. We can ignore the other lines relating to this floater, but I did want to touch on the fact they were related and did do specific things although in this case they are not relevant.

Right away its noticeable that there’s whole lot of flags and a good chunk switched off (value ‘0’). There are flags representing alterations we may want to switch on for the FauxLiner that that weren’t obviously accessible from the GUI. The string we pulled from the desk file isn’t particularly nice to look at, really understandable nor clear. We need to figure what these flags do and break them up eliminating some that are being set to default values and causing clutter, in addition to changing the bool values of some others.

Open the hscript reference page for neteditor. Look up the ‘-S’ flag that appears with the value of ‘tree’ in our panel configuration. What?! According to the docs the only values accepted are ‘user’, ‘alpha’, ‘type’, ‘hier’, and ‘netbox’? This is partially why we didn’t start with the command as in the docs. Incomplete documentation is an issue that can be ran into now and again as hscript faces antiquation and the equivalents have not appeared in hython, along with obsoleted hscript that may not function as expected. If you look through the long list of configuration flags for the neteditor, it can be noted there are several that do not appear in the docs and vice verse. We need to add the flags from the docs we may need and test toggling the values on the undocumented ones to observe what they do. First we need a floating net editor to play with.

SHFT+ALT+t will open a text port. Create a floating pane  (differs from a floating panel as already lacks the tab UI) with dimension 600×600 named FauxLiner with  the following
pane -F -w 600 600 -n FauxLiner

the following ensures its a neteditor
pane -m neteditor FauxLiner

we can then run (filling in one or two flags in place of ‘…’ and see what happens
neteditor …. FauxLiner

this can get tricky as some changes may not be apparent unless other flags have been set (ie flags affecting list mode wont have an apparent effect if we are not in list mode currently. Likewise some flags are expected in order so keeping with the order as we had copied from the desk file makes it easier.  When adding a new flag from the docs, care should be taken as to where in the sequence of flags it is added and sometime this requires a little trial by error. In the end the sequence of flags below got the results i was looking for:

neteditor -K 0.3 -C 0.55 -p 0 -n 1 -x 0 -w 0 -k 0 -I 0 -B 1 -D 0 -L 0 -S tree  FauxLiner

Earlier, issues with pinning and linking were mentioned. We want to assign this floater an unused pane link group. For those unaware, in addition to the newer pane pinning behavior there are also pane link groups. These allow a number to be assigned to panes. All panes with the same group number move together similar to the behavior of all panes being unpinned.  This behavior tends to work nicer with some scripts in addition to a powerful way of managing a large amount of panes that can accumulate.

We don’t want the FauxLiner to get accidentally included in a group. Essentially we want it permanently pinned and unaffected via other pane navigation, by setting it to an unused group. The menu under the pin displays 1-9 as the group options. Similarly these are the same as accessible via hython. However using hscript we can set any 1 or 2 digit group number. This is great setting above ‘9’ means there would be no way to have it accidentally included via the gui or python.  To set it to ’99’ we use:

pane -l 99 FauxLiner

remember the issue during the mockup of all neteditors toggling to list mode initially once we get to  the level the floating pane was set to list or deeper? What we need is hierarchal level that above anything set in GUI. Such a level does exist and is called ‘the director’ and displayed as ‘/’. By opening the Fauxliner at the director level we not only have access to every node in the scene going deeper, but now set on a level above what can be accessed normally bypassing our list toggling pitfall! (*NOTE: an interesting side effect of having everything listed from the director downwards is being able to select the manager network nodes immediately below the director i.e. ‘/obj’ etc..) The following opens the list at ‘/’ via ‘-h /’ and is combined with the toggling off of the navigation in the pane.

pane -a 1 -A0 -h / FauxLiner

We now have a complete (and very compact) hscript that can be used to create our FauxLiner!!!
pane -F -w 600 600 -n FauxLiner
pane -m neteditor FauxLiner
pane -l 99 FauxLiner
pane -a 1 -A0 -h / FauxLiner
neteditor -K 0.3 -C 0.55 -p 0 -n 1 -x 0 -w 0 -k 0 -I 0 -B 1 -D 0 -L 0 -S tree  FauxLiner

This COULD be pasted into a .cmd file in the script path and sourced to recreate our FauxLiner, as a complete tool. But this doesn’t totally meet the objective of being accessible via python and lacks configurability.

We can formulate hscript commands as a string argument to a python function that calls hscript from python and return results. The function is appropriately named hscript and is a method of the hou module. If we look at the HOM reference “…specify multiple commands by using ‘;’ or the newline character as the separator…”.  So, we need to encapsulate each command in a python string ending with a newline ( \n ) and send it as arg to the hou.hscript() function. To keep things clean as possible, we will assign each individual line to a variable named meaningfully to the commands purpose, place them in a list, and lastly join them to a larger string to be evaluated.

# build command strings
cmd_make_floater      = ‘pane -F -w 600 600 -n  FauxLiner \n
cmd_link_pane           = ‘pane -l 99 FauxLiner \n
cmd_set_tab_type      = ‘pane -m neteditor FauxLiner \n
cmd_format_tab         = ‘pane -a 1 -A0 -h / FauxLiner \n
cmd_setup_neteditor  = ‘neteditor -K 0.3 -C 0.55 -p 0 -n 1 -x 0 -w 0 -k 0 -I 0 -B 1 -D 0 -L 0 -S tree  FauxLiner\n

# create the hscript arg string and ececute it
hscript_cmds = [cmd_make_floater,cmd_link_pane, cmd_set_tab_type, cmd_format_tab, cmd_setup_neteditor ]
hscript_string = ‘ ‘.join(hscript_cmds)
hou.hscript(hscript_string)

Now that we have our hscript nicely wrapped in hython, lets turn it into a function. We are also going to add some args for the window height and width, and the pane link group (in that rare case 99 is occupied). A check is also added to look for the FauxLiner floater already existing as since it is a flat list and the selections are global. Lastly, we find the floater we created so we may return a py ref to it. Here the finished script below.

import hou
def
fauxLiner(width=450, height=600, pane_link=99):

# check if it already exist
if hou.ui.findPaneTab(‘FauxLiner’) != None:

return None

# convert the passed numebrs to strings
width        = str(width)
height       = str(height)
pane_link = str(pane_link)

# build command strings
cmd_make_floater     = ‘pane -F -w ‘ + width + ‘ ‘ + height + ‘ -n  FauxLiner \n
cmd_link_pane           = ‘pane -l ‘ + pane_link + ‘ FauxLiner \n
cmd_set_tab_type      = ‘pane -m neteditor FauxLiner \n
cmd_format_tab         = ‘pane -a 1 -A0 -h / FauxLiner \n
cmd_setup_neteditor  = ‘neteditor -K 0.3 -C 0.55 -p 0 -n 1 -x 0 -w 0 -k 0 -I 0 -B 1 -D 0 -L 0 -S tree  FauxLiner\n

# create the hscript arg string and ececute it
hscript_cmds = [cmd_make_floater,cmd_link_pane, cmd_set_tab_type, cmd_format_tab, cmd_setup_neteditor ]
hscript_string = ‘ ‘.join(hscript_cmds)
hou.hscript(hscript_string)

 # get a py ref to the window
result = hou.ui.findPaneTab(‘FauxLiner’)

return result

FauxLiner final version in houdini 11

FauxLiner showing muli-node selction from different heirarchical levels in H11

Thats about it! We now have a functioning floating Outliner-like pane that should not disrupt other parts of Houdini’s interface! It also inherited a few nice features from the regular list view I chose to leave exposed including the filter box and the filter by type tabs on the left (which can still be stowed).

You can now delete the old scrap.desk as it no longer of use. Continue to the fourth and final part for after-thoughts, usage, caveats, and download info.

FauxLiner: part 2 — Why. (and why not.)

Node Tree/List View: The Network Editor has two notable view modes that can be toggled on. This is the first place new users tend to look for an Outliner like functionality — its close, but not quite. If you put your mouse over the network pane and then press ‘w’ followed by ‘t’, you will have a tree of your session on the left and a list of the nodes at the current select hierarchy level on the right.

h11 tree and list node view

H11 Network pane in tree/list view mode

However this mode does NOT allow us to select multiple nodes at different levels easily and leads to disappointment. The behavior is expected and does make sense and when thought about, looks like and behaves similar to a OS file browser. (*NOTE: This too fits the case since technically the hip file is an archive that can be expanded out into the filesystem — but that’s a topic for another blog..) Similar to i.e. windows explorer you can use the left tree to navigate to different levels and list contents on the right (*NOTE: actually where Explorer shows children of the selected, list view shows siblings). Since the left side is intended for navigation -multiple nodes/nets can not be selected, and since the right only shows a list relative to the selected, there is no way to multi-select nodes at different levels. If you toggled these views on, press ‘w’ and then ‘t’ to return to our default node view.

Custom List and Desktop: What we want would be similar to the list view where multiple selections are allowed, but organized similar to the tree view, displaying multiple hierarchal levels in the session — fortunately such a view does exist from with in the GUI (although not overly accessible) and this will be what the new floater is eventually based on. To get to it:

  • place mouse pointer in the network pane
  • ALT+SHFT+w to tear off a copy
  • place mouse over new copy
  • press ‘t’ to toggle list mode
  • RMB and from the popup..  List Order –> Tree
  • LMB the top icon on the far left looking like an arrow (this get rid of the columns representing the node flags)
  • since the stowbar with alignment, color swatch etc.. is only relevant to the node graph view we may want to stow this as well
  • ‘ALT+\’ will hide the network controls (not needed since we are listing everything)
  • In our final version the tab can also be hidden since this will be a separate floater specific for the FauxLiner. This can be toggled via ‘Pane Tab Operations Menu’ (the little triangle in a circle on the upper right of the pane. Pane Interface –> Pane Tabs
network pane list view. Tree List Ordered

H11 Network List mode. List Ordered as Tree

…. hmmm Now we have something that kind of looks like the Outliner. We might be tempted to save this with the Desktop and use as is.

But, there are issues:

  • its is attached to the saved desktop
  • it always opens with the desktop even when unneeded
  • there is no easy way to reopen it once the window gets closed
  • can easily interfere with pane linking/pinning behaviors
  • the current level when the settings were altered is now in list mode. So, navigating in a different network pane, we will encounter this mode toggle on
  • in general the functionality of the network graph as usual is depleted as it is somewhat tied to our custom view

But this is still a good starting point. So lets save the Desktop temporarily as ‘scrap’. From the top menu bar… Windows –> Desktops –> Save Current Desktop As.. enter ‘scrap’ (without the quotes of course) as the name, LMB save, and we should get a confirmation from Houdini. If you want to continue to use this session and Desktop as Normal. Unstow all the bars and follow the above steps resetting the options back.

HScript and Python: TDs and pipelines have taken to Python with gusto. It allows rapid development and the reuse of libraries between applications (as most major 3D apps now have a python interface).  Unlike some other 3D packages that wrapped former proprietary scripting in python, sidefx seems to have implemented it from the ground up. This is fantastic for stability and robustness but there is a speed bump that pops up frequently…. hython (Houdini’s python) allows us to deal with nodes as programming objects and gives access to many newer features and options unavailable from hscript (Houdini’s former primary scripting language). On the other side of the coin,hscript allows us to deal with the session in terms similar to a filesystem which is often useful (I found particularly so when render farm processing) and still gives access to ALOT of options and areas not yet implemented in hython and many that likely will never be. (*NOTE: a down side of this particular point is some hscript no longer really applies as it was written before the 9.x UI overhaul)

Because of the reasons above, TDs VERY often find themselves mixing the two languages using a variety of techniques, the most common using the Houdini provided functions which allow the calling of one language from the other.  Almost all sizable projects in either language will have to employ such strategies as well as tasks which involve delving into less than often manipulated aspects of the GUI — The FauxLiner falls into the latter scenario.

In the next session we will work out how to get a functioning FauxLiner.