Simple-Material-Flattener/operators.py

105 lines
3.9 KiB
Python

import bpy
import bpy.ops
from bpy.types import Operator
class SMF_OT_flatten_materials(Operator):
bl_idname = 'scene.flatten_materials'
bl_label = 'Flatten materials'
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return True
def execute(self, context):
# self.scene = context.scene
# bpy.context.selected_objects
# object.material_slots[0].material.node_tree.nodes (list)
# bpy.ops.object.material_slot_select()
# bpy.ops.object.mode_set(mode='EDIT') (mode='OBJECT)
# bpy.types.ShaderNodeTexImage() ???
# bpy.ops is expensive and should be avoided: re-assign verts without ops?
# view a verts mat? or a mats verts?
selected_objects = [i for i in bpy.context.selected_objects]
store_selected_objects = selected_objects.copy()
last_image = None
#select none
bpy.ops.object.select_all(action='DESELECT')
for o in selected_objects:
bpy.context.view_layer.objects.active = o
imageMaterialNames = {}
print("gettings materials from %s" % o.name)
# select this object
o.select_set(True)
# switch to edit Mode
bpy.ops.object.material_slot_remove_unused()
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='DESELECT')
for slot in o.material_slots:
nodes = slot.material.node_tree.nodes
# Check to not break more complex materials
if not self.CheckIsSimpleMaterial(nodes):
print("not simple enough")
continue
image = self.getImage(nodes)
if not last_image: last_image = image
if last_image == image:
print("add to selection")
o.active_material_index = slot.slot_index
bpy.ops.object.material_slot_select()
continue
# materials are not the same: Finish up last image and start again
if last_image in imageMaterialNames:
print("re-assigning materials")
print("Hard Mode")
# select other material's mesh # active material index bpy.data.objects["name"].active_material_index : INT
o.active_material_index = o.material_slots[imageMaterialNames[last_image]].slot_index
# assign to this slot # bpy.ops.object.material_slot_assign()
bpy.ops.object.material_slot_assign()
else:
print("new texture path: %s" % last_image.filepath)
imageMaterialNames[last_image] = o.material_slots[o.active_material_index].name
bpy.ops.object.material_slot_assign()
bpy.ops.mesh.select_all(action='DESELECT')
last_image = image
# select this material
o.active_material_index = slot.slot_index
# select this materials faces
bpy.ops.object.material_slot_select()
bpy.ops.object.material_slot_assign()
# switch to object mode
bpy.ops.object.mode_set(mode='OBJECT')
# remove unused slots
bpy.ops.object.material_slot_remove_unused()
# reselect all
for o in selected_objects:
o.select_set(True)
return {'FINISHED'}
def getImage(self, nodes):
for node in nodes:
if node.type == 'TEX_IMAGE':
return node.image
else:
return False
def CheckIsSimpleMaterial(self, nodes):
if len(nodes) != 3: return False
else: return True