I am working on script/addon that will run bake operator every frame before rendering. The main purpose of the script is to bake diffuse shadows and color to an image so that I can use it in the emission shader of the hair particles, this is to render stylized hair. I need to bake image texture before calling render operator, but I can not figure out how to do so. I am trying to call ops.object.bake() in the render_pre handler but It does not work as it neglects the time that bake operator needs and proceds with rendering, wich basically crashes blender (i guess) One of the sollution I have in mind is to call render in object_bake_complete handler but In this case I need to create my own operator that will call bake and proceeds with rendering of the frame. I wanted to make it easy for the user to just press render_animation and it renders the animation but each frame before it starts rendering it bakes the texture.
import bpy
obj = bpy.context.active_object
mat = obj.active_material
baking_texture = mat.node_tree.nodes.active
enabled_hair = []
Collect hair particles to turn off before baking
if obj:
for modif in obj.modifiers:
if modif.type == 'PARTICLE_SYSTEM' and modif.show_render:
print(f'add particle to the list: {modif.name}')
enabled_hair.append(modif)
Check if baking_texture is None or if its type is not 'TEX_IMAGE'
if baking_texture is None or baking_texture.type != 'TEX_IMAGE':
# Collect image texture for baking
for node in mat.node_tree.nodes:
if node.type == 'TEX_IMAGE':
if node.image is None:
continue
else:
baking_texture = node
break
This is where we turn off hair, bake the texture, turn on hair
def bake_texture(scene):
global enabled_hair
# Turn off hair
for hair in enabled_hair:
print(f'mute particles: {hair.name}')
hair.show_render = False
# Call bake texture
print("Bake Texture")
bpy.ops.object.bake('INVOKE_DEFAULT')
Set a flag to check if rendering has started
rendering_started = False
#set flag to distinguish render from baking
#baking = False
def start_rendering(scene):
global rendering_started
#global baking
rendering_started = True
#baking = True
print("Start Rendering")
bake_texture(scene)
def change_frame(scene):
global rendering_started
#global baking
if not rendering_started:
baking = True
print("Frame changed")
bake_texture(scene)
def finish_rendering(scene):
print("finished rendering")
global rendering_started
rendering_started = False
def finish_baking(scene):
global enabled_hair
print("finished baking")
# Turn on hair
for hair in enabled_hair:
print(f'un-mute particles: {hair.name}')
hair.show_render = True
Remove the handler if it already exists
def uppend(target, handler):
if handler in target:
target.remove(handler)
print(f'removed handler: {handler.name}')
target.append(handler)
print(f'added handler: {handler.name}')
Add the handler to both frame change and render events
if(enabled_hair and baking_texture):
uppend(bpy.app.handlers.frame_change_post, change_frame)
uppend(bpy.app.handlers.render_pre, start_rendering)
uppend(bpy.app.handlers.render_complete, finish_rendering)
uppend(bpy.app.handlers.render_cancel, finish_rendering)
uppend(bpy.app.handlers.object_bake_complete, finish_baking)
uppend(bpy.app.handlers.object_bake_cancel, finish_baking)