One attribute, Two drivers?

Hey Guys,
I’ve been following this site for a while now, and you guys have solved many of my inquiries without me even having to post. I love this place.
But now I’ve come place in the road where no matter how much searching on Google I may do, I find no solution.
Well, enough of that, here’s my question:

Is it possible to have 2 separate controllers (NurbsCurves) that both have identical enum attributes that control each other?
let me explain:
Basically, I have Controller_A & Controller_B. They both have an enum attribute called 'Flipbook, the entries under the enum are named: 1,2,3
What I need the controllers to do: When I change Controller_B.Flipbook to 2, I need Controller_A.Flipbook to change to 2 (easy with connections, sdk, expressions etc.)
But here’s the tricky bit: When Controller_A.Flipbook changes to 2, I need Controller_B.Flipbook to change to 2.
So basically When Controller_A changes Controller_B needs to update and visa-versa.

Is that possible, does this even make sense?
(Every solution I can come up with ends with an infinite loop.)

Much thanks in advanced, I’ve been banging my head over this for 2 days now.

one way, if you put the attribute on the shape node you can instance the curve shape on to another transform and the attribute will live in both places. parent -add -shape

Yea!! that might be possible. from my point of view it needs swapping method of values that exchange attributes.

I would go with a script job (If it’s Maya we’re talking about) that listens for attribute changes on your curves and gets and sets attributes. Instead of a direct connection.

if we are talking about maya, you can save the current value to something like an optionVar, and then every other control would query the current value and set itself to match.

basically…
objectA attr gets set to “A”.
optionVar is set to “A”.
controllers that are not objectA query the optionVar and update their Attr to match.

basically, to avoid the loop, store the current value outside the controllers.

Thanks everybody for your quick responses!

@Calon = Yes, I’m talking about Maya (I should have specified that) :slight_smile:

@rgkovach123 = Does this sound correct?:
ObjectA gets set to “A”
I create an optionVar that queries the value of ObjectA, which in turn gets set to “A”.
ObjectB queries the value of the optionVar and also gets set to “A”

But what if I set ObjectB to “B”?
The optionVar has to query the value objectB which is set to “B” and then set ObjectA to “B”

Wouldn’t that create a loop? because objectA has a value of “A” and I just changed objectB to “B” so the optionVar wouldn’t know which object to query from.

Personally I think bclark’s solution is far far more elegant (assuming your animators know where to look for the attribute on the shape node).

If you’re going to use an attributeChange scriptJob then be aware this will get called whenever the attribute changes not just when the user changes it (e.g it will get called every frame of playback while the value is being animated via animCurve). If your end user uses autokey and decides to key all of the driver attributes you’re likely to end up with a mess of keyframes (not to mention the overhead of running the scriptjob multiple times per scene update).

the optionVar never queries the objects, it just gets set to a value everytime one of the controllers is modified.

could you just put the attribute on a single Controller, like a parent controller, and then push this value down to the rest of the controllers? its very easy to setup a single attribute to drive multiple attributes. But getting two controllers to update each other is kind of a pain.

Just a mention/warning about keeping the attribute on the shape node: The other TA here (Nick) has pointed out that setting a key on the controller will not key the enum attribute on the (instanced) shape, as ‘set keyframe’ only applies to the currently selected object, not its children.

Phil

[QUOTE=rgkovach123;17479]could you just put the attribute on a single Controller, like a parent controller, and then push this value down to the rest of the controllers? its very easy to setup a single attribute to drive multiple attributes. But getting two controllers to update each other is kind of a pain.[/QUOTE]

First off, Thank you everyone! I really appreciate you guys lending a helping hand!

@RGKovach = I don’t want to add any extra controllers because our pose system and export system won’t be compatible. I just need to get maya to have two controllers that update each other.

With the optionVar:
So every time either ObjectA or Object B changes, the optionVar updates. Then trickles down its value to ObjectA and ObjectB?
I can then put a conditional statement (to avoid a loop) that says:
if optionVar != objectA.attribute
change objectA.attribute to optionVar value
if optionVar != objectB.attribute
change objectB.attribute to optionVar value

Ah Ha! I think I got it!

Another option may be to just directly connect ObjectA.attr to ObjectB.attr and then lock ObjectB.attr. That way the attribute and value will still exist and be visible on both controls but will only be set/keyable on A (setting A will update B).

The main issue here is that maya doesn’t like bi-directional data flow because it messes with the DG evaluation.

[QUOTE=Warheart;17483]Another option may be to just directly connect ObjectA.attr to ObjectB.attr and then lock ObjectB.attr. That way the attribute and value will still exist and be visible on both controls but will only be set/keyable on A (setting A will update B).

The main issue here is that maya doesn’t like bi-directional data flow because it messes with the DG evaluation.[/QUOTE]

I could do that but I need both controls.

So to make this a little more specific:
for example:
The two controllers are the IK and FK control over the Left_Hand
When FK is visible IK controls are hidden and visa-versa.
The attribute I want to add is an enum that controls the visibility of pieces of geometry that are skinned to that joint (Hand_Joint)–(while one piece is visible all others are hidden)
The exporter looks at which piece of geometry is visible at each frame and creates the in-game animation.
You can think of it as a 3D flip-book.

So when the animator animates in FK he needs the attribute on the FK controller, and visa-versa: when in IK he needs the attribute on the IK controller.
That’s why I need an attribute on both controls that control the same thing (visibility on pieces of geometry).
The main bit is that they need to update each other, so I don’t have one controller saying one thing and another saying a conflicting thing

[QUOTE=Age914;17482]First off, Thank you everyone! I really appreciate you guys lending a helping hand!

@RGKovach = I don’t want to add any extra controllers because our pose system and export system won’t be compatible. I just need to get maya to have two controllers that update each other.

With the optionVar:
So every time either ObjectA or Object B changes, the optionVar updates. Then trickles down its value to ObjectA and ObjectB?
I can then put a conditional statement (to avoid a loop) that says:
if optionVar != objectA.attribute
change objectA.attribute to optionVar value
if optionVar != objectB.attribute
change objectB.attribute to optionVar value

Ah Ha! I think I got it![/QUOTE]

technically whichever controller triggers the change doesn’t need to be updated. If ObjectA changes to a new value, it updates the optionVar, then each other controller updates.

In that case if it were me I’d put the attribute on a control that’s always visible (a lot of rigs have a specific ik/fk control for this reason). I understand that you can’t add controls but would it not be possible to do something like move the attribute to an existing control like the clavicle or the rig root and drive all the other attributes from that?

[QUOTE=Warheart;17491]In that case if it were me I’d put the attribute on a control that’s always visible (a lot of rigs have a specific ik/fk control for this reason). I understand that you can’t add controls but would it not be possible to do something like move the attribute to an existing control like the clavicle or the rig root and drive all the other attributes from that?[/QUOTE]

That is extremely true, and probably the option I will go with if I cant figure this thing out. But this challenge has racked my brain for days now, and I’d feel defeated if I couldn’t do what I wanted to do.

[QUOTE=rgkovach123;17489]technically whichever controller triggers the change doesn’t need to be updated. If ObjectA changes to a new value, it updates the optionVar, then each other controller updates.[/QUOTE]

How do I get maya to know which object changed its value so that when it goes up to the optionVar and then back down to the controllers, it skips the changed controller.
Would I need a combination of optionVar and scriptJob?

Does this sound like the correct order of operations?:

  1. ObjectA.attribute changes to “B”
  2. OptionVar has a scriptJob that says “If ObjectA or B.attribute changes, reflect this on the optionVar value”. OptionVar changes to “B”.
  3. OptionVar has a scriptJob that says “if it’s value changes trickle down to ObjectA and B.attribute”
  4. Conditional statement saying:
    if optionVar doesn’t equal objectA.attribute :
    change objectA.attribute to optionVar value
    if optionVar doesn’t equal objectB.attribute :
    change objectB.attribute to optionVar value

having a visible root controller that is outside your export rig that drives the other controllers is the best solution.
but to answer your question, you’ll need a script attached to each controller’s attribute. optionVars aren’t entities that can have a script job attached to them.

you’ll need to write a simple proc that takes as an input the controller that was modified. the procedure will need to know the complete list of controllers that should be updated. this can be a global variable, or something you infer from the passed in controller. the proc then just iterates over all the controllers, EXCEPT the input controller and updates their attrs. actually, you don’t even need the optionVar.

here is an over-simplified example. I dont use MEL anymore, so excuse my fuzzy memory on the syntax…

global string $controllerList[];

global proc updateControllers()
{
// get the currently selected controller
string $source = ls -sl;

// get the value off the passed in controller
int $val = `getAttr "blah.blah"`;

// loop over the controllers in the global list

// skip the source controller
if $controllers[i] == $source { continue; }

// else update the controller's value
setAttr "blah.blah" $val;

}

One more alternative- You can also wrap each node in an asset and then publish or create the attribute to the asset so no matter what node you select it will show up. This can be a better choice when you don’t want to have to instance shape nodes and then remember the attr is down there… The asset keeps it up top and easy to see/key/select.