View Full Version : Detecting CA value changes
Chinwagon 06-23-2006, 11:25 AM Hey there. I'm trying to get two objects to dynamically hide and unhide when a slider's value is changed whilst a checkbox (in this case called AutoHide) is active:
on AutoHide changed state do
(
if state == on then
(
TheSlider = $Object03.modifiers[#Attribute_holder].parameters[1]
(
if TheSlider.value > 50 then
(
hide $Object01
unhide $Object02
)
else if TheSlider.value < 50 then
(
unhide $Object01
hide $Object02
)
)
)
else if state == off then unhide #($Object01, $Object02)
)
At this stage it works, but only when the checkbox is clicked, where I want it to do it when the slider is moved too. However, if I add an "on TheSlider changed sliderVal do" under the slider definition, I get a syntax error.
This checkbox code is in a custom attribute which is a seperate rollout from another CA that contains the slider. Do they need to be in the same rollout? What's the solution?
:¬/
|
|
Kenzor
06-23-2006, 12:14 PM
Are you trying to animate visibility?
why not add a 'visibility track' to the object in 'track view' ?
Chinwagon
06-23-2006, 01:21 PM
No, I don't want animate the visibility, I actually want to set up a CA checkbox that - when activated - will literally hide certain objects and unhide others when a slider is set at certain amounts.
:¬)
djlane
06-23-2006, 03:17 PM
In the past I have used something like this:
on spn_Hide buttonup do
(
if spn_Hide.value > 50 then ( hide $theobject) else ( unhide $theobject)
)
I hope it helps
Dan Lane
Not sure that I follow Brad. Do you have two seperate CA definitions? or just two different rollouts in on CA def?
[Edit]
This uses two caDefs on one object. The second def stores a reference to the first but i couldnt' get it to work both ways due to a dependancy loop issue. I did a work around though that got it to work.
Try this out Brad:
sph=sphere()
emptyMod=(EmptyModifier())
addModifier sph emptyMod
tea=teapot()
def=attributes test
(
parameters testP rollout:testR
(
hideIt type:#boolean ui:hideItCb
hideNode type:#node
-- test2Ref type:#maxObject --Will not allow me to do this in both directions
)
fn hideItFn val=
(
if hideIt then
(
print val
case of
(
(val<=50): hide hideNode
(val>50): unhide hideNode
)
)else
(
unhide hideNode
)
)
rollout testR "Test"
(
checkBox hideItCb "Hide It:"
on hideItCb changed state do
(
--((refs.dependents this)[4]) is a work around for a dependancy loop problem is I try to
--store a reference in each of the CADefs of the other. I can do it one way but
--not both.
if state==true and ((refs.dependents this)[4]).test2.theSlider<=50 then
(
hide hideNode
)
if state==false then unhide hideNode
)
)
)
def2=attributes test2
(
parameters testP rollout:testR
(
theSlider type:#float ui:theSliderSl
testRef type:#maxObject --Store a reference to the first def
)
rollout testR "Test 2"
(
slider theSliderSl "Slider:"
on theSliderSl changed val do
(
testRef.hideItFn val
)
)
)
custAttributes.add emptyMod def
custAttributes.add emptyMod def2
emptyMod.test.hideNode=tea
--emptyMod.test.test2Ref=emptyMod.test2
emptyMod.test2.testRef=emptyMod.test
select sph
Chinwagon
06-25-2006, 06:22 PM
Your script works really well, but I'm still getting my head around a few of the things you've done that are new to me (ie. the "case" definition and functions within CAs).
I have two sepearate definitions on the one object. It's just how I prefer to work using your rigging utils. If I want to break it up into two CA scripts that I can use with your utils which one does the function go into? I guess I also need to have the relevant nodes stored in each CA script as I need to access the state of the sliders/checkbuttons in each one (although that refs.dependents bit could be a clever way around it...).
Being greedy, I'd also like to have it update when the timeslider is moved and when the slider's keyframe value is changed, but I think I can figure that one out...
:¬)
luigi
06-26-2006, 11:55 AM
case of is quite nice so you have to define a lot of if then else
bu in the case of using if :
"
if TheSlider.value > 50 then
(
hide $Object01
unhide $Object02
)
else if TheSlider.value < =50 then
(
unhide $Object01
hide $Object02
)
"
yo have to define a reaction when the value is equAl to 50 If not your script wil get an error when is exactly equal to 50 ;)
paul already done it in shis sample script ;).
Are the object gone to be defined by node or by name?
Glad that you are learning from it Brad. There are a few things going on in the script that I don't think many people know about.
The case statement as luigi as pointed out is a cleaner way of dealing with nested if statements. From what I can rememer is was also faster then a bunch of if statements but i could be wrong on that. It is usualy used with radioButtons where you could say case radioButton.state of and then list the integers that represent the different states of the radio button. I stepped it up a bit and instead of just an integer I placed an expression instead for each of the states of the case statement.
The next thing that I did was store a reference to the first definition in the second using maxObject. Using this method to means that you don't have to refer to objects by name. You also don't have to worry about the stack changing, the modifier the attributes are on chaning name or even the definition being moved somewhere else on the rig.
Using refs.depentents this is a great way to refer back to the object that the definition is on. It returns an array of depentents so you need to check which in the array that you need.
Using Functions inside of definitions is something that I use all the time. I often have definitions that are only functions and noting else. You can access these functions from else where in Max and use those functions. I will do this if I'm using script controllers and I have a bunch that are similar and need like functions. I will store the function in a ca def and access that def from the script controller. As you know you can also have a function inside of a rollout in the def and that is perfectly valid as well and can also be accessed if needed with theDef.theRollout.theFunction(). This can be a pain if you have a definition that has multiple rollouts that all use the same set of functions.
Brad, can I ask why you have multiple definitions and not just one with multiple rollouts?
Chinwagon
06-27-2006, 03:08 PM
OK...
So I decided to put the checkbutton inside the same rollout as the slider and it's saved me some headaches. I've put the main calculation into a function and it works a lot cleaner now.
However, as I mentioned earlier, I wanted to have the hiding/unhiding update when scrubbing the timeslider, which I have achieved by adding a registertimecallback to the function when the checkbutton is true and unregistering it when it is false. So far so good...
Now it gets more complex as I have two objects with CAs that I want do the same thing in an interlinked sort of way. ie. the slider's value is instanced and when one checkbutton is active, the one on the other object is active too. The problem comes when I activate the checkbutton on one object, select the other and turn it off. I've registered the callback with the first object but turning it off in the other doesn't unregister it.
How can I access the function inside the CA of another object? Also, the function doesn't work unless one of the objects is selected. Do I need to make it some sort of global function? Can I instance checkbuttons' values without having them be animateable?
As an insight to my workflow, to store nodes, what I do is an old-fashioned node store of one object that has a position script controller on it. That script controller contains nicely named node variables of all the objects I want to store in the scene. That way, I can add and remove nodes with a more visual (ie. more intuitive for me) interface and don't have any dependency loops troubles. From there I can access those nodes by name by doing something like this:
IK_ArmCtrl = this.Node_Storage.node.position.controller.getnode "IK_ArmCtrl"
It may look a long-winded, but it makes more sense to me.
One thing I also noticed in your example script Paul, is that you have the function between the parameters and rollout sections. I could only access it when it was within the rollout. Is it better to have the function outside of the rollout and if so, what CA code do I need to access it?
It seems as I get the answer to one question, five more are raised...
The reason I uses multiple definitions is because when I started using the PEN rigging utils, I didn't know you could have multiple rollouts in the one CA, plus I like to see a list of the rollouts I have on an object in the edit attributes window. Once again, just something I've become used to. I guess as I get deeper into the script side of rigging I see I will probably have to change that method.
BTW, thanks Luis and Paul for the "case" description, I knew of it but as usual, I didn't know the best situation to implement it.
:¬)
Does that help?
s=sphere()
empt=emptyModifier()
addModifier s empt
def=attributes test
(
parameters testP rollout:testR
(
someText type:#string UI:theSphereEt default:"Sphere"
)
fn changeTheString str=
(
someText=str
)
rollout testR "Test"
(
editText theSphereEt "The Sphere"
)
)
custAttributes.add empt def
--Here I access the function that is in the def stored on the modifier
empt.changeTheString "crap"
--or
$sphere01.modifiers[1].changeTheString "What Ever"
select s
max modify mode
Chinwagon
06-29-2006, 01:29 PM
Thanks for your help Paul, I've got it working now. Putting the function in between the parameters and the rollout information got what I want out of it.
Thanks again.
:¬)
Brad when calling the Function from out side the def it shouldn't matter where the Function is in the def unless it is calling the the parameter block. If it is above the parameter block then the PB would be out of scope of the function. Once it is moved below then it is in scope.
I hope that we get to see the final results of your scripts.
luigi
06-30-2006, 12:33 PM
HI this thread is becoming quite interesting.
i have a question for you guys . I am a good fun of naming convention and a fun of using node so your script are not name dependens.
But i will like to know if for example for hide or unhide , if you are dealing with a massive group of objects doing it by weak referencing or selected by node will make the thinks work slow ? is not to much time consuming setup of the node and store them in a object in your rig?
Is posible t o have a kind of array for nodes so you can ad or extract node to it and hide or unhide the entire array?
the way in doing know it know is by name convention adding letter at the end of the object thta tell me what properties the object have.
have A for animation h for hide and f for freeze.
So i have a floating script that help me managing the scene.If a keep to my name convention every knew character i do work perfectly and i dont need to setup and store all the nodes.
I work in a studio so i can keep my pipeline solid , what do you think is better do all in a way not depending of names or makes names solid and get advantage fo this.
If you have other ideas or workflow will be great to know about it.
I store every thing in my rigs as a weak reference. I store that data in a scripted modifier that is added to the rig. I then have the ability to group certain nodes and have properties for them. This is my version of the character node but mine is completly flexable. As you add nodes to the system you can also flag what the mirror objects are and how they should be mirrored so that you can mirror animation and poses.
CGTalk Moderation
06-30-2006, 04:02 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.
vBulletin v3.0.5, Copyright ©2000-2012, Jelsoft Enterprises Ltd.