Notifications
Clear all

[Closed] Mini-Challenge #5. Are you ready?

i know that anyone who works with animation sooner or later meets this task.
i’m not asking everyone for sharing the code (because it might be your personal treasure), but i appreciate the seeing your numbers to compare. thanks.

This is not the way to do it, but I’ll put it out there for people to rip on:


 (	
 	fn findAnimatedNodes =
 	(
 		clearListener()
 		select$*
 		sceneSelection = selection as array
 		arrAnims = #()
 		
 		for i=1 to sceneSelection.count do
 		(
 			local check = false
 			
 			for j=1 to 20 do (try(if (sceneSelection[i][3][j].keys != undefined) then (check = true))catch())
 			for j=1 to 20 do (try(if (sceneSelection[i][4][j].keys != undefined) then (check = true))catch())
 			for j=1 to 20 do (try(if (sceneSelection[i][5][j].keys != undefined) then (check = true))catch())
 			
 			if check == true then (append arrAnims sceneSelection[i])
 		)
 		
 		return arrAnims
 	)
 	
 	(
 		t1 = timestamp()
 		m1 = heapfree
 		a = findAnimatedNodes()
 		format "nodes:%
	time:% memory:%
" a.count (timestamp() - t1) (m1 - heapfree)
 	)
 	
 )
 

 nodes:1000
 time:585 
 memory:66176L
 

I’m sure this isn’t the way to do it, or if I’m even returning the array that you wanted denisT.
I’m interested in seeing other’s code

99ms
796 keyed nodes found

don’t know if I missed something…

1 Reply
(@denist)
Joined: 10 months ago

Posts: 0

you are not missing, you are finding more than me
which is absolutely possible.
and you do it very fast!

can you post at least the bitarray of keyed object index numbers?
like #{objects[n0],objects[n…], …}

(
	local ss = StringStream ""; showClass "*Float:*controller*"  to:ss; seek ss 0
	local clas = #()
	while not eof ss do append clas (execute (filterString (readLine ss) ":")[1])
	local sset = #()
	for c in clas do
	(
		local insts = getClassInstances c
		local keyed = for o in insts where o.keys.count > 0 collect o
		join sset keyed
	)
	local all = #()
	for c in sset do join all (refs.dependentNodes c)
	all = makeUniqueArray all
-- 	format "nodes: %
" all.count
)

– 104ms
– nodes found: 632

well denisT, now that I check, I forgot to make the array Unique.
tried to change the seed, but random always gives less than 700 keyed nodes

max TV has a option to display only animated tracks, but it misses a lot of tracks!

1 Reply
(@denist)
Joined: 10 months ago

Posts: 0

you check only float controllers, but it might be any type. in real life you don’t know which type of controllers are animated in the scene. so you have to check them all.

I was hoping to add to the list the missing/complex tracks, thinking that max has a fixed amount of controllers.

but your right, I’m gonna try something else, more like brute force…

 lo1

this is my attempt at thinking out of the $Box

(
	local ts = timestamp()
	local mem = heapfree
	global animatedNodes = #()
	
	fn myCallbackFilterFunction theAnimatable theParent theSubAnimIndex theGrandParent theNode = 
	(	
		if isController theanimatable and theanimatable.keys.count>0 then
		(
			appendIfUnique animatedNodes theNode
			false
		)
		else true
	)
	
	with redraw off
	(	
		trackbar.filter = #all
		local filtind = maxops.trackbar.registerFilter myCallbackFilterFunction undefined "." 1 active:on
		select objects
		maxops.trackbar.redraw forceRedraw:on
		maxops.trackbar.unregisterfilter filtind
		clearSelection()
		format "Time: %ms
" (timestamp()-ts)
		format "Memory: %
" (mem-heapfree)
		format "Nodes Found: %
" ((animatedNodes).count)
		ok
	)
)
Time: 132ms
Memory: 352L
Nodes Found: 753

Just to quickly clarify Denis,

The array of nodes that is output – are you looking for an array of every node and every material that has an animation, or every single value that is animated?

IE does the array contain:

#(box01, box02, box03)
or
#(box01 scale controller, box01transform controller, box02 rotate controller, box03 rotate controller)

I guess the second one would be more useful as you can have access to all keys very easily. Is this what you’re after?

1 Reply
(@denist)
Joined: 10 months ago

Posts: 0

the list of all animated controllers is more useful, but let’s talk now just about the list of animated nodes.

Hm, I wonder how we’ll look for correctness with such an unpredictable amount of animated nodes. I get 600 invariably but is that correct?

My function is not even optimized but the most interesting is, I think, after test it on different Max versions on my computer, I get so freakish and weird results:

Max 9 SP2 64: nodes:600 | time:8907 memory:4351776L
Max 2009 x32: nodes:600 | time:1922 memory:1520L
Max 2009 x64: nodes:600 | time:265 memory:105848L
Max 2011 x32: nodes:600 | time:688 memory:2712248L
Max 2011 x64: nodes:600 | time:516 memory:4877968L

So, as you see, its so easy to make wrong conclusions, and so difficult to reach meaningful conclusions.
Code optimization in Max is a (how to say…) pitfall (:

5 Replies
(@denist)
Joined: 10 months ago

Posts: 0

heh… max, max, max… 2011 is slower than 2009… show you method please … it will be very interesting to see the bottleneck

(@panayot)
Joined: 10 months ago

Posts: 0

ok, nothing special in my function, as i said its not ever optimized (:

fn GetSubAnimsTree obj &res = (
	for i = 1 to obj.numSubs do (
		append res obj[i]
		GetSubAnimsTree obj[i] res
	)
)
fn findAnimatedNodes = 
(
	local nCount = objects.count
	local index = #{1..nCount}
	for i = 1 to nCount do
	(
		local subA = #(), numK = 0
		GetSubAnimsTree objects[i] &subA
		for a in subA where isController a.track while numK == 0 do
			if (v = a.track.keys.count) > 0 do numK += v
		index[i] = numK > 0
	)
	for id in index collect objects[id]
)

…but still confusing results (from version to version), right? (:

(@denist)
Joined: 10 months ago

Posts: 0

it seems like [i]they[/i] broke something in recursive function method… it will be interesting to see the difference in 2010 and 2012… i can do it tomorrow… actually it’s already today

ps. don’t use [i] in code… it’s reserved for italic font.

(@denist)
Joined: 10 months ago

Posts: 0

i’ve tested it on 2010(64) and 2012(64).
it’s exactly the same time: 362
memory is slightly different: 129880L against 110664L

(@panayot)
Joined: 10 months ago

Posts: 0

well, excuse me for the ‘stupid’ question but did you perform gc() before each test?
also did you try the code in other versions and what you’ve get?

that was my plan for tomorrow, but you showed it first.
at first glance everything looks right and complete… using the method is also easy to collect keyed controllers as well.
can we filter only material or ca sources?

2 Replies
 lo1
(@lo1)
Joined: 10 months ago

Posts: 0

Seems you can do that by checking the superClassOf theGrandParent within the callback filter function. I haven’t verified that though.

(@denist)
Joined: 10 months ago

Posts: 0

no… in general case it will not work this way. the subanim depth might be deeper. probably we have to see dependents and filter them by superclass. but backward recursion will slow the method down dramatically.

OK thanks for the clarification.

This is what I came up with last night. Looking at the code this morning it looks like the wrong way to go about doing it, but it executes quite quickly I guess. Surely the best method is one that picks up every node even if it is very slow, and once we know the complete total number of animated nodes we can then optimise. It’s interesting that everyone is getting different totals!

Results:
nodes:499
time:65 memory:94872L



(
	
	
	local animatedNodes = #()
	local found = false
	
	
	--Recursively work through object controllers to find any keys
	function findCtrlKeys obj index = (
		if obj.controller[index].keys.count > 0 then (
			append animatedNodes obj
			found = true
		)
		else (
			if obj.controller[index+1] != undefined and not found do findCtrlKeys obj (index+1)
		)
	)

	
	--Main function
	function findAnimatedNodes = (
	
		--Loop through all nodes
		for a in $* do (
			
			found = false
			
			--Find any keys in object controllers
			findCtrlKeys a 1
			
			--Find any keys in object base properties
			if not found do (
				propNames = getPropNames a
				for b in propNames while not found do (
					ctrl = (getPropertyController a.baseObject b)
					if ctrl != undefined do if ctrl.keys.count > 0 do (
						append animatedNodes a
						found = true
					)
				)
			)
			
			--Find any keys in object modifier properties
			if not found do (
				for b in a.modifiers do (
					propNames = getPropNames b
					for c in propNames while not found do (
						ctrl = (getPropertyController b c)
						if ctrl != undefined do if ctrl.keys.count > 0 do (
							append animatedNodes a
							found = true
						)
					)
				)
			)
			
		)
		
		--Loop through all materials
		--Add recursive function here
		
		return animatedNodes
		
	)
	
	
	--Run Function with timestamp
	t1 = timestamp()
	m1 = heapfree
	a = findAnimatedNodes()
	format "nodes:%
	time:% memory:%
" a.count (timestamp() - t1) (m1 - heapfree)
	
)

Page 2 / 5