2
$\begingroup$

I have a simple script like this:

import bpy
frame = 0

def tester(scene):
    global frame
    frame = scene.frame_current
    print(frame)

bpy.app.handlers.frame_change_pre.append(tester)

It should print out the current frame. If I just play the animation, works as expected, but when I start rendering it gives back multiple numbers on each frame.

(I'm only using this script to demonstrate, the problem is occurring in a more complex script. But the anomaly is the same.)

I'm getting results during rendering like this:

1
0
1
1 
Saved: 'C:\......'
2
1
2
2
Saved: 'C:\......'
3
2
3
3
Saved: 'C:\......'

and so on...

Any guess why and how can I prevent this from happening? (I'm trying to insert an if statement that is prevening the recalculation of an already calculated frame, but this solution is way more hacky than it should be...)

$\endgroup$
0

2 Answers 2

3
$\begingroup$

Clean the handlers.

with no handlers appended at all, running question script will print the frame once.

There is only one function assigned

>>> for f in bpy.app.handlers.frame_change_pre:
...     f.__name__, f.__module__
...     
('tester', '__main__')

running question script three more times

>>> for f in bpy.app.handlers.frame_change_pre:
...     f.__name__, f.__module__
...     
('tester', '__main__')
('tester', '__main__')
('tester', '__main__')
('tester', '__main__')

will see frame printed 4 times. (One assumes you made an edit to get the -1)

Clear the handler.

Can clear all the functions assigned to a hander via

bpy.app.handlers.frame_change_pre.clear()  

to remove all the methods from each time you run script above.

Or iterate over appended funcions and remove those where f.__name__ == "tester" or by module if testing in text editor (__name__ == "__main__")

When a handler is assigned a method via an addon, it can be appended in the register and removed in the unregister. The namespace of the addon ensures its the same method both times my_addon.foo_function whereas when run from main thread "__main__.foo_function" is not seen as the same.

Example in console of removing any frame change pre handler function added via main thread.

>>> fs2remove = [f for f in bpy.app.handlers.frame_change_pre
...     if f.__module__ == "__main__"]

>>> fs2remove
[<function tester at 0x7ffac5165ca0>, <function tester at 0x7ffac51659d0>, <function tester at 0x7ffac5165d30>, <function tester at 0x7ffac5165550>, <function tester at 0x7ffac5165700>]
>>> while fs2remove:
...     bpy.app.handlers.frame_change_pre.remove(fs2remove.pop())
...     
>>> bpy.app.handlers.frame_change_pre[:]
[] 
$\endgroup$
0
2
$\begingroup$

At firts, thanks for the detailed answer, but the problem wasn't there. The scipt I've provided only creates 1 handler and it's fine. In my original script I've created a reset function too, that clears the app handlers if it's restarted or if it's already added. But I found the problem! --->IT WAS THE MOTION BLUR. The script was called multiple times as the motion blur needed the frame to be calculated multiple times. If I turn off motion blur, everyting calculates only once. Can we think of it as a bug? As I discovered, it also messes up other scripts that should run once on every frame

$\endgroup$
1
  • $\begingroup$ Motion blur is achieved by rendering intermediary frames and merging them together, so if you need to apply some script to e.g. update a position of something, if the script wouldn't run, the position wouldn't be updated and so the motion blur wouldn't work. $\endgroup$ Commented Feb 19, 2021 at 8:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .