0
$\begingroup$

I'm tring to bake an EMIT texture. The script works inside blender, but when launched in headless mode (-b -p) gives me an

Error: No active image found, add a material or bake to an external file

an extract of the code:

        tree = mat.node_tree
        bake_node = tree.nodes.new('ShaderNodeTexImage')
        bake_node.name = 'bake_node'

        img = bpy.data.images.new("_bake", 512, 512)
        bake_node.image = img

        # trying to select stuff to avoid the error...   
        obj.select_set(True)
        obj.active_material = mat
        bake_node.select = True
        tree.nodes.active = bake_node

        bpy.ops.object.bake(type='EMIT')
        img.save_render(filepath=str(out_path))

as you can see i tried to activate the image in every way, but no luck. I've also read that the external mode of the bake method (save_mode='EXTERNAL') is not really implemented (and, in fact, doesn't work).

Any idea? Thanks.

$\endgroup$

1 Answer 1

0
$\begingroup$

I am doing texture baking in headless mode and it works for me. Not sure what is the problem with your script but here is my script:

import bpy
import logging
import sys

console_handler = logging.StreamHandler(sys.stdout)
log = logging.getLogger(__name__)
log.addHandler(console_handler)

cuda_devices, opencl_devices = bpy.context.preferences.addons['cycles'].preferences.get_devices(
)

bpy.context.scene.render.engine = "CYCLES"
bpy.context.scene.cycles.device = "GPU"
bpy.context.preferences.addons["cycles"].preferences.compute_device_type = "CUDA"

for device in cuda_devices:
    print(f'Activating {device.name}')
    device.use = True
    break

# need object mode for make_single_user
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.make_single_user(
    type="ALL", object=False, obdata=False, material=True)

if 'dynamic' in bpy.data.collections:
    bpy.data.collections['dynamic'].hide_render = True

for object in list(bpy.data.objects):
    if object.active_material is None:
        log.warning("Object %s doesn't have a material. Skipping.", object.name)
        continue

    log.info("Working on %s", object.name)
    bpy.ops.object.select_all(action='DESELECT')
    object.select_set(True)

    bpy.context.view_layer.objects.active = object
    for slot in object.material_slots:
        if slot.material is None:
            continue

        material = slot.material
        if not material.use_nodes:
            log.warning(
                "Active Material of object %s doesn't use nodes. Skipping.", object.name)
            continue

        nodes = material.node_tree.nodes

        gltf = None
        shadow = None
        occlusion = None
        for node in nodes.values():
            if node.label == "Shadow":
                shadow = node
            elif node.label == "Occlusion":
                occlusion = node
            elif node.type == "GROUP" and node.node_tree and node.node_tree.name == "glTF Metallic Roughness":
                gltf = node

        if gltf is None:
            log.warning("Skipping %s: no gltf node defined", object.name)
            continue

        shadow_input = None
        occlusion_input = None
        for input in gltf.inputs:
            if input.name == "Shadow":
                shadow_input = input
            elif input.name == "Occlusion":
                occlusion_input = input

        if shadow_input is None:
            log.warning(
                "Skipping %s: gltf group doesn't define a shadow input", object.name)
            continue

        if occlusion_input is None:
            log.warning(
                "Skipping %s: gltf group doesn't define a occlusion input", object.name)
            continue

        shadow = nodes.new(type="ShaderNodeTexImage")
        shadow.label = "Shadow"

        occlusion = nodes.new(type="ShaderNodeTexImage")
        occlusion.label = "Occlusion"

        shadow_output = shadow.outputs[0]
        occlusion_output = occlusion.outputs[0]

        material.node_tree.links.new(shadow_input, shadow_output)
        material.node_tree.links.new(occlusion_input, occlusion_output)

        image = bpy.data.images.new("shadow", 256, 256)
        shadow.image = image

        nodes.active = shadow
        shadow.select = True

        bpy.ops.object.bake(type="SHADOW")
        image.pack()
        shadow.select = False

        image = bpy.data.images.new("occlusion", 256, 256)
        occlusion.image = image

        nodes.active = occlusion
        occlusion.select = True

        bpy.ops.object.bake(type="AO")
        image.pack()
        occlusion.select = False

    object.select_set(False)

bpy.ops.wm.save_mainfile()

You can probably delete like 70% of it or so for your usecase. I am especially unsure if the CUDA stuff in the beginning even works. Also this is highly specific to my use case (all the stuff around the glTF node in there) but maybe it helps you solve your issue.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .