October 17, 2005

Puppet Animation

Here's a link to the Quicktime movie file of my first stab at an animation using my Puppet CHOP. The model is not complicated, and the texturing is anything but perfect, but... consider that once everything was rigged and setup I "performed" this animation with a Logitech Extreme 3D Pro joystick in about 30 seconds, in real-time.

Movie Link

September 21, 2005

Joystick Puppetry

I had a great session last evening working with the brand new Joystick CHOP I had constructed. I was able to accomplish three major things:

  • First, I was able to build a simple rigged model and attached animation CHOPs to it. Simplistic, but a good milestone;
  • Second, I was able to improve on my rendering capabilities, using VEX and SHOPs to create some interesting materials for my model;
  • Third, I was able to use the Joystick CHOP to record real-time performance animation - which was my real goal when I started this Joystick project.

My puppet model was fairly simple. The goal was to build a muppet-like creature with spheres and half-spheres, and some other simple geometry and texture maps to create something reasonably interesting. For the purposes of the puppetry rig, I wanted something that had the following features:

  • Eyes that could blink
  • Eyebrows that could look angry or worried
  • A mouth that opened and closed
  • Rotate, or shake, the head back and forth
  • Nod the head fowards and tilt it backwards
  • Tilt the head from side to side

I had a Logitech Extreme 3D Pro Joystick to work with, which provided a number of buttons and joystick axes to play with:
Logitech_joystick
The joystick has the traditional X- and Y- axis, which I mapped to tilting the head backwards, forwards and from side-to-side. The joystick also has the ability to "twist" by turning the handle, so I mapped that to turning the head from side to side. There was a throttle axes on the rear of the device, which I attached to the eyebrows: full throttle was "angry eyes", and no throttle was "worried eyes". Finally, I attached the mouth opening and closing to trigger button (pressing the trigger opened the mouth), and a button near my thumb on the joystick handle mapped to closing (blinking) the eyes. For the mouth and blinking, the effect was binary - so they were either opened or closed.

The model took a while to construct (a couple of hours), even though it was fairly simple. It looks pretty "muppet"-like:
Puppet0_1
I created the various Joystick CHOP inputs and networked them together with a Merge:
Puppet2_1
In this snapshot of the CHOP network, you can see I have the Record data locked (the little yellow square): I had already recorded my performance, and flipped that flag on to preserve the motion I had created. I also piped the output through a Lag CHOP, which created nice "ease in/out" motions for the otherwise pretty binary and jittery buttons and joystick axes. The net effect of the Lag CHOP on the motion data is pretty natural and pleasing, I think.

Here are some snapshots of frames from the animation:
Fr1_1
Fr283_1
Fr384

September 17, 2005

Creating a Joystick CHOP with the HDK

I was finally successful in writing a custom CHOP to accept real-time input from a Joystick.

I spent a fair amount of time mulling this over, writing code, discarding code, re-writing code, etc. until I finally did it right. The biggest challenge I faced was deciding what bloody parameters I needed in the CHOP. So I did some research on libararies I could use to input the Joystick data: that would, in turn, give me a good foundation on how I would design the CHOP.

I looked briefly at the DirectX APIs, but quickly decided that since Houdini was a cross-platform application I needed a cross-platform solution. I found the Simple DirectMedia Layer, or SDL at http://www.libsdl.org - an open source, cross platform media layer for doing cross platform games on Windows, Linux, Mac, etc.

Note that to make SDL work you either have to compile it yourself and install it on your computer, or you can pick up the pre-built binaries that exist on the SDL web site. I elected to just use the pre-built libraries. I copied the runtime DLL into my windows PATH (I confess, I just put it in c:/windows), and I put the .lib file as well as the SDL subdirectory containing the SDL header files in the directory where I was building the CHOP source code.

I was then able to use the following command line to build my CHOP:

hcustom -l SDL.lib -I ./SDL CHOP_Joystick.C

I'll also mention that as a starting point, I used the Houdini sample code CHOP_FifthGlove.h and CHOP_FifthGlove.C as reference for how to go about building the CHOP. In essence, this Joytick CHOP was going to poll the device values when requested to by the Houdini system, convert its values to "normalized" values and insert the values into the CHOP channels.

The SDL libraries provided APIs for accessing the Joystick, and after a bit of reading I decided I wanted to keep it simple in my first attempt. So, while SDL provides support for Joystick Axes, Buttons, Hats and Trackwheels, I decided to only support Axes and Buttons.

Initially I wanted to write a single CHOP that could read every Axis and every Button on a single Joystick, but I quickly realized that this was going to be very tricky... at least for me. I wasn't familiar with the fine details of CHOP programming and I didn't have access to deep API documentation either, so I was relying strictly on the sample CHOP programs provided by Houdini. So the concession I made was that my Joystick CHOP would output one single channel, as described by the CHOP. If the animator configured the CHOP to watch the X-axis, it would spit out the value of the X-axis. If the animator configure the CHOP to watch the trigger button, it would spit out the value of the trigger button. To build a system that read from all the various axes and buttons on a Joystick, you would have to create multiple Joystick CHOP objects and merge their outputs together.

I also decided that the axis would have values from [-1, +1] and that buttons would have values of 0 (not pressed) or 1 (pressed).

The Joystick CHOP interface would have main parameters:

  • Active (Boolean): When true, the Joystick CHOP would read from the device. When false, it would not read from the device.
  • Joystick ID (int): This is the integer ID of the Joystick as detected by SDL. This is a little RAW, and I could have tried to have the CHOP detect the Joystick and even provide its name in the CHOP menu (e.g. "Logitech Extreme 3D Pro"), but that was getting a little complicated for my taste. I wanted to get something working first.
  • Value Type (enum): This is one of "Axis" or "Button", indicating that this Joystick CHOP listens to an Axis input or a Button input.
  • Value ID (int): This was the specific Axis or Button (depending on the value of Value Type) that the CHOP would listen to on the device.

After a few long evenings of re-learning C++ and playing with the various API calls in SDL to make it all work, it finally started compiling and working. Here's a screen shot of the Joystick CHOP in action:

Joystick_chop_example

And here's a snippet of source code from the CHOP itself - this is the actual call where we get the values from the Joystick hardware:

if (VALUE_TYPE() == JOYSTICK_TYPE_AXIS)
    {
        if (SDL_JoystickNumAxes(myJoystick) <= VALUE_ID())
        {
            cerr << "No joystick axis with index " << VALUE_ID()
                 << " (max " << SDL_JoystickNumAxes(myJoystick)-1
                 << ")" << endl;
            return;
        }
        float axisValue = 0.0F;
        axisValue = (float)SDL_JoystickGetAxis(myJoystick, VALUE_ID());
        // cout << "axis = " << SDL_JoystickGetAxis(myJoystick, VALUE_ID()) << endl;
        // cout << "joystick opened = " << SDL_JoystickOpened(0) << endl;
        value = axisValue / -32767.5F;
    }
    else if (VALUE_TYPE() == JOYSTICK_TYPE_BUTTON)
    {
        if (SDL_JoystickNumButtons(myJoystick) < VALUE_ID())
        {
            cerr << "No joystick button with index " << VALUE_ID()
                 << " ( max " << SDL_JoystickNumButtons(myJoystick)-1
                 << ")" << endl;
            return;
        }
        value = (float)SDL_JoystickGetButton(myJoystick, VALUE_ID());
    }
    else
    {
        cerr << "Unknown Joystick Value Type" << endl;
        return;
    }

If anybody is interested in getting a copy of the source code for the Joystick CHOP, let me know, and I'll gladly provide it.

September 06, 2005

LookAt

One of the things I've always wanted to model is an armature system with a hydrolic "motor" that could move the arms, kind of like C3P0 on Star Wars (look at the little linkage between his upper arm and forearm):

Swc3p0statue1_2

I knew I wanted to use the LookAt feature of geometry. It took me about 30 or 40 minutes, but I came up with something kind of interesting. Here's what I did. First, I create an interesting model for one half of the armature, like this:

Arm1

Note that the main axis of the armature extends up the y-axis, and the center of the "pivot" is at (0,0,0). This isn't essential, but it made it easier when I had to move things around later.

Then I went back to the geometry level and duplicated that geometry (with a ^C ^V) and parented the new geometry to the original. I rotated it 180 degrees in the Y direction, and about 120 in Z, to give me:

Arm2

Then I created two new geometry objects at the object level, filling their geometry with a single sphere SOP. I moved them so they were kind of embedded yet protruding from the individual armature. Each pivot is parented to each linkage, so any movement in the linkage moves the pivot along with it. The arm assembly with the pivots is show here:

Arm3

After this, I created two "hydrolic" rods parented to the pivots. I used the Tube SOP for the rods, and made one slightly larger than the other, so that when they were "attached" it would look like one was sliding inside the other. For now, I created the tubes so that they extended in the positive direction down the Z axis. I did this because the LookAt transformation in Object points the Z-axis of the coordinate space towards the thing you are looking at:

Arm4

At this point, note that the hydrolic rods are just extending in opposite directions. This is because they are parented to the pivots, the pivots are parented to the armature, and one of the armatures is rotated in 180 degrees.

Next, we open hydrolic rod Objects and select the LookAt from Transform tab. For each of the rods, we select the LookAt object to be the pivot for the opposite rod. This will make the rods always orient towards the opposing pivot, making them look like they are always attached:

Arm6

Now you can rotate the second armature (the "child" armature) and the hydrolic rods will be pinned to the pivots and will slide in and out of each other, like this:

Arm7

Arm8

Download hydroarm.hipnc

September 04, 2005

Custom code and the HDK (Joysticks)

I have a few simple projects in mind that I will eventually start posting here, but during the last few days I've found myself exploring a bit of a tangent with Houdini.

I want to try animating things in Houdini using external controllers. Nothing like motion capture suits like Flock of Birds, or expensive data gloves or anything - just regular cheap gaming peripherals like the Logitech Extreme 3D Pro joystick I have sitting on my desk.

My first inclination was to understand how things like that worked in Houdini, so I immediately loaded the program and began exploring the interface and help files. I ended up in the CHOPs (Motion and Audio) section of the interface, but couldn't find anything with respect to Joysticks. I played around with the Mouse CHOP, and actually recorded some simple data with it. But I couldn't find anything related to Joysticks - so I assumed that there must be a lower level way of doing this.

I found the PipeIn and Network CHOPs and thought that this would be a reasonable way of inputing the Joystick data. Eventually I was able to locate a description of the file format used by Houdini to parse the data from PipeIn. So being ambitious, I wrote a Python script (and yes, I still use Python) to connect to the Houdini Network CHOP. My plan was to use Python and PyGame, a set of open-source Python bindings to the OpenSDL gamine libraries (which provide Joystick support).

Unfortunately I couldn't get this to work, for whatever reason. I could create a server that could make connections and spit out random channel values, but I couldn't make it connect to the network CHOP. I went to bed thinking I would revisit my network CHOP in the days to come.

Then I think I had a dream. I dreamt that it would be really cool if there was some kind of software SDK that would let you extend Houdini with your own SOP/CHOP/POP/etc. code to do what you wanted. When I woke up from the dream, I was almost disappointed that I had only been dreaming... after all, that would be the perfect way to input Joystick data into a CHOP. So you can imagine my joy when I sat down to investigate this, and there was indeed a Houdini Development Kit that let you write your own CHOPs!!!!!

Here's what I learned about getting going with the HDK in Houdini:

  • First, if you want to compile on Windows (I have Windows XP) you're going to need to have Microsoft Visual C++ installed. This costs money, so if you're the frugal type you may want to go the Linux route with its less expensive (free) development tools.
  • Next, you need to have the environment variable HFS set to wherever you installed Houdini. Set this in your Control Panel -> System -> Environment Variables. For me this was HFS=C:\Program Files\Side Effects Software\Houdini 8.0.345
  • Next, you need to have the Houdini bin directory in your PATH, once again setting this in your Windows environment variables. For me this meant adding C:\Program Files\Side Effects Software\Houdini 8.0.345\bin to my path.
  • Next, you need to have the Microsoft Visual C++ executable directory in your PATH. I think MSVC did this for me when I installed it - so check your PATH, and refer to your MSVC documentation if you think your PATH is not correct.
  • When all of this is done, bring up a command shell and CD to your Houdini bin directory by typing "cd %HFS%\bin"
  • Run the command "hdkinstall"
  • Walk through installing the HDK - you will need to get a license key in order to install the HDK. For me this was a bit complicated: it didn't happen automatically, so I needed to follow some instructions generated by the installed, go to the Side Effects web site, manually generate a license key and copy-and-paste it into the Side Effects license key manager (hkey).
  • Finally, I was able to compile and install the Houdini sample CHOPs located in %HDK%\toolkit\samples\CHOP

So, if you follow that admittedly  rough set of instructions, you can also get the Houdini HDK working with the Apprentice edition.

To cap off the night, I copied one of the sample programs and modified it to compile and link some SDL code. I tried running Houdini, and after playing around with where to put the SDL.dll file (I ended up putting it in c:\Windows\System) I successfully ran Houdini with my new hybrid CHOP that contained the code to initialize the joystick system. My Joystick CHOP doesn't yet read any Joystick data - that's my project for the coming days - but it does execute and initialize without bringing the whole system down. That's a good start. Here's proof:

Joystick_chop1
And interesting note to end on: Working through the Houdini code brought back a lot of memories of working at Side Effects almost 10 years ago! The code style is very similar to 1994!

August 30, 2005

Hello World

To kick things off, I'm going to do a little excercise. This is not a difficult Houdini task - but I want to test the new Blogger.com image posting service and I want to get things rolling a bit.

I remember when I was first getting into CG, I badly wanted to render a wine glass. I have no idea why. I wanted to draw the profile of the wine glass and revolve it around to make a solid object. My first attempts at doing this were in the Computer Graphics Lab at the University of Waterloo with Alias PowerAnimator, back in the early 90s.

In computer programming, "Hello World" is often showcased as the introductory example when demonstrating a programming language. The wine glass is my "Hello World" and I'm going to make one, right here and right now.

Curiously, one of the most challenging things I had to learn when I was "relearning" Houdini, was how to draw a curve. Its actually quite easy, but I think requires a bit of hand-holding. First, go into "Objects" mode in the Houdini interface:

Objects_1

Create a new Geometry, and call it "wineglass", like this:

Wineglass_1

Select it, and press the 'i' key to edit the Geometry's SOP network. When you enter the SOP editor, you'll see a single "File" SOP, loading the classic Houdini "Axis Cube" - delete it, because we're going to start from scratch.

In the View Window (it will have "View" at the top left of the screen): click in the window to ensure you have focus. First, we want to go into an orthographic "front" view to draw the profile of our wine glass. To do this, hit 'T' with the cursor int he view window. The window will change to show all four views (Top, Front, Side and Perspective). Move the cursor into the "Front" view and hit 'T' again. This will expand the "Front" view so it consumes the entire viewing area.

Frontview_1

With the cursor in the View area, hit TAB. From the menu that appears, select "Curve":

Curvemenu_1

(you can type "Curve" to help narrow down the selection - play a bit with these menus, they're really powerful). The nice thing about doing it this way is that Houdini automatically enters you into "Edit" mode on the Curve SOP, so you're essentially ready to edit.

Draw the left-hand profile of a wine glass in the orthographic front view, something like this:

Profile_1

Now move over to the SOP network editor, and add a Revolve SOP after the Curve SOP, play with its parameters, and set its display flag:

Revolved_1

Voila! A simple wine glass.

Finalwineglass_1

August 29, 2005

About Houdini Gems

Houdini Gems is a way for me to chronicle my adventures in learning to use the amazing software package called Houdini by Side Effects Software.

The adventure started for me in 1994, when as a University of Waterloo student I had a co-op job at Side Effects. I was one of these new punks that was learning this "C++" language, and I was extremely passionate about CG. Kim and Greg were kind kind (and brave) enough to take me on board and I became a part (a short part) of the Side Effects family. I had an opportunity to work with some of the most amazingly brilliant people I've ever worked with: Mark E, Mark M, Cristin, Dale, Ramin, Kim, Greg (and Lee!), and others. Some of you aren't there any more, but that group of people is forever burned into my memory.

We were working on the "next generation" of Prisms - Prisms 7, I think we called it at the time (or was it 6?). It, of course, eventually became Houdini and I'm extremely proud to have worked on it. I don't know if any of my code remains in the Side Effects source code repositories, but I remember working on several of the SOPs while I was there: The basic primitives (circle, grid, etc.), Twist, and an early version of the LSystems SOP (and whoever took that over, I apologize - it was at the end of my work term, and I was rushing to finish it).

Over the years I've often peeked into Side Effects to see what was going on. When they released the Apprentice Edition a few years back, I was elated. I downloaded it and played with it a bit, but never found (or made) the time to immerse myself.

Now, with the release of Houdini 8 in Beta, I've decided I'm going to make a concerted effort to really learn this amazing piece of software. This blog is going to be an attempt at chronicling the learning process. I'm hoping its useful enough that complete noobs (like me) can use it as a starting point to learn the software.