Skip to main content
added 188 characters in body
Source Link
Carneiro
  • 91
  • 1
  • 4

Although the question is already old, can help more developers.
You can create a modal operator and check the state of the 'is_dirty' property of the image.

import bpy

class ModalTimerOperator(bpy.types.Operator):
    bl_idname = "wm.modal_timer_operator"
    bl_label = "Modal Timer Operator"
    _timer = None
    _img = None

    def modal(self, context, event):
        if event.type in {'RIGHTMOUSE', 'ESC'}:
            self.cancel(context)
            return {'CANCELLED'}

        if event.type == 'TIMER':
            if self._img.is_dirty: # <--- Wait until the image is marked as dirty
                self.finish(context)
                return {'FINISHED'}

        return {'PASS_THROUGH'}

    def execute(self, context: bpy.context):
        if context.scene.render.engine != 'CYCLES':
            context.scene.render.engine = 'CYCLES'
        
        if not context.active_object.select_get() or not context.active_object.type == 'MESH':
            self.report({'WARNING'}, "No valid selected objects")
            return {'FINISHED'}

        obj = context.active_object
        mats = obj.data.materials
        mats_len = len(mats)

        if mats_len == 0 or not mats[0]:
            mat_new = bpy.data.materials.new('BakeMaterial')
            if mats_len == 0:
                mats.append(mat_new)
            else:
                mats[0] = mat_new
            pass

        mat = mats[0]
        mat.use_nodes = True
        nodes = mat.node_tree.nodes
        tex_node = nodes.new('ShaderNodeTexImage')
        tex_node.name = 'BakeNode'
        tex_node.select = True
        nodes.active = tex_node
        self._img = bpy.data.images.new('BakeResult', 1024, 1024)
        tex_node.image = self._img

        self.report({'INFO'}, "Execute")
        result = bpy.ops.object.bake('INVOKE_DEFAULT', type='DIFFUSE')
        if result != {'RUNNING_MODAL'}: # <--- Important to check the result
            self.report({'WARNING'}, "Failed to start baking")
            return {'FINISHED'}

        wm = context.window_manager
        self._timer = wm.event_timer_add(0.5, window=context.window)
        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        self.report({'INFO'}, "Baking map cancelled")

    def finish(self, context):
        wm = context.window_manager
        wm.event_timer_remove(self._timer)
        self.report({'INFO'}, "Baking map completed")
        #save_image() # <--- Call the function after baking

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

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

if __name__ == "__main__":
    register()
    bpy.ops.wm.modal_timer_operator()

Although the question is already old, can help more developers.
You can create a modal operator and check the state of the 'is_dirty' property of the image.

import bpy

class ModalTimerOperator(bpy.types.Operator):
    bl_idname = "wm.modal_timer_operator"
    bl_label = "Modal Timer Operator"
    _timer = None
    _img = None

    def modal(self, context, event):
        if event.type in {'RIGHTMOUSE', 'ESC'}:
            self.cancel(context)
            return {'CANCELLED'}

        if event.type == 'TIMER':
            if self._img.is_dirty: # <--- Wait until the image is marked as dirty
                self.finish(context)
                return {'FINISHED'}

        return {'PASS_THROUGH'}

    def execute(self, context: bpy.context):
        if context.scene.render.engine != 'CYCLES':
            context.scene.render.engine = 'CYCLES'
        
        if not context.active_object.select_get() or not context.active_object.type == 'MESH':
            self.report({'WARNING'}, "No valid selected objects")
            return {'FINISHED'}

        obj = context.active_object
        mats = obj.data.materials
        mats_len = len(mats)

        if mats_len == 0 or not mats[0]:
            mat_new = bpy.data.materials.new('BakeMaterial')
            if mats_len == 0:
                mats.append(mat_new)
            else:
                mats[0] = mat_new
            pass

        mat = mats[0]
        mat.use_nodes = True
        nodes = mat.node_tree.nodes
        tex_node = nodes.new('ShaderNodeTexImage')
        tex_node.name = 'BakeNode'
        tex_node.select = True
        nodes.active = tex_node
        self._img = bpy.data.images.new('BakeResult', 1024, 1024)
        tex_node.image = self._img

        self.report({'INFO'}, "Execute")
        bpy.ops.object.bake('INVOKE_DEFAULT', type='DIFFUSE')

        wm = context.window_manager
        self._timer = wm.event_timer_add(0.5, window=context.window)
        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        self.report({'INFO'}, "Baking map cancelled")

    def finish(self, context):
        wm = context.window_manager
        wm.event_timer_remove(self._timer)
        self.report({'INFO'}, "Baking map completed")
        #save_image() # <--- Call the function after baking

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

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

if __name__ == "__main__":
    register()
    bpy.ops.wm.modal_timer_operator()

Although the question is old, can help more developers.
You can create a modal operator and check the state of the 'is_dirty' property of the image.

import bpy

class ModalTimerOperator(bpy.types.Operator):
    bl_idname = "wm.modal_timer_operator"
    bl_label = "Modal Timer Operator"
    _timer = None
    _img = None

    def modal(self, context, event):
        if event.type in {'RIGHTMOUSE', 'ESC'}:
            self.cancel(context)
            return {'CANCELLED'}

        if event.type == 'TIMER':
            if self._img.is_dirty: # <--- Wait until the image is marked as dirty
                self.finish(context)
                return {'FINISHED'}

        return {'PASS_THROUGH'}

    def execute(self, context: bpy.context):
        if context.scene.render.engine != 'CYCLES':
            context.scene.render.engine = 'CYCLES'
        
        if not context.active_object.select_get() or not context.active_object.type == 'MESH':
            self.report({'WARNING'}, "No valid selected objects")
            return {'FINISHED'}

        obj = context.active_object
        mats = obj.data.materials
        mats_len = len(mats)

        if mats_len == 0 or not mats[0]:
            mat_new = bpy.data.materials.new('BakeMaterial')
            if mats_len == 0:
                mats.append(mat_new)
            else:
                mats[0] = mat_new
            pass

        mat = mats[0]
        mat.use_nodes = True
        nodes = mat.node_tree.nodes
        tex_node = nodes.new('ShaderNodeTexImage')
        tex_node.name = 'BakeNode'
        tex_node.select = True
        nodes.active = tex_node
        self._img = bpy.data.images.new('BakeResult', 1024, 1024)
        tex_node.image = self._img

        self.report({'INFO'}, "Execute")
        result = bpy.ops.object.bake('INVOKE_DEFAULT', type='DIFFUSE')
        if result != {'RUNNING_MODAL'}: # <--- Important to check the result
            self.report({'WARNING'}, "Failed to start baking")
            return {'FINISHED'}

        wm = context.window_manager
        self._timer = wm.event_timer_add(0.5, window=context.window)
        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        self.report({'INFO'}, "Baking map cancelled")

    def finish(self, context):
        wm = context.window_manager
        wm.event_timer_remove(self._timer)
        self.report({'INFO'}, "Baking map completed")
        #save_image() # <--- Call the function after baking

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

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

if __name__ == "__main__":
    register()
    bpy.ops.wm.modal_timer_operator()
added 69 characters in body
Source Link
Carneiro
  • 91
  • 1
  • 4
import bpy

class ModalTimerOperator(bpy.types.Operator):
    bl_idname = "wm.modal_timer_operator"
    bl_label = "Modal Timer Operator"
    _timer = None
    _img = None

    def modal(self, context, event):
        if event.type in {'RIGHTMOUSE', 'ESC'}:
            self.cancel(context)
            return {'CANCELLED'}

        if event.type == 'TIMER':
            if self._img.is_dirty: # <--- Wait until the image is marked as dirty
                self.finish(context)
                return {'FINISHED'}

        return {'PASS_THROUGH'}

    def execute(self, context: bpy.context):
        if context.scene.render.engine != 'CYCLES':
            selfcontext.report({'WARNING'}, "Current scene.render .engine does not support= baking")'CYCLES'
            return {'FINISHED'}
        if not context.active_object.select_get() or not context.active_object.type == 'MESH':
            self.report({'WARNING'}, "No valid selected objects")
            return {'FINISHED'}

        obj = context.active_object
        mats = obj.data.materials
        mats_len = len(mats)

        if mats_len == 0 or not mats[0]:
            mat_new = bpy.data.materials.new('BakeMaterial')
            if mats_len == 0:
                mats.append(mat_new)
            else:
                mats[0] = mat_new
            pass

        mat = mats[0]
        mat.use_nodes = True
        nodes = mat.node_tree.nodes
        tex_node = nodes.new('ShaderNodeTexImage')
        tex_node.name = 'BakeNode'
        tex_node.select = True
        nodes.active = tex_node
        self._img = bpy.data.images.new('BakeResult', 1024, 1024)
        tex_node.image = self._img

        self.report({'INFO'}, "Execute")
        bpy.ops.object.bake('INVOKE_DEFAULT', type='DIFFUSE')

        wm = context.window_manager
        self._timer = wm.event_timer_add(0.5, window=context.window)
        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        self.finishreport(context{'INFO'}, "Baking map cancelled")

    def finish(self, context):
        self.report({'INFO'}, "Bakingwm map= completed")context.window_manager
        #save_imagewm.event_timer_remove(self._timer)
        wmself.report({'INFO'}, ="Baking context.window_managermap completed")
        wm.event_timer_remove#save_image(self._timer) # <--- Call the function after baking

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

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

if __name__ == "__main__":
    register()
    bpy.ops.wm.modal_timer_operator()
import bpy

class ModalTimerOperator(bpy.types.Operator):
    bl_idname = "wm.modal_timer_operator"
    bl_label = "Modal Timer Operator"
    _timer = None
    _img = None

    def modal(self, context, event):
        if event.type in {'RIGHTMOUSE', 'ESC'}:
            self.cancel(context)
            return {'CANCELLED'}

        if event.type == 'TIMER':
            if self._img.is_dirty:
                self.finish(context)
                return {'FINISHED'}

        return {'PASS_THROUGH'}

    def execute(self, context):
        if context.scene.render.engine != 'CYCLES':
            self.report({'WARNING'}, "Current render engine does not support baking")
            return {'FINISHED'}
        if not context.active_object.select_get() or not context.active_object.type == 'MESH':
            self.report({'WARNING'}, "No valid selected objects")
            return {'FINISHED'}

        obj = context.active_object
        mats = obj.data.materials
        mats_len = len(mats)

        if mats_len == 0 or not mats[0]:
            mat_new = bpy.data.materials.new('BakeMaterial')
            if mats_len == 0:
                mats.append(mat_new)
            else:
                mats[0] = mat_new
            pass

        mat = mats[0]
        mat.use_nodes = True
        nodes = mat.node_tree.nodes
        tex_node = nodes.new('ShaderNodeTexImage')
        tex_node.name = 'BakeNode'
        tex_node.select = True
        nodes.active = tex_node
        self._img = bpy.data.images.new('BakeResult', 1024, 1024)
        tex_node.image = self._img

        self.report({'INFO'}, "Execute")
        bpy.ops.object.bake('INVOKE_DEFAULT', type='DIFFUSE')

        wm = context.window_manager
        self._timer = wm.event_timer_add(0.5, window=context.window)
        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        self.finish(context)

    def finish(self, context):
        self.report({'INFO'}, "Baking map completed")
        #save_image()
        wm = context.window_manager
        wm.event_timer_remove(self._timer)

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

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

if __name__ == "__main__":
    register()
    bpy.ops.wm.modal_timer_operator()
import bpy

class ModalTimerOperator(bpy.types.Operator):
    bl_idname = "wm.modal_timer_operator"
    bl_label = "Modal Timer Operator"
    _timer = None
    _img = None

    def modal(self, context, event):
        if event.type in {'RIGHTMOUSE', 'ESC'}:
            self.cancel(context)
            return {'CANCELLED'}

        if event.type == 'TIMER':
            if self._img.is_dirty: # <--- Wait until the image is marked as dirty
                self.finish(context)
                return {'FINISHED'}

        return {'PASS_THROUGH'}

    def execute(self, context: bpy.context):
        if context.scene.render.engine != 'CYCLES':
            context.scene.render.engine = 'CYCLES'
        
        if not context.active_object.select_get() or not context.active_object.type == 'MESH':
            self.report({'WARNING'}, "No valid selected objects")
            return {'FINISHED'}

        obj = context.active_object
        mats = obj.data.materials
        mats_len = len(mats)

        if mats_len == 0 or not mats[0]:
            mat_new = bpy.data.materials.new('BakeMaterial')
            if mats_len == 0:
                mats.append(mat_new)
            else:
                mats[0] = mat_new
            pass

        mat = mats[0]
        mat.use_nodes = True
        nodes = mat.node_tree.nodes
        tex_node = nodes.new('ShaderNodeTexImage')
        tex_node.name = 'BakeNode'
        tex_node.select = True
        nodes.active = tex_node
        self._img = bpy.data.images.new('BakeResult', 1024, 1024)
        tex_node.image = self._img

        self.report({'INFO'}, "Execute")
        bpy.ops.object.bake('INVOKE_DEFAULT', type='DIFFUSE')

        wm = context.window_manager
        self._timer = wm.event_timer_add(0.5, window=context.window)
        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        self.report({'INFO'}, "Baking map cancelled")

    def finish(self, context):
        wm = context.window_manager
        wm.event_timer_remove(self._timer)
        self.report({'INFO'}, "Baking map completed")
        #save_image() # <--- Call the function after baking

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

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

if __name__ == "__main__":
    register()
    bpy.ops.wm.modal_timer_operator()
added 252 characters in body
Source Link
Carneiro
  • 91
  • 1
  • 4

Although the question is already old, here is my solutioncan help more developers.
You can create a modal operator and check the state of the 'is_dirty' property of the image.

import bpy

class ModalTimerOperator(bpy.types.Operator):
    bl_idname = "wm.modal_timer_operator"
    bl_label = "Modal Timer Operator"
    _timer = None
    _img = None

    def modal(self, context, event):
        if event.type in {'RIGHTMOUSE', 'ESC'}:
            self.cancel(context)
            return {'CANCELLED'}

        if event.type == 'TIMER':
            if self._img.is_dirty:
                self.finish(context)
                return {'FINISHED'}

        return {'PASS_THROUGH'}

    def execute(self, context):
        if context.scene.render.engine != 'CYCLES':
            self.report({'WARNING'}, "Current render engine does not support baking")
            return {'FINISHED'}
        if not context.active_object.select_get() or not context.active_object.type == 'MESH':
            self.report({'WARNING'}, "No valid selected objects")
            return {'FINISHED'}

        obj = context.active_object
        mats = obj.data.materials
        mats_len = len(mats)

        if mats_len == 0 or not mats[0]:
            mat_new = bpy.data.materials.new('BakeMaterial')
            if mats_len == 0:
                mats.append(mat_new)
            else:
                mats[0] = mat_new
            pass

        mat = mats[0]
        mat.use_nodes = True
        nodes = mat.node_tree.nodes
        tex_node = nodes.new('ShaderNodeTexImage')
        tex_node.name = 'BakeNode'
        tex_node.select = True
        nodes.active = tex_node
        self._img = bpy.data.images.new('BakeResult', 1024, 1024)
        tex_node.image = self._img

        self.report({'INFO'}, "Execute")
        bpy.ops.object.bake('INVOKE_DEFAULT', type='DIFFUSE')

        wm = context.window_manager
        self._timer = wm.event_timer_add(0.5, window=context.window)
        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        self.finish(context)

    def finish(self, context):
        self.report({'INFO'}, "Baking map completed")
        #save_image()
        wm = context.window_manager
        wm.event_timer_remove(self._timer)

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

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

if __name__ == "__main__":
    register()
    bpy.ops.wm.modal_timer_operator()

Although the question is already old, here is my solution.
You can create a modal operator and check the state of the 'is_dirty' property of the image.

import bpy

class ModalTimerOperator(bpy.types.Operator):
    bl_idname = "wm.modal_timer_operator"
    bl_label = "Modal Timer Operator"
    _timer = None
    _img = None

    def modal(self, context, event):
        if event.type in {'RIGHTMOUSE', 'ESC'}:
            self.cancel(context)
            return {'CANCELLED'}

        if event.type == 'TIMER':
            if self._img.is_dirty:
                self.finish(context)
                return {'FINISHED'}

        return {'PASS_THROUGH'}

    def execute(self, context):
        if context.scene.render.engine != 'CYCLES':
            self.report({'WARNING'}, "Current render engine does not support baking")
            return {'FINISHED'}

        obj = context.active_object
        mats = obj.data.materials
        mats_len = len(mats)

        if mats_len == 0 or not mats[0]:
            mat_new = bpy.data.materials.new('BakeMaterial')
            if mats_len == 0:
                mats.append(mat_new)
            else:
                mats[0] = mat_new
            pass

        mat = mats[0]
        mat.use_nodes = True
        nodes = mat.node_tree.nodes
        tex_node = nodes.new('ShaderNodeTexImage')
        tex_node.name = 'BakeNode'
        tex_node.select = True
        nodes.active = tex_node
        self._img = bpy.data.images.new('BakeResult', 1024, 1024)
        tex_node.image = self._img

        self.report({'INFO'}, "Execute")
        bpy.ops.object.bake('INVOKE_DEFAULT')

        wm = context.window_manager
        self._timer = wm.event_timer_add(0.5, window=context.window)
        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        self.finish(context)

    def finish(self, context):
        self.report({'INFO'}, "Baking map completed")
        wm = context.window_manager
        wm.event_timer_remove(self._timer)

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

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

if __name__ == "__main__":
    register()
    bpy.ops.wm.modal_timer_operator()

Although the question is already old, can help more developers.
You can create a modal operator and check the state of the 'is_dirty' property of the image.

import bpy

class ModalTimerOperator(bpy.types.Operator):
    bl_idname = "wm.modal_timer_operator"
    bl_label = "Modal Timer Operator"
    _timer = None
    _img = None

    def modal(self, context, event):
        if event.type in {'RIGHTMOUSE', 'ESC'}:
            self.cancel(context)
            return {'CANCELLED'}

        if event.type == 'TIMER':
            if self._img.is_dirty:
                self.finish(context)
                return {'FINISHED'}

        return {'PASS_THROUGH'}

    def execute(self, context):
        if context.scene.render.engine != 'CYCLES':
            self.report({'WARNING'}, "Current render engine does not support baking")
            return {'FINISHED'}
        if not context.active_object.select_get() or not context.active_object.type == 'MESH':
            self.report({'WARNING'}, "No valid selected objects")
            return {'FINISHED'}

        obj = context.active_object
        mats = obj.data.materials
        mats_len = len(mats)

        if mats_len == 0 or not mats[0]:
            mat_new = bpy.data.materials.new('BakeMaterial')
            if mats_len == 0:
                mats.append(mat_new)
            else:
                mats[0] = mat_new
            pass

        mat = mats[0]
        mat.use_nodes = True
        nodes = mat.node_tree.nodes
        tex_node = nodes.new('ShaderNodeTexImage')
        tex_node.name = 'BakeNode'
        tex_node.select = True
        nodes.active = tex_node
        self._img = bpy.data.images.new('BakeResult', 1024, 1024)
        tex_node.image = self._img

        self.report({'INFO'}, "Execute")
        bpy.ops.object.bake('INVOKE_DEFAULT', type='DIFFUSE')

        wm = context.window_manager
        self._timer = wm.event_timer_add(0.5, window=context.window)
        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        self.finish(context)

    def finish(self, context):
        self.report({'INFO'}, "Baking map completed")
        #save_image()
        wm = context.window_manager
        wm.event_timer_remove(self._timer)

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

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

if __name__ == "__main__":
    register()
    bpy.ops.wm.modal_timer_operator()
Source Link
Carneiro
  • 91
  • 1
  • 4
Loading