1
$\begingroup$

Currently, I'm working on a lot of files imported from Autodesk Maya to be rendered in Blender 2.8 EEVEE. And of course, the material looks bad when rendered. And will be a lot of work to fix all of these materials on every blend file by hand. So, I tried this python script to replace materials in the current file with the fixed one from other file:

import bpy

scn = bpy.context.scene
D = bpy.data
filepath = '//10_rrd.blend'

with bpy.data.libraries.load(filepath, link=False) as (data_from, data_to):
    data_to.materials = data_from.materials

for mat in D.materials:
    for mat_fix in data_to.materials:
        if mat_fix.name == mat.name:
            print('Found a material copy for '+mat.name+' with name '+mat_fix.name)
            mat.diffuse_color = mat_fix.diffuse_color
            mat.metallic = mat_fix.metallic
            mat.roughness = mat_fix.roughness
            mat.specular_intensity = mat_fix.specular_intensity

The problem is:

Instead of replacing the properties of the material in current blend file, It appends the full material as a new material (with those '.001' suffix) in the current file without touching the materials that needs to be replaced.

What's wrong with my code? Is there is any fix? or should I stick with traditional way of replacing material of every object after it's appended?

By the way, It's not a problem of EEVEE.

$\endgroup$
2
  • $\begingroup$ I guess bpy.data.libraries.load()... appends the material as a new one. Does it print your "Found a material..." in the console? $\endgroup$
    – Benedikt
    Apr 29, 2019 at 7:03
  • $\begingroup$ Yes, it is. But it doesn't change the existing material, just print that there is a copy of the material. $\endgroup$ Apr 29, 2019 at 7:51

1 Answer 1

3
$\begingroup$

This code

with bpy.data.libraries.load(filepath, link=False) as (data_from, data_to):
    data_to.materials = data_from.materials

works correctly and you will get appended materials with suffix*.001* in your actual blend file. I propose , maybe not very elegant solution, but it works I have tested on my side. And it gives you possibility not to replace all materials after adding. The script looks in next way:

import bpy

scn = bpy.context.scene
D = bpy.data
filepath = '//10_rrd.blend'    

actual_names = []
dict_names = {}

for i in range(len(D.materials)):
    s = D.materials[i].name + "_actual"
    dict_names[s] = D.materials[i].name
    D.materials[i].name = s
    actual_names.append(D.materials[i].name)    

with bpy.data.libraries.load(filepath, link=False) as (data_from, data_to):
    data_to.materials = data_from.materials  


all_names = []
for m in bpy.data.materials:
    all_names.append(m.name)

# finding name of added materials
s = set(actual_names)
new_added = [x for x in all_names if x not in s]

for mat in D.materials:    
    for mat_fix_name in new_added:
        value = dict_names.get(mat.name, None)        
        if mat_fix_name == value:
            print('Found a material copy for '+mat.name+' with name '+mat_fix_name)
            mat.diffuse_color = D.materials[value].diffuse_color
            mat.metallic = D.materials[value].metallic
            mat.roughness = D.materials[value].roughness
            mat.specular_intensity = D.materials[value].specular_intensity

print('-----------------------------------------------')

#clear appended materials
for mat_fix_name in new_added:
    D.materials[mat_fix_name].user_clear()
    bpy.data.materials.remove(D.materials[mat_fix_name])

#roll back names
for mat in D.materials:
    old_name = dict_names.get(mat.name, None)
    if old_name is not None:
        mat.name = old_name
$\endgroup$
1
  • $\begingroup$ Thank you, I haven't think that far since I'm new to Phyton and with the change of 2.80 API (though looks like the Append API haven't changed). $\endgroup$ May 6, 2019 at 15:06

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.