0
$\begingroup$

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
FILE_PATH = "/home/vandy/startUpProjects/tailorMade/pythonScripts/"

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,
    link = False) 
    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()
$\endgroup$

2 Answers 2

1
$\begingroup$

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


def addGroupToScene(grp, scn):
    for obj in grp.objects:
        scn.objects.link(obj)

#
#

fname = "//cube.blend"

print(fname)
with bpy.data.libraries.load(fname, link=True) as (src, dst):
    # 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:
    scn.objects.link(omnitile)
    # now it is.
except:
    pass

# link all the objects from group "frogs" to the current scene
addGroupToScene(library_get("frogs", bpy.data.groups), scn)

Your version would probably have dst.materials = ["mainMaterial"] and mat = library_get("mainMaterial", bpy.data.materials)

$\endgroup$
4
  • $\begingroup$ thanks for the suggestion. I have modified my code. But the problem still persists. The material is not getting applied. I still get a blank .png. Below is my modified code: codepad.co/snippet/ehzu7AHY $\endgroup$
    – bot4u
    Commented Sep 13, 2016 at 9:30
  • $\begingroup$ 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. $\endgroup$
    – Mutant Bob
    Commented Sep 13, 2016 at 15:54
  • $\begingroup$ 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 $\endgroup$
    – bot4u
    Commented Sep 13, 2016 at 17:05
  • $\begingroup$ You should probably post an answer to your own question that says "the scene's rendering engine did not match the materials, and here is how I fixed it" $\endgroup$
    – Mutant Bob
    Commented Sep 14, 2016 at 14:38
0
$\begingroup$

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

$\endgroup$

You must log in to answer this question.

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