I'm writing a script to make playblast (animation preview) via OpenGL render. I want to start play back rendered frames right after rendering is done. How I can do it? For now my code looks like this =)

#start opengl render


#play rendered sequence
  • 1
    $\begingroup$ doesn't it already work if you call both operators subsequently? Scripts run blocking usually, waiting for every command to finish and freezing the UI until script is done. $\endgroup$
    – CodeManX
    Nov 10, 2013 at 23:11
  • $\begingroup$ By the way that should be bpy.ops.render.play_rendered_anim(), with parentheses for the method call. $\endgroup$
    – wchargin
    Nov 11, 2013 at 3:11
  • $\begingroup$ @WChargin: You're right, thanks! I'll edit my post. $\endgroup$ Nov 11, 2013 at 18:45

1 Answer 1


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'}


            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
        self.timer = wm.event_timer_add(2.0, context.window)
        bpy.ops.render.opengl('INVOKE_DEFAULT', animation=True)

        return {'RUNNING_MODAL'}

def register():


I'd be very glad if a cleaner solution is available, but haven't found it so far.

  • $\begingroup$ What if your render has a giant black section in the middle? $\endgroup$
    – wchargin
    Nov 11, 2013 at 3:12
  • $\begingroup$ @WChargin: I don't know what you mean by black section. The operator only monitors the file resulted by the render process, so it's only sensitive to the scene's render output format, not to any content of the scene itself. $\endgroup$
    – Adhi
    Nov 11, 2013 at 3:20
  • $\begingroup$ right, but by default the file is all black (or all transparent, I'm not sure), so if there's a large section that's all black (or all transparent) the file size won't change while it's rendering. $\endgroup$
    – wchargin
    Nov 11, 2013 at 15:27
  • $\begingroup$ Have you tried the operator and getting such result? Even if the latest image in the video file doesn't change, frame count does, and it should affect file size. But if it really happen, one could compare st_mtime (modification time) instead. st_size suits the purpose of animation preview. $\endgroup$
    – Adhi
    Nov 12, 2013 at 2:05
  • $\begingroup$ Would the bpy.app.handlers.render_complete callback (blender.org/documentation/blender_python_api_2_67b_release/…) work for this? Or is that limited to still renders? $\endgroup$
    – Mike Pan
    Nov 13, 2013 at 7:27

You must log in to answer this question.

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