PDA

View Full Version : How to make Expressions work in referenced scenes?


Taunise
01-10-2013, 03:06 AM
This is something that's bothered me over a number of scripts I've done.

Is there a way to make expressions able to pick up namespaces so they work in referenced files?

Previously I had a bit of a search and replace that would find the missing attribute's namespace and tack it on to what I was trying to do but ths seems like a really irritating waste of time, surely there must be a way around this?

For example, I have:


global proc warn(){
float $followingHead = `getAttr mySphere.followHead`;

if ( $followingHead == 1 ){

setAttr -lock true "mySphere.tx";

setAttr -lock true "mySphere.ty";

setAttr -lock true "mySphere.tz";

}//end if

else if ( $followingHead < 1) {

setAttr -lock false "mySphere.tx";

setAttr -lock false "mySphere.ty";

setAttr -lock false "mySphere.tz";

}

}// end proc

scriptJob -attributeChange mySphere.followHead warn;



I have this stored in a script node, as an expression which runs on maya open/close. It all works fine.

Until I reference the scene in. In the new file, it doesn't realise that mySphere is now called REF:mySphere and the script ceases to work completely.

My previous fix was to do a search through the name of the script node, copy the text before the colon and tack it on to the attributes I'm trying to affect. But this seems overly heavy handed for what is essentially a simple namespace repathing.

Does anyone know of a solution?

Cheers.

Nyro
01-10-2013, 09:52 AM
Add this to the beginning of your script:

$sphereList = `ls -r 1 "mySphere"`;
$sphere = $sphereList[0];
Then modify your script, replacing each occurent of "mySphere" with "$sphere", e.g.


global proc warn(){
float $followingHead = `getAttr ($sphere + ".followHead")`;

if ( $followingHead == 1 ){

setAttr -lock true ($sphere + ".tx");

// etc.
// etc.

uiron
01-10-2013, 10:07 AM
you have to think of some way you can discover the node without knowing it's name at all. Easiest it seems would be linking your sphere to your script node via message (adding new attribute to script node first). Then, script node queries it's own attribute (`getAttr .sphereLinkedMessage`), gets object's name via that link, stores that in a variable and you can do pretty much anything you want at this point.

Taunise
01-10-2013, 07:39 PM
Add this to the beginning of your script:

$sphereList = `ls -r 1 "mySphere"`;
$sphere = $sphereList[0];
Then modify your script, replacing each occurent of "mySphere" with "$sphere", e.g.


global proc warn(){
float $followingHead = `getAttr ($sphere + ".followHead")`;

if ( $followingHead == 1 ){

setAttr -lock true ($sphere + ".tx");

// etc.
// etc.

This is a clever solution, but after trying and fiddling with it for a wee bit, i dont think it works.

in your example, $sphere would need to exist as its correct value when you open the scene, because the script job needs to know what object's attribute change property to run on. The ls won't work at this point however, because nothing is selected. The scene has only just been loaded.

you have to think of some way you can discover the node without knowing it's name at all. Easiest it seems would be linking your sphere to your script node via message (adding new attribute to script node first). Then, script node queries it's own attribute (`getAttr .sphereLinkedMessage`), gets object's name via that link, stores that in a variable and you can do pretty much anything you want at this point.

Yeah, this approach does work, and it's similar to what I've used it on previous scripts, but it's very heavy handed when all I'm trying to do is lock and unlock attributes. I was looking for a slightly more elegant way to go about it.

Referenced files are a pain :(

Nyro
01-10-2013, 08:31 PM
in your example, $sphere would need to exist as its correct value when you open the scene

Yes, it would have to exists. But since the whole issue here is that you're referencing it in, I simply assume that it existed along with the scriptNode in the original (referenced) scene.

That said, the other solution is more robust as there is less chance of accidentally referring to the wrong object.

Taunise
01-10-2013, 08:37 PM
Yes, it would have to exists. But since the whole issue here is that you're referencing it in, I simply assume that it existed along with the scriptNode in the original (referenced) scene.

That said, the other solution is more robust as there is less chance of accidentally referring to the wrong object.

No my point was that $sphere has to be defined when the scene opens.

So when the scene opens you would be running the ls command.

But ls only works on selected things. When a maya scene opens, nothing is selected. So even though the sphere itself exists, it won't be able to find it and assign its name to $sphere...or am I missing something?

gmask
01-11-2013, 03:40 AM
use `node` in your expression to get the namespaced name of the node

string $name=node;

Nyro
01-11-2013, 06:11 AM
But ls only works on selected things. When a maya scene opens, nothing is selected. So even though the sphere itself exists, it won't be able to find it and assign its name to $sphere...or am I missing something?

No. You're mistaken, which isn't all that surprising given that by far the most common usage of the ls command is:

ls -sl

The 'ls' command itself simply lists objects in the scene. You can specify what objects you want to list via the command's flags, e.g.

ls -sl // list selected objects
ls -type "transform" // list all transform nodes in the scene
ls "pCube1" // list all objects called 'pCube1'
ls -recursive "sphere" // list all objects named 'sphere', but look in all namespaces for them (as opposed to merely in the implied ':' (root) namespace)

When dealing with scripts and expressions, it is very important not to get too hung up on the idea that commands need something to be selected to work. 98% of all commands don't. Using the selection is just the default way most commands handle the non-existence of object arguments when they are called.

gmask
01-11-2013, 05:29 PM
Yeah ls is great but the tip I just gave in my previous post is far better for this particular issue :buttrock:

Nyro
01-11-2013, 06:11 PM
Yeah ls is great but the tip I just gave in my previous post is far better for this particular issue :buttrock:

Agreed. Much less chance of accidentally referring to the wrong object with your method, unless you can be reasonably sure that your particular sphere is uniquely named.

gmask
01-11-2013, 08:03 PM
Agreed. Much less chance of accidentally referring to the wrong object with your method, unless you can be reasonably sure that your particular sphere is uniquely named.


Generally speaking.. I always avoid non unique names in any referenced asset. The only reason you need `node` however is to get the namespace that the expression is in and then you can add the name space to the full path of whatever object in your reference hierarchy you are running the script on.

string $node=node;

string $namespace=substitute(":.*$",$node,"");

string $path=$namespace+":myobject";

or

string $path=$namespace+":mygroup|"+$namespace+":myobject;

Nyro
01-11-2013, 09:18 PM
or use a regex :)

gmask
01-12-2013, 04:10 AM
or use a regex :)

whatever floats your boat.. if you're willing to fish for node names using ls then using substitute shouldn't be a stretch. :rolleyes:

Nyro
01-13-2013, 02:29 PM
By the way, this just occured to me because I'm currently working on a script that has to deal with referenced objects:

It is still possible to reference a scene without using a namespace; the alternative option is using a string Prefix.

If the user chooses this option, then the nodes in question will not have a namespace and thus no colon ":" to identify the prefix (or namespace) by.

In such a case, there really is no way around identifying the node via its unique name (or at least a unique substring in its name). If there is, I'd love to hear it.

gmask
01-14-2013, 12:46 AM
By the way, this just occured to me because I'm currently working on a script that has to deal with referenced objects:

It is still possible to reference a scene without using a namespace; the alternative option is using a string Prefix.

If the user chooses this option, then the nodes in question will not have a namespace and thus no colon ":" to identify the prefix (or namespace) by.

In such a case, there really is no way around identifying the node via its unique name (or at least a unique substring in its name). If there is, I'd love to hear it.

Oh I thought that option had been removed for references? In any case you could prefix the names of an imported asset. :surprised

There's a number of ways you could handle this.. you could make a rule about how the prefix is formatted so that it can be pattern matched. You could require that no name has an underscore in the name and use the underscore as a delimiter. You could try to presume that the first string before an underscore is the prefix. You could use two underscores in a row as the delimiter.. you could use "_ns_" as a delimiter. When you import or reference the asset the first time you could set a string attribute on the asset or perhaps on the expression or create an expression that has the prefix stored in it.

Taunise
01-14-2013, 01:24 AM
It really is a bit rediculous that you can't just query an object's namespace.

For the current project, im pretty happy to just ignore the string prefix, we always use namespaces with colons anyway.

Thanks for all the input guys.

If anyone does have any other bright ideas, let me know.


Edit: I found this little tidbit in the Maya Command Reference about the referenceQuery command, which should be able to give you the parent namespace of an object.

However, when I run the test script at the bottom of the page (http://download.autodesk.com/global/docs/maya2012/en_us/Commands/referenceQuery.html) and then run the following command:
referenceQuery -parentNamespace mid:botRN;
It should return the object's namespace, but instead I get the following error:

Error: line 0: Invalid flag '-parentNamespace' //

It doesn't work in Python either.

There was a mention of it only being added in Maya 6.5 but im running 2011.5x64

Anyone know?

uiron
01-14-2013, 05:23 AM
There is just this one tiny problem you're gonna face after you get this working - you can't lock attributes in a referenced node:D

Anyway, to get this thing working (that is, until I've hit the brick wall above), I used a uniquely named script node (just put a random generated prefix to it), then use messages to navigate from script node to sphere. I could not successfully use "node" procedure in 2011 to get script node name, like was suggested, but that would simplify things further, if you could get it working.

This one prepares our scene - just for testing;

global proc setupScene(){
$sphere = `sphere`;
addAttr -at "float" -keyable 1 -ln "followingHead" $sphere[0];

$scriptNode = `scriptNode -st 1 -name "lockUnlockAttributesScriptNode_29872351830985518764563897"`;
addAttr -at "message" -ln "sphereLink" $scriptNode;
connectAttr ($sphere[0]+".message") ($scriptNode+".sphereLink");
}

setupScene();


this is the actual expression (please note that spaces in node name are added by cgtalk.com)

global proc string getSphereName() {
$name=`ls -recursive 1 lockUnlockAttributesScriptNode_29872351830985518764563897`;
$sphere = `listConnections ($name[0]+".sphereLink")`;
return $sphere[0];
}

global proc warn(){
$sphere = getSphereName();
float $followingHead = `getAttr ($sphere+".followingHead")`;
$lock = $followingHead == 1;
setAttr -lock $lock ($sphere+".translate");
}

global proc installScriptJob(){
$sphere = getSphereName();
scriptJob -attributeChange ($sphere+".followingHead") warn;
}

installScriptJob();

gmask
01-14-2013, 02:04 PM
I could not successfully use "node" procedure

It's a little weird.. when I originally heard about this I believe it returned the full path including namespace.. but now in 2012 it appears that expressions work inside their namespace and you don't even need to know the namespace to use setAttr or getAttr? Anyway I don't know if I have access to older version of maya where I could test his.

uiron
01-14-2013, 02:30 PM
I've tried calling
$nodeName = node;

..but it did not work in 2011 maya.

gmask
01-14-2013, 05:08 PM
I've tried calling
$nodeName = node;

..but it did not work in 2011 maya.

Hmm .. when you say it does not work.. do you mean you get an error or you don't get the results you were expecting?

Actually this is not working as I recall it working.. it's just returning the name of the referenced expression without the name space which is not helpful. :cry:

gmask
01-14-2013, 05:37 PM
Try this..

create an expression..

add this to the expression..

namespace -set ":";
string $node=node;
print("$node="+$node+"\n");

Then reference this scene with a namespace and it should print the name of the expression with the namespace. From there you can extract the namespace however you like and proceed from there.

gmask
01-14-2013, 09:04 PM
It appears that expressions by default will run inside their namespace so you can also put this in an expression..

string $ns=`namespaceInfo -cur`;

print($ns+"\n");

I'm starting to think they must have fixed something in a recent version.

gmask
01-15-2013, 05:11 PM
..but it did not work in 2011 maya.

Okay was able to test several of the methods I've mentioned and they all worked in 2011.5.. and above.. I couldn't test in 2011.

I created scenes that had the following expressions.. saved the scene and then referenced them into a new scene

namespace -set ":";
string $node=node;
print("$node="+$node+"\n");
worked..

string $ns=`namespaceInfo -cur`;
print($ns+"\n");
worked..

float $x=sin(frame);
setAttr pSphere1.translateX $x;
float $tx=`getAttr pSphere1.translateX`;
print($tx+"\n");
also worked.. and you don't even need to know the namespace.. it just assume you mean the sphere inside the namespace of the referenced scene... which is how this should have worked all along.

I assume somewhere between 2009 and 2011 this was fixed.

gmask
01-16-2013, 10:18 PM
Are these methods not working for anybody but me? Uiron (http://forums.cgsociety.org/member.php?u=178659)?

CGTalk Moderation
01-16-2013, 10:18 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.