QTreeView / QModel Example (PyQT)

Quick tutorial on how to populate a QTreeView with a QModel. This example was build using PyQT4 and has been tested with the default 2.6.4 python distribution. The package contains a PyDev project and all the necessary modules. Simply run the main.py file to show the dialog together with the QTreeView

The model is constructed with a set of viewable items, derived from a set of base components. This divide might not be necessary but I prefer a strict division between items that can be viewed and the data that is made visible.

This is a typical example of show (better yet, try) don’t tell. So go ahead and download the package. As always, feel free to ask questions!

tree_view

Creating a VEX DSO: Adding Photoshop PSD Support to Houdini

This post will try to explain how to write and install your own VEX DSO plugin for Houdini, written in C++. The included example project creates a plugin called VexImageReader. This plugin can be used to read all sorts of images, including psd and dds files. The reader can be used in all vex context layers and is added as a function called: readimage.

The function takes as input arguments a U and V coordinate, an input string (image name) and a wrap mode. By calling the function Houdini evaluates the image at that specific coordinate and returns an interpolated color value (RGBA). The reader supports most popular image formats and reads 8, 16 and 32 bit grayscale and color images.

Before we start, download the necessary files right HERE. Inside this package you will find:

  • The source code and Visual Studio 2008 project file (code)
  • The FreeImage library source code (freeimage/Source)
  • A compiled x64 windows DSO (build)
  • A compiled x64 windows FreeImage library (freeimage/Dist)
  • An otl that wraps the Vex function call in to a VOP (otl)
  • An example HIP file (hipfile)
  • The VEXdso include file, used by Houdini to add the VEX plugin to the houdini DSO table.

As mentioned above, I included the compiled plugin. This means you (probably) don’t have to compile your own if you run Houdini 12.5 on a Windows x64 machine. I have tested the setup with Houdini version 12.5.427, on a windows 7 x64 machine. If you have a different Houdini version or use a different operating system, you will have to compile it yourself. On windows you can use the VexImageReader Visual Studio project. For more information on how to write and build DSO’s using the HDK, please read: Setting up the HDK for Houdini 12 with Visual Studio.

The code should be cross-platform compatible. For this tutorial all code, compile and project references are relative to Visual Studio 2008.

Notes on compiling the VexImageReader DSO

Compiling a VEX DSO is pretty much the same as compiling any other DSO. The only thing worth pointing out is that (in this case) we need to link against the FreeImage library. Again, if running the configuration mentioned above, you can use the precompiled FreeImage library (freeimage/Dist). Otherwise you need to compile your own. I have included the header and source files, but you probably want to get the latest version of FreeImage right here. FreeImage is a great Open Source library project for developers who would like to support popular graphics image formats like PNG, BMP, PSD, JPEG, TIFF and others as needed by today’s multimedia applications. FreeImage is easy to use, fast, multithreading safe, compatible with all 32-bit or 64-bit versions of Windows, and cross-platform (works both with Linux and Mac OS X).

To ensure the FreeImage library is included and linked properly, point to the right header files and library by editing the Visual Studio project properties:

After compiling the project VexImageReader.dll should be stored in the Output directory specified for the project. In my case that is: $(OutDir)\vex\VexImageReader.dll. Note the vex intermediate directory. This is of great importance for Houdini in order to pick it up on launch. Why this is will be discussed in the next section.

Loading the VEX DSO in Houdini

I found it rather difficult to get Houdini to pick up the VEX plugin. After reading through the Side Effects forum, Od-Force and HDK documentation I managed to create a setup that makes Houdini import the plugin on launch.

The HDK documentation states that, in order to install the DSO you need to: create a table in the Houdini path so that the VEX engine can find your plug-ins. The table lists the location of the dynamic link objects which should be loaded by the VEX engine. In order to do this we need to know how we can add objects to this table that are recognized by the VEX engine, and therefore included.

As you might know, Houdini uses the HOUDINI_PATH variable to look for releavant data to load or initialize. It also checks some pre-determined subdirectories of the directories included in the HOUDINI_PATH. One of those is called vex. In this subdirectory it expects to find a file called VEXdso. This VEXdso file lists additional VEX dso’s that need to be added to the VEX engine. This is where I added the VexImageReader.

The package you downloaded includes the VEXdso file that is required for loading the plugin (dependencies\vex\VEXdso). Copy the VEXdso file to a location that is included in the HOUDINI_PATH and make sure it’s in a subfolder of that path called “vex”. Houdini will parse the file and now look for a plugin called VexImageReader.dll.

The path to the VEXdso file should read: %HOUDINI_PATH%\vex\VEXdso

Now Houdini knows to look for a plugin with the name VexImageReader.dll, it will try to find it using the CUSTOM_DSO_PATH variable. Again, for VEX extensions Houdini appends “vex” to paths defined in there.

The path to the plugin should read: %CUSTOM_DSO_PATH%\vex\VexImageReader.dll

I created two user variables in Windows to automate the lookup. Both variables point to the same directory and contains a “vex” subfolder. This folder will contain the VEXdso file and all the vex plugins. This way everything is in one place and easier to edit or look after.

  • VEX_PATH = (YOUR PATH HERE)
  • CUSTOM_DSO_PATH : %VEX_PATH%\HoudiniDSO
  • HOUDINI_PATH : %VEX_PATH%\HoudiniDSO;&

The last thing to take care of is to include the location of the FreeImage.dll in the PATH variable. This way Houdini can find the FreeImage library when the function is evaluated.

If all went well Houdini is now able to add the plugin to the VEX engine. To verify that the plugin loaded correctly, type in a Houdini Textport the following: dsoinfo -vq This should print all the custom functions available to VEX and their signature.

Wrapping the function in an OTL

The plugin itself only adds a function to the VEX instruction set, accessible through code. It’s always nice to have a vop to access that functionality, so you can use it inside (for example) a vop sop. By using an inline VOP it’s easy to wrap the function in a vop operator and create an otl out of it. This otl becomes available to all the vop operators in Houdini (wow, imagine reading this without having any knowledge of the Houdini architecture. I truly hope people don’t).

When opening the example file (hipfile\image_sample.hip) you can see the function used in a SOP, COP and SHOP context. This means you can use it to manipulate geometry, composite images, build shaders and drive particles. Vex is a truly wonderful language and instruction set. Implementing your own vex extensions can be a bit tricky, and the setup is far from easy. Luckily the same settings apply for all compiled dso’s and the same setup can be used for all plugins.

Famous Last Words

The code and data included in this tutorial comes without any sort of warranty. Suggestions on how to improve the plugin are welcome! The only filter algorithm implemented is bilinear. Feel free to add other ones, this should be ‘relatively’ easy with the way the project is setup. The plugin is (should be) thread safe, did not encounter any issues with the number of threads set to 1. Images are cached and released based on the active operator.

Links

SESI HDK Vex Operators

Mario Marengo Saves The Day

Extracting DSO Information

 

Setting up the HDK for Houdini 12 with Visual Studio 2008

Thought I’d share my Visual Studio setup for creating and compiling custom DSO’s for Houdini 12. Included are a Solution, 2 project files, documented examples and a houdini file.

Get the package HERE

The reason I use Visual Studio is because of it’s great debugger and clear way of structuring (and maintaining) code. Unfortunately there isn’t much help on how to set VS up in order to use it with the Houdini development kit. This guide should have you up and running in no time. After completion you should be able to compile and load the compiled dso’s in Houdini and inspect them using the debugger.

Quick note on the HDK: The HDK is a comprehensive set of C++ libraries. These are the same libraries that the Side Effects programmers use to develop the Houdini family of products. With the HDK, you can create plugins that define nodes, commands etc. I often use the HDK to optimize earlier prototypes written Python and sometimes Vex. But this isn’t always necessary. Only when speed becomes an issue I rewrite some older operators to gain some responsiveness.

First things first. Houdini 12 is compiled for windows using MSVC9, shipped with Visual Studio 2008. For that reason it’s only possible to compile Houdini plugins with that specific Visual Studio compiler. So try to get your hands on a complete Visual Studio 2008 installation. I believe the express edition won’t work because you can’t link to dll’s, but never tried. When running a 64 bit version of Houdini, make sure to install the x64 compiler as well. This option is turned off by default. For this tutorial I will focus on the x64 version of Houdini.

After installation the compiler can be found here: C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\amd64
If you haven’t included the x64 compiler during installation this directory is missing…

You should have a Houdini 12 version installed (duh ;)). This particular setup is tested with Houdini 12.1.33×64 and 12.1.92×64. Both versions worked fine. It’s important to remember that rather significant code changes can happen between Houdini releases, even daily builds. Therefore your code might stop working or won’t compile when switching to a different version. I try to stick with a specific release for as long as possible (most often Production builds), and only switch when necessary (new major release, a bug fix etc.)

Now Houdini and Visual studio are installed, it’s time to set up the Windows environment. We’ll do two things here:

  • Set up some environment variables that will be referenced in the visual studio solution and projects
  • Specify a new DSO path where the plugins will be stored

Open up the environment variables dialog in windows and add the following variables:

  • H12_PATH : C:\Program Files\Side Effects Software\Houdini %H12_VERSION% where Houdini is installed
  • H12_VERSION: 12.1.33 the version you are using
  • HOUDINI_DSO_PATH: %CUSTOM_DSO_PATH%;& extends the default dso path
  • CUSTOM_DSO_PATH: G:\WorkCoen\HoudiniDSO where the custom dsos are stored (customize to your liking)

For the second step we want to create a Solution that contains a project that can be compiled in x64. In the package provided you will find a solution that can be opened in Visual Studio 2008. This solution contains 2 projects that define 2 different types of operators: the well know SOP Star and my own UV Interpolator. After setting up the projects we can build them and debug the operators using VS.

First we want to check that each project is linked against the correct Houdini library. Open the project properties and browse to Linker > General > Additional Library Directories. This value for this field should state:

  • $(H12_PATH)\custom\houdini\dsolib

The Output File parameter controls where the dll will be stored. This directory needs to be included in the HOUDINI_DSO_PATH.
For that reason I pointed it to the CUSTOM_DSO_PATH variable.

  • $(CUSTOM_DSO_PATH)\$(ProjectName)_$(ConfigurationName).dll

Now for the actual header files. Houdini ships with a lot of them and they be found (in all their glory) right here:

  • $(H12_PATH)\toolkit\include
Make sure the Additional Include Directories parameter points to that directory

The command line arguments are important. They define how the operator is build by the compiler. Houdini uses a lot of arguments and I don’t know them by heart. What I do know is that the -O argument is an optimzation preventing me to debug my code. When you want to dive in and look for the source of a problem there are two important arguments to set / remove:

  • Remove -Ox (disables optimalization)
  • Add -d (enables debugging)
I currently use the following arguments:
  • -TP
  • -Zc:forScope
  • -DVERSION=”$(H12_VERSION)”
  • -DI386
  • -DWIN32
  • -DSWAP_BITFIELDS
  • -D_WIN32_WINNT=0x0501
  • -DWINVER=0x0501
  • -I .
  • -I “$(VS2008_PATH)/VC/include”
  • -I “C:/Program Files/Microsoft SDKs/Windows/v6.0A/Include”
  • -I “$(H12_PATH)/toolkit/include”
  • -MD
  • -EHsc
  • -GR
  • -DSESI_LITTLE_ENDIAN
  • -DNEED_SPECIALIZATION_STORAGE
  • -DAMD64
  • -DSIZEOF_VOID_P=8
  • -DMAKING_DSO

If we want to launch Houdini from within Visual Studio to debug the dso’s, it’s important to set up the Debugging properties. The Command property should point to the Houdini version you’d like to launch. In this case that’s:

  • $(H12_PATH)\bin\hmaster.exe (houdini master)

To ensure the dso is loaded when Houdini is launched, the CUSTOM_DSO_PATH variable is added to the HOUDINI_DSO_PATH variable, specified in the Environment property

  • HOUDINI_DSO_PATH=$(CUSTOM_DSO_PATH);&

With all of the above in place you should be able to build the projects and start Houdini by pressing F5 (launching the current active project). Everything should be loaded and an empty session should appear. From here on try to create the node (Star or UV Interpolator) and put down a break point somewhere in the source code. When the node is cooked the break point should be hit (if it’s in the right place). Happy debugging!

 

Some useful external resources:

Opening Up Houdini

There are times when you want to get information from other applications, or your own, into Houdini. Although there are many useful operators for loading and exporting information, opening up a port offers more or additional functionality.

A while back I was asked to create a protocol that would enable us to do exactly that in Houdini. This could be from Maya or any other application. In this post I won’t discuss the various serialization methods but will try to open a door on how to start your own (simple) server when launching houdini. One could use this server that runs in the back-ground (in a seperate thread) to directly access information, execute tasks or sample data (in a custom node for example).

A possible use could be to access external data to reconstruct meshes without writing a single file to disk.

To achieve this we need to open a port on startup that can receive data independently from the session a user is working in. Therefore not locking up Houdini.

A couple of files are searched for and run when Houdini is launched. Most noticably 123.cmd, 456.cmd, 123.py and 456.py. 123.cmd and 123.py run when Houdini launches without loading a file. 456.py and 456.cmd are run whenever the session is cleared or a file is loaded. Another option could be to create a file called pythonrc.py. This file is always invoked when Houdini starts up.

For this example I created a file called 123.py and made sure the HOUDINI_SCRIPT_PATH was confifgured correctly to find that file when it launches. If unsure on how to do that, simply create the file in you Houdini script folder.

For example: $HFS/houdini/scripts/456.py > C:/Program Files/Side Effects Software/Houdini 12.0.581/houdini/scripts/456.py. There should already be a file called 123.cmd (the hscript equivalent) in there. Appending your own custom HOUDINI_SCRIPT_PATH location is advisable! When upgrading Houdini, scripts remain accessible.

Once the file has been created we want to start the server when we launch a new Houdini session. I’ve given the server a permanent port to connect to (2000) but it is possible to assign multiple ones for every session running. In this case it means that from wherever you are, you can connect to exactly one Houdini session by sending data over port 2000. Most likely you want to connect to ‘localhost’, which is the computer you are using.

To seperate the object from the initialization steps, a seperate HServer class is created and instantiated in the 123.py file. There can be only one port open and one instance of this class running, making it a singleton. And although Python’s definition of a singleton is weird, it is preferred in this case.

# import our server module
import hdaemon

# start the python server
thread_name = hdaemon.startHPythonServer('python_server')
print "started python sever in thread: %s" % thread_name

These lines of code are executed when houdini launches. When the instance of houdini is exited, the port will close and the thread will stop. But what is actually started, and how? The following piece of code shows what happens when trhe startHPythonServer function is called.

The module ‘hdaemon’ holds the HPythonServer object and 2 methods for starting and stopping it. The start method checks for a thread already running with the name ‘python_server’. If a thread with that name is still active, no new port will be opened and no new process will be returned. If the server is not running, a new HPythonServer is created and started in a seperate thread.

The socket module is used as the low level network interface.

"""
@package hdaemon
This package defines a Python Server that can be used to communicate with Maya
@author Coen Klosters
"""


import threading
import socket
import uuid
import hou

class HPythonServer(threading.Thread):
    """
    Simple Python Server running in a seperate thread within houdini, listerning to commands
    Connect to Houdini using the HPORT specified.
    """

   
    CLIENT_IDENTIFIER = "HPythonServer"
    HOUDINIPORT = 2000
   
    def __init__(self, inClientIdentifier=None ):
        """
        Constructor
        @param self The object pointer
        @param inClientIdentifier A string that allows the overriding of the client identifier.
        """

       
        threading.Thread.__init__(self)     # initialize the thread
       
        if inClientIdentifier is not None:
            self.CLIENT_IDENTIFIER = inClientIdentifier
       
        self.__thread_running = True        # when set to false, cancels the socket to listen
        self.__guid = uuid.uuid4()          # unique identifier name
        self.__associated_socket = None     # Initialize the socket
           
        # Start the thread
        self.setDaemon(True)
        self.start()

           
    def stop(self):
        """
        Close the socket and stop the thread
        @param self The object pointer
        """

        self.__thread_running = False
        self.__associated_socket.close()

   
    def setup(self,inConnection):
        """
        Listens to the connection given to receive external data.
        @param self The object pointer
        @param inConnection The incoming server connection
        """

       
        operation = True
        conn, addr = inConnection.accept()
        print 'Connected to: ', addr
        while self.__thread_running:
            data = conn.recv(4096)          #make sure it's a power of two!
            if data == "print":
                print "switching to print mode"
                operation = True
            if data == "evaluate":
                print "switching to evaluation mode"
                operation = False
                continue
           
            if operation:               # if in print mode, print whatever received
                print data
            else:
                hou.session.dataobject.data = data  # otherwise store the data in the houdini session currently active
               
            if not data: break
           
        print "connection broken with: %s" % str(addr)
       

    def run(self):
        """    
        This is the override of the threading.Thread.run() function which is started on the AssetDaemonPythonClient's thread.
        As long as the __thread_running variable is True we will stay in this function listening for data from the socket.
        @param self The object pointer
        """

       
        HOST = ''                                  # Localhost
        PORT = self.__class__.HOUDINIPORT          # Port to connect to Houdini with
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            s.bind((HOST, PORT))
            s.listen(1)
        except socket.error:
            s.close()
            s = None
            return -1
       
        while self.__thread_running:
            self.setup(s)


def startHPythonServer(inDaemonThreadName):
    """
    Helper function for setting up and starting a HPythonServer
    @param inDaemonThreadName The name to use for the thread containing the client, this name is used to ensure the client works as a singleton
    @return object instance
    """

    mcd_thread = None
    for thread in threading.enumerate():
        if thread.name == inDaemonThreadName:
            mcd_thread = thread
   
    if mcd_thread == None:
        mcd_thread = HPythonServer()
        mcd_thread.name = inDaemonThreadName
       
    return mcd_thread

     
def stopHPythonServer(inDaemonThreadName):
    """
    Helper function for stopping an HPythonServer
    @param inDaemonThreadName The name of the thread that the client should be running in, by using this name the function will find the thread and stop it.
    """

    mcd_thread = None
    for thread in threading.enumerate():
        if thread.name == inDaemonThreadName:
            mcd_thread = thread
           
    if mcd_thread is not None:
        mcd_thread.stop()

When launching Houdini, a seperate thread running alongside Houdini should be waiting for packages to arrive. To connect to Houdini simply specify the server and port you want to connect to. Messages that are send are printed to screen in Houdini.

To connect to Houdini, do the following.

import socket

HOST = 'localhost'                          # The remote host
PORT = 2000                             # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))                 # Connect
s.send("Hellow Houdini, I am your father")      # Send a message
s.close()                       # Close the connection

Off course, sending simple strings doesn’t get you far. In order to actually do something useful, the data needs to be serialized / deserialized. But that’s something I might address some other time. A handy tip is to look in to the hou.session module. This module can be used to store received data and is accessible throughout Houdini! Think of parsing mesh data that can be accessed in a python Sop. Very useful!

Pyro 2 Work Flow Examples

I totally forgot I had these laying around.. Thought I’d share them.
Simple examples on how to use some of the Pyro 2 functionality, such as inheriting object motion, object collision, clustering etc.
Not very visual but could be useful. Small post-it notes explain the various subsets present in the netwerk.

Note that the examples only work with Houdini 12 +.

Get the package HERE

Houdini Grid Based Fluids And Dynamics

A while back I got an invite to do a two day seminar in Seoul.

Teaching at the university of Seoul about Houdini’s Dynamics environment and recursive functionality. After waiting for over a year I find it’s about time to release the training material.

Below you will find a link to a rar package containing a pdf, example files and demo otls.

The material consists of an introduction in to recursiveness in Houdini, Houdini’s Dynamics environment, Houdini Volume primitives and fluid solvers. Starting simple and ending with building a custom fluid solver incorporating a simple Dynamic Resize model and simple volume shape operators.

Hopefully enough to get anyone going within Houdini’s dynamic environment. But most importantly, to create awareness regarding the full set of possibilities this environment has to offer. Never again should you wonder what this magic shelf button does.

Any question feel free to mail or post a comment.

Also note that some of the .hip files might have incomplete geometry. Creating a simple new geo reference should suffice. I will try to get the files up to date as soon as possible.

Download the package HERE