Planet Tech Art
Last update: February 05, 2016 09:00 PM
February 03, 2016


The latest Patreon contributors:

Aron Durkin
Sreemanendu Bhatta

Thanks guys! I appreciate the support.

by Morgan Loomis at February 03, 2016 09:53 AM

February 01, 2016

January 31, 2016

New Tool: ml_toolbox

Courtesy of my Patreon supporters, I’ve uploaded the first tool of 2016, ml_toolbox!

ml_toolbox is a utility for organizing scripts in maya. It came about from having a very crowded scripts directory, with no good way to organize or group scripts on disk and also have them easily accessible in maya. I like shelves, but they take some setting up, and can get crowded. The idea with this is that you organize your scripts into folders, and then those folders are used to generate menus in maya.

To try it out, if you download, you’ll get the script and the required root folder (ml_toolbox_menu). It comes with a few example scripts which are organized in maya’s default folders already. Extract the script and folder to your scripts directory, and run import ml_toolbox;ml_toolbox.main(), and you’ll see the scripts in the folders show up in maya’s menus (File, Create, etc.). They’re prefixed with a * for quick identification.

From there, just create new folders and add your own scripts to them. If you want to get rid of a menu, just move it or delete it. If a folder matches an existing Maya menu name, the tools will be added to that menu, if it doesn’t, a new menu will be created. The only requirement for the scripts is for mel files the name of the procedure needs to be the same as the name of the file (which is generally the case), and for python scripts the primary function should be called main() or ui(). See the header of the script for more info on advanced use, or I can go into more detail if people would like. All the scripts on this site should work fine with it.

Version: 2
31.5 KiB

Create custom menus in Maya's main menu bar for organizing scripts, just by putting them into directories. Insert tools into the existing maya menus, or easily add entirely new menus.

Platforms:Windows 8
Category:Animation Scripts
Date:1 February, 2016

And last, I have to mention that I’m writing this an hour before midnight on the last day of January, and so I know I definitely would have shirked this deadline without the Patreon supporters, so I can say that the experiment is working so far. Thank you guys! Time to start thinking about next months tool…

by Morgan Loomis at January 31, 2016 10:02 AM

January 30, 2016

Anger is my muse

Last week, a coworker asked me to start blogging again. It’s hard to find material to blog about when things are going well and you’re so excited to do work, though!

It is for me at least. Anger is my muse.

I find it really difficult to stop having fun doing and start writing about doing. When I’m angry about something, writing helps collect my thoughts and discuss the ideas with others. Writing is a way of doing.

So, let’s see if I can muster up enough anger to start blogging again? I’ll dig up some skeletons from my past, and see if I can write about all the great stuff we’re doing at Cozy.

by Rob Galanakis at January 30, 2016 06:49 AM

5 years.  Man, it goes so fast.  It’s amazing to think where I...

5 years.  Man, it goes so fast.  It’s amazing to think where I was in my life when I started this blog.  I hope I can get back to posting some more, haven’t had much time lately, but I’m working on it.  Been playing with the 3d printer quite a bit though.  Really enjoying it.  It’s a nice mix of the science and art.  I find I’m able to flex both of my brain muscles.  Hopefully on the 10 year post, I will have a lot more words on the page.  Until then!

by at January 30, 2016 05:56 AM

January 29, 2016

First module of the year!

It's been a busy few months at work, and the blogging has been pretty light. But I promised some folks on the slack that I'd share some code for dealing with Mays's ShaderFX system: a very useful toolkit but not the best documented or automatable part of Maya. Since it's New Years' Resolution time, I thought I'd kill two birds with one stone and put up some notes to go with the code
All of shaderfx in maya is organized by a single, undocumented command. Which is pretty lame.
However, it’s not as bad as it seems once you figure out the standard command form, which is always some variant of this form:
    shaderfx -sfxnode <shader node> -command <command> <node id>
The sfxnode argument tells maya which sfx shader to work on. The command flag indiciates an action and the node id specifies an node in the network. Nodes are assigned an id in order of creation, with the firstnode after the root ordinarily being number 2 and so on – however the ids are not recycled so a network which has been edited extensively can have what look like random ids and there is no guarantee that the nodes will form a neat, continuous order.
Many commands take additional arguments as well. Those extra always follow the main command; thus
    shaderfx -n "StingrayPBS1" -edit_int 19 "uiorder" 1;
sets the value of the uiorder field on node 19 to a value of 1.
The shaderfx command can also return a value: to query the uiorder field in the example above you’d issue

    shaderfx -n "StingrayPBS1" -getPropertyValue 19 "uiorder";
// Result: 1 //

So, the good news is that the shaderfx command is actually pretty capable: so far, at least, I have not found anything I really needed to do that the command did not support. For some reason the help documentation on the mel command is pretty sparse but the python version of the help text is actually quite verbose and useful.
Still, it’s kind of a wonky API: a single command for everything, and no way to really reason over a network as a whole. Worse, the different types of nodes are identified only by cryptic (and undocumented) numeric codes: for example a Cosine node is 20205 – but the only way to find that out is to use the getNodeTypeByClassName command (and, by the way, the node type names are case and space sensitive).

Cleanup crew

With all that baggage I was pretty discouraged about actually getting any work done using shaderfx programmatically. However a little poking around produced what I hope is a somewhat more logical API, which I’m sharing on github.
The sfx module is a plain python module - you can drop it into whatever location you use to story your Maya python scripts. It exposes two main classes:
SFXNetwork represents a single shader network – it is a wrapper around the Maya shader ball. The SFXNetwork contains an indexed list of all the nodes in the network and also exposes methods for adding, deleting, finding and connecting the nodes in the network.
SFXNode represets a single node inside the network. It exposes the properties of the node so they can be accessed and edited using python dot-style syntax.
The module also includes to submodules, sfxnodes and pbsnodes. These make it easier to work with the zillions of custom node ids: Instead of remembering that a Cosine node is type 20205, you reference sfxnodes.Cosine. I’ll be using the StingrayPBSNetwork class and the pbsnodes submodule in my examples, since most of my actual use-case involves the Stingray PBS shader. The syntax and usage, however, are the same for the vanilla SFXNetwork and sfxnodes – only the array of node types and their properties.
Here’s a bit of the basic network functionality.

Create a network

To create a new shaderfx network, use the create classmethod:
from sfx import StingrayPBSNetwork
import sfx.pbsnodes as pbsnodes

network = StingrayPBSNetwork.create('new_shader')
That creates a new shaderball (note that it won’t be connected to a shadingEngine by default – that’s up to you).

Listing nodes

An SFXNetwork contains a dictionary of id and nodes in the field nodes. This represents all of the graph nodes in the network. Note I’ve used a different shader than the default one in this example to make things easier to read.
print network.nodes
# { 1 : <sfxNode UnlitBase (1)>, 2: <sfxNode 'MaterialVariable' (2)> }

print network.nodes[2]:
# <sfxNode 'MaterialVariable' (2)>
The keys of the dictionary are the node ids. As already noted, these are not guaranteed to be in a continuous order depending on what you do to the network - however they are stable and they will always match the id numbers shown in the shaderfx ui when you activate the show node IDs toggle in the ShaderFX window.
The values of the node dictionary are SFXNode objects.

Adding new nodes

To add a node to the network use its add() method and pass a class from either the sfxnodes or pbsnodes submodule to indicate the type.
if_node = network.add(pbsnodes.If)
# creates an If node and adds it to the network

var_node = network.add(pbsnodes.MaterialVariable)
# creates a MaterialVariable node and adds it to the network

Connecting nodes

Connecting nodes in shaderfx requires specifying the source node the source plug, the target node and the target plug. Unforunately the plugs are indentifited by zero-based index numbers: the only way to know them by default is to count the slots in the actual shaderfx UI. Output plugs are usually (not always) going to be index zero but the target plugs can be all over the map.
To make this cleaner, each SFXNode object exposes two fields called inputs and outputs, which have named members for the available plugs. So to connect the ‘result’ output of the var_node object to the input named ‘B’ on the if_node:
network.connect(var_node.outputs.result, if_node.inputs.b)
If the connection can’t be made for some reason, a MayaCommandError will be raised.
It’s common to have to ‘swizzle’ the connections: to connect the x and z channels of a 3-pronged output to channels of an input, for example. Mismatched swizzles are a common cause of those MayaCommandErrores. You can set the swizzle along with the connection by passing the swizzle you need as a string
network.connect(var_node.outputs.result, if_node.inputs.b, 'z')
# connects the 'x' output of var_node to the b channel of the input

Setting node properties

Nodes often have editable properties. There are a lot of different ones so it is often necessary to inspect a node and find out what properties it has and what type of values those properties accept. Every SFXNode object has a read-only member properties, which is a dictionary of names and property types. Using the same example objects as above:
### BLah blah example here
If you know that a property exists on an object you can query it or set it using typical python dot syntax:
node =[5] 
# get the node at index 5 in this network

# { 'min': 'float', 'max': 'float', 'method': 'stringlist' }

print node.min
# 1.0
# getting a named property returns its value.

node.min = 2.0
# sets the node value

print node.min
# 2.0
If you try to access a property that doesnt exist, an error will be raised:
print node.i_dont_exist
# AttributeError: no attribute named i_dont_exist

node.i_dont_exist = 99
# MayaCommandError

Help wanted!

So, there’s the basics. This module is pretty simople but I’ve found it extremely helpful in workign with SFX nodes. It will be much easier to work with, of course, if you already know your way around ShaderFX. Please let me know how it works for you – and as always bug reports and pull requests are very welcome!

by Steve Theodore ( at January 29, 2016 08:58 AM

Some fixups for sfx

I've posted a couple of fixes to the code for the shaderfx module I posted a little while ago.  +Sophie Brennan spotted a problem with the way that module handled some kinds of nodes -- which I had assumed were just plain old objects but which were in fact buttoned-up group nodes.  Since they didn't use the same method to report their outputs as the rest of shaderfx they could not easily be created or connected using the module.

Luckily  +Kees Rijnen, the main author of shaderfx, noticed the blog post and helpfully  pointed me at the source of the problem which I've included in a fix.

If you are using the original version of the code this may be a breaking change.  To unify the way that individual nodes and groups are connected,  I changed the connect() and disconnect() methods to take only two arguments where they previously took 4.  In the first pass you would write

network.connect( node1,, node2, node2.inputs.rgb)

which was needlessly wordy.  So connect() and disconnect() now sport the cleaner, simpler syntax

network.connect(,   node2.inputs.rgb)

As always, comments and pulls are encouraged!

by Steve Theodore ( at January 29, 2016 08:52 AM

January 21, 2016

Rigging Dojo Python 101 Course Trailer

Rigging Dojo Mentor, Ryan Griffin, leads you through python scripting in Maya in our Python 101 course. Ryan developed a tool set in python to handle the rigging of wide range of 100+ characters, including cinematic quality characters as. for Skylander Super Chargers, and it is the inspiration for the course project. During the 8 […]

The post Rigging Dojo Python 101 Course Trailer appeared first on Rigging Dojo.

by Rigging Dojo at January 21, 2016 03:20 AM