[Closed] Wire,Script,Constraint,… which one is faster?
I always have problem with viewport refresh(fps) when i rig a complex character.Wire parameters,Script controller,Constraint controller,IK,… which one is faster? which one turns the rig to be a unassailable(heavy) rig?
When researching this myself I found a document someone had written performing speed tests on each option. I’ll try and find it when I get home as it was an interesting read, but it basically concluded to:
Wire Parameters > Fastest
Expression Controller > Fast
Script Controller > Slowest
It makes sense when you think about what max has to do regarding each solution. Wire params is much faster than expression/script due to it’s simplicity, so when you can get away with it try and use the ‘simplest’ solution.
http://forums.cgsociety.org/showpost.php?p=7229039&postcount=1
the ‘wire’ controller performance depends on complicity of the used expression. ‘wire’ expression is mxs kind. so it might make ‘wire’ the same slow as script controller. but usually people don’t use wiring with heavy expressions.
the simplest solution would be to use controller instancing, multiply curves and list controllers to create one way linear transformations like <controller A> = 2<controller B> + 3<controller C>. I use wire parameters only when I need a 2 way connection, expressions only when I need a more complicated equation and a script controller only when I need memory / history dependence or I need to access data that is only exposed through a script.
i've checked some of my "standard" human like rigs for controller usage. there is a result:
-- whole rig:
(class: bezier_float count:2197)
(class: prs count:284)
(class: Euler_XYZ count:276)
(class: bezier_scale count:266)
(class: Position_XYZ count:228)
(class: bezier_point3 count:206)
(class: Orientation_Constraint count:142)
(class: rotation_list count:123)
(class: rotation_ListDummyEntry count:123)
(class: Position_Constraint count:115)
(class: position_list count:75)
(class: position_ListDummyEntry count:75)
(class: Float_Expression count:70)
(class: boolean_float count:20)
(class: bezier_position count:17)
(class: IKControl count:16)
(class: float_list count:13)
(class: float_ListDummyEntry count:13)
(class: Scale_Wire count:12)
(class: IKChainControl count:8)
(class: Link_Constraint count:7)
(class: LinkTimeControl count:7)
(class: LookAt_Constraint count:5)
(class: bezier_color count:4)
(class: Float_Wire count:2)
(class: Master_Point_Controller count:2)
(class: Position_Expression count:2)
(class: Block_Control count:1)
(class: point3_list count:1)
(class: point3_ListDummyEntry count:1)
(class: point4_list count:1)
(class: point4_ListDummyEntry count:1)
(class: Reservoir count:1)
(class: scale_list count:1)
(class: scale_ListDummyEntry count:1)
(class: SharedMotionFlowsFloatController count:1)
-- animation part of rig:
(class: bezier_float count:1755)
(class: Euler_XYZ count:271)
(class: Position_XYZ count:223)
(class: bezier_scale count:176)
(class: prs count:176)
(class: rotation_list count:123)
(class: rotation_ListDummyEntry count:123)
(class: position_list count:75)
(class: position_ListDummyEntry count:75)
(class: Float_Expression count:70)
(class: Orientation_Constraint count:39)
(class: boolean_float count:20)
(class: bezier_position count:17)
(class: IKControl count:16)
(class: float_list count:13)
(class: float_ListDummyEntry count:13)
(class: Position_Constraint count:12)
(class: IKChainControl count:8)
(class: Link_Constraint count:7)
(class: LinkTimeControl count:7)
(class: LookAt_Constraint count:5)
(class: bezier_color count:4)
(class: Float_Wire count:2)
(class: Position_Expression count:2)
(class: Block_Control count:1)
(class: point3_list count:1)
(class: point3_ListDummyEntry count:1)
(class: point4_list count:1)
(class: point4_ListDummyEntry count:1)
(class: Reservoir count:1)
(class: scale_list count:1)
(class: scale_ListDummyEntry count:1)
(class: SharedMotionFlowsFloatController count:1)
As usual, denisT comes up with the gold
Thanks for posting the link, this is really interesting. It’s surprising just how memory intensive script controllers are.
I’ll try and find the document I was referring to when I get home as it has similar (yet far less extensive) results, and as you said maybe the wire param came out fast because a very simple expression was used.
This is the document I was referring to. It’s quite old now, but is still worth a read and has some interesting points:
it’s very old technique. weak reference to node solves all problems now. see the help Weak References To Nodes in the Expression/Script Controll
there is other illustration why you shouldn’t read or trust any ‘smart’ but ‘old’ tutorials:
delete objects
global source = dummy name:"source" boxsize:[20,20,20]
global target = dummy name:"target" boxsize:[10,10,10]
(
fn perform c type:"0" iterations:100000 =
(
t1 = timestamp()
m1 = heapfree
for k=1 to iterations do c.value
format "% >> time:% memory:%
" type (timestamp() - t1) (m1 - heapfree)
)
gc()
c = source.pos.controller = createinstance position_script
c.setexpression "dependson target; $target.pos"
perform c type:#path_script
targetCA = attributes targetCA
(
parameters main
(
target type:#node
)
)
c = source.pos.controller = createinstance position_script
custattributes.add c targetCA
c.target = target
c.setexpression "dependson target; this.target.pos"
perform c type:#ca_node_script
targetCA = attributes targetCA
(
parameters main
(
target type:#maxobject
)
)
c = source.pos.controller = createinstance position_script
custattributes.add c targetCA
c.target = NodeTransformMonitor node:target
c.setexpression "dependson this.target.node; this.target.node.pos"
perform c type:#ca_monitor_script
c = source.pos.controller = createinstance position_script
c.addnode "target" target
c.setexpression "target.pos"
perform c type:#node_script
c = source.pos.controller = createinstance position_script
c.addobject "target" target.pos.controller
c.setexpression "target.value"
perform c type:#track_script
c = source.pos.controller = createinstance position_expression
c.addvectornode "target" target
c.setexpression "target"
perform c type:#node_expression
c = source.pos.controller = createinstance position_expression
c.addvectortarget "target" target.pos.controller
c.setexpression "target"
perform c type:#track_expression
c = source.pos.controller = createinstance Position_XYZ
paramwire.connect target[#transform][#position] source[#transform][#position] "Position"
perform c type:#anim_wire
c = source.pos.controller = createinstance Position_Constraint
c.appendtarget target 100
perform c type:#track_constraint
c = source.pos.controller = target.pos.controller
perform c type:#track_instance
)
Love weekReferences, for the most part my rigs have wire params over anything else unless I am using some sort of matrix or vector math… then I use a script controller or expression. I am in no way saying this is the best way, but it is the way that works for me!
do you ask me about my favorite?
it’s expression controller for ‘one-way’ connection and wire controller for ‘two-way’.