AFAIK Blender still has no built-in facility to do this, without freezing the GUI. I was stuck with that problem before, and the hack I used in a production code is to query render result's filesize through os.stat
, and check it at an interval using a TIMER
event. If the size is unchanged from previous query, render is considered finished.
Querying filesize only works for video output; for image sequence output, try querying file count in the target directory. And depending on scene complexity, interval might need to be tweaked. Here's a sample code to test with:
import bpy
import os
class VIEW3D_OT_render_and_execute(bpy.types.Operator):
"""Render and Execute"""
bl_idname = 'view3d.render_and_execute'
bl_label = 'Render and Execute'
bl_options = {'REGISTER'}
prev_stat = None
timer = None
def modal(self, context, event):
if event.type == 'TIMER':
if not self.prev_stat:
self.prev_stat = os.stat(context.scene.render.filepath)
return {'PASS_THROUGH'}
cur_stat = os.stat(context.scene.render.filepath)
if self.prev_stat.st_size != cur_stat.st_size:
self.prev_stat = cur_stat
return {'PASS_THROUGH'}
context.window_manager.event_timer_remove(self.timer)
print("Render finished.") # POST-RENDER CODE HERE
return {'FINISHED'}
return {'PASS_THROUGH'}
def execute(self, context):
if context.scene.render.image_settings.file_format != 'FFMPEG':
self.report({'ERROR'}, 'Only works for video output.')
return {'FINISHED'}
wm = context.window_manager
wm.modal_handler_add(self)
self.timer = wm.event_timer_add(2.0, context.window)
bpy.ops.render.opengl('INVOKE_DEFAULT', animation=True)
return {'RUNNING_MODAL'}
def register():
bpy.utils.register_module(__name__)
register()
I'd be very glad if a cleaner solution is available, but haven't found it so far.
bpy.ops.render.play_rendered_anim()
, with parentheses for the method call. $\endgroup$