I have folder A and folder B. There are many textures like "Image 1" in folder A, and many terrain models like "Image 2" in folder B. I want to connect the textures of the same name to terrain modeling using "Blender Python".
1 Answer
Here is a script that imports all *.obj files from a given folder. For each imported model it tries to load a JPG image with the same name from another folder. If found it will create a material from a template material and assign it to the imported model. If the model already had a material then the material in the first slot will get replaced. Other material slots are not affected.
Note: There must be a template material named "Material for imports" that has an Image Texture node. This material will be duplicated and assigned to the imported model. The image will be replaced with the imported JPG image.
It's recommended to open the System Console window (main menu Window > Toggle System Console) to check the output of the script for errors. Press Ctrl+C in the console window to abort the script.
import bpy
import os
import glob
def import_obj_file(obj_path):
bpy.ops.object.select_all(action='DESELECT')
# Call the obj import operator and pass the absolute file path
bpy.ops.import_scene.obj(filepath = obj_path)
# Get the imported object from context, print the name and its reference
obj = bpy.context.selected_objects[0]
if not obj is None:
print(f"Imported {obj.name}, type: {obj.type}")
else:
print(f"ERROR: imported object found {obj_path}")
return obj
def load_image(image_folder, image_name):
# look for image. If not found try to load it
image = bpy.data.images.get(image_name)
if image is None:
try:
# load image
image_path = f"{image_folder}/{image_name}"
image = bpy.data.images.load(image_path)
print(f"Loaded image: {image_path}")
except:
print(f"ERROR: Image not found: {image_path}")
return image
def assign_material(obj, image, material_template):
mat_name = obj.name
# look for material, if not found create a new one
mat = bpy.data.materials.get(mat_name)
if mat is None:
# create new material from template
template = bpy.data.materials.get(material_template)
mat = template.copy()
mat.name = mat_name
mat.node_tree.nodes['Image Texture'].image = image
# assign material to object
obj.material_slots[0].material = mat
if __name__ == "__main__":
obj_folder = "c:/tmp/objs" # <--------- folders with the files to import
image_folder = "c:/tmp/images"
mat_template = "Material for imports" # <---- material to be duplicated for all imports
obj_files = glob.glob(f"{obj_folder}/*.obj", recursive = False)
for obj_path in obj_files:
imported_obj = import_obj_file(obj_path)
image_basename = os.path.basename(obj_path).split('.')[0]
image_name = image_basename + ".jpg" # <--- file extension of images
image = load_image(image_folder, image_name)
if not imported_obj is None and not image is None:
assign_material(imported_obj, image, mat_template)
else:
print("ERROR: cannot assign material, object or image missing")
print(f"{len(obj_files)} files processed.")
Check this answer on how to run a script in Blender.
bpy.ops.import_scene.obj()
, then load the image, create a simple material that uses the image texture, and then assign it to the model. So far, so good. But what should happen then? Import the next one and all into the same current blend file...? $\endgroup$