Showing posts with label Python. Show all posts
Showing posts with label Python. Show all posts

Thursday, 14 March 2013

Maya Python API and my Custom Deformer Node

Its been an interesting couple of weeks.
For some time now I've been reading up on the Maya API (this is how plug-ins are made for Maya), but never delving right in because it looked so daunting. Why? Well, learning the API and yet another language (C++) at the same time seemed just too much to take in.

Thankfully, it turns out that there are two Maya APIs, one in C++ (the original), and the other in Python (not to be confused with Python scripting in Maya, which is what I have been doing up until this point).

The main differences between the two is that C++ plugins run much faster than python plugins. However Python plugins don't need to be re-compiled for the many different versions of Maya on different operating systems; and as I'm more fammilliar with Python code is also much easier to read.

So what I have been working on is a custom deformer node with the Python API. I've called it ecs_Displace (prefixed with my initials), and what it does is it displaces geometry based off of a texture. In much the same way as using a displacement map at render time, this will deform the geometry directly, with visible results in the Maya viewport.
It can take any kind of image, including animated procedural textures, both 2D and 3D.
It can even be used to create simple bulging effects without a texture plugged in, using weight painting to isolate the effect.
Here is a demo.



Supports 2D and 3D Textures - Including projected 2D textures. Textures can be layered and animated to build up different effects.

Supports Vector Displacement Maps - Works in both Object Space and Tangent Space to create deformations that can overlap.

Smart Sampling Feature - To increase the performance, rather than re-sampling the textures every time the deformer needs to re-evaluate, it can optionally store and remember that sampled data; only re-sampling when the texture is changed. It can be switched off entirely, and forced to always sample.

Capping Options - Provides a simple way to limit the amount that the geometry can be displaced, by capping the values at the desired threshold.

Supports Multiple Objects - One deformer can be applied to multiple meshes.

Supports Deformer Membership - Limits the number of vertices to run the calculations on.

Supports Weight Painting - Smoothly paint the influence of displacement over the mesh.


Of course, I'm not the first person to do this though, as there are a couple of other plug-ins that do the same basic thing; iDisplace, SOuP (specificity the peak node, although not quite a simple to setup) and L3Deformer(which isn't free). In all these cases, they are C++ plug-ins, so they are much faster, but the code is inaccessible as they are compiled, and they do not provide the source code. Which of course means that if you need a specific compiled version and they don't have it, then your're a bit stuck.

Anyway, after spending the time to recreate this kind of deformer, I am very happy with what I have learnt, and maybe eventually, when I've had more experience with the API, I will attempt to convert my deformer to C++... and then multi-thread it! OK, I'm getting a bit ahead of myself!

Meanwhile, on the Scripting side of things, I am in the process of creating a base template UI for all my custom tools. Kind of like how all of the tools in Maya follow the same basic template, which is basicaly just a box with widgets in that is not dock-able, can be scaled to sizes that don't even fit the widgets, and can only have one tool open at a time! Mine will be better ;)
But more on that another day.

A Flock of Pixels

Tuesday, 5 February 2013

Python in Maya


So this is the first post for 2013 and it's been around 4 months since the last post. So what have I been up to in that time? Learning Python! ...and how to use it in Maya.
Here is a very short demo of a python script that I was working on this morning.


So what you have just seen are a bunch of hair follicles being made all over the mesh, based on the positions of the locators around it. The locators don't have to be sitting on the mesh as it  works out the nearest point. We can then use the follicles to stick things to a deforming mesh.

One thing to be aware of is that the mesh should be UV mapped first as changing the UVs later on will shift all the follicles around, but apart from that, it's a fairly decent alternative to the Rivet script by Michael Bazhutkin.

So apart from allowing you to stick objects to meshes, this is also handy if you are rigging a ribbon spine. No more second guessing the UV parameters in the follicle settings!

The script also works in a very clean way by not making any unnecessary nodes; So rather than making an entire hair system, which would then be deleted; the follicles are created with the following command.

// Mel
createNode "follicle" ;

# Python
createNode("follcile")

It is also worth noting that you can also create the node with this command too.

// Mel
shadingNode -asUtility "follicle" ;

# Python
shadingNode("follicle", asUtility=True)

The only difference is that specifying it as a shading node utility, makes the node visible in the hypershade utilities section. In fact, you can do either of these for any node in Maya, as long as you get the name right.

Now at this point you still then need to connect several attributes from the mesh to the follicles, and then work out the UV coordinates for the position you want, as hair follicles are positioned based on UVs.

The closest point can be calculated with some other nodes. There is the 'closestPointOnMesh' node (for polygons) or the 'closestPointOnSurface' node (for nurbs surfaces). The cool thing about using these nodes are that once you make the connections and keep it there, what you will get is a follicle that can slide around the surface, following the locator.


I'm sure there are plenty of interesting effects that could be made with this technique. You could combine this with a dynamic spring and maybe create a car with suspension driving along a bumpy road, or a boat on the ocean.

I've made several other little helpful scripts as I've been learning Python, which I might be showing over the next few weeks.

Although writing it in Python was fun to do, I wont be making this script downloadable as there is already a Mel equivalent on Creative Crash, which works in almost exactly the same way, but by the looks of things goes another step further and constrains the objects to the follicles too. You can find that here.


I think that is enough for today. Until next time!
Oh, maybe just one more thing. I made this spine rig entirely in Mel. This was before I started using Python.


A Flock of Pixels.