Showing posts with label Maya. Show all posts
Showing posts with label Maya. 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.

Sunday, 30 September 2012

Maya - outMesh inMesh


So I'm back again with the second part to my previous post, which you can see here. I will point out now that while all this stuff may already be findable on the internet, you kind of need to know what you are looking for. It is also worth noting that this is probably only going to be relevant to the intermediate/advanced Maya user.

So, this post is a compilation of examples, tips and techniques on how to use two very powerful attributes in Maya - outMesh and inMesh.


outMesh and inMesh

- What is outMesh and inMesh

So lets start with something simple. Whenever you create a polygon primitive with history, you are actually creating three nodes; the shape node, the transform node and also the creation node. The creation node is the node that contains all the initial settings for that primitive, such as radius and subdivision width etc, and its output is plugged into the inMesh attribute of the shape node.

All polygon shape nodes have an inMesh attribute, but also an outMesh attribute. It is possible to take the outMesh of one polygon shape and plug it into the inMesh of another shape.
This connection simply allows for one shape to use the mesh of another shape as its source, creating an exact duplicate. Because they are connected, any changes made to the source mesh, will cause the destination mesh to update. Now this might sound like it is doing a similar job to what 'duplicate instancing' does in Maya, however there is one very important difference.
Take a look at this short video.



 - What about instances

Now 'duplicate instancing' is a nice idea in Maya but is almost completely useless in a production environment. Essentially it works by duplicating the transform node only, and making them all share the same shape node. So they all share the same mesh, the same UVs, and unfortunately the same shader and the same render stats, making it a pain to work with when rendering. The only other real benefit of Maya's duplicate instance is that it keeps the file size down. Here's an example to show what I mean.

You might have, lets say, a model of a crate (or maybe a couple), and you want to duplicate them a hundred times to create a space filled with crates. To randomise the look, you would want to create separate textures for each (or as many variations as you can come up with), and when it comes to rendering, you have, lets say, some foreground crates, a character, and some background crates. Like in the following scene from one of my most recent projects.



 Still - The Place Where Lost Things Go

It makes sense to separate these into three layers, but you can't because the crates are all sharing the same render stats as they are all sharing the same shape node! How is one supposed to set 'primary visibility' 'off', or 'cast shadows' 'on' on certain crates etc... It's impossible. The only way around this is to have more ACTUAL duplicates, which isn't exactly keeping the scene optimised because it increases the file size unnecessarily. This of course is bad news for me because I increment my saves like mad!


- The benefits of inMesh and outMesh

Now going back to outMesh and inMesh; in this technique you're instead connecting one shape to another shape. The cool thing is that, unlike instancing, you now have a duplicate that has it's own shape node and will update with any changes you make to the source mesh, including topological changes to the mesh, UVs, and even deleting history, AND like instancing, does still keeps the file size down.

Of course, anyone who is using scene referencing in their pipeline can do a similar thing, except that it does require having separate files for each object. That would seem completely over the top if all you want to do is duplicate a screw to be used on a model 100's of times!

In this example, the hemispheres on this Dalek are all based off of one master hemisphere. Apart from allowing me to making slight tweaks to the existing mesh, it also demonstrates how quickly I am able to replace masses of geometry with a completely different mesh, by temporarily connecting in another object.



OK, so there is a better alternative to duplicate instance, so what?

Well, that car example I showed in the previous post is an example of what can be done with outMesh and inMesh. The key is in the construction history!

The rest of this post is going to go over some other examples of how you can use these attributes.



Further Examples

- Rigging

Before skinning any character, if you were to first make a connected duplicate (with outMesh to inMesh) and skin that duplicate, you can now work on that characters rig, without worrying about whether the UVs or the model are perfect. Using the source mesh you can, at any time change your characters UV layout, or even tweak the model (assuming you don't mess with the topology in this case), and then delete the history. All the changes will be carried through to the rigged version of the character.

It is worth noting that the UV editor sometimes fails to update, but saving, closing and re-opening the scene fixes this. While it is actually possible to change the UV's of any skinned object without this method, it's not exactly straight forward. This method simplifies it.

Another technique is to daisy chain a series of duplicates, and applying various deformers on each version. Effectively giving you a lot more control than if you just rely on applying a series of deformers to one object and messing with the history list. For example, you could start with your base model, then a duplicate for adding blendshapes to, then another duplicate which you then skin to joints.

Technically you can also make a connected duplicate, and re-model or re-sculpt it, without deformers, using traditional modelling techniques, without affecting the source mesh (as demonstrated in the very first video). Why would we do this? Maybe you want to apply corrective blendshapes to a character.

While working with blendshapes you can delete blendshape target meshes without removing the blendshape target itself to reduce file size, but you can't easily make a change to a blendshape once you've deleted the mesh.
The problems with keeping the blendshape meshes is that it obviously make the file bigger, and if you do make any changes to the source mesh, you would want all the blendshapes to have the same tweaks, on top of the tweaks that the blendshapes were made for!
So why not create a bunch of connected duplicates at almost no extra cost in file size, and re-sculpt them instead. And any slight changes to the base mesh will cause all the blendshape meshes will update too!
This video shows a better example of how you can connect meshes together.



 - Dynamics

It turns out that nDynamics and Maya Fluids both have outMesh attributes. If anyone has ever attempted a liquid sim with nParticles, one of the things you will end up doing is converting your particle sim to a mesh. The one little annoyance with using the official convert "nParticles to Polygons" operation is that it hides the original particles. The node is still there, but the display of the particles is gone. There may be a way to bring them back, although I gave up after hours of searching. So you guessed it; you can do the same thing by creating a shape node, and connecting the outMesh in the nParticle node to the inMesh of the shape node. Now we can see both the particles and the mesh at the same time to really fine tune the sim, and at any time hide the display of the mesh or particles, without anything permanently disappearing.
So this video demonstrates the same basic process applied to nParticles.



- Smoothing

OK, this is the last set of examples! Every polygon shape node has an outMesh, but it also has an outSmoothMesh attribute! This outputs the smooth mesh preview version of the shape.
Why is this one worth mentioning?
So you've rigged a character, and you want to render it smoothed. Smooth mesh preview calculates so much faster than the smooth operation in the modelling section. It also means that your higher res character can have its own separate mesh, allowing you to have different shaders for it. ie - you can have simple colour shaders for better, and faster viewing in the 3D viewport on the low res mesh, and more complex shaders ( which may not look correct in the 3D viewport ) designed for rendering on the high res mesh.



As an extra, it also means that you can now render smooth mesh previews in Maya software renderer! Which is cool because this then gives us access to Maya's cool raytracing and direct illumination!

Seriously though, if we daisy chained a series of smooth mesh preview duplicates, we can then sculpt in a similar fashion to Mudbox with layers of subdivisions. Now all Maya needs is a faster viewport, some decent brushes, better Transfer Maps and you wouldn't need Mudbox!



OK, that was probably quite an exhausting read, and I'm guessing that only a few people will find this interesting, but if there is anyone who genuinely finds this useful, please leave a comment, and I may eventually create some Mel scripts to simplify some of these techniques.

So that is it for now. I'd be interested to hear if anyone else comes up with some interesting uses for this, and if anyone else knows of more information on outMesh and inMesh then feel free to share it.

Here is a list of websites that I've found for further reading.
http://lesterbanks.com/2012/09/driving-a-shape-by-inmesh-outmesh-connections-in-maya/
http://petershipkov.com/tutorials/blendShapes/blendShapes.htm
http://misterdi.cgpot.com/tutorial/instance/instance.html

A Flock of Pixels


Saturday, 15 September 2012

Maya - Modelling With Symmetry

In my last post I said that I had come across something incredibly simple, but brilliantly powerful in Maya. Although I did say I would reveal all in my next post, there is quite a lot to write about so I shall tease you all for a bit longer.

What I'm showing today is just one of my videos of examples of how a few very simple node connections can be used to do so many different things.

So, what I've come up with here is an interesting way to model in Maya with true live mirroring. There are a few techniques to model symmetrically. The simplest is to turn reflection on in the tool settings, but that doesn't help very much when drawing new edge loops etc,. Another is to use duplicate instance, to create a live flipped copy of one half of the mesh. That will work fine in a lot of cases, that is however until you smooth preview the mesh, and a seem appears down the centre where the join is!
So is there another, better way? Take a look at this.



What I have here is a cage mesh wireframe of one half of the object. I can make any changes I like to it (even clearing the history), and the smooth mesh preview underneath updates, and there is no line down the middle because the smooth version is one complete mesh.
It still works without smooth mesh preview on, and it's also possible to just have the mesh underneath smoothed, with an un-smoothed wireframe.

Admittedly, this takes some effort to set up, and would first need to be automated by a script for it to be totally useful. However you can see how this could be particularly useful for modelling cars or any other symmetrical, smooth surfaces for that matter.

Some of you keen eyed viewers may be able to spot half of the solution of how I achieved this in the video. The trick is how to be able to create a second mesh that is based off of another mesh. 'Duplicate instance' isn't the answer!

I think that is enough info for this post! More to come!

A Flock of Pixels

Edit - It appears I'm not the first to come up with this! I've only just gone and found someone on Creative Crash with a script that appears to do the exact same thing!

http://www.creativecrash.com/maya/downloads/scripts-plugins/modeling/poly-tools/c/maya-real-symmetry-modeling--2/comments#tabs

Well, it was still an exciting discovery at the time, even if someone did beat me to it!
I still plan on sharing all my other findings.

A Flock of Pixels