3
$\begingroup$

I just made a scene with a city made of mostly identical skyscrapers. I did that by copying and pasting. Then I joined all of them with Ctrl+J, but now I can't undo the join and I have got around 300+ glass and wall materials in one obj. My question is how do I merge them into 1 glass and 1 wall material so I can change all windows and all walls at once? Selecting them all is not an option. I have 1000+ windows in my scene and now in one obj.

Short version: I mucked up and now I need to clean up 300+ materials. How can I do that? Maybe an add-on?

edit: I tried deleting all but the first glass and wall. i had one skyscraper left that had colors.

edit2: my materials are in alternating order. like glass, wall, glass, wall, glass, wall.... i think you get the idea.

$\endgroup$
  • $\begingroup$ Can you post the blend file (or just a small sample of it with the problem)? I'm not sure what your material slots look like and what order they are in. $\endgroup$ – David Mar 16 '17 at 14:22
  • 2
    $\begingroup$ Script is needed to do this. It has to know some pattern to know how to merge. Do the materials have a naming convention? Let's say all glass materials have "glass" in them? Or are they in some specific order? Or do all glass materials have the same setting/nodes? $\endgroup$ – Jaroslav Jerryno Novotny Mar 16 '17 at 14:27
  • $\begingroup$ Close to your need, but not sure it can do it all (untested) wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/… $\endgroup$ – lemon Mar 16 '17 at 18:22
  • 3
    $\begingroup$ Possible duplicate of How to append many objects without appending materials $\endgroup$ – Duarte Farrajota Ramos Mar 17 '17 at 0:10
  • $\begingroup$ This is not as straightforward as it seems. When you copy - paste objects in Blender, unfortunately not only the object is duplicated, but also the materials on the object. So that's why you get materials called Glass.001, Glass.002, Glass.003 and so on. For Blender, those are now entirely different materials, even though they look identical. If you had used Shift D to duplicate the objects, the materials would have remained singular, even after joining the meshes. The only solution here is a brute-force addon which changes material assignments by name. It's possible but not safe $\endgroup$ – aliasguru Mar 19 '17 at 14:42
3
$\begingroup$

The following script extends from the already linked answer in that it removes any double-materials and assigns the 'correct' materials to the faces respectively. However, you'll need to understand that a few assumptions are made here:

  • your original material is named something
  • the duplicates are named something.045, something.046 and so on
  • they are REALLY duplicates
  • you've saved your scene before you run this :)
  • the active object in your scene is the mesh object you want to clean

Copy the following Python code to a text editor within your file and run it:

import bpy

# only search on own object materials
mat_list = [x.material.name for x in bpy.context.object.material_slots]
remove_slots = []


# the following only works in object mode
bpy.ops.object.mode_set(mode='OBJECT')

for s in bpy.context.object.material_slots:
    if s.material.name[-3:].isnumeric():
        # the last 3 characters are numbers
        # that indicates it might be a duplicate of another material
        # but this is pure guesswork, so expect errors to happen!
        if s.material.name[:-4] in mat_list:

            # there is a material without the numeric extension so use it
            # this again is just guessing that we're having identical node trees here

            # get the material index of the 'clean' material
            index_clean = mat_list.index(s.material.name[:-4])
            index_wrong = mat_list.index(s.material.name)
            print(index_wrong, index_clean)

            # get the faces which are assigned to the 'wrong' material
            faces = [x for x in bpy.context.object.data.polygons if x.material_index == index_wrong]

            for f in faces:
                f.material_index = index_clean

            remove_slots.append(s.name)

# now remove all empty material slots:
for s in remove_slots:

    if s in [x.name for x in bpy.context.object.material_slots]:
        print('removing slot %s' % s)
        bpy.context.object.active_material_index = [x.material.name for x in bpy.context.object.material_slots].index(s)
        bpy.ops.object.material_slot_remove()

It should turn this:

start

into this:

finish

$\endgroup$
  • $\begingroup$ replying to a very old question, but its nice to be able to mark it solved $\endgroup$ – laundmo Jun 19 at 22:55
0
$\begingroup$

If you enter edit mode, you can select each glass material, and click select (Not sure if you can select all of them, and click select once or do them individually off the top of my head) then once everything that uses all of your glass materials is selected, delete all but one of them with the minus button near the top of the panel, then select that one material and click the "Assign" button underneath the panel. Rinse and repeat for the walls.

$\endgroup$

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.