2
$\begingroup$

I am trying to batch render few sequence like 1 to 10 and then 30 to 50 but rendering stops after completing one sequence.

def execute(self, context):
    batcher = bpy.context.scene.batch_render
    sce = bpy.context.scene
    rd = sce.render
    batch_count = 0
    for it in batcher.frame_ranges:
        batch_count += 1
        print("***********")
        if (it.end_frame < it.start_frame):
            print("Skipped batch " + str(it.start_frame) + " - " + str(it.end_frame) + ": Start frame greater than end frame")
            continue
        sce.frame_start = it.start_frame
        sce.frame_end = it.end_frame

        sce.render.filepath = it.filepath

        bpy.ops.render.render('INVOKE_DEFAULT',animation = True)


    sum = 0
    for it in batcher.frame_ranges:
        if (it.end_frame >= it.start_frame):
            sum += (it.end_frame - it.start_frame)
    print("Rendered " + str(len(batcher.frame_ranges)) + " batches containing " + str(sum) + " frames")
    return {'FINISHED'}    

if I put this line:

bpy.ops.render.render('INVOKE_DEFAULT',animation = True)

then it renders only one batch

if I put this line :

bpy.ops.render.render(animation = True)

it renders all batch without any issue .. but it freeze blender and doesn't show render progress bar.

I want to see progress bar and do batch rendering.

$\endgroup$

1 Answer 1

3
$\begingroup$

I'd suggest using handlers for this task. Below is a script that adds a full set of render handlers, and prints the current frame (if possible) and name of the handler when that handler fires.

import bpy

frame_handlers = [name for name in dir(bpy.app.handlers)
                  ]
def handler_function(name):
    def handler(scene):

        print(f"{getattr(scene, 'frame_current', 'N/A')} : {name}")

    return handler


for name in frame_handlers:
    handler = getattr(bpy.app.handlers, name, None)
    if isinstance(handler, list):
        handler.clear() # clear first for testing
        handler.append(handler_function(name))

System console output for a 2 frame animation render, must have started render with current frame set at 0. (v 2.91)

0 : render_init
1 : render_pre
1 : frame_change_pre
1 : frame_change_post
Saved: '/tmp/0001.png'
 Time: 00:00.47N/A : render_stats
 (Saving: 00:00.03)

1 : render_post
1 : render_write
2 : render_pre
2 : frame_change_pre
2 : frame_change_post
Saved: '/tmp/0002.png'
 Time: 00:00.38N/A : render_stats
 (Saving: 00:00.02)

2 : render_post
2 : render_write
0 : render_complete
0 : frame_change_pre
0 : frame_change_post

Experiment and see the order the handers are called firing "render_init"... etc until, "render_compete"

Setting it up

In Operator execute, set the scene settings to first batch, call the render op and add the render_complete handler.

# add the handler.
   bpy.app.handlers.render_complete.append(render_complete)

The render complete handler

change scene settings to the next batch item and call render op again

You will need to keep tabs on which batch is rendered with an active_index property (or similar), (also handy for displaying the items in a UIList widget) Please note this is just code typed into answer and not tested.

def render_complete(scene):
    batches = scene.frame_ranges
    i = batches.active_index
    if i < len(batches) - 1:
        batch = batches(i+1)
        # set up scene 
        bpy.ops.render.render('INVOKE_DEFAUT', animation=True)
    else:
        #clear this hander
        bpy.app.handers.render_complete.remove(render_complete)

Experiment...

$\endgroup$
0

You must log in to answer this question.

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