I try to render with freestyle wireframe, so i use mark_freestyle_edge in my script. But when i create after-render handler and try to clear marked edges i get that error: bpy.ops.object.mode_set.poll() failed, context is incorrect… How to fix it?
Here is part of my code:
@persistent
def onRenderFinished(scene):
objects = bpy.context.scene.objects
for object in objects:
for i, l in enumerate(bpy.context.scene.layers):
if object.layers[i] == True and object.layers[i] == l:
if object.type == "MESH":
bpy.context.scene.objects.active = object
bpy.ops.object.mode_set(mode='EDIT') <b># ERROR DISPATCHES HERE</b>
bpy.ops.mesh.mark_freestyle_edge(clear=True)
bpy.ops.object.mode_set(mode='OBJECT')
return
class WRender(bpy.types.Operator):
def execute(self, context):
objects = bpy.context.scene.objects
for object in objects:
for i, l in enumerate(bpy.context.scene.layers):
if object.layers[i] == True and object.layers[i] == l:
if object.type == "MESH":
bpy.context.scene.objects.active = object
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.mark_freestyle_edge(clear=False)
bpy.ops.object.mode_set(mode='OBJECT')
renderCompleteHadler = bpy.app.handlers.render_complete
global onRenderFinished
if onRenderFinished not in renderCompleteHadler:
renderCompleteHadler.append(onRenderFinished)
bpy.ops.render.render('INVOKE_DEFAULT')
return {'FINISHED'}
def register():
bpy.utils.register_class(WRender)
def unregister():
bpy.utils.unregister_class(WRender)
if __name__ == "__main__":
register()
import bpy
# add menu and button in toolprops region
class ToolPropsPanel(bpy.types.Panel):
bl_label = "my Buttons in Tool props"
bl_space_type = "VIEW_3D"
bl_region_type = "TOOL_PROPS"
def draw(self, context):
self.layout.operator("clear.mark_freestyle_edge")
def onRenderFinished(scene):
objects = bpy.context.scene.objects
bpy.ops.object.select_all(action='DESELECT')
return # dummy, pass rest of pard of program for testing
for object in objects:
for i, l in enumerate(bpy.context.scene.layers):
if object.layers[i] == True and object.layers[i] == l:
if object.type == "MESH":
bpy.context.scene.objects.active = object
print("Before error")
object.select = True
print(object.name)
bpy.ops.object.mode_set(mode='EDIT') # ERROR DISPATCHES HERE
print("After error")
bpy.ops.mesh.mark_freestyle_edge(clear=True)
bpy.ops.object.mode_set(mode='OBJECT')
return
class onRenderFinished(bpy.types.Operator):
bl_label = "RenderFinished"
bl_idname = "on_render.finished"
def execute(self, context):
objects = bpy.context.scene.objects
bpy.ops.object.select_all(action='DESELECT')
for object in objects:
for i, l in enumerate(bpy.context.scene.layers):
if object.layers[i] == True and object.layers[i] == l:
if object.type == "MESH":
bpy.context.scene.objects.active = object
print("Before error")
object.select = True
print(object.name)
bpy.ops.object.mode_set(mode='EDIT') # ERROR DISPATCHES HERE
print("After error")
bpy.ops.mesh.mark_freestyle_edge(clear=True)
bpy.ops.object.mode_set(mode='OBJECT')
return {'FINISHED'}
class WRender(bpy.types.Operator):
bl_label = "Clear Mark freestyle edge"
bl_idname = "clear.mark_freestyle_edge"
def execute(self, context):
# only set edge select mode on for mesh edit
bpy.context.tool_settings.mesh_select_mode = [False, True, False]
objects = bpy.context.scene.objects
for object in objects:
for i, l in enumerate(bpy.context.scene.layers):
if object.layers[i] == True and object.layers[i] == l:
if object.type == "MESH":
bpy.context.scene.objects.active = object
object.select = True
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.mark_freestyle_edge(clear=False)
bpy.ops.object.mode_set(mode='OBJECT')
object.select = False
renderCompleteHadler = bpy.app.handlers.render_complete
global onRenderFinished
if onRenderFinished not in renderCompleteHadler:
renderCompleteHadler.append(onRenderFinished)
bpy.ops.render.render('INVOKE_DEFAULT')
bpy.ops.on_render.finished() # directly execute
return {'FINISHED'}
def register():
bpy.utils.register_class(WRender)
def unregister():
bpy.utils.unregister_class(WRender)
if __name__ == "__main__":
bpy.utils.register_class(onRenderFinished)
# register menu and button
bpy.utils.register_module(__name__)
executes directly after render starts, without waiting for its completion, all freestyle marked edges clears before render finised and so dont draws on render result. I need to clear freestyle marked edges after render completed otherwise i get wrong result - marked edges are not visible.
Korchy, you are right. Need a flag to indicate rendering is finished or not.
import bpy
import time
# add menu and button in toolprops region
class ToolPropsPanel(bpy.types.Panel):
bl_label = "my Buttons in Tool props"
bl_space_type = "VIEW_3D"
bl_region_type = "TOOL_PROPS"
def draw(self, context):
self.layout.operator("clear.mark_freestyle_edge")
def onRenderFinished(scene):
global render_finished
render_finished = True
print("render_finished", render_finished)
return # dummy, bypass rest of pard of program for testing
objects = bpy.context.scene.objects
bpy.ops.object.select_all(action='DESELECT')
for object in objects:
for i, l in enumerate(bpy.context.scene.layers):
if object.layers[i] == True and object.layers[i] == l:
if object.type == "MESH":
bpy.context.scene.objects.active = object
print("Before error")
object.select = True
print(object.name)
bpy.ops.object.mode_set(mode='EDIT') # ERROR DISPATCHES HERE
print("After error")
bpy.ops.mesh.mark_freestyle_edge(clear=True)
bpy.ops.object.mode_set(mode='OBJECT')
return
class onRenderFinishedNew(bpy.types.Operator):
bl_label = "RenderFinished"
bl_idname = "on_render.finished"
def execute(self, context):
objects = bpy.context.scene.objects
bpy.ops.object.select_all(action='DESELECT')
for object in objects:
for i, l in enumerate(bpy.context.scene.layers):
if object.layers[i] == True and object.layers[i] == l:
if object.type == "MESH":
bpy.context.scene.objects.active = object
object.select = True
print(object.name)
bpy.ops.object.mode_set(mode='EDIT') # ERROR DISPATCHES HERE
bpy.ops.mesh.mark_freestyle_edge(clear=True)
bpy.ops.object.mode_set(mode='OBJECT')
return {'FINISHED'}
class WRender(bpy.types.Operator):
bl_label = "Clear Mark freestyle edge"
bl_idname = "clear.mark_freestyle_edge"
def execute(self, context):
# only set edge select mode on for mesh edit
bpy.context.tool_settings.mesh_select_mode = [False, True, False]
objects = bpy.context.scene.objects
for object in objects:
for i, l in enumerate(bpy.context.scene.layers):
if object.layers[i] == True and object.layers[i] == l:
if object.type == "MESH":
bpy.context.scene.objects.active = object
object.select = True
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.mark_freestyle_edge(clear=False)
bpy.ops.object.mode_set(mode='OBJECT')
object.select = False
renderCompleteHadler = bpy.app.handlers.render_complete
global onRenderFinished
if onRenderFinished not in renderCompleteHadler:
renderCompleteHadler.append(onRenderFinished)
global render_finished
render_finished = False
print("render_finished", render_finished)
bpy.ops.render.render('INVOKE_DEFAULT')
while render_finished == False:
print("Waiting rendering")
print("render_finished", render_finished)
time.sleep(.200) # pause for a while (0.2 sec) to let render running
print("Do clear mark job after render_finished")
bpy.ops.on_render.finished() # directly execute
return {'FINISHED'}
def register():
bpy.utils.register_class(WRender)
def unregister():
bpy.utils.unregister_class(WRender)
if __name__ == "__main__":
bpy.utils.register_class(onRenderFinishedNew)
# register menu and button
bpy.utils.register_module(__name__)
Korchy, you are right. Need a flag to indicate rendering is finished or not. <br>
<br>
import bpy<br>
import time<br>
<br>
# add menu and button in toolprops region<br>
class ToolPropsPanel(bpy.types.Panel):<br>
bl_label = "my Buttons in Tool props"<br>
bl_space_type = "VIEW_3D"<br>
bl_region_type = "TOOL_PROPS"<br>
def draw(self, context):<br>
self.layout.operator("clear.mark_freestyle_edge")<br>
<br>
def onRenderFinished(scene):<br>
global render_finished #flag<br>
render_finished = True<br>
print("render_finished", render_finished)<br>
return # dummy, bypass rest of pard of program for testing<br>
<br>
objects = bpy.context.scene.objects<br>
bpy.ops.object.select_all(action='DESELECT')<br>
for object in objects:<br>
for i, l in enumerate(bpy.context.scene.layers):<br>
if object.layers[i] == True and object.layers[i] == l:<br>
if object.type == "MESH":<br>
bpy.context.scene.objects.active = object<br>
print("Before error")<br>
object.select = True<br>
print(object.name)<br>
bpy.ops.object.mode_set(mode='EDIT') # ERROR DISPATCHES HERE<br>
print("After error")<br>
bpy.ops.mesh.mark_freestyle_edge(clear=True)<br>
bpy.ops.object.mode_set(mode='OBJECT')<br>
return<br>
<br>
class onRenderFinishedNew(bpy.types.Operator):<br>
bl_label = "RenderFinished"<br>
bl_idname = "on_render.finished"<br>
<br>
def execute(self, context):<br>
objects = bpy.context.scene.objects<br>
bpy.ops.object.select_all(action='DESELECT')<br>
for object in objects:<br>
for i, l in enumerate(bpy.context.scene.layers):<br>
if object.layers[i] == True and object.layers[i] == l:<br>
if object.type == "MESH":<br>
bpy.context.scene.objects.active = object<br>
object.select = True<br>
print(object.name)<br>
bpy.ops.object.mode_set(mode='EDIT') # ERROR DISPATCHES HERE<br>
bpy.ops.mesh.mark_freestyle_edge(clear=True)<br>
bpy.ops.object.mode_set(mode='OBJECT')<br>
return {'FINISHED'}<br>
<br>
class WRender(bpy.types.Operator):<br>
bl_label = "Clear Mark freestyle edge"<br>
bl_idname = "clear.mark_freestyle_edge"<br>
<br>
def execute(self, context):<br>
# only set edge select mode on for mesh edit <br>
bpy.context.tool_settings.mesh_select_mode = [False, True, False]<br>
objects = bpy.context.scene.objects<br>
for object in objects:<br>
for i, l in enumerate(bpy.context.scene.layers):<br>
if object.layers[i] == True and object.layers[i] == l:<br>
if object.type == "MESH":<br>
bpy.context.scene.objects.active = object<br>
object.select = True<br>
bpy.ops.object.mode_set(mode='EDIT')<br>
bpy.ops.mesh.mark_freestyle_edge(clear=False)<br>
bpy.ops.object.mode_set(mode='OBJECT')<br>
object.select = False<br>
renderCompleteHadler = bpy.app.handlers.render_complete<br>
global onRenderFinished<br>
if onRenderFinished not in renderCompleteHadler:<br>
renderCompleteHadler.append(onRenderFinished)<br>
global render_finished<br>
render_finished = False<br>
print("render_finished", render_finished)<br>
bpy.ops.render.render('INVOKE_DEFAULT')<br>
<br>
while render_finished == False:<br>
print("Waiting rendering") <br>
print("render_finished", render_finished)<br>
time.sleep(.200) # pause for a while (0.2 sec) to let render running <br>
<br>
print("Do clear mark job after render_finished")<br>
bpy.ops.on_render.finished() # directly execute<br>
<br>
return {'FINISHED'}<br>
<br>
<br>
def register():<br>
bpy.utils.register_class(WRender)<br>
<br>
def unregister():<br>
bpy.utils.unregister_class(WRender)<br>
<br>
<br>
if __name__ == "__main__":<br>
bpy.utils.register_class(onRenderFinishedNew)<br>
# register menu and button<br>
bpy.utils.register_module(__name__)
Grammer, interesting decision. It works, but not the way i need - render process is not shown that case, only render result. If not to show render process bpy.ops.render.render(write_still=True) can be used. But i want to follow the rendering process - it is the main reason, i used bpy.ops.render.render(‘INVOKE_DEFAULT’).
Is it any other way to display render process with controlling its completion without using while loop?
Korchy, thank you for let me more about your program.
After checked Blender 2.72a source, knew that global flag ‘is_rendering’ is still True when a render complete handler is triggered. When ‘is_rendering’ is still True,context is not objects editing related. Editing can be done after rendering has finished and ‘is_rendering’ has turned False. Found’scene_update’ handler can be used. The temporary method summary:
add scene_update handler in render_complete handler, and
do objects editing in scene update handler.
As a result, there is no while loop and rendering process will be shown normally on screen.
Code is based on your original one. And for test convenient, panel and button are added.
# add menu and button in toolprops region
class ToolPropsPanel(bpy.types.Panel):
bl_label = "my Buttons in Tool props"
bl_space_type = "VIEW_3D"
bl_region_type = "TOOL_PROPS"
def draw(self, context):
self.layout.operator("clear.mark_freestyle_edge")
def onRenderFinished(scene):
# Rendering is finished, but the global flag 'is_rendering' is still True.
# let's put editing process into scene update handler list which will be
# executed after 'is_rendering' is False.
sceneUpdatePostHadler = bpy.app.handlers.scene_update_post
global onSceneUpdatePost
if onSceneUpdatePost not in sceneUpdatePostHadler:
sceneUpdatePostHadler.append(onSceneUpdatePost)
return
def onSceneUpdatePost(scene):
# scene update too often, to avoid run this handler more than once, remove it
global onSceneUpdatePost
bpy.app.handlers.scene_update_post.remove(onSceneUpdatePost)
print("Context mode:", bpy.context.mode)
objects = bpy.context.scene.objects
for object in objects:
for i, l in enumerate(bpy.context.scene.layers):
if object.layers[i] == True and object.layers[i] == l:
if object.type == "MESH":
print("Object:", object.name)
bpy.context.scene.objects.active = object
bpy.ops.object.mode_set(mode='EDIT') # ERROR DISPATCHES HERE
bpy.ops.mesh.mark_freestyle_edge(clear=True)
bpy.ops.object.mode_set(mode='OBJECT')
return
class WRender(bpy.types.Operator):
bl_label = "Clear Mark freestyle edge"
bl_idname = "clear.mark_freestyle_edge"
def execute(self, context):
objects = bpy.context.scene.objects
for object in objects:
for i, l in enumerate(bpy.context.scene.layers):
if object.layers[i] == True and object.layers[i] == l:
if object.type == "MESH":
bpy.context.scene.objects.active = object
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.mark_freestyle_edge(clear=False)
bpy.ops.object.mode_set(mode='OBJECT')
renderCompleteHadler = bpy.app.handlers.render_complete
global onRenderFinished
if onRenderFinished not in renderCompleteHadler:
renderCompleteHadler.append(onRenderFinished)
bpy.ops.render.render('INVOKE_DEFAULT')
return {'FINISHED'}
def register():
bpy.utils.register_class(WRender)
bpy.utils.register_class(ToolPropsPanel)
def unregister():
bpy.utils.unregister_class(WRender)
bpy.utils.unregister_class(ToolPropsPanel)
if __name__ == "__main__":
register()