Oct 122012
 

PyQt4 UI Development for Maya

Just released my 3rd python-based online training video through cmiVFX.com

Introduction

This tutorial is about learning PyQt4 python bindings for the Qt Framework, and how to introduce new UI elements to Maya as a platform.
We discuss what comprises a “Framework” and a “GUI Framework”, and how Qt and PyQt4 work together.

 

Getting Started With PyQt4

There are multiple ways of getting a working installation of PyQt4, both for the general system and for Maya. We look into these approaches to get your system up and running to begin working with PyQt4!
We also talk about what is included, such as command line tools and applications, tips on how to test and learn the code, and how to structure a project.

 

PyQt4 Fundamentals

Lets get crackin’ and learn the basics!
• What is a QObject? What is a QWidget? Common PyQt4 classes are explained in detail
• Working with the Qt Designer application, to build a UI visually
• Layouts: Making widgets resize elegantly and stay organized in your design
• Coordinate space: How do widgets transform in your 2D screen space?
• QApplication and the Qt Event Loop: The engine that runs your UI
• Events, Signals, and Slots: How components communicate changes and how the application can respond to changes to make it dynamic

 

General Examples

With an understanding of the framework components, we can begin working with fully functional stand-alone examples.
• Common PyQt4 app template
• Subclassing Widgets: Creating custom functionality to the existing classes provided by PyQt4
• Dialogs: Raising dialog windows above existing windows, Modal vs Non-modal, and creating forms. We look at different ways to validate the data provided by the user, to these dialog forms.

 

PyQt4 And Maya Introduction

Finally, some Maya action! Maya has a slightly different approach to using PyQt4…
• How does the QApplication and event loop work?
• Common Maya PyQt4 app template
• Looking at the Maya API’s MQtUtil class
• The sip module: Helping us translate between Maya’s Qt and our own PyQt4 code

 

Replicating Maya’s UI Components

What better way to see examples of creating UI for Maya than to replicate some existing functionality? This gives us the opportunity expand with custom functionality
In this chapter we will take two different UI components in Maya, and do a basic custom version of our own, and show to how link them up to Maya’s own callbacks.
Some Features Of This Chapter Include
• The QTableWidget
• Model / View separation with QTreeView
• Docking windows into the Maya interface
• Mixing together PyQt4, the Maya API, Maya commands, and callbacks
• Sorting model data

 

Customizations

A button can be a button, and a slider might look alright in its stock form, but sometimes we want to customize the look of our widgets. This chapter introduces multiple ways of achieving custom looks to our components
• Stylin’ Stylesheets: Use CSS-like syntax for applying style sheets to widgets
• Painting By … Paint events: For even more control, we can tell a widget exactly how to draw itself on the screen. We will look at two different examples of how to use custom painting.

Previous cmiVFX tutorials:

Jun 212012
 
kinect-xl

A recent project of mine involves research and development with an XBOX 360 Kinect Sensor. Being a python guy, I started searching for python bindings to some OSX-supported framework. When you just get started looking into this area it can be a little confusing. There are a number of layers to the software stack to enable one to accomplish anything meaningful. This is just a short and general blog post outlining the basics of what I have discovered thus far, to help anyone else that might also be getting started.

At the lowest level, you need a driver. Something that can talk to the USB device that is the Kinect sensor. When you purchase the XBOX Kinect for Windows version of the sensor, and you are going to be developing on windows, much of this whole stack is provided to you by way of the Kinect SDK. But for the open source folks with the standard XBOX 360 sensor, you need to piece together your own solution.

Two drivers that I have discovered thus far:

I had started OpenKinect (libfreenect) because it comes with a python wrapper included. There were a few dependencies (I will talk about specific build steps in just a moment), but once I got this installed I was able to fire up the included  glview app and see both depth and rgb data streaming in from my sensor. The role of these drivers is to provide simply the basic streams. That is, the depth, rgb, audio, and a few other sensor data streams. If your goal is to start tracking players, seeing skeletons, and registering gestures, the drivers are not enough. You would be required to make your own solution from this raw data at this phase in the game.

You would now want to look into middleware that can take the raw data and provide to you an API with higher level information. This would include finding users in the scene for you, tracking their body features, and giving you various events to watch for as the data streams.

Being that my goal was to have python bindings, I found my options to be much more limited than if I were going to be developing in C++. Wrappers have to exist for the framework you want. This is where my research really started ramping up. I spent a few days dealing wtih compiling issues, as well as having an actual bad power adapter that had to be exchanged. But all said and done, here is what I have settled on thus far…

  1. Driver: PrimeSense Sensor
  2. OpenNI Framework
  3. NITE middleware for OpenNI
  4. PyOpenNI python bindings

Install Details

Install homebrew (package manager)

http://mxcl.github.com/homebrew/

Install build tools

Install python2.7

Suggestion: virtualenv Environment

This is not a requirement. But I recommend using virtualenv to set up an environment that specifically uses python2.7 so that you don’t have to fight with mixed dependencies and versions.

Create a virtualenv called “kinect”

Install libusb (patched version)

There is a special patched version of the libusb library, in the form of a homebrew formula.

Now copy platform/osx/homebrew/libusb-freenect.rb -> /usr/local/Library/Formula/

Install SensorKinect drivers

Then uncompress Bin/SensorKinect093-Bin-MacOSX-v*tar.bz2

Install OpenNI framework
  1. Go here: http://www.openni.org/Downloads/OpenNIModules.aspx
  2. Download Unstable Binary for MacOSX
  3. sudo ./install.sh
Install NITE middleware (for OpenNI)
  1. Go here: http://www.openni.org/Downloads/OpenNIModules.aspx
  2. Download Unstable MIDDLEWARE of NITE for OSX
  3. sudo ./install.sh
Install PyOpenNI

Be aware that on OSX, PyOpenNI requires a framework build of python 2.7+ and that you must build it for x86_64 specifically. Also, I was having major problems with cmake properly finding the python includes location. I had to suggest a fix, so please see here for the necessary corrections. I have referenced a patched fork of the repository below.

copy the lib/openni.so module to the python2.7 site-packages

Examples

Once you have everything installed, you can try out the examples that are included both in the NITE source location that you downloaded and also in the PyOpenNI source location:

  1. NITE/Samples
  2. PyOpenNI/examples
I also tried out ofxKinect (github.com/ofTheo/ofxKinect) on the side, which is an addon for  OpenFrameworks. This is kind of a separate path than the OpenNI stack. I would say its more like an advanced offering of libfreenect. Using the included example, I recorded a 3D point cloud that is built on the fly from the RGB and depth data:

 

Nov 202011
 

A question came up in the Maya-Python mailing list that I thought was a really good topic, and should be reposted.

Someone asked how you can create maya UI objects and embed them within your main PyQt application. Specifically he wanted to create a modelPanel and embed it so that he would have a camera view within his own PyQt window.

Here is my example of how to achieve this…

You need sip and the MQtUtil functions to convert between maya node paths and python Qbjects. Its the same idea as having to use those functions to get a reference to the maya MainWindow, in order to parent your dialog.

Nov 152011
 

Second video in the python for maya series, just released through cmiVFX!

Python For Maya – Volume 2

If you watched the first video, you now have a good grasp on Python. Sweet. Let’s plow through some more involved concepts like python juggernauts!

With a working knowledge of the python scripting language, and the Maya Python commands API, we can continue to learn new ways to solve more challenging problems, create complete scripts, and build user interfaces around our tools. We also introduce the Maya Python API; a lower-level interface into Maya.

This video focuses more on breaking down full scripts, as opposed to typing out syntax. Its jam packaged with information and moves fast to deliver you as much brain food as possible. The first segment of the video transitions from beginning to intermediate level, with the majority of the video being intermediate, and finishing out by touching on advanced concepts. The included project files are abundant, complete, and full of helpful documentation so that you can take your time and learn about each piece of the tools.

If you check it out, leave me feedback!
http://cmivfx.com/store/328-Python+For+Maya+Vol+02

First video can be found here

Nov 092011
 

This is a follow up post to my previous one on Installing PyQt4 for Maya 2011

Recently while putting together my next video tutorial for Python for Maya, I came to a section where I wanted to demo PyQt4 in Maya2012. But I was concerned that viewers would have to go through the complicated steps of building PyQt4. I noticed that other people have made available precompiled PyQt installers for windows (here) but I could not find any for OSX or linux. So I decided to put together a build.

I created a new project on github called MyQt4
https://github.com/justinfx/MyQt4

Its a Makefile for completely downloading and building PyQt4 for maya, and generating a .pkg installer. Hopefully someone can contribute improvements since I dont have a ton of experience writing makefiles, and also that someone might create a linux version.

Here is a link to the latest pkg build:

Snow Leopard: 

Lion:  

Mountain Lion:

Here are builds other people have made:

Oct 082011
 

Just released my first online video tutorial, through cmiVFX

Python Introduction Vol 01 – Maya

Amazing at Animation? Master of Modeling? Conquistador of Character Rigging?

But how is your Python?

This course brings the talented artist into the fold of the technical-side of Maya. Learn the basics of Python, and its place in your 3D workflow, with visual examples and real world problems. Get a kick-start on adding some automation into your life, and solving common problems in a fraction of the time. By the end of this video, you should have a deeper understanding of one of the languages Maya speaks under the hood, and how to start viewing your scenes in terms of glorious Python code!

Check it out: http://cmivfx.com/store/320-Python+Introduction+Vol+01+-+Maya

If you check out this course, please leave me some feedback! I would love to hear your thoughts.
Stay tuned for more installments to come!

Jan 072011
 

Update:

I am now hosting a built package for Maya2011: MyQt4.7.4-maya2011-x64-osx-10.6.pkg
And for Maya 2012+, see: Installing pyqt4 for maya2012


Personally, when trying to run PyQt from within Maya 2009/2010 using the pumpThread method, I never had much luck. The best I ever got was the ability to bring up a dialog but not without locking up the UI, even though the pumpThread tool is meant to address that.

Anyways, when I found out Maya 2011 was rewritten based on Qt for the UI, I was really stoked. I saw the example video of being able to design a ui file in Designer, and just directly open it in a maya script, and all I could think about was designing Qt GUIs so much more easily now. Turns out that Maya 2011 didn’t actually ship with PyQt included for licensing reasons I’m sure. But it included documentation on how one could go about building PyQt for maya. Unfortunately I had tons of issues that caused maya to just crash when importing PyQt.

What I finally figured out was a mish-mash of information from the maya documention, and different forums and user groups. So I decided to make this easier on anyone having the same problems as I did, and just collect that information into one place. This process is for OSX. I’m sure most of it is probably still relevant to linux or win, except for the last parts with ‘install_name_tool’. You would just need to make sure to find the right Qt/PyQt/SIP packages for your OS.

Building PyQt4 for Maya 2011 on OSX

Update for Maya 2012

While Maya uses newer versions, it seems the versions from the 2011 install still work. But here they are anyways incase you want the newer version for 2012:


Make sure you have downloaded and installed the latest XCode from Apple. Its also included on your OSX installation disc.

Qt: Maya has a specific version of Qt built into it. This is Qt 4.5.3.
  1. Download:  qt-mac-opensource-src-4.5.3.tar.gz
  2. Extract:
  3. Build and install:
SIP: The maya docs recommend sip version 4.10
  1. Download this specific SIP:   sip-4.10.tar.gz
  2. Extract:
  3. Build and install:
PyQt4: The maya docs suggest PyQt 4.7
  1. Download this specific PyQt: PyQt-mac-gpl-4.7.4.tar.gz
  2. Extract:
  3. Set up some environment variables before building:
  4. Build and install:
  5. PyQt4 will now be installed into Maya’s python site-packages, BUT will be linked against the wrong Qt binaries. The maya docs have an annoying multi step set of commands but they don’t copy/paste nicely, so here is a for-loop you can use:

At this point you should be able to start up Maya and import and run PyQt from the script editor. You no longer need the pumpThread. Here is a test code snippet that I borrowed from here (the original had typos in it that I corrected)

It doesn’t seem like you even need the install of Qt 4.5.3 that we did at this point since we changed the links, unless you use another Qt module besides QtCore, QtGui, QtSvg, QtXml, QtOpenGL (such as QtNetwork), but this could be solved by copying over the missing libs to where Maya is expecting them. Example for copying over QtNetwork:

If you happen to have a mixed library environment like me, with more than one python lib location for code, and you see any funny errors while importing a module, just make sure that mayas python site-package is always in the front of the sys.path:

And there you have it. PyQt4 now installed in Maya 2011 under OSX.


References:

Oct 082010
 
AtomSplitter

We finally decided to release the source code for AtomSplitter, since we were getting some feedback that the application builds weren’t 100% working on every possible system.

Project site:
http://redmine.justinfx.com/projects/atomsplitter

The current version is 1.6.2,  which adds the cmivfx chatroom to a tab, and some minor bug fixes. More info:
http://www.cmivfx.com/productpages/product.aspx?name=AtomSplitter_1.6

Update #1:

I have posted the AtomSplitter project on github now: https://github.com/justinfx/AtomSplitter

 

Aug 312010
 
AtomSplitter

 

AtomSplitter has been updated to v1.6, available through cmivfx.com

AtomSplitter 1.6 – cmiVFX.com

Updates:

  • Exports Terragen .tgd scene file format

See the original post.

Aug 092010
 
curvesExample-white

This is a story about my journey in solving a problem at work involving curves. The solution seemed really simple at first, but because of a stupid Maya issue, this turned into me having to rewrite the tool 3 times before I discovered a surprising solution.

The Problem:

Because we rely heavily on the process of importing Illustrator .ai files into Maya as nurbsCurves, we constantly have to deal with curves that intersect themselves. This is a result of the curves having been hand drawn originally in the art department, and they posed issues during rendering after being planar-ized.

We needed a way to detect self-intersecting nurbsCurves, so that we could fix them before working with them as nurbsSurfaces.

Loop Curves (self-intersection)

Getting started. I hate you, Maya:

The obvious place for me to start was to use the existing curveIntersect command. This command will tell you if two curves intersect, and at what points. Although it requires that you tell it 2 individual curves to test, I figured I could just split the single curve into parts (using detach curve), and pair off all the parts to test them. And here is where I ran into something that just pissed me off. While it works great to tell you where the intersection is… when it DOESN’T find an intersection, it prints a “Warning: Could not find curve-curve intersection” line. Printing to the script editor in maya is SUPER expensive as I have found. Everything slows down. This was the initial reason I decided not to use this method. I later found out the RIGHT hack way to deal with this is to wrap the entire process in scriptEditorInfo commands to suppress warnings being printed to the Script Editor and re-enable after. This method does prevent the amazing slowness, but still has the unacceptable flood of warnings once suppression is turned back off again. So even with this fix, I still found this approach to be too slow. For a single complex curve object that might have, say, 500 spans… that would be 124750 unique combinations that would have to be tested with the curveIntersect command. In a test of just looping that many times and calling this command, the process took 54 seconds! No way could this work, with a scene that could easily have 2000+ nurbsCurves!

Great. Now I get to investigate my own intersection detection from scratch.

Approach #2 – Brute Force

I’m a film school graduate… not a computer science major. Never thought I would have to use the kind of math I TRIED to implement for a first solution. Solving the cubic function of every curve segment to find the intersections? Meh. Too hard.

Next I thought of an idea to take a curve and sample N-amount of points from start to end parameter. So lets say 1000 samples. I would get 1000 points on the curve, then compare each point to the other non-neighboring points to see if they are within a distance tolerance of each other. If they are, I consider this a point in the curve where it looped and self-intersected. This method did work. It was still not super fast, but no where NEAR as slow as using the intersect command. I built in some dynamic scaling of the sampling and tolerance to accommodate for curves of different size and complexity.  Even though I had to test 499500 point combinations per nurbsCurve for the 1000 point samples, this was only math and not a repeat call to curveIntersect. Ultimately, I was still not where I needed to be in terms of usability. A complex curve could still be a few seconds to test. Still too slow.

Approach #2.5 – Brute Force mixed with a fast little pre-check

Amongst the tons of search results I waded through on google, I found a really cool little trick someone came up with: http://forums.cgsociety.org/archive/index.php/t-517347.html

He suggested a cool hack where you planar the surface, then convert it to polygon with certain options, and then count the number of resulting faces that were produced. Theoretically there should only be 1 face if the curve never intersected itself. If it did, those loops should also have faces.

Well then, why couldn’t I just use this method as my detection algorithm? While it was pretty darn fast since no iteration is involved, I discovered a few limited cases where I was getting False Negatives: The method said there was only one face (no intersection) on a curve that actually did have a self intersection. So I decided to use this as a pre-check to save time. If it DID say there was self-intersection, great! Log it. Otherwise, slow test it with the brute force method.

Approach #3 – Math that I never learned

At this point I had accepted the solution for detecting self-intersection, and moved on to writing a maya UI for the tool. It would detect loops and optionally even report back the best estimate to the point where it actually occurred. But once I started writing another bigger tool that would use this script, I just knew it could be done faster with the power of math and without the poop of maya script command calls.

Bezier Clipping Method

I discovered a paper written about a method called “Bezier Clipping” : Curve intersection using Bezier Clipping

For this method to be used on a single curve, one would first need to split the curve into its segments, in my case producing a bunch of cubic curves. With each pair of combinations, a bounding box check would be performed. If the bounding boxes do not overlap, you are done. No intersection would have occurred. If the bounding boxes did overlap, then you would start drilling down the check by clipping away sections of the curves outside the bounding box overlap. You can discover the intersection pretty fast by either drilling down until the segments are small enough to represent the single point, or the segments are now small enough to be considered linear and a you can use the slopes to find the intersection.

I was really stoked by this idea. The paper made it look really straight forward. I ended up writing a really cool custom wrapper around a nurbsCurve object that could represent a sub-section of the curve, and could easily give me things like the length and parameter range. It had a split() method that could split the curve at a given length or parameter and give me back two sub-curves, of which each could further be split. This class was integrated into the Bezier Clipping method and I finally got it all working. The initial tests were amazingly fast, but I ended up finding that the process became quite slow on large numbers of complex curves. I attribute this to my implementation of the bezier clipping, not the method itself. I didn’t take the time to actually generate proper sub-segments based on the bounding box overlap, and instead just did a simple 50/50 split of each curve, and tested the new combinations. I think I was just so bummed about the performance results that I didn’t feel like making the improvements to the process would make enough of a difference. What I had now was ultimately slower than my brute force method when tested against an entire scene of curves. So I decided to just go back to that.

Approach #4 – The unexpected trick

Whilst working on the larger project meant to make use of the loop detection script, I discovered something amongst the curve commands. offsetCurve includes the function of clipping away loops while creating the new offset curve object. My idea was to create an offsetCurve with the minimal changes, at a zero distance, so the curves would be right on top of each other. Then I could just compare the area/length/etc attributes of the curves to see if there was a change. This was really fast and really accurate, down to the smallest loops. Right now I’m comparing the area and length values rounded to a certain tolerance. This method was amazingly fast, and a fraction of the code.

The only minor downside was I found that because of the rounding I needed to do to compare the values, every so often a couple curves would be found as self-intersecting when they were not. Thats much better than MISSING curves during the detection. So what I did was combine the earlier face-counting solution with this one, to fail over between the two. The combination was really fast and accurate, without 100,000 warnings showing up in the stupid script editor.

All in all

I’m really surprised how many versions of this tool I had to write, to ultimately end up at a really simple one. I never would have thought to look at this offsetCurve command for a solution. Had to dig into some math I never thought I would use, also. So THATS what those stupid polynomial equations were for?