Question

I'm writing a MEL script that will rename all of the joints in a joint hierarchy to a known format. The idea is that you would select the Hip joint and the script would rename the Hips, and go through every other joint and rename it based on its position in the hierarchy.

How can you traverse through a joint hierarchy in MEL?

Was it helpful?

Solution

If you assign to $stat_element the name of your top joint in the hierarchy and run the following code, it will add a prefix "myPrefix_" to all children elements of that joint.

string $stat_element = "joint1";
select -r $stat_element;
string $nodes[] = `ls -sl -dag`;
for($node in $nodes){
    rename -ignoreShape $node ("myPrefix_" + $node);
}

Hope this helps

OTHER TIPS

If you need to make detailed decisions as you go along, instead of bulk-renaming, traversing the hierarchy is pretty simple. The command is 'listRelatives'; With the 'c' flag it returns children of a node and with the 'p' flag it returns the parent. (Note that -p returns a single objects, -c returns an array)

Joint1
    Joint2
        Joint3
        Joint4

listRelatives -p Joint2
// Result: Joint1 //
listRelatives -c Joint2
// Result: Joint3, Joint4

The tricky bit is the renaming, since maya will not always give you the name you expect (it won't allow duplicate names at the same level of the hierarchy). You'll need to keep track of the renamed objects or you won't be able to find them after they are renamed in case the new names don't match your expectations.

If you need to keep track of them, you can create a set with the set command before renaming; no matter what becomes of the names, all of the objects will still be in the set. Alternatively, you can traverse the hierarchy by selecting objects and renaming the current selection -- this won't record the changes but you won't have problems with objects changing names in the middle of your operation and messing up your commands.

It can be messy to do this in MEL if you have non-unique names because the handle you have for the object is the name itself. Once you rename a parent of a node with a non-unique name, the child's name is different. If you stored the list of all names before starting to rename, you will get errors as the rename command will attempt to rename nodes that don't exist. There are 2 solutions I know of using MEL. But first, here's the pyMel solution which is much easier and I recommend you use it.

PyMel Solution:

import pymel.core as pm
objects = pm.ls(selection=True, dag=True, type="joint")
pfx = 'my_prefix_'
for o in objects:
    o.rename(pfx + o.name().split('|')[-1])

As pm.ls returns a list of real objects, and not just the names, you can safely rename a parent node and still have a valid handle to its children.

If you really want to do it in MEL, you need to either rename from the bottom up, or recurse so that you don't ask for the names of children before dealing with the parent.

The first MEL solution is to get a list of long object names and sort them based on their depth, deepest first. In this way you are guaranteed to never rename a parent before its children. The sorting bit is too convoluted to be bothered with here, and the recursive solution is better anyway.

Recursive MEL solution:

global proc renameHi(string $o, string $prefix) {

    string $children[] = `listRelatives -f -c -type "joint $o`;
    for ($c in $children) {
        renameHi( $c ,$prefix ) ;
    }

    string $buff[];
    int $numToks = tokenize($o, "|", $buff);
    string $newName = $buff[( $numToks - 1)];

    $newName = ($prefix + $newName);
    rename($o,$newName);
}

string $prefix = "my_prefix_";
string $sel[] = `ls -sl -type "joint"`;
for ($o in $sel) {
    renameHi($o, $prefix);
}

This recursive solution drills down to the leaf nodes and renames them before renaming their parents.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top