MAYA: EASY SNAPPING SCRIPT (TUTORIAL)
This code lets a user save an object's coordinates with a double-click of a shelf button, and then using a single click, apply those coordinates. This can snap two objects together, or let you snap an object to the same position across several frames; it can be useful for locking down feet or hands while animating, or for positioning before applying constraints. Because its in simple MEL script, it should be applicable in any Maya version back to 2012.
First we need to save the position and rotation we want to snap to. Create a shelf button and in the Shelf Editor, put this MEL script in the "Double Click Command" tab for that button.
global proc storeSnapValues() {
global float $storedT[];
global float $storedR[];
string $sourceObj[] = `ls -sl`;
if (size($sourceObj) == 0) {
warning("No object selected!");
return;
}
string $objName = $sourceObj[0];
$storedT = `xform -query -worldSpace -translation $objName`;
$storedR = `xform -query -worldSpace -rotation $objName`;
print("Transform stored from: " + $objName + "\n");
}
storeGlobalTransform();
Here's the breakdown for each line.
// We need a function (a chunk of code) we can call anytime from anywhere (like from a single click on the same button), not just in the code we have here.
// We can use "proc" to define a function. Calling it "global" makes it accessible from any other code we decide to run from anywhere in Maya.
global proc storeSnapValues() { //This creates the function called "storeSnapValues"
global float $storedT[]; // Global variable for Translation (T)
global float $storedR[]; // Global variable for Rotation (R)
// We need to store the values as "global" so they can also be referenced from anywhere.
// For our purposes, just know that "float" is a type of variable, a number that has a decimal place. It is different from a "string" or an "interger" or "int", which are other data types.
// The next part is "$storedT" and "$storedR". Leading with "$" tells Maya that this is the name of the variable.
// The "[]" at the end tells Maya there are going to be MULTIPLE values stored inside this variable. This changes it from a single float to an "array" of floats.
// We're going to have to get which object we currently have selected in order to save its Translate and Rotate values.
string $sourceObj[] = `ls -sl`;
// This is a value type called a "string". Strings are typically bits of text, names, or labels. You can also have an array of strings.
// The backticks (`) run the command inside and take the returned value and assign it to our string or variable.
// 'ls -sl' is short for "list selection". It creates a list of everything you have selected, and then returns each item in that list to be the value of each string in our array.
// If the size of the array we just made is zero, there's nothing in it. We show a little warning and then end the function with "return;". There's no need to keep running code if we don't have anything selected.
if (size($sourceObj) == 0) {
warning("No object selected!");
return;
}
// To simplify the next few lines of code, we're going to save the value of the FIRST OBJECT in our list (even if its only one object, its fine).
// The first item is actually indexed with a 0. So we save the "0th" string in the array to a single string.
string $objName = $sourceObj[0];
// The float arrays we made before now need to get their values from the saved object.
$storedT = `xform -query -worldSpace -translation $objName`;
$storedR = `xform -query -worldSpace -rotation $objName`;
// Here we see an "xform" command, paired with the tags "-query -worldSpace -translation". It "queries" or asks maya the transform (shortened to xform) the objects worldSpace translation or rotation. The values are then saved to our array of floats in X-Y-Z order.
print("Transform stored from: " + $objName + "\n");
// A print command just gives us a little heads up as to what we actually just did.
}
storeSnapValues();
//Then we call the function to run the code.
Now, when we select a different object, we need to be able to apply those values with a single click. Under the "Command" tab for our button, put this MEL script.
global proc applySnapValues() {
global float $storedT[];
global float $storedR[];
string $targetObj[] = `ls -sl`;
if (size($targetObj) == 0) {
warning("No object selected!");
return;
}
if (size($storedT) == 0 || size($storedR) == 0) {
warning("No transform data stored! Double-click first to store.");
return;
}
string $objName = $targetObj[0];
xform -worldSpace -translation $storedT[0] $storedT[1] $storedT[2] $objName;
xform -worldSpace -rotation $storedR[0] $storedR[1] $storedR[2] $objName;
print("Transform applied to: " + $objName + "\n");
}
applySnapValues() ;
Here's the breakdown for each line of code.
// We're going to create another global function to apply our saved values. We'll call it "applySnapValues"
global proc applySnapValues() {
global float $storedT[];
global float $storedR[];
// We do have to declare these again. If they have the exact same name, Maya will know that they are the same variables as before.
string $targetObj[] = `ls -sl`;
// Let's get a list of all the objects we have selected (even if its just one object) and save it to an array of strings.
// Again if we don't have anything selected, we don't have to run any code, and we can return.
if (size($targetObj) == 0) {
warning("No object selected!");
return;
}
// What if we run the apply command, but no data is stored? We'll check and see if our global float values are empty. If they are, then we won't run any more code.
if (size($storedT) == 0 || size($storedR) == 0) {
warning("No transform data stored! Double-click first to store.");
return;
}
// Let's assign the first object in our selection list to a single string, just like before.
string $objName = $targetObj[0];
// Instead of running the "xform" command inside backticks, we're just going to run it to APPLY transform values. Note that we're not using the "-query" tag this time.
xform -worldSpace -translation $storedT[0] $storedT[1] $storedT[2] $objName;
xform -worldSpace -rotation $storedR[0] $storedR[1] $storedR[2] $objName;
// For the translation and rotation, we apply the worldSpace X,Y,Z values (in order). This should move the object. If you have auto-key on, they object is also keyed in its new position.
print("Transform applied to: " + $objName + "\n");
// A print statement as a heads up for what we just did.
}
applySnapValues();
// Run the function!