Eliminate duplicate materials .001 .002 .003 after Append

Hi Im looking for a script to eliminate multiple materials, when I Append models which use identical materials I end up with lots of duplicates, like glass, glass.001 glass.002, glass.003. … Then I have to “Databrose” which dosnt have the nice new material previews.
I really dont want to write my own as Im lazy and busy although I will probably end up doing so.
Im pretty sure there isnt any way to “use existing” or “replace” materials when importing but please let me know if there is as this would help also.

Any help appreciated.
lobo_nz

I have the same problem when importing a wrl generated by Catia. Anything possible about this?

Here’s a script I wrote for 2.49 that will “ease” this…

(It could be modified to automatically pattern match based on name, but I personally think that could be dangerous so made it a “wizard”

Usage?

run the script… (I think I put it in the “objects” category rather than the materials one… but you could always run it form the text editor…

it’ll pop up a list of materials for you to choose a material to replace, then offer a similar popup for what to replace it with…

It will then find and replace all references to the first material with the second…

If you save the scene and reload the “replaced” material will be gone…

Here’s a link
http://www.cowtoolsmedia.co.uk/scripts/substitutemat.py.zip

inside the script is a function:

mw_replaceMat(inMat,outMat, allScenes =True,sel =False)

You could import my script, build a list of materials with “auto names” and then call that function to automate it more… but the trick is when you get close to the 21 character limit and thenames have been truncated…

How many materials have you got that are 21 characters long? I guess it could be an option to delete any of this length, 21 char (abcdefghijklmnopqrst) This is an extreme conditional but I cant really think of any other way of doing it…

I’ve done some video game work where the naming conventions imposed by the client meant that 21 characters for a material name was woefully inadequate… I ended up having to use all sorts of hacks and workarounds in blender and maya to get stuff named right once transferred to Maya…

Which is why the “wizard” approach works for me… it only takes a few minutes for even very complex scenes… but truncated names aside:

a “slightly” dangerous way to do it (could potentially damage any material name with a “.” if what precedes the dot is the same name as another material in the scene.

importing my script and then doing something like the following should do what you want:


import bpy
import substitutemat
from substitutemat import*

mats = bpy.data.materials
for m in mats:
    #find the name without any auto numbered stuff:
    nm = m.name.split('.')[0]


    #check to see if the portion before the "." matches an existing material
    if nm in mats:
        mw_replaceMat(m.name, nm)

any material names that got truncated and didn’t match would have to be cleaned by just running the first script wizard I posted… which is safer I guess, and only necesary with long material names anyway!

Oops, of course I’m checking a list of material objects against a string! that’s never match…


import bpy 
import substitutemat 
from substitutemat import* 
 
mats = bpy.data.materials 
#build a list of material names in the scene: 

matnames = [] 
for m in mats: 
    matnames.append(m.name) 
 
 
for m in mats: 
    #find the name without any auto numbered stuff: 
    nm = m.name.split('.')[0] 
    #check to see if the portion before the "." matches an existing material 
    if nm in matnames: 
         mw_replaceMat(m.name, nm)

This is about the fourth edit of this!

do you think we could ask the devs to increase the character limit in the next svn release? any idea why 21?

I asked Letterip ages ago… he said he’d pass it on…

this stuff, whilst probably easy for someone to do, really takes someone to “need” it themselves to do the code… I’d patch it myself if I could code!!!

your scripting so you can code :s

I was just assuming that the number 21 was just a variable set somewhere…

Any similar script to this one still in existence?

here’s a very basic snippet that worked for me, at least for simple scenes


## 'desduplicar' materiales

import bpy
mats = bpy.data.materials

for obj in bpy.data.objects:
    for slt in obj.material_slots:
        part = slt.name.rpartition('.')
        if part[2].isnumeric() and part[0] in mats:
            slt.material = mats.get(part[0])

2 Likes

don’t see it as an import script

it only checks for same name with number at the end

do you want to convert it as an import script too ?

but if there are like 1000 mat this might get very sluggish !

happy bl

would this work also for nodegroups, changing the appropriate bpy.data.stuff?

1 Like

to deduplicate nodegroups in materials it could be something like this:


## deduplicate nodegroups in materials from name

import bpy
n_gs = bpy.data.node_groups

for mat in bpy.data.materials:
    for nt in mat.node_tree.nodes:
        if nt.type == 'GROUP':
            part = nt.node_tree.name.rpartition('.')
            if part[2].isnumeric() and part[0] in n_gs:
                nt.node_tree = n_gs.get(part[0])

but you need to be careful as it will go through all materials
there’s also the new id_remap thing meant for this situations I believe

1 Like

Like a charm, thank you! In addition, I used to replace upper/lowercase duplicates:

for obj in bpy.data.objects:    for slt in obj.material_slots:
        if slt.name != slt.name.lower() and slt.name.lower() in mats:
            slt.material = mats.get(slt.name.lower())

Works as expected. Thank you for script! Save me a lot this time.

tried that script and it does not et rid of same name with different index at the end

anyone has a working script for 2.79

thanks
happy bl

I posted this in the released scripts and themes forum last year. It takes all of the materials with different indexes and assigns them to the material with the base name. So, objects with the materials called mat, mat.001, mat.002, mat.003, etc will all be assigned the mat material.

Edit: sorry, it’s been a while since I’ve had to use this. Actually, what you do is pick a material slot that you like. So it could be mat.002 and all materials with the prefix mat will be assigned the material mat.002.

does it re assign faces to the first mat too ?

that is one problem I see with the old script
unless this is an API bug

don’t understand how come you can get many material with same name now

will test your addon

thanks
happy bl

but I would prefer to do it on the selected objects not all ob
I mean in some scene I may have 100’s of objects with over 2 millions verts or more

takes too much time and may change appearance of some render

thanks
happy bl