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…

from PyQt4 import QtCore, QtGui

import maya.cmds as cmds
import maya.OpenMayaUI as mui

import sip

global app


class MyDialog(QtGui.QDialog):

    def __init__(self, parent, **kwargs):
        super(MyDialog, self).__init__(parent, **kwargs)
        
        self.setObjectName("MyWindow")
        self.resize(800, 600)
        self.setWindowTitle("PyQt ModelPanel Test")

        self.verticalLayout = QtGui.QVBoxLayout(self)
        # need to set a name so it can be referenced by maya node path
        self.verticalLayout.setObjectName("mainLayout")
        # First use SIP to unwrap the layout into a pointer
        # Then get the full path to the UI in maya as a string
        layout = mui.MQtUtil.fullName(long(sip.unwrapinstance(self.verticalLayout)))
        cmds.setParent(layout)

        self._cameraName = cmds.camera()[0]
        nodeName = cmds.modelPanel(cam=self._cameraName)
        # Find a pointer to the modelPanel that we just created
        ptr = mui.MQtUtil.findControl(nodeName)
        # Wrap the pointer into a python QObject
        self.modelPanel = sip.wrapinstance(long(ptr), QtCore.QObject)

        # add our QObject reference to the modelPanel to our layout
        self.verticalLayout.addWidget(self.modelPanel)

    def show(self):
        super(MyDialog, self).show()
        # maya can lag in how it repaints UI. Force it to repaint
        # when we show the window.
        self.modelPanel.repaint()
                    

def show():
    global app
    # use a shared instance of QApplication
    app = QtGui.QApplication.instance()

    # get a pointer to the maya main window
    ptr = mui.MQtUtil.mainWindow()
    # use sip to wrap the pointer into a QObject
    win = sip.wrapinstance(long(ptr), QtCore.QObject)
    d = MyDialog(win)
    d.show()

    return d

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.

 

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/tutorials/view/328/Python+For+Maya+Vol+02

First video can be found here

 

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:  MyQt4.8.6-maya2012-x64-osx-10.6.pkg

Lion:  MyQt4.8.6-maya2012-x64-osx-10.7.pkg   (Thanks Chris!)

Here are builds other people have made:

 

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/tutorials/view/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!

 
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.

COMMAND LINE HELP

OSX:
AtomSplitter.app/Contents/MacOS/AtomSplitter <chan file> [out file]

Linux:
AtomSplitter <chan file> [out file]

Windows:
AtomSplitter.exe <chan file> [out file]

=========================================

HELP:
>>> AtomSplitter -h

Usage: AtomSplitter <chan file> [out file]

Options:
-h, --help
        show this help message and exit
-o OBJ, --obj=OBJ
        Optional nuke-exported pointCloud .obj file
-f FPS, --fps=FPS
        Set FPS rate (default 24)
-x WIDTH, --width=WIDTH
        Set frame width (default 2048)
-y HEIGHT, --height=HEIGHT
        Set frame height (default 1556)
--filmwidth=FILMWIDTH
        Set film aperature width in mm (default 24.576)
--filmheight=FILMHEIGHT
        Set film aperature height in mm (default 18.672)
-s SCALE, --scale=SCALE
        Scale the translation values by this amount
-F FORMAT, --format=FORMAT
        Output format (fbx, action, terragen)
 
AtomSplitter

 

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

AtomSplitter 1.5 – cmiVFX.com

Updates:

  • Added the ability to convert point cloud data, exported from Nuke as a .obj, to be included in the fbx/action export.

See the original post.

 
AtomSplitter

 

AtomSplitter (chanToFbx) has been updated to v1.2, available through cmivfx.com

AtomSplitter 1.2 – cmiVFX.com

Updates:

  • Camera rotation order set to ZXY, which is the Nuke camera default
  • Fixed a bug where the FocalLength value was not being keyframed properly
  • Added a scene scale field, for adjusting the translation values globally.

If you haven’t visited cmiVFX.com before, PLEASE check them out. Chris Maynard does an amazing job rounding up top talent in the industry to create these outstanding visual fx tutorials. The information is always cutting edge.

See the original post.

 
taskMonster2

I get to do a lot of interesting applications at SouthPark. This one in particular was the most challenging use of PyQt that I have experienced to date.

The backstory….
The art department wanted a tool to help them track assigned tasks, the progress, and to share media and notes associated with the tasks. Furthermore, they wanted to be able to skin the interface with custom graphics to make it their own.

Progress…
During the winter break (about a month) I was able to come up with version 1.0 of TaskMonster. It was written in python, using PyQt for the UI, sqlalchemy to talk to the database, and twisted for the client/server communication. Each client app sends messages to a small server daemon which in turn tells the rest of the clients about the updates.

Version 2.0 Alpha…
Tony Postma, from the art department, put together a design in Corel which I could hopefully implement in the UI.  It called for the users to be represented as little pods in a circle around the supervisor, Adrien Beard. And each user pod could be clicked and rotated into place, in order to view that persons tasks.
After a bunch of testing I was able to design a rotating widget that could dynamically lay out N widgets around it in a circle, track their position, and jump to any other widget. I was also able to break down the corel->illustrator file, into a combination of SVG and PNG images, and skin the UI via CSS stylesheets.
Its currently an alpha release. I guess I need to really learn how to control the widget painting, to make it faster. Never had to do this much before.

What I came up with…        Click here to watch the demo video

 

You know when you have all these widgets laid out in your class, and you are hooking up all the connections, and you say “Aw dammit I have to subclass QLabel now just so make it ignore blahEvent”? You end up with all these little widget subclasses, where all they are doing is ignoring an event.

I noticed I was doing this a few times, in more than one of my classes, and finally got annoyed for the last time. I figured there had to be a simple way of just overloading the method on the normal object when I create an instance. Fortunately python considers everything objects and pretty much anything can be changed. So I did this:

myLabel = QLabel()
myLabel.mousePressEvent = lambda event: event.ignore()

Magic.

I have also had to make clickable widgets, such as QLabel:

myLabel = QLabel()
myLabel.mousePressEvent = lambda event: myLabel.emit(SIGNAL("clicked"))

Or if you had to do more than just a single statement:

myLabel = QLabel()
def clickedEvent(event):
    myLabel.emit(SIGNAL("clicked"))
    # do other stuff
        # do stuff
    event.accept()
myLabel.mousePressEvent = clickedEvent

I like this better than piling up subclasses that don’t do much.

 

I had a project where I was designing a statistics reporting site, to track production stats. I wanted to have really nice graphs that pulled from the database and were somewhat live and interactive. XML/SWF Charts is this awesome flash-based app that lets you embed graphs in your pages which receive their data from XML. There are tons of graph types and ways to customize the look.

http://www.maani.us/xml_charts/index.php

So, the thing is… I wanted to use Django for the site. I decided to write a python module that wraps around the API for SWF charts, so that the XML could easily be generated for me after just setting all my parameters. Thought I might post this here for any python fans wanting nice looking graphs in their site.

Really, this doesn’t just apply to django. You could just call out from anything to python code that will generate your XML for you.

Example:

chart = SwfChart()

# the data
chart.addRow( 'Person A', 1, 10, 5.5 )
chart.addRow( 'Person B', 6, 4.45, 8 )
chart.addColumnLabel( 'Day1', 'Day2', 'Day3' )

# Extra graph settings
chart.addFilter('shadow', 'low', distance=2, angle=45, alpha=35, blurX=5, blurY=5)
chart.addFilter('shadow', 'high', distance=3, angle=45, alpha=35, blurX=10, blurY=10)
chart.addFilter('bevel', 'bevel1', strength=10, quality=3, distance=2)
chart.setChartBorder(top=1, bottom=2, left=0, right=0, color='000000')
chart.setChartLabel(color='000000', alpha=80, size=8, position='outside', hide_zero=True)
chart.setChartTransition(type='scale', delay=.5, duration=.5, order='series')
chart.setChartRect(shadow='high')
chart.setLegend(size=12, alpha=90, fill_alpha=30)
chart.setAxisTicks(category_ticks=True, value_ticks=True, minor_count=3)
chart.setContextMenu(about=False)

# if you have the licensed version
chart.setLicense('license string')

Now at this point, the object can be treated like a string to get the xml, or just call getXML() :

print chart

print chart.getXML()   # same thing

xml = str(chart)   # or assign the XML string somewhere

You can download the swfcharts.py module and use it freely. If you find it helpful, post a comment or shoot me an email.

Download swfcharts.py

Pydoc located here for convenience:
swfcharts python documentation

© 2011 Justin Israel | justinfx.comSuffusion theme by Sayontan Sinha