3
$\begingroup$

I use Blender 2.83. For a addon (accessible from the 3D-View) I want to bake texture maps. I am perfectly able to do it without scripting. But with python I was not sucessful sofar.

To reduce my problem to the barest minumum I start with a selected object with valid UV. I then execute the following python script:

import bpy

obj = bpy.context.active_object

# Creating a texture node, linked with a new image
mat = obj.data.materials[0]
mat.use_nodes = True
texImage = mat.node_tree.nodes.new('ShaderNodeTexImage')
img = bpy.ops.image.new(name= obj.name + '_BakedTexture')
texImage = img

# !!! No image is linked to the texture node !!!

# Baking to the newly created image
# The following part works if I create the texture node and the assigning of the image by hand
bpy.context.view_layer.objects.active = obj
bpy.ops.object.bake(type='DIFFUSE', save_mode='EXTERNAL', filepath='C:\\TEMP\\baked.png', use_automatic_name=True, width=512, height=512)

I think what I am missing is the correct linking of the image to the texture node. I consulted similar questions such as

Set active image node with python

but their answers did not help (code for Blender 2.7 that is not compatible anymore, i guess).

$\endgroup$

1 Answer 1

8
$\begingroup$

I think I will give you some basic steps, that is, add a node of type "TEX_IMAGE", assign your image to it. therefore:

obj = bpy.context.active_object
# You can choose your texture size (This will be the de bake image)
image_name = obj.name + '_BakedTexture'
img = bpy.data.images.new(image_name,1024,1024)

   
#Due to the presence of any multiple materials, it seems necessary to iterate on all the materials, and assign them a node + the image to bake.
for mat in obj.data.materials:

    mat.use_nodes = True #Here it is assumed that the materials have been created with nodes, otherwise it would not be possible to assign a node for the Bake, so this step is a bit useless
    nodes = mat.node_tree.nodes
    texture_node =nodes.new('ShaderNodeTexImage')
    texture_node.name = 'Bake_node'
    texture_node.select = True
    nodes.active = texture_node
    texture_node.image = img #Assign the image to the node
    
bpy.context.view_layer.objects.active = obj
bpy.ops.object.bake(type='DIFFUSE', save_mode='EXTERNAL')

img.save_render(filepath='C:\\TEMP\\baked.png')
    
#In the last step, we are going to delete the nodes we created earlier
for mat in obj.data.materials:
    for n in mat.node_tree.nodes:
        if n.name == 'Bake_node':
            mat.node_tree.nodes.remove(n)

Avoid as much as possible to use bpy.ops, in this case, as you can see, it is easy to create an image with the methods bpy.data.images.new () Any blender object can be created with that method.

bpy.data.objects.new()
bpy.data.materials.new()
bpy.data.scenes.new()
...
...

bpy.ops it is good to use it only when you have no alternatives, as in this case with the bpy.ops.object.bake()

this allows you to create something, and assign it directly to a variable, as in the example of img = bpy.data.images.new() So you don't have to go crazy to have access to it.

Another way for save the image is:

# Use filepath_raw and not filepath, by my experience is the best way
# This is without data refreshing,It shouldn't cause any problems

img.filepath_raw = 'C:\\TEMP\\baked.png'
img.save()
$\endgroup$
5
  • $\begingroup$ I've been adapting this for my own work, populating an existing node for baked textures, but it won't save. I have a script already that generates images and saves them like: //textures/imagename.png' But when I try to do the same for the baked image it tells me RuntimeError: Error: Could not write image: No such file or directory, '//bakes/DiffuseBake.png' Now I know the folder exists, because the same script checks if it exists and makes it if not. So why is this not working: imgbake.save_render(filepath = "//bakes/DiffuseBake.png") $\endgroup$ Oct 25, 2022 at 15:08
  • $\begingroup$ I figured out a workaround, have the script generate the image, assign it to the image node, then save it as an image. The rendering function seems to not like interacting with the path function. $\endgroup$ Oct 25, 2022 at 18:23
  • $\begingroup$ I Have update the Answer, Check if it helps you. It is always better to save the image directly without going through the node tree, unless you want to manipulate it. $\endgroup$
    – Noob Cat
    Oct 25, 2022 at 21:57
  • $\begingroup$ I tried that, actually. It didn't like it, just didn't put the image anywhere. It was weird. $\endgroup$ Oct 25, 2022 at 22:31
  • 1
    $\begingroup$ Keep in mind that with C:\\TEMP\\baked.png it will only work on windows. You could use bpy.data.filepath and have some logic to check of the file is saved. $\endgroup$
    – clankill3r
    yesterday

You must log in to answer this question.

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