[Closed] Custom Attributes : Controller not updating
Hi,
If I assign a scripted controller to a custom attribute and add a node or track to it it doesn’t update the controller when I close the dialog.
If I assign the same scripted controller to a list controller in for example the X position of the object it does update and give me back some values…
So it seems that a controller in a custom attribute doesn’t get evaluated and so doesn’t do anything. I would rather not assign the script controller to a position controller via a list controller, cause it’s just messy… I want it to be in the custom attribute def and update constantly…
Any ideas?
-Johan
You basically want to control the object with the custom attribute indirectly – something you can do but maxhelp advises against it. This is the staple of dynamic systems because a lot of the time you need a external variable to check against and update if need be – the way i handle this is with a struct variable. But you’d have to bake the keys of the object your controlling into actual keys – else the rendering will be screwed up.
i.e when an object is controlled in-directly with a script controller your syncing issues with playback, rendering, anim preview etc.
If you want something in the def, either use a callback or use an script_controller on another object indirectly. Be warned though as you might get rendering/playback oddities.
If its a slider or a spinner why not just instance the controller between the two? or use wireparams?
Well all I want is to call a function defined in a CA from a script controller preferably in the same CA… to keep it tidy… I can add a script controller to a position controller but it’s sooo messy I think… and I definetly not what I want although it works…
I figured that if a script controller gets a animated track or node assigned it would pick up on the updates… but that’s not true it seems… the track holding the script controller needs to be in the validate loop as well it seems… hope you get my drift…
So basicly I have everything working but now I want that a scripted controller in a CA gets updated the same as it would be on a position track.
Otherwise I would have to do some checking if a controller is already in place etc… and cleanup… now I can easily just remove the attribute holder and all is clean again…
-Johan
you need to add a maxObject as a variable that will be a trigger to update the controller…
ie you want to use have it so whenever you scale sphere01 the controller updates
you can add sphere01 as a node or you could add the scale controller as a target (not an object as it wont cause updates)
it will then update when you affect the added maxobject
mark
I tried that but it doesn’t evaluate on rendertime…
Here’s a code example of what I try to do
(
-- Use box in this example
o = box()
o.position =[random -20 20, random -20 20, 0]
p = plane()
with animate on
(
at time 0 p.pos = [0,0,0]
at time 100 p.pos = [0,0, random 40 60]
)
-- Define the customAttribute structure
local lDef = attributes lAttributes
(
parameters lControls
(
refNode type:#maxObject
Updater type:#float
)
fn changeHeight =
-- Do something
(
obj = this.refNode.node
with animate off --don't want no animation keys!
obj.height = currenttime as integer / TicksPerFrame
)
)
-- The players
local em = (emptyModifier())
local fs = (float_script())
-- Add everything together
addModifier o em
custAttributes.add em lDef
-- Custom Attribute assign
o.attribute_holder.refNode = nodeTransformMonitor node:o forwardTransformChangeMsgs:false
-- Script Controllers assign
/*-- Doesn't work at all...
o.attribute_holder.Updater.controller = fs
*/
-- doesn't work on rendertime....
o.position.z_position.controller = fs
-- Float script settings
fs.addObject "dummy" p
fs.addNode "ref" o
fs.script = "ref.attribute_holder.changeHeight();
0;"
-- CODE THAT FAILS
/*
"
local refsArray = refs.dependents this
local ref = for i in refsArray where superClassof i == AttributeDef collect i
if ref.count >= 1 then
(
ref[1].changeHeight()
)
0
"
*/
)
As you can see it works in the viewport… but when rendering a sequence it doesn’t show or stays a height=0.
Now if you uncomment the
o.attribute_holder.Updater.controller = fs (line 44)and comment out the line below, you get the situation that I’m after… I want the script controller to be contained in the CA (everything in one place).
I only added the animated plane to act as an event for the script controller, but that doesn’t do anything…really…
But right now nothing works… can it be done… why isn’t the scriptcontroller updating on rendertime etc?
Thanks, if anyone has a clue…
-Johan
This is what i said. Why not use a callback, or a transform change handler?
Its like this your driving a car by telling it where to go, now when it comes to rendering it has no one to tell it where to go. Because the viewport update did it before.
Putting the controller on the attribute makes a firm link, and not a refresh-driven link, if you can call it that.
Thanks all, I guess I will try callbacks or change handlers…
Eek, I now know it works like this, but you agree this is not what you would expect… if I put an script controller with a node reference in it (needed to update the controller via the nodetransformmonitor right!?) you would expect the controller to update…
Why I don’t want it, as I stated, is that I like the idea of a contained object (attribute holder+CA’s) to quickly do things and easily delete it without having to take care of extra objects or controller or callbacks or any other garbage collections… but so now we agree it’s bugged, or at least doesn’t work as expected, I think I will go for a callback or change handler… sadly…
Thanks all,
-Johan
as far as I see, marktsang, your solution does not seem to work, except if you use UI for the custom attribute, and only if the modify panel/or dialog containing the rollout is active.
In any case, I think that the only controller that sends the needed messages is the transform contorller and subcontrollers, any other parameters in the scene like CAs, are mute, unless you make them talk
The only simple solution I can think, would be to create a script controller inside the scale controller, or similar controller, that sends messages to other script controllers, hence those update:
forceupdate1.value = forceupdate1.value
forceupdate2.value = forceupdate2.value
where forceupdate is a variable containing the script controller inside the CA
I suppose you can create a central node, that updates several different CAs in the scene
or something like that
Is it me or is that really not the way you want to use this sort of stuff… I wonder if this is by design… cause I don’t get it. I only want a controller (inside a CA) that evaluates every frame… I shouldn’t be building a network of controllers to pass a message around or should I…
Does anyone else have similar experiences?
-Johan
it does look like the script controller within a custom attribute block simply doesn’t get evaluated when the time changes (be it viewport or render).
The basic minimum should be…
test_ca =
attributes test_ca version:1 attribID:#(0xdeadbeef, 0xbaadf00d) (
parameters prams (
test type:#float animatable:true
)
)
custAttributes.add $ test_ca -- $ here is some object
$.test.controller = float_script()
$.test.controller.script = "displayTempPrompt ((random 1.0 100.0) as string) 500;1.0"
…but alas, it’s not. Adding a variable to the controller that points to the node, using that variable in the script, using the ‘F’ (frame) variable in the script, etc… no go.
I call ‘bug’ unless it is indeed by design (can’t imagine why, though)
I’m guessing this is a bug as I have tried everything to get it to update and it will not. I even tried dependsOn and still that did not force an update.