6
$\begingroup$

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
bpy.ops.render.opengl(animation=True)

### TODO: WAIT UNTILL RENDERING IS DONE

#play rendered sequence
bpy.ops.render.play_rendered_anim()
$\endgroup$
  • 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 '13 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 '13 at 3:11
  • $\begingroup$ @WChargin: You're right, thanks! I'll edit my post. $\endgroup$ – Roman Volodin Nov 11 '13 at 18:45
6
$\begingroup$

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.

$\endgroup$
  • $\begingroup$ What if your render has a giant black section in the middle? $\endgroup$ – wchargin Nov 11 '13 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 '13 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 '13 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 '13 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 '13 at 7:27

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.