3
$\begingroup$

I have two blender files that have different materials with the same names.

Both were originally in Blender Internal, but I manually converted the BI materials to eevee in one of them.

The other file, which has a lot of materials with the same exact names as in the other, does not have the updated versions yet, and I'd like to easily swap them out for the ones I manually converted.

enter image description here

enter image description here

enter image description here

I have almost 600 materials in the first file that may need to replace the old ones in the second file, so if I can avoid having to go through each one, that would be awesome.

$\endgroup$

1 Answer 1

3
$\begingroup$

Python script

Change the path on line 3 src_file = "E:/tempmymat.blend"

import bpy

src_file = "E:/tempmymat.blend"

D = bpy.data


def main():
    # find materials that you want to replace
    bad_mats = {m.name:m for m in D.materials if not m.library}
    
    # load materials to replace with
    with D.libraries.load(src_file, link=True) as (src, me):
        me.materials = [name for name in src.materials if name in bad_mats]
    
    # create copies of the loaded file's materials, rename them and store
    # a convenient dictionary pointing from old materials to new materials
    replacements = {}
    for m in me.materials:
        new_mat = m.copy()
        bad_mat = bad_mats[m.name]
        new_mat.name = m.name
        replacements[bad_mat] = new_mat
        
    # find old materials and replace with new materials
    for o in D.objects:
        for slot in o.material_slots:
            replacement = replacements.get(slot.material)
            if replacement:
                slot.material = replacement
                
    # unlink old materials and the external file (library)
    for m in bad_mats.values():
        D.materials.remove(m)
    D.libraries.remove(D.libraries[-1])


main()

if not m.library is used on the first line of main() in order to ensure there's a single material with each name. If you need to make it work with materials linked to other files also being replaced, remove that condition. If you're worried that as a result you can indeed get multiple materials with the same name in that dictionary, you need to come up with some other method of associating a loaded material with an existing material.

Related:

How to know which object is using a material

How can I replace a material from Python?

How to Link/Append a data-block using the Python API?

$\endgroup$
3
  • $\begingroup$ It worked! Thank you! $\endgroup$ Jul 12, 2021 at 21:05
  • $\begingroup$ Thanks for the great answer, Markus. It was a good head start into scripting Blender for me. Unfortunately, your script does not do deep copies of materials. That means that image texture for example get lost when unlinking the source file. Is there an easy way to copy all dependencies of material nodes? $\endgroup$ Nov 3, 2022 at 18:00
  • $\begingroup$ Try link=False $\endgroup$ Nov 3, 2022 at 18:55

You must log in to answer this question.

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