9
$\begingroup$

I've attached a function to the frame change handler:

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

All works fine when I drag the slider on the Timeline. But when I render with the "Animation" button, it doesn't work. I found that:

  1. Blender offers only a limited set of API functions while rendering. (See also the answer by Jerryno to another question: Accessing screen areas from render handler) Is there any form of documentation, why this is the case and which functions can be accessed while rendering, and which cannot?

  2. Blender doesn't wait for a script updating the scene before it advances to render the next frame. Is there by chance a API call that makes Blender wait for a script to finish before rendering on?

If the answer to both questions is "no", is there maybe a script that offers animation rendering with manual frame advance, like this:

  1. Render the first frame, apply postpro etc, write it to correct file name
  2. Go back to the viewport, advance a frame
  3. Render next frame, apply postpro* etc...

*With postpro(duction) I mean apply everything what the compositor would do in the the regular rendering pipeline, if compositing is switched on.

$\endgroup$
  • 2
    $\begingroup$ I believe the answer is no to both. A custom render script that advances frame by frame should be fairly easy to do (standard operator with a for loop that calls Scene.frame_set() and bpy.ops.render.render()), but there could be some performance implications. $\endgroup$ – CoDEmanX Aug 2 '15 at 9:29
  • $\begingroup$ @bortran Please give an example, what do you mean by 'postpro' exactly (color grading, adding a watermark, cropping the render...) For CoDEmanX's suggestion, you can find an example script here: blender.stackexchange.com/questions/1718/… $\endgroup$ – p2or Aug 2 '15 at 12:20
  • $\begingroup$ Wouldn't it make more sense to render all frames from the viewport, then import them into the compositor as an image sequence and render them all out again? (You can automate that one too if you need to) $\endgroup$ – TLousky Aug 29 '15 at 9:24
  • $\begingroup$ @TLousky well, that was never the point. I don't know why someone edited my question like that, but the point was to be able to execute custom python operations between rendering frames of an animation, and the trouble that brings. Like Render Animation -> Frame 1 finished -> frame_change_pre triggers -> my python script moves an object -> Frame 2 starts rendering with that changes. Which doesn't work. $\endgroup$ – bortran Sep 1 '15 at 8:26
  • 1
    $\begingroup$ @poor No problem, man. I must admit I'm not yet used to all functionality of stackexchange and also sometimes I fail to express my question or answer clearly, cause I'm not a native english speaker. Nevermind! ;) $\endgroup$ – bortran Sep 2 '15 at 7:49
1
$\begingroup$

You can loop through frames and render each one and do whatever you want before rendering the next one like this:

import bpy

s=bpy.context.scene

s.render.resolution_x = 512 # just for my example
s.render.resolution_y = 512

for i in range(s.frame_start,s.frame_end):
    s.frame_current = i

    s.render.filepath = (
                        "C:\\temp\\" # some path
                        + str(s.frame_current ).zfill(3)
                        )
    bpy.ops.render.render( #{'dict': "override"},
                          #'INVOKE_DEFAULT',  
                          False,            # undo support
                          animation=False, 
                          write_still=True
                         )

    # Do whatever you want here
    # Changing render resolution is one of the things imposible to do with
    # handlers while rendering an animation so let's do that

    if s.render.resolution_y == 512:
        s.render.resolution_y = 256
    else:
        s.render.resolution_y = 512

The problems start if you want to see the render happening in the UI. If you uncomment 'INVOKE_DEFAULT' it breaks everytihing because the script is unable to know when the started render finishes. People have tried to work around that, but things get ugly from here. See this question if you want to pursue this.

$\endgroup$
0
$\begingroup$

Assuming you have the handler written, and that it works manually, I was able to solve your issue using the code below in a separate script.

import bpy
bpy.data.scenes['Scene'].render.filepath = '/Users/.../MyImages'
bpy.context.scene.frame_current = bpy.context.scene.frame_start
bpy.ops.render.render(animation=True)
$\endgroup$
  • 1
    $\begingroup$ I fail to see how this has anything to do with answering the question. Did you test your solution? Am I missing something? This does not change Blender's behavior while rendering animations in any way. $\endgroup$ – Martin Z Oct 30 '18 at 21:46

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.