[Closed] Limiting updates for script controllers?
I’ve been messing around with script controllers, and have found that they tend to update a bit more often than is actually necessary. I’m concerned that a scene with a lot of them could end up getting really sluggish. Take the following as an example of what I mean about unneccesary updating:
b = box pos:[1, 0, 0] length:1 width:1 height:1
theScaleScript = Scale_Script()
b.scale.controller = theScaleScript
theScaleScript.addTarget "posX" $Box01.pos.controller.X_Position.controller
dyn_Script = stringstream ""
format "format \"\%\
\" posX
" to:dyn_Script
format "
" to:dyn_Script
format "b.lengthSegs = posX
" to:dyn_Script
format "b.widthSegs = posX
" to:dyn_Script
format "b.heightSegs = posX
" to:dyn_Script
format "[posX, posX, posX]" to:dyn_Script
dyn_Script = dyn_Script as string
theScaleScript.script = dyn_Script
This only needs to be updated when the x position of the box is changed, but you can see from the output to the listener that the script is called any time a change is made to the position or rotation of the box (selecting scale crashes Max, at least for me).
Is there a way to set the script controller to update only on a change in the x position? Maybe even just some way to check if the value has changed, and if it hasn’t to skip the rest of the script?
Couldn’t you store a constant on the script controller, and put the code inside an if statement that only executes when the stored constant value is different from the value you are checking. So:
if someStoredConstant != thebox.pos.x then
(
someStoredConstant = box.pos.x
doSomething()
)
I managed to get something that does what I want. I don’t know if it is the most efficient way to do it, but it could save time for more complex script controllers.
I couldn’t figure out a way to define a variable from within the controller that would save a value (I guess it would have to be outside the scope of the controller), so I’m currently using the helper as a workaround.
If anyone can show me a better way to do this, I would be very appreciative!
b = box pos:[1, 0, 0] length:1 width:1 height:1
p = point size:1
theScaleScript = Scale_Script()
b.scale.controller = theScaleScript
theScaleScript.addTarget "posX" $Box01.pos.controller.X_Position.controller
theScaleScript.addTarget "pointX" $Point01.pos.controller.X_Position.controller
dyn_Script = stringstream ""
format "if posX != pointX do
" to:dyn_Script
format "(
" to:dyn_Script
format "format \"\%\
\" posX
" to:dyn_Script
format "
" to:dyn_Script
format "b.lengthSegs = posX
" to:dyn_Script
format "b.widthSegs = posX
" to:dyn_Script
format "b.heightSegs = posX
" to:dyn_Script
format "$Point01.pos.controller.x_position = posX
" to:dyn_Script
format ")
" to:dyn_Script
format "[posX, posX, posX]" to:dyn_Script
dyn_Script = dyn_Script as string
theScaleScript.script = dyn_Script
OLD:
Sorry, a constant wouldn’t work for what I need. I do want the script to be called any time the X position is changed, not only when it is different from a particular set value.
Hi Kevin!
I’ve had problems with something similar.
Test this; Unckeck “Time Configuration” / “realtime” and ALSO “Loop” and then set your time timeline to say 0-10 frames. Go to beginning of timeline, clear listener, press play.
You should see 10 print outs of format by your script…
Put “Realtime” back on, and press play. You’ll get twice or triple the amount of formats…
So i don’t have answer for this, only have noticed this. Maybe script controller tries to update as often as it can or something. Same goes for transformations. Rotation will trigger update as much as move. I haven’t found anything in docs, but then again, haven’t had time to dig into this.
For storing data, you could try storing values to a variable inside custom attribute:
-- Create a Custom Attribute
aCA = attributes data
(
-- Variable to store something "permanently"
local vala = 0.0
-- Do something
fn test =
(
)
-- Empty on purpose
parameters main
(
)
)
-- Add to your base object or modifier...
CustAttributes.add $.modifiers[1] aCA #Unique BaseObject:false
-- Get or set value
$.modifiers[1].data.vala
$.modifiers[1].data.vala = 5.0
I hope this helps a bit! Seems like there is no easy way to control how many times script controller will update for a frame, but maybe i’m wrong!
I think max is not implemented that way, it should, if script controller would allow the creation of keys, that would be a mess. but your script controller is going to be evaluated anyways, even if you think it is not
@S_S1
when realtime is active, and max is playing… max uses ticks, so it is indeed evaluating more times I suppose to make it fluid
when realtime is off it only uses frames.
when the timeslider is dragged it always uses frames
some notes…:
controllers depends on the matrix itself, so scale and rotation are tied anyway, but :
when a frame is evaluated position is evaluated first then rotation then scale
POS ROT SCALE controllers (always in that order)
but subanims X Y Z themselves are evaluated always no matter tha axis you move(tied)
when the max scale tool is active, the object selected, and scale controller has no subanims, the transform gizmo is visible and the mouse is over it: the scale controller is evaluated (it should not, a bug?)
if a controller has subanims (ie: POS X Y Z) max does evaluate those but not the subanims of other controllers (ie: ROT XYZ or SCALE XYZ)
subanims behabes like max hierarchies, “Linked”.
In a Hierarchy, max gives priority to the parent, and childs tend to jump evaluations, it may happen something similar with controllers