I've created a certain number of book cover textures (with their respective roughness maps) but I really don't want to create a material for every book and then assign their respective textures manually. I'm talking of hundreds of books. There's a way to do this automatically?

  • $\begingroup$ There is a commercial Cycles Node Setup that allows setup random textures on the same material, if that is what you are looking for. If plugged in by the same order diffuse/ should be kept in sync. (Disclaimer: Shameless publicity, I made that product) $\endgroup$ Commented Mar 25, 2017 at 23:53
  • $\begingroup$ Not ideal solution but it should do the trick. Thank you! $\endgroup$
    – J. Sena
    Commented Mar 26, 2017 at 0:06
  • 1
    $\begingroup$ Same free node group is included here for years, also there is an answer over here explaining the principle, so honestly I think 10 bucks isn't really worth it... Can you list some advantages against the other ones? @DuarteFarrajotaRamos $\endgroup$
    – brockmann
    Commented Mar 27, 2017 at 9:00
  • $\begingroup$ No advantage, it is basically the same thing pre-packaged if you wish to save the trouble. $\endgroup$ Commented Mar 27, 2017 at 12:55

2 Answers 2


Working with you having some structure setup with your naming, let's say you have an object called "book1" and you have images "book1_diffuse.png" and "book1_roughness.png" you can create a material called "book1" that uses both images and then assign the material to the object.

import bpy
from glob import glob
import os

# adjust this to point to your texture directory
# can start with // to refer to the current blend file dir
texture_dir = '//textures'

diffuse_imgs = glob('*_diffuse.png')
for img in diffuse_imgs:
    mat_name = img.split('_')[0]
    mat = bpy.data.materials.new(mat_name)
    mat.use_nodes = True
    m_nodes = mat.node_tree.nodes
    m_links = mat.node_tree.links
    diff_node = m_nodes['Diffuse BSDF']

    imgnode = m_nodes.new('ShaderNodeTexImage')
    imgnode.location.x = diff_node.location.x - 200
    imgnode.location.y = diff_node.location.y
    imgnode.image = bpy.data.images[img]
    m_links.new( diff_node.inputs['Color'], imgnode.outputs['Color'] )

    roughnode = m_nodes.new('ShaderNodeTexImage')
    roughnode.location.x = imgnode.location.x - 200
    roughnode.location.y = imgnode.location.y - 50
    roughimg = mat_name+'_roughness.png'
    roughnode.image = bpy.data.images[roughimg]
    m_links.new( diff_node.inputs['Roughness'], roughnode.outputs['Color'] )

    uvnode = m_nodes.new('ShaderNodeUVMap')
    uvnode.location.x = roughnode.location.x - 200
    uvnode.location.y = roughnode.location.y - 100
    uvnode.uv_map = 'UVMap'
    m_links.new(imgnode.inputs['Vector'], uvnode.outputs['UV'])
    m_links.new(roughnode.inputs['Vector'], uvnode.outputs['UV'])

    bpy.data.objects[mat_name].active_material = mat

You can easily expand that to include any number of image textures for each material and add in a mix and glossy node if you wanted. You can find the node types you can use listed here.

If you have a random number of book objects, you could create the materials and add them to a list as you go, then go through the list of objects and pick a random material to assign to each.

  • $\begingroup$ I'm new to Blender and don't know much about Python but I searched how to run a python script and it didn't worked for me. Tried to load in the text editor and run but nothing happens. $\endgroup$
    – J. Sena
    Commented Mar 27, 2017 at 0:10
  • $\begingroup$ Most likely the diffuse_imgs = line will need to be adjusted, as it is it will find the images in the current directory. I just added an adjustment to the first few lines to make that easier. $\endgroup$
    – sambler
    Commented Mar 27, 2017 at 7:20
  • $\begingroup$ Still not working. Tried a few times and got this error everytime: Error: Cannot read 'Cube_diffuse.png': no such file or directory Traceback (most recent call last): File "D:\TEMP\untitled.blend\test.py.001", line 22, in <module> File "C:\Program Files\Blender Foundation\Blender\2.78\scripts\modules\bpy\ops.py", line 189, in _call_ ret = op_call(self.idname_py(), None, kw) RuntimeError: Error: Cannot read 'Cube_diffuse.png': No such file or directory. Don't know why it's trying to read Cube_diffuse.png since I don't have a "Cube" in my scene. $\endgroup$
    – J. Sena
    Commented Mar 29, 2017 at 17:10

One way is to (within one material) have a shader for each book variation, with the textures plugged into them accordingly, and mix the shaders together using the "Random" output from the "Object Info" node (found in the "input" node category) as the factor. This "random" output simply selects all the objects with the material in question and randomly assigns some of them as white and some of them as black.

Of course, this will require one Mix Shader node for pretty much every variation of the book, so it's still not neat, clean, and simple, but it will be more effective than assigning a separate material to each book :P


You must log in to answer this question.

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