2
$\begingroup$

What I'm doing: Running a script from the Scripting workspace in Blender UI.

What the script does: There is a main 'for loop' that append objects one by one from another .blend file and render them individually.

What's my issue: Sometimes I want to stop a script before it end because I'm not happy with the renders. When a script is running you can't access Blender UI (it's basically frozen), therefore I have two options to stop it. Shutting down Blender or doing CTRL+C in the System Console. Shutting down Blender is annoying, and CTRL+C doesn't work when Blender is currently rendering (<- this is important!).

What I want to be able to do: I want to find a way to stop Blender from rendering in order to access Blender UI faster and make my adjustments before starting the script again.

Typical code line that handle my renders:

bpy.ops.render.render()

I'm not going to post any more code than that, the rest is irrelevant. If you are after the bounty just create a basic scene and render it from a script with the line above and see for yourself how the UI freeze and you can't do anything to stop the render.

$\endgroup$
  • 3
    $\begingroup$ Do you use a custom modal operator or do you just call bpy.ops.render.render()? Would be helpful to see your actual code. $\endgroup$ – p2or Feb 19 at 15:52
  • 1
    $\begingroup$ Isn't that you want to do, stop the current render? If that's not the case, please give a precise description of what you're trying to achieve and post the full code that performs the rendering, so we can give you a proper answer. $\endgroup$ – Robert Gützkow Feb 19 at 17:25
  • 1
    $\begingroup$ Generally it's not a good idea to call a modal operator from a modal operator, since it's not really supported, but an adjusted version of this answer should solve your problem. $\endgroup$ – Robert Gützkow Feb 20 at 12:17
  • 1
    $\begingroup$ Yeah, that's a better explanation @ArthurBlaquart In this case I think an even nicer approach would be linking the objects dynamically per frame, meaning that all the objects of another blend (or multiple blends) are displayed per frame in your pack shot blend/scene. Here you can find a first script to play with. Just specify an asset blend file, add a prefix to all objects you'd like to render (like "RNDR_Cube"), excute the script in your packshot blend and scrub through the timeline. Does that simplify your life? $\endgroup$ – p2or Feb 20 at 12:41
  • 2
    $\begingroup$ You can just set link to False to append the object, easy... I'm pretty sure that we can make it work better and there are a lot of things how we can improve your workflow. However, as already requested multiple times, we all need to know what you are doing in this case (limited by the operator). So what exactly is too crumbersome? How do you modify your objects? I suggest don't waste your (and our) time and tell us your 'holy secrets' in order to have a real conversation about the facts @ArthurBlaquart $\endgroup$ – brockmann Feb 21 at 11:29
2
+250
$\begingroup$

To my knowledge there isn't really a good way to do this from a single Blender process. But I will give a few suggestions how it can be done.

Option 1: Render in a subprocess

This can be done using render farm or net rendering software. The idea is that your master will then create the scene that needs to be rendered, save the scene to disk and use python to start a sub process to do the actual rendering.

Option 2: Construct the scene in a subprocess

A variant of the previous version where the master will create a python script with how to construct the scene and perform the rendering. You can then start blender as a subprocess to the the scene constructing + actual rendering. The subprocess can be stopped by python script.

Option 3: Sample Batch Rendering

With sample batch rendering you will render a number of samples. (15 for example) and after 15 samples when you want to continue you offset the seed and render the next 15 samples. and do that until all the samples have been rendered. During the rendering you can combine the renders using the compositor, python script or external image tool. You could also do that from a master blender process.

The open movie spring was rendered this way so at an early stage of rendering you could check if all textures could be found.

| improve this answer | |
$\endgroup$
  • 1
    $\begingroup$ As one of the most important operators (rendering the image), I think it really deserves some love. Actually it would already help if someone would implement a way to allow passing optional arguments for the frame or the file path. If we could avoid the modal operator (hack) would be brilliant, see how messy that is: blender.stackexchange.com/a/153254/31447 $\endgroup$ – brockmann Feb 21 at 11:19
1
$\begingroup$

In relation to this question: How to interrupt a rendering which is not displayed in the UI to interact with?

If it comes to stopping a batch render, I suggest you to not use the for loop, as it freezes the interface.

A nice way to do this is to use a modal. with timer event So you create a list of the objects to render, at each modal cycle you will render.render on the object in the list[0], then you will use to eliminate the object rendered with list.pop(0) and you will delete the object from the list, in the next cycle it will be examined if len (list)> 0 otherwise you will exit the modal. in addition in the modal you can insert if event.type in {'RIGHTMOUSE', 'ESC'}:           

This allows you to stop the modal loop, so it will stop your script, but it won't stop the last render it is running, but I'm sure what you are looking for is to stop the loop, so I think this answer could be useful.

This example replaces your loop loop, as the loop loop cannot be stopped, or at least it is an operation that I have never been able to do. So it will be all in the timer event, which will be ended when the list of objects to be rendered is empty. In addition, this method will leave the interface free and will not block it, like the request to your question.

import bpy

class ModalExample(bpy.types.Operator):
    """Operator which runs its self from a timer"""
    bl_idname = "object.modal_operator"
    bl_label = "Modal Timer Operator"

    _timer = None
    list= None

    def modal(self, context, event):

        if event.type in {'RIGHTMOUSE', 'ESC'}:   
            #stop with Esc or Rightmouse        
            self.cancel(context)
            return {'CANCELLED'}

        if event.type == 'TIMER':

            if len(self.list)>0:  #if obj in list go to render                      

                context.scene.render.filepath = '\\youpath'                                         
                bpy.ops.render.render(animation=False, write_still=True)                   

                self.list.pop(0)            
            else:
                #else stop 
                self.cancel(context)
                return {'CANCELLED'}

        return {'PASS_THROUGH'}

    def execute(self, context):

        self.list=[o for o in context.scene.objects] ##try to render by number of object in scene   

        self._timer = wm.event_timer_add(2, window=context.window)#You will be able to decide how many seconds the modal timer should run 
        wm = context.window_manager
        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def cancel(self, context):                
        wm = context.window_manager
        wm.event_timer_remove(self._timer)


def register():
    bpy.utils.register_class(ModalExample)


def unregister():
    bpy.utils.unregister_class(ModalExample)


if __name__ == "__main__":
    register()

    # test call
    bpy.ops.object.modal_operator('INVOKE_DEFAULT')

So in this modal you can insert your script, which does what it has to do, in this example it is only the basis of a burst render.

| improve this answer | |
$\endgroup$
-2
$\begingroup$

(if your on windows)

At the webiste of sysinternals you can find a tool to kill processes pskill.exe. And then run pskill.exe blender

Normally to run blender from console you only require a small commandline what i usually did when i had a lot of re-renders when things had to be adjusted, i made a small script that only outputed the command line based upon the allready logged frames, i only had top copy the line and alter the start frame.

My script also devided a job over multiple PC's, though i dont have the script anymore it be easy to create something alike it.

| improve this answer | |
$\endgroup$

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.