Blender Plugin 1.8.0
NEW: - auto gen. Emptys at mesh origin - fix naming convention from point to underscore - auto gen. Collections for Unreal export FIX: - "Fix Material Names" completely redone (pls test)
This commit is contained in:
169
Blender/_Source/L1960_Tools_1_8_0/Helper.py
Normal file
169
Blender/_Source/L1960_Tools_1_8_0/Helper.py
Normal file
@@ -0,0 +1,169 @@
|
||||
import bpy
|
||||
import re
|
||||
|
||||
### FIX MATERIALS ###
|
||||
|
||||
class MESH_OT_fix_material_names(bpy.types.Operator):
|
||||
"""Fixes the material naming, if duplicated are present e.g. Material.001, Material.002 ..."""
|
||||
|
||||
bl_idname = "mesh.fix_material_names"
|
||||
bl_label = "Fixes the material naming, if duplicated are present"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
#Remove all duplicated materials
|
||||
self.merge_duplicated_materials()
|
||||
|
||||
#Merge material slots for every mesh in the scene
|
||||
#for obj in bpy.context.scene.objects:
|
||||
#if obj.type == "MESH":
|
||||
#self.merge_material_slots(obj)
|
||||
|
||||
self.report({'INFO'}, 'All duplicated Materials fixed')
|
||||
return {"FINISHED"}
|
||||
|
||||
def merge_duplicated_materials(self):
|
||||
for material in bpy.data.materials:
|
||||
if material.name[-3].isnumeric():
|
||||
opti_matName = material.name[:-4]
|
||||
if bpy.data.materials.get(opti_matName): #check if og_mat exists
|
||||
material.user_remap(bpy.data.materials.get(opti_matName))
|
||||
print("Removed Material: " + material.name)
|
||||
bpy.data.materials.remove(material)
|
||||
else:
|
||||
material.name = opti_matName
|
||||
|
||||
def merge_material_slots(self, obj):
|
||||
duplicated_material_list = []
|
||||
|
||||
#create list with indexes of material slots with the same name
|
||||
for og_slot in obj.material_slots:
|
||||
for slot in obj.material_slots:
|
||||
if slot.name == og_slot.name:
|
||||
if slot.slot_index == og_slot.slot_index:
|
||||
continue
|
||||
if og_slot.slot_index in duplicated_material_list:
|
||||
continue
|
||||
duplicated_material_list.append(int(slot.slot_index))
|
||||
|
||||
#delete all material slots within list
|
||||
for slot_index in sorted(duplicated_material_list, reverse=True):
|
||||
obj.data.materials.pop(index = slot_index)
|
||||
|
||||
|
||||
### GROUP OBJECTS TO COLLECTIONS ###
|
||||
|
||||
class MESH_OT_group_objects_in_collections(bpy.types.Operator):
|
||||
"""Groups objects by name into seperate collections, usefull for Unreal Decogon import"""
|
||||
|
||||
bl_idname = "mesh.group_objects_in_collections"
|
||||
bl_label = "Groups objects by name into seperate collections, usefull for Unreal Decogon import"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
# Erstellen einer leeren Dictionary zur Speicherung der Collections nach Basisnamen
|
||||
collection_dict = {}
|
||||
|
||||
# Durchlaufen aller Objekte in der Szene
|
||||
for obj in bpy.context.scene.objects:
|
||||
# Überprüfen, ob das Objekt ein leeres Elternobjekt ist
|
||||
if obj.type == 'EMPTY':
|
||||
# Anwenden der Regex auf den Objektnamen
|
||||
match = re.match(r'^(.*?)_(.*?)_(\d+)([a-zA-Z]+)$', obj.name)
|
||||
if match:
|
||||
prefix = match.group(1)
|
||||
name = match.group(2)
|
||||
number = match.group(3)
|
||||
letter = match.group(4)
|
||||
|
||||
# Extrahieren des Basisnamens für die Collection
|
||||
base_name = f"L1960_{name}"
|
||||
|
||||
# Hinzufügen des Objekts zur entsprechenden Liste in der Dictionary
|
||||
if base_name not in collection_dict:
|
||||
collection_dict[base_name] = {}
|
||||
if number not in collection_dict[base_name]:
|
||||
collection_dict[base_name][number] = {}
|
||||
if letter not in collection_dict[base_name][number]:
|
||||
collection_dict[base_name][number][letter] = {'empty': obj, 'children': []}
|
||||
|
||||
# Durchlaufen der Dictionary und Erstellen der Collections
|
||||
for base_name, number_dict in collection_dict.items():
|
||||
# Erstellen einer neuen Collection für den Basisnamen
|
||||
base_collection = bpy.data.collections.new(base_name)
|
||||
bpy.context.scene.collection.children.link(base_collection)
|
||||
|
||||
# Durchlaufen der sortierten Liste der Objekte und Verschieben in die Collections
|
||||
for number, letter_dict in number_dict.items():
|
||||
# Erstellen einer Collection für die Nummer und Verschieben des leeren Elternobjekts dorthin
|
||||
number_collection = bpy.data.collections.new(f"{base_name}_{number}")
|
||||
base_collection.children.link(number_collection)
|
||||
|
||||
# Durchlaufen der Buchstaben und Erstellen der Buchstaben-Collection unter der Nummer
|
||||
for letter, obj_data in letter_dict.items():
|
||||
empty = obj_data['empty']
|
||||
children = empty.children
|
||||
|
||||
letter_collection = bpy.data.collections.new(f"{base_name}_{number}{letter}")
|
||||
number_collection.children.link(letter_collection)
|
||||
|
||||
# Verschieben des leeren Elternobjekts in die entsprechende Collection
|
||||
letter_collection.objects.link(empty)
|
||||
|
||||
# Verschieben der Kinder des leeren Elternobjekts in die entsprechende Collection
|
||||
for child in children:
|
||||
letter_collection.objects.link(child)
|
||||
|
||||
# Entfernen des leeren Elternobjekts und seiner Kinder aus der Szene
|
||||
bpy.context.collection.objects.unlink(empty)
|
||||
for child in children:
|
||||
bpy.context.collection.objects.unlink(child)
|
||||
|
||||
self.report({'INFO'}, 'All objects sorted')
|
||||
return {"FINISHED"}
|
||||
|
||||
### FIX NAMING CONVENTIONS ###
|
||||
|
||||
class MESH_OT_fix_naming_conventions(bpy.types.Operator):
|
||||
"""Changes . to _ to solve naming issues with workbench"""
|
||||
|
||||
bl_idname = "mesh.fix_naming_convention"
|
||||
bl_label = "Changes . to _ to solve naming issues with workbench"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
for obj in bpy.data.objects:
|
||||
obj.name = obj.name.replace(".","_")
|
||||
|
||||
self.report({'INFO'}, 'Fixed Naming')
|
||||
return {"FINISHED"}
|
||||
|
||||
class MESH_OT_generate_empty_for_mesh(bpy.types.Operator):
|
||||
"""Generates a Empty with the objects name at it´s position"""
|
||||
|
||||
bl_idname = "mesh.generate_empty_for_mesh"
|
||||
bl_label = "Generates a Empty with the objects name at it´s position"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
scene = bpy.context.scene
|
||||
Selection = bpy.context.selected_objects
|
||||
FilteredSelection = [obj for obj in Selection if obj.type != 'EMPTY']
|
||||
ActiveObj = bpy.context.active_object
|
||||
|
||||
for obj in FilteredSelection:
|
||||
oldEmpty = scene.objects.get("Socket_" + obj.name)
|
||||
if oldEmpty:
|
||||
oldEmpty.location = obj.location
|
||||
oldEmpty.rotation_euler = obj.rotation_euler
|
||||
else:
|
||||
obj.select_set(True)
|
||||
bpy.ops.object.empty_add(type='PLAIN_AXES', align='WORLD', location=obj.location, scale=(1, 1, 1), rotation=obj.rotation_euler)
|
||||
empty = bpy.context.active_object
|
||||
empty.name = "Socket_" + obj.name
|
||||
|
||||
#Change back to selection and select old active
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
|
||||
self.report({'INFO'}, 'Generated Emptys for selectes Meshes in Scene')
|
||||
return {"FINISHED"}
|
||||
Reference in New Issue
Block a user