Monthly Archives: September 2011

Use Partial To Query UI Control

from functools import partial

def foo(a, arg=None):
print ‘first’,a
print ‘2nd’,arg
b= partial(foo, ‘default’)
#first default
#2nd None
#first default
#2nd addon
#<functools.partial object at 0x74c60>

Partial is a way to pack a func with a preset argument.  In the example above, calling b() has the same effect of calling foo(‘default’), and calling b(‘addon’) equals foo(‘default’, ‘addon’). This is quite useful when you want to query values from UI controls in Maya. For example:

import maya.cmds as cmds
from functools import partial
def foo(inst=None, arg=None):
retrieved = cmds.floatSliderGrp(inst.aSlider, query=True, value=True)
# omitted do something with retrieved

class Bar(object):
def __init__(self):
# omitted ui setup
self.aSlider = cmds.floatSliderGrp( label=’foo value’, v=0.5, min=0, max=1, cc=partial(foo, self) )
# omitted ui setup

So aSlider is a slider control as a member of Bar, with its change command assigned to function foo(). Need to expose the control to foo(), so the value can be queried for use. Since cc flag must be assigned to a function object, cc = foo(self) cannot work. Partial packed foo(self) into an object and solved this problem.

Leave a comment

Filed under Maya API, Python

PyQt Draggable Tree

This is a minimal test about how to do drap-and-drop within a QTreeWidget.

First let the tree setAcceptDrops. Then declare mouseMoveEvent, dropEvent, dragEnterEvent, and let dragMoveEvent = dragEnterEvent. The rest is to set mimeData, by which the information can be transferred between those events. Here only a string, name of the item, will be sent.

Click LMB on an item, drag-and-drop onto another, a new item will be created and attached to the latter. The drop event must hit an item.


Leave a comment

Filed under Python, Qt

CUDA Image Compaction

Left: import image; Middle: compacted non-black pixels before sort; Right: compacted pixels sorted by descending luminance values.

This is a test performing stream compaction using CUDA. Stream Compaction is the process to locate sparsely and randomly populated useful elements within a large data stream, then relocate them into a tightly packed and better order.

The process can be described by a few steps:

1. Divide all elements into a number of groups. For each group, count the valid elements inside it.

2. Perform prefix sum (scan all groups) to find out start location of each group in the compacted data.

3. For each group, deduce the location of each valid element inside it, then relocate.

4. Sort the packed valid elements if necessary.

Each step is processed by a different CUDA kernel. For example:

__global__ void
 count_valid_elements(uchar4 *color, uint *num_valid, uint group_size)
 uint pos = blockIdx.x * blockDim.x + threadIdx.x;
 uint count = 0;
 for(uint i = 0; i < group_size; i++)
 uint pix_loc = pos * group_size + i;
 if(color[pix_loc].w > some_threshold)
 num_valid[pos] = count;

This kernel is launch per-group, and counting is done sequentially. No shared memory is involved. Another example:

__global__ void
 relocate(uint *prefix_sum, uchar4 *color, uchar4 *data, uint group_size)
 uint pos = blockIdx.x * blockDim.x + threadIdx.x;
 uint offset = prefix_sum[pos];
 for(uint i = 0; i < group_size; i++)
 uint pix_loc = pos * group_size + i;
 if(color[pix_loc].w > some_threshold)
 data[offset] = color[pix_loc];

In the relocate kernel, each group already knows where it should start in the result data, so simply add up the offset for each valid element and write the memory. Collision (different threads write to the same location) will not happen.

Here I use luminance value of the pixel to decide if the element is valid. Pixels too dark will be eliminated, and the rest will be packed. If most pixels are valid, you can still see parts from the original image before sort.

Again, luminance value is used as the key of sort. To find out how many valid elements need to be sort is a bit tricky. The clue is offered by the last group. Add last valid count and last prefix sum, and you have the number of valid elements. Device memory access is provided by Thrust:

uint num_valid_element = scanPtr[num_group-1] + countPtr[num_group-1];

Those mostly dark images will be heavily reduced and packed.

So through all those difficulties, you have reduced a few beautiful images from HST into a mush of meaningless dots, what’s the point? Well, stream compaction is essential to many more interesting applications. You can use it to reduce irrelevant elements, say particles outside view frustum, so expensive calculation will be wasted on them. It is also useful to mesh subdivision/tessellation, collision detection, hierarchical data construction.  A few hints here.

Leave a comment

Filed under CUDA

Take A Snapshot In Maya

// keep the old format
int    $format    =    `getAttr "defaultRenderGlobals.imageFormat"`;
// set to render to .png image
setAttr    "defaultRenderGlobals.imageFormat" 32;
// playblast one frame to a specific file
playblast    -frame 1    -format    "image"    -cf    "D:/foo.png" -v 0    -wh    240    175    -p 100;
// restore the old format
setAttr    "defaultRenderGlobals.imageFormat" $format;

Above is a chunk of MEL will take a snapshot of what’s inside active view port and save to a .png image file to disk. Could be useful when you want to save a thumbnail of the scene.

Leave a comment

Filed under MEL

Module And Resources

Suppose you have a file named like above, and someone want to use it as a module in his/her program, like:

The problem is the above file only works when started from the same folder where is saved. The module file should be put away into sys.path, so Python can find and import the module no matter where the program is started. Typically module files go to C:\Python26\Lib\site-packages

To test if it works, lauch Python command line, try:

import iconLabel

Another problem is those icon images, circle and square, are lost. Relative file path like:

image= QtGui.QPixmap('./circle.png')

only works when the file is started from the same path where the images are saved. Using absolute path:

image = QtGui.QPixmap('D:/somewhere/circle.png')

still cannot work because everyone to use the module should have a copy of those images in the same path.

Resources will be the solution. Save a .qrc file, iconLabel.qrc:

<!DOCTYPE RCC><RCC version="1.0">

Run command:

pyrcc4 iconLabel.qrc -o

Will create a module file,, contains those images. Inside

import iconLabel_rc

and change all file path to start with ‘:’, i.e.

desc.image_path = ':circle.png'

Run the module file again, Python will create binary code for both iconLabel and iconLabel_rc. Copy both .pyc files to sys.path, and this module is ready to go. You can remove from sys.path, just use the .pyc files. This will be helpful in case you don’t want to give up your source code.

For more details about Qt resources, go here.

Leave a comment

Filed under Python, Qt