0
$\begingroup$

Updating texture image node issue using python.

I have several different texture input files that I want to render out using the same node group setup and blender file.

Python doesn't seem to be updating the texture image node as expected

I'm using @Chris script located at https://blender.stackexchange.com/a/218744/86978

I've narrowed down the issue to the line bpy.data.images[fileName].filepath = eachFile # change this to you texture name

when it tries to execute this line it creates an error KeyError: 'bpy_prop_collection[key]: key "2plantpic_test.png" not found' or if I use the full path it gives this error KeyError: 'bpy_prop_collection[key]: key "/tmp/tex_tures/2plantpic_test.png" not found'

Things I've tried / checked:

  1. The files are located in the directory /tmp/tex_tures/
  2. If I rem out the line bpy.data.images[fileName].filepath = eachFile the files and directories get created but the different image texture files I want to be rendered out aren't rendered (since it doesn't change the texture image node).
  3. Replaced the bpy.data.images line with eachFile = bpy.data.images.load(eachFile) but the image textures still aren't being updated to the new PNG images

How the script is suppose to work:

  1. Loop through all PNG files in the /tmp/tex_tures
  2. Replace the image texture file node with each PNG file found and render them out.
  3. Place the render files into their own separate directory

The Script is below:

import bpy
import glob
import os


print ("Script start")

scn = bpy.context.scene

here = bpy.path.abspath('/tmp/tex_tures') #textures location

output_path = scn.render.filepath

for eachFile in glob.glob(os.path.join(here, '*.png')):
    print("-------------------")
    print("eachFile: ",eachFile)
    fileName = bpy.path.basename(eachFile)
    print("fileName: ",fileName)
    fileNameStart = os.path.splitext(fileName)[0]
    print("fileNameStart: ", fileNameStart)
    
    eachFile = bpy.data.images.load(eachFile)
    #bpy.data.images[fileName].filepath = eachFile # change this to you texture name
    #bpy.data.images[eachFile].filepath = eachFile # change this to you texture name
    #print("texture name used: ",bpy.data.images[fileName].name)
    #bpy.data.images['/tmp/tex_tures/2plantpic_test.png'].filepath = eachFile # change this to you texture name
    
    directory = os.path.join(here, fileNameStart)
    print("directory", directory)
    if not os.path.exists(directory):
        os.makedirs(directory)
    scn.render.filepath = os.path.join(directory,"")

    bpy.ops.render.render(animation=True)
    
bpy.context.area.ui_type = 'TEXT_EDITOR'

I'm using Ubuntu 20.04 Linux Blender 2.93.3 I've also attached the blender file and image of nodes

img1

Thanks

$\endgroup$
5
  • $\begingroup$ Use the name of the image used in your texture node. IMO prob should texture_node.image = bpy.data.images.load(filepath) To load and assign new image to texture instead of loading new image into old. Would instead look at using an image sequence as mentioned in other answers or in blender.stackexchange.com/questions/217733/… $\endgroup$
    – batFINGER
    Aug 26 at 15:20
  • $\begingroup$ Thanks I've replace the bpy.data.images line with eachFile = bpy.data.images.load(eachFile) but the image textures still aren't being updated to the new PNG images. $\endgroup$
    – Rick T
    Aug 26 at 15:36
  • $\begingroup$ In the line: bpy.data.images[fileName] the fileName has to be a string of an already loaded image datablock in the blend file. Chris uses an existing image datablock and replaces the source filepath of the image in his loop, not the complete datablock. To create a more "correct" and clean solution, you should probably use what @batFINGER mentioned in the comment above. $\endgroup$
    – Bert VdB
    Aug 26 at 15:36
  • $\begingroup$ ie look at your texture node in the blend (which I haven't DL'd) and use the name of the image it currently uses. To use load bpy.data.materials["The name of your material"].node_tree.nodes["The name of your texture node"].image = bpy.data.images.load(filepath) or if in a node group bpy.data.node_groups["The name of your node group"].node_tree.... $\endgroup$
    – batFINGER
    Aug 26 at 15:59
  • $\begingroup$ @batFINGER I uploaded a image copy of the node tree. I was just trying to replace the texture images in the texture node with the PNG image files. I'm not using any materials are you saying that's required? $\endgroup$
    – Rick T
    Aug 26 at 16:57
2
$\begingroup$

You can use BlendDataImages.load() to load and assign the image to the texture node in one go as already explained in How to load an image from disc and assign it to a newly created image texture node?. How you can get a reference to any shader node is nicely explained in Control Cycles/Eevee material nodes and material properties using python?.

Demo on how to iterate through a list of images (by using the default hdris), assign each to the default cube, set the render path based on the originals and call the render operator:

enter image description here

import bpy
import os

C = bpy.context
scn = C.scene

# Get the images
folder = bpy.path.abspath("//images")
images = [os.path.join(folder, f) for f in os.listdir(folder) if f.endswith(".exr")] 

# Get the material
mat = C.object.active_material
nodes = mat.node_tree.nodes

# Get the node
img_node = nodes.get("__PLACEHOLDER__")
if img_node:
    # Iterate through all images, replace the image
    for img in images:
        img_node.image = bpy.data.images.load(img)
        # Set the output path and render (jpg is a placeholder)
        img_folder, img_file = os.path.split(img)
        img_name, img_ext = os.path.splitext(img_file)
        scn.render.filepath = bpy.path.abspath("//rndr_{}.jpg".format(img_name))

        bpy.ops.render.render(write_still=True)

As mentioned by @batFINGER in the comments, more god-like would be converting the list of images into a real sequence (img_000.exr, img_001.exr, img_002.exr etc.) and control the playback using the Offset property of the image node. Explanation: Is possible play video in reverse mode into Texture Image node?

$\endgroup$
1
  • $\begingroup$ Thanks that helped $\endgroup$
    – Rick T
    Aug 28 at 5:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.