I have an idea about some mini-challenge… Working with one of my projects I found that to collect all animated nodes in a scene is not a trivial task.
First is it’s not easy to find all animated things of the node.
Second is it’s not easy to do it fast and complete.
Are you interested in this challenge? I can give a test scene for the playing… Do you wanna play?
Mini-Challenge #5. Are you ready?
I’m trying to think of a quick way of doing this and all I can come up with is horrible loops within loops.
Sounds like a good challenge. I’m in
Great! We have a company!
Here is a test scene:
(
seed 0
delete objects
smat = Standard()
cont = Bezier_Float()
addnewkey cont 50f
smat.opacity.controller = cont
mmat = MultiMaterial numsubs:2
mmat[2] = smat
attr = attributes attr
(
parameters params
(
value type:#float
)
)
modi = NoiseModifier()
modi.scale.controller = cont
text = Noise()
text.size.controller = cont
empt = EmptyModifier()
custattributes.add empt attr
empt.attr.value.controller = cont
cmat = Standard()
custattributes.add cmat attr
cmat.attr.value.controller = cont
mats = #(smat, mmat, Standard diffusemap:text, cmat, Standard(), Standard())
nodes = for k=1 to 1000 do
(
b = box()
if (random 1 10) < 5 do b.mat = mats[random 1 mats.count]
if (random 1 10) < 3 do b.controller.pos.controller[1].controller = cont
if (random 1 10) < 2 do addmodifier b modi
if (random 1 10) > 8 do addmodifier b empt
if (random 1 10) > 9 do
(
custattributes.add b attr baseobject:on
b.baseobject.value.controller = cont
)
if (random 1 10) < 2 do
(
custattributes.add b attr baseobject:off
b.value.controller = cont
)
if (random 1 10) > 7 do b.width.controller = cont
if (random 1 10) < 1 do
(
converttomesh b
animatevertex b #all
addnewkey b.baseobject[#master_point_controller].vertex_1.controller 40f
)
)
gc()
)
there are only 1000 nodes… but to get all animated ones takes … I don’t tell how long it takes. Just try and see.
The animated node is any node that has any related animated track.
The animated track is a track that has a key.
Here is a life situation: select all animated nodes to move/scale all their keys …
It’s pretty usual, isn’t it?
But before doing this just try to find all animated nodes
try to cover at least all types/kinds of animation that I give in the test.
but the main idea is to find any source of animation…
here is a reference point (my version):
(
t1 = timestamp()
m1 = heapfree
a = findAnimatedNodes()
format "nodes:%
time:% memory:%
" a.count (timestamp() - t1) (m1 - heapfree)
)
/* result is:
nodes:753
time:244 memory:1704L
*/
my first attempt was ~1.5 sec to get them all…
~15 secs for 10,000 nodes is VERY slow. I was really shocked.
~2.5 secs is still slow. But hopefully we will find a better solution.
here are some numbers (not 100% sure that I’m right):
only transform animation: 183
only modifiers animation: 111
only material animation: 197
…
Hmm this is proving to be pretty difficult. There are so many damn properties to check!!
So far I have a function that checks for baseObject properties, modifier properties and controllers (recursively). I still need to add materials but this is quite tricky.
Results:
nodes:499
time:94 memory:39544L
P.S. I’m a little unsure what the memory usage means. Is this the memory consumed by the function during processing? In bytes or kb, or something else?
you are in very good speed and in good memory usage. i don’t think that the memory leaking is an issue of this challenge. but it’s a right practice to check the memory usage. when you call any of your functions you have to be sure that the function will complete before it eats all memory and crashes the system.
How to check if there is animation on an object?
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
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!
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…
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?