0
$\begingroup$

I am creating a Python script that bakes the textures for each object in the scene, and then deletes all the shader nodes of the materials of each object and replaces them with image texture nodes of the baked diffuse and roughness maps. However, I've noticed that, after running the program, all of the image texture nodes have been replaced with the baked maps of only the last object and the baked maps of the other objects have vanished.

This is the code that creates the images that get baked onto

def bakeObj(obj, dest, img_size):
    obj.select_set(True)
    bpy.context.view_layer.objects.active = obj 

    imgDiffuse = bpy.data.images.new(obj.name + '_Diffuse',img_size,img_size) 
    imgRough = bpy.data.images.new(obj.name + '_Rough',img_size,img_size) 

In between I bake the textures of the object onto imgDiffuse and imgRough. Then this is the code for the assignment of the images in the same function.

for mat in obj.data.materials:
    print(mat.name)
    mat.use_nodes = True
    nodes = mat.node_tree.nodes
    
    # delete nodes 
    for n in mat.node_tree.nodes: 
        excludedNodes = {'Principled BSDF','Material Output'}
        if n.name not in excludedNodes:
            mat.node_tree.nodes.remove(n)


    diffuse_node = nodes.new('ShaderNodeTexImage')
    diffuse_node.name = 'Diffuse_node'
    diffuse_node.image = imgDiffuse
    
    rough_node = nodes.new('ShaderNodeTexImage')
    rough_node.name = 'Rough_node'
    rough_node.image = imgRough
    
    # stick baked texture in material
    principled_bsdf_node = mat.node_tree.nodes["Principled BSDF"]
    links = mat.node_tree.links
    links.new(principled_bsdf_node.inputs[0], diffuse_node.outputs[0])
    links.new(principled_bsdf_node.inputs[9], rough_node.outputs[0])

This entire function is called once per object via a loop. For a more detailed illustration of the issue, see the images below. This is the setup of the objects. The highlighted material "shader_crustacean" should have been assigned the texture files corresponding to its parent object "crustacean(1, 1).parts(0, factory=LobsterBodyFactory)"

enter image description here

Instead, it has the texture files corresponding to the last object "crustacean(1,1).parts(10).extra(BezierCurve.015, 10)". The same occurs for all other materials.

enter image description here

Meanwhile, the image dropdown menu seems to show that all the other files have actually disappeared or were overwritten somehow.

enter image description here

It seems that the last call of the function somehow causes all the other textures to get destroyed. Is this some kind of memory overwriting issue or weird bug with blender? For reference, this is all being run in headless mode.

$\endgroup$

1 Answer 1

0
$\begingroup$

This example is only for one object having its material ready to bake.

import bpy

obj = bpy.context.object
obj_mat = obj.active_material

img_dif = bpy.data.images.new(obj.name + "_diffuse", 1024,1024)
img_rgh = bpy.data.images.new(obj.name + "_roughness", 1024,1024)
img_nrm = bpy.data.images.new(obj.name + "_normal", 1024,1024)

obj.select_set(True)

image_texture = obj_mat.node_tree.nodes.new('ShaderNodeTexImage')
image_texture.image = img_dif
obj_mat.node_tree.nodes.active = image_texture

bpy.ops.object.bake(type='DIFFUSE')

image_texture.image = img_rgh
obj_mat.node_tree.nodes.active = image_texture

bpy.ops.object.bake(type='ROUGHNESS')

image_texture.image = img_nrm
obj_mat.node_tree.nodes.active = image_texture

nodes = obj_mat.node_tree.nodes
links = obj_mat.node_tree.links
for node in nodes:
    if node.type not in {"BSDF_PRINCIPLED", "OUTPUT_MATERIAL"}:
        nodes.remove(node)
        
principled_bsdf_node = nodes["Principled BSDF"]
diffuse_node = nodes.new("ShaderNodeTexImage")
roughnes_node = nodes.new("ShaderNodeTexImage")
normale_node = nodes.new("ShaderNodeTexImage")
normal_map_node = nodes.new("ShaderNodeNormalMap")

diffuse_node.image = bpy.data.images[obj.name+ "_diffuse"]
roughnes_node.image = bpy.data.images[obj.name+ "_roughness"]
normale_node.image = bpy.data.images[obj.name+ "_normal"]

links.new(diffuse_node.outputs[0], principled_bsdf_node.inputs[0])
links.new(roughnes_node.outputs[0], principled_bsdf_node.inputs[9])
links.new(normale_node.outputs[0], normal_map_node.inputs[1])
links.new(normal_map_node.outputs[0], principled_bsdf_node.inputs[22])

This example is for multiple objects:

import bpy

for obj in bpy.context.selected_objects:
#    obj = bpy.context.object
    obj_mat = obj.active_material

    img_dif = bpy.data.images.new(obj.name + "_diffuse", 1024,1024)
    img_rgh = bpy.data.images.new(obj.name + "_roughness", 1024,1024)
    img_nrm = bpy.data.images.new(obj.name + "_normal", 1024,1024)

    obj.select_set(True)

    image_texture = obj_mat.node_tree.nodes.new('ShaderNodeTexImage')
    image_texture.image = img_dif
    obj_mat.node_tree.nodes.active = image_texture

    bpy.ops.object.bake(type='DIFFUSE')

    image_texture.image = img_rgh
    obj_mat.node_tree.nodes.active = image_texture

    bpy.ops.object.bake(type='ROUGHNESS')

    image_texture.image = img_nrm
    obj_mat.node_tree.nodes.active = image_texture

    bpy.ops.object.bake(type='NORMAL')

And the last, this example is for one object having multiple material slots.

import bpy

obj = bpy.context.object

img_dif = bpy.data.images.new(obj.name + "_diffuse", 1024,1024)
img_rgh = bpy.data.images.new(obj.name + "_roughness", 1024,1024)
img_nrm = bpy.data.images.new(obj.name + "_normal", 1024,1024)
obj.select_set(True)

for slot in obj.material_slots:
    obj_mat = slot.material
    image_texture = obj_mat.node_tree.nodes.new('ShaderNodeTexImage')
    
    image_texture.image = img_dif
    obj_mat.node_tree.nodes.active = image_texture

bpy.ops.object.bake(type='DIFFUSE')

for slot in obj.material_slots:
    obj_mat = slot.material
    image_texture = obj_mat.node_tree.nodes.new('ShaderNodeTexImage')
    
    image_texture.image = img_rgh
    obj_mat.node_tree.nodes.active = image_texture

bpy.ops.object.bake(type='ROUGHNESS')

for slot in obj.material_slots:
    obj_mat = slot.material

    image_texture = obj_mat.node_tree.nodes.new('ShaderNodeTexImage')
    image_texture.image = img_nrm
    obj_mat.node_tree.nodes.active = image_texture
    
bpy.ops.object.bake(type='NORMAL')
```
$\endgroup$
1
  • $\begingroup$ Although this didn't directly solve the issue, I was having issues with successive baking passes interfering with each other and this fixed that, which allowed me to use an alternate implementation that circumvents manually recreating image tex nodes. Thanks! $\endgroup$
    – user167693
    May 23, 2023 at 16:09

You must log in to answer this question.

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