Render Camera script: changing execution context breaks for-loop

Probably this has been discussed before, but I didn’t find any details. Ages ago I have pieced together a script to render all cameras in a blend to separate images. I create a lot of booths for trade shows and such stuff and it is just very convenient when I can place a few dozen cameras around an object and just hit render before going home, to find all perspectives rendered when I return. I have a script that does that quite nicely. It’s simple, it iterates through all cameras and just renders them to the output path of the file (adding the camera name to the filename).

However, there are times when I would like to see how far an image is rendered (or just check if I have made a fundamental mistake… once in the morning I found a bunch of renderings lit in bright pink because the environment map had been renamed)

So I would like to have the rendering progress displayed exactly as it is when just hitting F12. To do that I gathered that I would have to change the execution context from default “EXEC_DEFAULT” to “INVOKE_DEFAULT”. But when I do, only the first camera of the scene is rendered. For the other cameras the rendering command is just plainly skipped. I don’t see how this can be, as I see that the for loop does indeed loop through the cameras correctly.

Here is my code:

import os, bpy, bgl, blf, sys
from bpy import data, ops, props, types, context

# setup renderbutton for stills
class RenderAllCameras(bpy.types.Operator):
	bl_idname = "render_cams.button"
	bl_label = "All stills"

	def execute(self, context):
		print('')
		print('Rendering stills for all cameras...')
		renderStuff(False)
		return{'FINISHED'}

# setup renderbutton for animations
class RenderAllAnims(bpy.types.Operator):
	bl_idname = "render_anims.button"
	bl_label = "All animations"

	def execute(self, context):
		print('')
		print('Rendering animations for all cameras...')
		renderStuff(True)
		return{'FINISHED'}

# render scene from all cameras
def renderStuff(animToggle):
	# get current scene, renderpath/filename and active camera
	currentScene = bpy.data.scenes[bpy.data.scenes.keys()[0]]
	renderPath = currentScene.render.filepath
	previousCamera = currentScene.camera

	# Loop all objects and find Cameras
	for obj in currentScene.objects:
		# Find cameras
		if ( obj.type =='CAMERA') :
			print("Rendering camera ["+obj.name+"]")  
			print(bpy.context.scene.render.display_mode)
			# Set camera as active and create filename for image
			currentScene.camera = obj
			currentScene.render.filepath = renderPath+"_"+obj.name
			# Render cameraview
			#bpy.ops.render.render(animation=animToggle, write_still=True )#it works, but no preview, only progess in the console
			bpy.ops.render.render('INVOKE_DEFAULT', write_still=True)#only renders camera 1, all others are skipped

	# reset renderpath/filename and active camera
	currentScene.render.filepath = renderPath
	currentScene.camera = previousCamera
	print('Done!')
	
# add section to render-panel
class RenderAllCamerasPanel(bpy.types.Panel):
	bl_label = "Render all cameras"
	bl_space_type = 'PROPERTIES'
	bl_region_type = 'WINDOW'
	bl_context = "render"
	bl_options = {'DEFAULT_CLOSED'}
	
	def draw(self, context):
		layout = self.layout
		row = layout.row(align=True)
		col = layout.column(align=True)
		col.operator_context = 'INVOKE_DEFAULT'
		row.operator("render_cams.button",icon = 'RENDER_STILL')		
		row.operator("render_anims.button",icon = 'RENDER_ANIMATION')
		
# register the class
def register():
	bpy.utils.register_class(RenderAllCameras)
	bpy.utils.register_class(RenderAllAnims)
	bpy.utils.register_class(RenderAllCamerasPanel)

def unregister():
	bpy.utils.unregister_class(RenderAllCameras)
	bpy.utils.unregister_class(RenderAllAnims)
	bpy.utils.unregister_class(RenderAllCamerasPanel)

Calling with ‘INVOKE_DEFAULT’ is non-blocking - e.g. the call returns immediately. All the subsequent calls to render() will fail because the first render is still running.
https://developer.blender.org/T52258
You could try calling it the default way and log your progress (timestamp, camera n of n, frame n of n) to a textfile.

hi you can try:

  1. https://en.blender.org/index.php/Extensions:2.6/Py/Scripts/Render/Render_Shots

  2. https://en.blender.org/index.php/Extensions:2.6/Py/Scripts/Render/Cube_Map

  3. you can duplicate the scene with link objects and change the camera property of each scene, in composition node add a render layer for each scene and send node file output

  4. You can also animate a camera in constant mode and in each frame you change to the desired position

  5. Create a master camera and using a script in each frame copy the position of one of the cameras Array

  6. In VSE editor add multiple time a scene an use camera override property

  7. with renders layer:

    • in render layer active options Views
    • click option multi-view
    • uncheck default (left,right) (is important)
    • create a view for each camera and add suffix example _A, _B, _C…
    • in panel of properties of view 3D (key N) find stereoscopy and choose Views
    • Rename a cameras with suffix example camera_A, Camera_B, Camera_C…
    • in node editor choose composition node
    • check use nodes
    • add node file output (shift+A, Output, File output)
    • connect output image of render layer to input image of file output
    • render (F12)

can help you:
https://en.blender.org/index.php/Extensions:2.6/Py/Scripts/Render/Rename_Outputs
https://en.blender.org/index.php/Extensions:2.6/Py/Scripts/Render/Notify_after_render

and sorry me english