# Applying materials on mesh models present in different blend files using python script

I am using python script to read the mesh data present in one .blend file and apply materials to it which is present in another .blend file. The output is exported as a .png.

I have written the below script to achieve this.

If I skip applying material to the mesh object, the mesh object is rendered as is in the .png. However, if I apply material to the mesh object, I am getting an empty .png file. Nothing gets rendered.
Expected: The materials should get applied to the mesh model and get rendered.

Not sure what I am missing. Tried quite a few ways, no luck. Appreciate it, if you could let me know where I am going wrong.

import bpy

def render_different_materials_on_mesh_object():
filepath = FILE_PATH + "remote.blend"
mesh_ob = get_mesh_object(filepath)
material_name = append_material()
apply_material_to_mesh_object(material_name, mesh_ob)
render_as_png()

def get_mesh_object(filepath):
bpy.ops.wm.open_mainfile(filepath=filepath)
scene = bpy.context.scene
for ob in scene.objects:
if ob.type == 'MESH':
bpy.context.scene.objects.active = ob
break
return bpy.context.object

def append_material():
filename = "mainMaterial"
section = "\\Action\\"
directory = FILE_PATH
filepath = FILE_PATH + "material1.blend/Material/mainMaterial"
bpy.ops.wm.append(
filepath="//material1.blend\\Material\\",
directory=FILE_PATH + "material1.blend\\Material\\",
filename=filename,
return filename

def apply_material_to_mesh_object(material_name, mesh_ob):
# Get material
mat = bpy.data.materials.get(material_name)
if mat is None:
# create material
mat = bpy.data.materials.new(name="Material")
# Assign it to object
if mesh_ob.data.materials:
# assign to 1st material slot
mesh_ob.data.materials[0] = mat
else:
# no slots
mesh_ob.data.materials.append(mat)

def render_as_png():
bpy.data.scenes['Scene'].render.filepath = FILE_PATH + 'test.png'
bpy.ops.render.render(write_still=True)

render_different_materials_on_mesh_object()


My first suggestion would be to avoid using bpy.ops and instead use code like http://web.purplefrog.com/~thoth/blender/python-cookbook/link-external-data-blocks.html which I have excerpted here:

import bpy

def library_get(name, data_blocks, libpath=None):
""" Since it is possible for a .blend file to have several objects
with the same name linked from different files, this routine lets us
hunt down the right one. """
for x in data_blocks:
if x.name == name and x.library is not None:
if libpath is None or libpath == x.library.filepath:
return x
return None

for obj in grp.objects:

#
#

fname = "//cube.blend"

print(fname)
# src has many properties, each of which is a list of name strings.
# dst is how we specify what we want to link from the library file.

# let's link the "dazed" scene
dst.scenes = ["dazed"]
# and the "omnitile" object
dst.objects = ["omnitile"]
# and an object group
dst.groups = ["frog"]

# and just to be fancy, let's count up how many linkable things there are
for dbt in dir(src):
name_list = getattr(src, dbt)
print("%s[%d]" % (dbt, len(name_list)))

# just because we linked an object doesn't mean that object is in any of our scenes.
omnitile = library_get("omnitile", bpy.data.objects)

scn = bpy.context.scene
try:
# now it is.
except:
pass

# link all the objects from group "frogs" to the current scene

Your version would probably have dst.materials = ["mainMaterial"] and mat = library_get("mainMaterial", bpy.data.materials)
• I looked at your code. It looks like the mesh is linked from another .blend file. If that is the case, you are not going to be able to modify the mesh. If you want to be able to modify that mesh you have to append instead of link. Change link=False for the mesh (so bpy.data.libraries.load(fname, link=False) ) to append. You can still link the material. If this is the case I shall edit my answer to emphasize this. – Mutant Bob Sep 13 '16 at 15:54
• link=False too is giving the same output. Figured out what was going wrong. The rendering engine was the default one(Blender render). Had to change it to cycles render. Adding this line of code just before calling the render method worked - bpy.context.scene.render.engine = 'CYCLES'. This works for both the code I shared in my question as well as the one here(updated): codepad.co/snippet/ehzu7AHY . Thanks for suggesting to use bpy.data.libraries. The rendering is faster by 15 seconds as compared to using bpy.ops – bot4u Sep 13 '16 at 17:05
Figured out why this issue was happening. The scene's rendering engine did not match. The default engine 'Blender render' was being used. In order to apply materials, we need 'cycles render'. Adding this line of code bpy.context.scene.render.engine = 'CYCLES'  before rendering fixed the issue. Thanks @Mutant Bob for suggesting to use bpy.data.libraries instead of bpy.ops, the rendering performance improved by 15 seconds. The code implementing Bob's suggestion is here: https://codepad.co/snippet/ehzu7AHY