« Node Frenzy! | Home
Walkthrough: Jitter Deformer Node
By riggerman | November 19, 2009
Hey all! As promised I will be explaining in my own not-so-technical words how I got a my own python scripted deformer node working in Maya! This is a reeeeeeeeeally beginners’ level post and shouldn’t be read by API expert.
Also, bear in mind this is not the jitter node from the devkit examples. I started with the
| yTwistNode file and worked my way to a deformer that moves all vertex of a mesh to random directions (controlled by a multiplier value).
Here’s a little screengrab of meshes being deformed with my plug-in. Thanks to my co-worker Paulo Nogueira for the idea of using toon shading with this node to achieve this nice hand-drawn trembling effect! Jitter Deformer in action! from Riggerman on Vimeo. Ok, so I’ll explain what I see it’s important in general first and then later concentrate on the actual deformation algorithm. Before dirtying our hands with the fun part, let’s see some boring parts that should be right or else nothing else works.
Pay attention now, because right under them we already have two really important lines:
These lines define important variables for your plug-in. The first var, kPluginNodeTypeName is the name of your node (speaking plain english, the string that identifies your node when using the createNode command in Maya). Let’s use the Search/Replace function (every text editor has it) to replace “yTwistNode” for “jitter“. These vars are used right at the end of our code, in the initializePlugin and uninitializePlugin functions.
NOTE: Do not change these functions names or else Maya won’t load your plug-ins. Ok, now that the gruesome part is over, we can focus in actually working on our node! The first step to this is to set its attributes - you know, the data it will work with! Check out this part of the code:
This code starts by instancing the MFnNumericAttribute object so we can access its functions. In this case we are creating a numeric attribute, but it could be a MFnTypedAttribute to work with strings or even a MFnGenericAttribute to work with mesh data. Check out the respective API help pages to see what kind of functionalities these guys have and how to use them. Alright! For the rest of this line we define the full attribute name, the short attribute name, its unit type and a default value; check the MFnNumbericAttribute create function API page for more info. Let’s set it like this:
Before moving on, we gotta create another attribute. Up to now we have a seed attribute that controls the randomness of the deformation, now we need something to control its amplitude. Copy and paste all this section right underneath the seed attribute and apply the necessary changes, like so:
This multiplier attribute will be the number we multiply with the random function to increase our deformation’s power. Ok! Now we have our attributes defined, let’s add them to our node. The code that does this is right underneath our attributes:
We only replaced the node’s name but the angle attribute is still there. Change all occurrences to seed. Ok, moving on! Duplicate the first and last lines changing seed to our second attribute, multiplier. You gotta end with something along these lines:
Alright, with most of our plug-in covered, all that is left is for us to define HOW the deformation is going to happen. We got all the material and room to do the job, now we just have to tell Maya how to use out input data. The first line define some important stuff. If you changed all angle occurrences, this line should be instancing a MObject as a variable called guess what… seed. Duplicate it for the multiplier attribute, like so:
Leave the initialization method as it is, we don’t need to change anything here. And finally, the cool part, the deform method! As you can see, this guy has a lot of convenient handles so we can access data from our node. We mainly use the dataBlock here that gives us access to our attributes and the geomIter iterator to loop through all points in our geometry, enabling to make changes to them! The deformation algorithm starts by getting our seed value as a double, but remember we changed the unit type of our attribute to float back there? Do the changes correctly here, don’t forget to duplicate it to also get our multiplier value and you should get:
Now we have these two nice variables to work with however we want, seedValue and multiplierValue. Oh wait, what do I see? We can get the node’s envelope value too! This way we can turn the deformation on and off in our calculations! You shouldn’t change theses lines:
Now that we have everything we need, let’s rock! We’ll use the geomIter iterator to loop through all points in our mesh and do all kinds of silly things with them:
Looks scary doesn’t it? Don’t worry, most of the weird formulas are the twisting calculations and we don’t need to understand these (at least not for this node!)
At this point you have a working node! You can experiment any calculations here that the node should work just fine. I’ll explain how to jitter the points using the random module. Remember I said we would set the random’s seed value so we can control it’s (pesudo)randomness? To understand that, fire up Maya’s script editor, go to a python tab and write:
Re-run this piece many times to get different values everytime. Now, try to run this code:
…and now you get always the same value, unless you change the seed value. Got it? Random module by default uses your machine’s time as seed but you can override that by setting the seed manually. That’s how we’re getting the same values over and over for our deformer node.
So if every point had the same seed, they would have the same value, right? I change this by adding the own point index value to the seed, making every point different! Now, what happens is that we still need something to shake these guys, not only scramble them a little and thats it. I did it by also adding the multiplierValue to it:
I could add another attribute to control the offset, but since I wanted a simple example I used this already create attribute (this way you scramble the points by modifying the multiplier attribute).
To add our randomized values to the point’s XYZ position we gotta transform our units into a MVector object. We do this like so:
Now we can sum our point position with the scrambled values:
Now you can save and load your plug-in in Maya using the Plug-in Manager! Test your node by creating a sphere and typing:
|
Well, this is the end of this walkthrough and I hope it helped you as much as it helped me to better understand it by writing. If you find anything wrong or have a suggestion, please email me or comment!
EDIT: (24/nov/2009)
Ryan Trowbridge has pointed out a faster way of computing the deformations:
Most (if not all) of the devkit examples set the points positions one by one while iterating the mesh points, but this method is slower and since our deformation isn’t neighbor dependent or anything like that, we can set the points position all at once using MItGeometry.allPositions ().
In his own words: “The problem with this is that when the node goes to deform, it is iterating through x amount of vertices and each time it iterates it updates the scene using setPosition() So a 10,000 vertice mesh is updating the scene 10,000 times (…) The reason this one is faster is it get all the vertices and sets all the vertices at once“.
Well, to do this we need to create a MPointArray object to store the information we need. This line goes before the iteration loop:
allPoints = OpenMaya.MPointArray()
Now, inside the loop we can replace the setPosition line for this one:
allPoints.append(point+normalVec)
This will insert each point value in the point array object, so we can pass on this big list all at once to the final command, that goes right outside the loop:
geomIter.setAllPositions(allPoints)
And that’s all! Now your deformer will run much faster! Thanks Ryan!
Topics: Maya Python |
Use this form to send your friend this post.
Comments
You must be logged in to post a comment.