Files
1960-utils/Blender/_Source/L1960_Tools_1_8_0/Helper.py
ProDeath21 5e62f1d81d 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)
2024-05-13 23:25:03 +02:00

170 lines
7.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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"}