diff --git a/Blender/_Release/L1960_Tools_1_3_0.zip b/Blender/_Release/L1960_Tools_1_3_0.zip new file mode 100644 index 0000000..ef3e6b0 Binary files /dev/null and b/Blender/_Release/L1960_Tools_1_3_0.zip differ diff --git a/Blender/_Release/L1960_Tools_1_4_0.zip b/Blender/_Release/L1960_Tools_1_4_0.zip new file mode 100644 index 0000000..63be180 Binary files /dev/null and b/Blender/_Release/L1960_Tools_1_4_0.zip differ diff --git a/Blender/_Release/L1960_Tools_1_5_0.zip b/Blender/_Release/L1960_Tools_1_5_0.zip new file mode 100644 index 0000000..43d7f01 Binary files /dev/null and b/Blender/_Release/L1960_Tools_1_5_0.zip differ diff --git a/Blender/_Release/L1960_Tools_1_6_0.zip b/Blender/_Release/L1960_Tools_1_6_0.zip new file mode 100644 index 0000000..a0e4b81 Binary files /dev/null and b/Blender/_Release/L1960_Tools_1_6_0.zip differ diff --git a/Blender/_Source/L1960_Tools_1_3_0/CubeProjection.py b/Blender/_Source/L1960_Tools_1_3_0/CubeProjection.py new file mode 100644 index 0000000..c586c48 --- /dev/null +++ b/Blender/_Source/L1960_Tools_1_3_0/CubeProjection.py @@ -0,0 +1,94 @@ +import bpy +from math import pi + +L1960_Arr_PlainData = [ + ["Proj_Empty_01", (0, 0, 2), (0, 0, 0)], + ["Proj_Empty_02", (2, 0, 0), ((pi * 90 / 180), 0, (pi * 90 / 180))], + ["Proj_Empty_03", (0, 2, 0), ((pi * 90 / 180), 0, (pi * 180 / 180))], + ["Proj_Empty_04", (0, 0, -2), ((pi * 180 / 180), 0, 0)], + ["Proj_Empty_05", (-2, 0, 0), ((pi * 90 / 180), 0, (pi * -90 / 180))], + ["Proj_Empty_06", (0, -2, 0), ((pi * 90 / 180), 0, 0)] +] + +class MESH_OT_add_auto_cube_projection(bpy.types.Operator): + """Check Empty´s for projecting, if not existing create new one´s""" + + bl_idname = "mesh.add_auto_cube_projection" + bl_label = "Add Plain_Axes to scene" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + + scene = bpy.context.scene + oldSelection = bpy.context.selected_objects + oldActive = bpy.context.active_object + + for EmptyData in L1960_Arr_PlainData: + + EmptyName = EmptyData[0] + EmptyLocation = EmptyData[1] + EmptyRotation = EmptyData[2] + + if not scene.objects.get(EmptyName): + bpy.ops.object.empty_add(type='PLAIN_AXES', align='WORLD', location=EmptyLocation, scale=(1, 1, 1), rotation=EmptyRotation) + empty = bpy.context.active_object + empty.name = EmptyName + empty.hide_select = True + empty.hide_set(True) + + #Change back to old selection and select old active + for obj in oldSelection: + obj.select_set(True) + bpy.context.view_layer.objects.active = oldActive + + self.report({'INFO'}, 'Added/Fixed Emptys for Projection to Scene') + return {"FINISHED"} + +class MESH_OT_add_modifier_to_mesh(bpy.types.Operator): + """Add Modifier to selected Mesh´s and prepare UV-Maps""" + + bl_idname = "mesh.add_modifier_to_mesh" + bl_label = "Add Modifier to selected Mesh" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + + newModifierName = "CubeTexModifier" + Arr_obj = bpy.context.selected_objects + if len(Arr_obj) < 1: + self.report({'WARNING'}, 'Select a mesh to add the UVProject-Modifier') + return {"CANCELLED"} + + empty_objs = [emp_obj for emp_obj in bpy.context.scene.objects if emp_obj.name.startswith("Proj_Empty")] + if len(empty_objs) < 6: + self.report({'WARNING'}, 'Create/Recreate projectors, they need to be set up first!') + return {"CANCELLED"}; + + for obj in Arr_obj: + + if obj.data.uv_layers.get("UVMap"): + obj.data.uv_layers['UVMap'].name = 'UVMap0' + + if not obj.data.uv_layers.get("UVMap0"): + obj.data.uv_layers.new(name = 'UVMap0') + + if not obj.data.uv_layers.get("UVMap1"): + obj.data.uv_layers.new(name = 'UVMap1') + + + if obj.type == "MESH" and newModifierName not in obj.modifiers: + obj.modifiers.new(type='UV_PROJECT', name=newModifierName) + mod = obj.modifiers[newModifierName] + mod.uv_layer = "UVMap1" + mod.projector_count = 6 + + i = 0 + for p in mod.projectors: + p.object = bpy.data.objects[L1960_Arr_PlainData[i][0]] + i = i+1 + else: + self.report({'INFO'}, 'UVProject-Modifier allready set') + return {"FINISHED"} + + self.report({'INFO'}, 'Added UVProject-Modifier to mesh') + return {"FINISHED"} \ No newline at end of file diff --git a/Blender/_Source/L1960_Tools_1_3_0/FixMaterials.py b/Blender/_Source/L1960_Tools_1_3_0/FixMaterials.py new file mode 100644 index 0000000..83e9dbd --- /dev/null +++ b/Blender/_Source/L1960_Tools_1_3_0/FixMaterials.py @@ -0,0 +1,65 @@ +import bpy + +def replace_material(bad_mat, good_mat): + bad_mat.user_remap(good_mat) + bpy.data.materials.remove(bad_mat) + + +def get_duplicate_materials(og_material): + + common_name = og_material.name + + if common_name[-3:].isnumeric(): + common_name = common_name[:-4] + + duplicate_materials = [] + + for material in bpy.data.materials: + if material is not og_material: + name = material.name + if name[-3:].isnumeric() and name[-4] == ".": + name = name[:-4] + + if name == common_name: + duplicate_materials.append(material) + + text = "{} duplicate materials found" + print(text.format(len(duplicate_materials))) + + return duplicate_materials + + +def remove_all_duplicate_materials(): + i = 0 + while i < len(bpy.data.materials): + + og_material = bpy.data.materials[i] + + print("og material: " + og_material.name) + + # get duplicate materials + duplicate_materials = get_duplicate_materials(og_material) + + # replace all duplicates + for duplicate_material in duplicate_materials: + replace_material(duplicate_material, og_material) + + # adjust name to no trailing numbers + if og_material.name[-3:].isnumeric() and og_material.name[-4] == ".": + og_material.name = og_material.name[:-4] + + i = i+1 + +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_duplicate_materials() + + self.report({'INFO'}, 'All duplicated Materials merged/fixed') + return {"FINISHED"} \ No newline at end of file diff --git a/Blender/_Source/L1960_Tools_1_3_0/__init__.py b/Blender/_Source/L1960_Tools_1_3_0/__init__.py new file mode 100644 index 0000000..db136c6 --- /dev/null +++ b/Blender/_Source/L1960_Tools_1_3_0/__init__.py @@ -0,0 +1,65 @@ +bl_info = { + "name": "L1960 Tools", + "author": "Prodeath21", + "version": (1, 3, 0), + "blender": (2, 80, 0), + "location": "3D Viewport > Sidebar > 1960Life category", + "description": "Set´s up the Projection-Modifier automatically and add´s in the Emptys if not allready created.", + "category": "Object", +} + +# ---------------------------------------------- +# Import modules +# ---------------------------------------------- +if "bpy" in locals(): + import imp + imp.reload(CubeProjection) + imp.reload(FixMaterials) + print("L1960 Tools: Reloaded multifiles") +else: + import bpy + from . import CubeProjection + from . import FixMaterials + +from . CubeProjection import MESH_OT_add_auto_cube_projection, MESH_OT_add_modifier_to_mesh +from . FixMaterials import MESH_OT_fix_material_names + +class L1960_PT_AutoAddProjection(bpy.types.Panel): + pass + #where to add the panel + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + + #add labels + bl_label = "1960-Life Tools" + bl_category = "1960-Life" + + def draw(self, context): + """define the layout of the panel""" + self.layout.label(text="UV-Projection") + row = self.layout.row() + row.operator("mesh.add_auto_cube_projection", text="Set up Projectors") + row = self.layout.row() + row.operator("mesh.add_modifier_to_mesh", text="Add Modifier to Mesh") + self.layout.separator() + self.layout.label(text="Materials") + row = self.layout.row() + row.operator("mesh.fix_material_names", text="Fix Material Name´s") + #self.layout.separator() + #self.layout.label(text="LOD´s") + #row = self.layout.row() + #row.operator("mesh.prepareLods_decimate", text="Create LOD´s with decimate") + +#register the panel with blender +modules = [L1960_PT_AutoAddProjection, MESH_OT_add_auto_cube_projection, MESH_OT_add_modifier_to_mesh, MESH_OT_fix_material_names] + +def register(): + for mod in modules: + bpy.utils.register_class(mod) + +def unregister(): + for mod in modules: + bpy.utils.unregister_class(mod) + +if __name__== "__main__": + register() \ No newline at end of file diff --git a/Blender/_Source/L1960_Tools_1_4_0/CubeProjection.py b/Blender/_Source/L1960_Tools_1_4_0/CubeProjection.py new file mode 100644 index 0000000..c586c48 --- /dev/null +++ b/Blender/_Source/L1960_Tools_1_4_0/CubeProjection.py @@ -0,0 +1,94 @@ +import bpy +from math import pi + +L1960_Arr_PlainData = [ + ["Proj_Empty_01", (0, 0, 2), (0, 0, 0)], + ["Proj_Empty_02", (2, 0, 0), ((pi * 90 / 180), 0, (pi * 90 / 180))], + ["Proj_Empty_03", (0, 2, 0), ((pi * 90 / 180), 0, (pi * 180 / 180))], + ["Proj_Empty_04", (0, 0, -2), ((pi * 180 / 180), 0, 0)], + ["Proj_Empty_05", (-2, 0, 0), ((pi * 90 / 180), 0, (pi * -90 / 180))], + ["Proj_Empty_06", (0, -2, 0), ((pi * 90 / 180), 0, 0)] +] + +class MESH_OT_add_auto_cube_projection(bpy.types.Operator): + """Check Empty´s for projecting, if not existing create new one´s""" + + bl_idname = "mesh.add_auto_cube_projection" + bl_label = "Add Plain_Axes to scene" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + + scene = bpy.context.scene + oldSelection = bpy.context.selected_objects + oldActive = bpy.context.active_object + + for EmptyData in L1960_Arr_PlainData: + + EmptyName = EmptyData[0] + EmptyLocation = EmptyData[1] + EmptyRotation = EmptyData[2] + + if not scene.objects.get(EmptyName): + bpy.ops.object.empty_add(type='PLAIN_AXES', align='WORLD', location=EmptyLocation, scale=(1, 1, 1), rotation=EmptyRotation) + empty = bpy.context.active_object + empty.name = EmptyName + empty.hide_select = True + empty.hide_set(True) + + #Change back to old selection and select old active + for obj in oldSelection: + obj.select_set(True) + bpy.context.view_layer.objects.active = oldActive + + self.report({'INFO'}, 'Added/Fixed Emptys for Projection to Scene') + return {"FINISHED"} + +class MESH_OT_add_modifier_to_mesh(bpy.types.Operator): + """Add Modifier to selected Mesh´s and prepare UV-Maps""" + + bl_idname = "mesh.add_modifier_to_mesh" + bl_label = "Add Modifier to selected Mesh" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + + newModifierName = "CubeTexModifier" + Arr_obj = bpy.context.selected_objects + if len(Arr_obj) < 1: + self.report({'WARNING'}, 'Select a mesh to add the UVProject-Modifier') + return {"CANCELLED"} + + empty_objs = [emp_obj for emp_obj in bpy.context.scene.objects if emp_obj.name.startswith("Proj_Empty")] + if len(empty_objs) < 6: + self.report({'WARNING'}, 'Create/Recreate projectors, they need to be set up first!') + return {"CANCELLED"}; + + for obj in Arr_obj: + + if obj.data.uv_layers.get("UVMap"): + obj.data.uv_layers['UVMap'].name = 'UVMap0' + + if not obj.data.uv_layers.get("UVMap0"): + obj.data.uv_layers.new(name = 'UVMap0') + + if not obj.data.uv_layers.get("UVMap1"): + obj.data.uv_layers.new(name = 'UVMap1') + + + if obj.type == "MESH" and newModifierName not in obj.modifiers: + obj.modifiers.new(type='UV_PROJECT', name=newModifierName) + mod = obj.modifiers[newModifierName] + mod.uv_layer = "UVMap1" + mod.projector_count = 6 + + i = 0 + for p in mod.projectors: + p.object = bpy.data.objects[L1960_Arr_PlainData[i][0]] + i = i+1 + else: + self.report({'INFO'}, 'UVProject-Modifier allready set') + return {"FINISHED"} + + self.report({'INFO'}, 'Added UVProject-Modifier to mesh') + return {"FINISHED"} \ No newline at end of file diff --git a/Blender/_Source/L1960_Tools_1_4_0/FixMaterials.py b/Blender/_Source/L1960_Tools_1_4_0/FixMaterials.py new file mode 100644 index 0000000..83e9dbd --- /dev/null +++ b/Blender/_Source/L1960_Tools_1_4_0/FixMaterials.py @@ -0,0 +1,65 @@ +import bpy + +def replace_material(bad_mat, good_mat): + bad_mat.user_remap(good_mat) + bpy.data.materials.remove(bad_mat) + + +def get_duplicate_materials(og_material): + + common_name = og_material.name + + if common_name[-3:].isnumeric(): + common_name = common_name[:-4] + + duplicate_materials = [] + + for material in bpy.data.materials: + if material is not og_material: + name = material.name + if name[-3:].isnumeric() and name[-4] == ".": + name = name[:-4] + + if name == common_name: + duplicate_materials.append(material) + + text = "{} duplicate materials found" + print(text.format(len(duplicate_materials))) + + return duplicate_materials + + +def remove_all_duplicate_materials(): + i = 0 + while i < len(bpy.data.materials): + + og_material = bpy.data.materials[i] + + print("og material: " + og_material.name) + + # get duplicate materials + duplicate_materials = get_duplicate_materials(og_material) + + # replace all duplicates + for duplicate_material in duplicate_materials: + replace_material(duplicate_material, og_material) + + # adjust name to no trailing numbers + if og_material.name[-3:].isnumeric() and og_material.name[-4] == ".": + og_material.name = og_material.name[:-4] + + i = i+1 + +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_duplicate_materials() + + self.report({'INFO'}, 'All duplicated Materials merged/fixed') + return {"FINISHED"} \ No newline at end of file diff --git a/Blender/_Source/L1960_Tools_1_4_0/PrepareLods.py b/Blender/_Source/L1960_Tools_1_4_0/PrepareLods.py new file mode 100644 index 0000000..79453db --- /dev/null +++ b/Blender/_Source/L1960_Tools_1_4_0/PrepareLods.py @@ -0,0 +1,13 @@ +import bpy + +class MESH_OT_prepare_lods_decimate(bpy.types.Operator): + """Copy current Mesh and apply decimate Modifier""" + + bl_idname = "mesh.prepare_lods_decimate" + bl_label = "Copy current Mesh and apply decimate Modifier" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + + self.report({'INFO'}, 'Currently not in use') + return {"FINISHED"} \ No newline at end of file diff --git a/Blender/_Source/L1960_Tools_1_4_0/__init__.py b/Blender/_Source/L1960_Tools_1_4_0/__init__.py new file mode 100644 index 0000000..1ca1d5c --- /dev/null +++ b/Blender/_Source/L1960_Tools_1_4_0/__init__.py @@ -0,0 +1,74 @@ +bl_info = { + "name": "L1960 Tools", + "author": "Prodeath21", + "version": (1, 4, 0), + "blender": (2, 80, 0), + "location": "3D Viewport > Sidebar > 1960Life category", + "description": "Set´s up the Projection-Modifier automatically and add´s in the Emptys if not allready created.", + "category": "Object", +} + +# ---------------------------------------------- +# Import modules +# ---------------------------------------------- +if "bpy" in locals(): + import imp + imp.reload(CubeProjection) + imp.reload(FixMaterials) + imp.reload(PrepareLods) + print("L1960 Tools: Reloaded multifiles") +else: + from . import CubeProjection + from . import FixMaterials + from . import PrepareLods + +import bpy + +from . CubeProjection import MESH_OT_add_auto_cube_projection, MESH_OT_add_modifier_to_mesh +from . FixMaterials import MESH_OT_fix_material_names +from . PrepareLods import MESH_OT_prepare_lods_decimate + +class L1960_PT_tools(bpy.types.Panel): + pass + #where to add the panel + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + + #add labels + bl_label = "1960-Life Tools" + bl_category = "1960-Life" + + def draw(self, context): + """define the layout of the panel""" + self.layout.label(text="UV-Projection") + row = self.layout.row() + row.operator("mesh.add_auto_cube_projection", text="Set up Projectors") + row = self.layout.row() + row.operator("mesh.add_modifier_to_mesh", text="Add Modifier to Mesh") + self.layout.separator() + self.layout.label(text="Materials") + row = self.layout.row() + row.operator("mesh.fix_material_names", text="Fix Material Name´s") + self.layout.separator() + self.layout.label(text="LOD´s") + row = self.layout.row() + row.operator("mesh.prepare_lods_decimate", text="Create LOD´s with decimate") + +#register the panel with blender +modules = [ L1960_PT_tools, + MESH_OT_add_auto_cube_projection, + MESH_OT_add_modifier_to_mesh, + MESH_OT_fix_material_names, + MESH_OT_prepare_lods_decimate +] + +def register(): + for mod in modules: + bpy.utils.register_class(mod) + +def unregister(): + for mod in modules: + bpy.utils.unregister_class(mod) + +if __name__== "__main__": + register() \ No newline at end of file diff --git a/Blender/_Source/L1960_Tools_1_5_0/CubeProjection.py b/Blender/_Source/L1960_Tools_1_5_0/CubeProjection.py new file mode 100644 index 0000000..c586c48 --- /dev/null +++ b/Blender/_Source/L1960_Tools_1_5_0/CubeProjection.py @@ -0,0 +1,94 @@ +import bpy +from math import pi + +L1960_Arr_PlainData = [ + ["Proj_Empty_01", (0, 0, 2), (0, 0, 0)], + ["Proj_Empty_02", (2, 0, 0), ((pi * 90 / 180), 0, (pi * 90 / 180))], + ["Proj_Empty_03", (0, 2, 0), ((pi * 90 / 180), 0, (pi * 180 / 180))], + ["Proj_Empty_04", (0, 0, -2), ((pi * 180 / 180), 0, 0)], + ["Proj_Empty_05", (-2, 0, 0), ((pi * 90 / 180), 0, (pi * -90 / 180))], + ["Proj_Empty_06", (0, -2, 0), ((pi * 90 / 180), 0, 0)] +] + +class MESH_OT_add_auto_cube_projection(bpy.types.Operator): + """Check Empty´s for projecting, if not existing create new one´s""" + + bl_idname = "mesh.add_auto_cube_projection" + bl_label = "Add Plain_Axes to scene" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + + scene = bpy.context.scene + oldSelection = bpy.context.selected_objects + oldActive = bpy.context.active_object + + for EmptyData in L1960_Arr_PlainData: + + EmptyName = EmptyData[0] + EmptyLocation = EmptyData[1] + EmptyRotation = EmptyData[2] + + if not scene.objects.get(EmptyName): + bpy.ops.object.empty_add(type='PLAIN_AXES', align='WORLD', location=EmptyLocation, scale=(1, 1, 1), rotation=EmptyRotation) + empty = bpy.context.active_object + empty.name = EmptyName + empty.hide_select = True + empty.hide_set(True) + + #Change back to old selection and select old active + for obj in oldSelection: + obj.select_set(True) + bpy.context.view_layer.objects.active = oldActive + + self.report({'INFO'}, 'Added/Fixed Emptys for Projection to Scene') + return {"FINISHED"} + +class MESH_OT_add_modifier_to_mesh(bpy.types.Operator): + """Add Modifier to selected Mesh´s and prepare UV-Maps""" + + bl_idname = "mesh.add_modifier_to_mesh" + bl_label = "Add Modifier to selected Mesh" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + + newModifierName = "CubeTexModifier" + Arr_obj = bpy.context.selected_objects + if len(Arr_obj) < 1: + self.report({'WARNING'}, 'Select a mesh to add the UVProject-Modifier') + return {"CANCELLED"} + + empty_objs = [emp_obj for emp_obj in bpy.context.scene.objects if emp_obj.name.startswith("Proj_Empty")] + if len(empty_objs) < 6: + self.report({'WARNING'}, 'Create/Recreate projectors, they need to be set up first!') + return {"CANCELLED"}; + + for obj in Arr_obj: + + if obj.data.uv_layers.get("UVMap"): + obj.data.uv_layers['UVMap'].name = 'UVMap0' + + if not obj.data.uv_layers.get("UVMap0"): + obj.data.uv_layers.new(name = 'UVMap0') + + if not obj.data.uv_layers.get("UVMap1"): + obj.data.uv_layers.new(name = 'UVMap1') + + + if obj.type == "MESH" and newModifierName not in obj.modifiers: + obj.modifiers.new(type='UV_PROJECT', name=newModifierName) + mod = obj.modifiers[newModifierName] + mod.uv_layer = "UVMap1" + mod.projector_count = 6 + + i = 0 + for p in mod.projectors: + p.object = bpy.data.objects[L1960_Arr_PlainData[i][0]] + i = i+1 + else: + self.report({'INFO'}, 'UVProject-Modifier allready set') + return {"FINISHED"} + + self.report({'INFO'}, 'Added UVProject-Modifier to mesh') + return {"FINISHED"} \ No newline at end of file diff --git a/Blender/_Source/L1960_Tools_1_5_0/FixMaterials.py b/Blender/_Source/L1960_Tools_1_5_0/FixMaterials.py new file mode 100644 index 0000000..b398704 --- /dev/null +++ b/Blender/_Source/L1960_Tools_1_5_0/FixMaterials.py @@ -0,0 +1,65 @@ +import bpy + +def replace_material(bad_mat, good_mat): + bad_mat.user_remap(good_mat) + bpy.data.materials.remove(bad_mat) + + +def get_duplicate_materials(og_material): + + common_name = og_material.name + + if common_name[-3:].isnumeric(): + common_name = common_name[:-4] + + duplicate_materials = [] + + for material in bpy.data.materials: + if material is not og_material: + name = material.name + if name[-3:].isnumeric() and name[-4] == ".": + name = name[:-4] + + if name == common_name: + duplicate_materials.append(material) + + text = "{} duplicate materials found" + print(text.format(len(duplicate_materials))) + + return duplicate_materials + + +def remove_all_duplicate_materials(): + i = 0 + while i < len(bpy.data.materials): + + og_material = bpy.data.materials[i] + + print("og material: " + og_material.name) + + # get duplicate materials + duplicate_materials = get_duplicate_materials(og_material) + + # replace all duplicates + for duplicate_material in duplicate_materials: + replace_material(duplicate_material, og_material) + + # adjust name to no trailing numbers + if og_material.name[-3:].isnumeric() and og_material.name[-4] == ".": + og_material.name = og_material.name[:-4] + + i = i+1 + +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_duplicate_materials() + + self.report({'INFO'}, 'All duplicated Materials fixed') + return {"FINISHED"} \ No newline at end of file diff --git a/Blender/_Source/L1960_Tools_1_5_0/PrepareLods.py b/Blender/_Source/L1960_Tools_1_5_0/PrepareLods.py new file mode 100644 index 0000000..ef61f03 --- /dev/null +++ b/Blender/_Source/L1960_Tools_1_5_0/PrepareLods.py @@ -0,0 +1,40 @@ +import bpy + +class MESH_OT_prepare_lods_decimate(bpy.types.Operator): + """Copy current Mesh and apply decimate Modifier""" + + bl_idname = "mesh.prepare_lods_decimate" + bl_label = "Copy current Mesh and apply decimate Modifier" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + + #Selected Mesh + obj = bpy.context.active_object + + if obj not in bpy.context.selected_objects or obj.type != "MESH": + self.report({'WARNING'}, 'Select a Mesh to continue') + return {"CANCELLED"} + + if not obj.name[:-1].endswith('LOD'): + obj.name = obj.name + '_LOD0' + + LODnumber = context.scene.lod_slider #Get from Slider + startLODcount = int(obj.name[-1]) + endLODcount = startLODcount + LODnumber + + for i in range (startLODcount + 1, endLODcount): + new_obj = obj.copy() + new_obj.data = obj.data.copy() + new_obj.name = obj.name[:-1] + str(i) + bpy.context.collection.objects.link(new_obj) + + for t in range (startLODcount, i): + newModifierName = 'LOD_Decimate_' + str(t) + new_obj.modifiers.new(type='DECIMATE', name=newModifierName) + mod = new_obj.modifiers[newModifierName] + mod.ratio = 0.49 + mod.use_collapse_triangulate = True + + self.report({'INFO'}, 'LOD´s created') + return {"FINISHED"} \ No newline at end of file diff --git a/Blender/_Source/L1960_Tools_1_5_0/__init__.py b/Blender/_Source/L1960_Tools_1_5_0/__init__.py new file mode 100644 index 0000000..7003c34 --- /dev/null +++ b/Blender/_Source/L1960_Tools_1_5_0/__init__.py @@ -0,0 +1,82 @@ +bl_info = { + "name": "L1960 Tools", + "author": "Prodeath21", + "version": (1, 5, 0), + "blender": (2, 80, 0), + "location": "3D Viewport > Sidebar > 1960Life category", + "description": "Set´s up the Projection-Modifier automatically and add´s in the Emptys if not allready created.", + "category": "Object", +} + +# ---------------------------------------------- +# Import modules +# ---------------------------------------------- +if "bpy" in locals(): + import imp + imp.reload(CubeProjection) + imp.reload(FixMaterials) + imp.reload(PrepareLods) + print("L1960 Tools: Reloaded multifiles") +else: + from . import CubeProjection + from . import FixMaterials + from . import PrepareLods + +import bpy + +from . CubeProjection import MESH_OT_add_auto_cube_projection, MESH_OT_add_modifier_to_mesh +from . FixMaterials import MESH_OT_fix_material_names +from . PrepareLods import MESH_OT_prepare_lods_decimate + +class L1960_PT_tools(bpy.types.Panel): + pass + #where to add the panel + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + + #add labels + bl_label = "1960-Life Tools" + bl_category = "1960-Life" + + def draw(self, context): + """define the layout of the panel""" + box = self.layout.box() + box.label(text="UV-Projection") + row = box.row() + row.operator("mesh.add_auto_cube_projection", text="Set up Projectors") + row = box.row() + row.operator("mesh.add_modifier_to_mesh", text="Add Modifier to Mesh") + self.layout.separator() + box = self.layout.box() + box.label(text="Materials") + row = box.row() + row.operator("mesh.fix_material_names", text="Fix Material Name´s") + self.layout.separator() + box = self.layout.box() + box.label(text="LOD´s") + row = box.row() + row.operator("mesh.prepare_lods_decimate", text="Create LOD´s") + box.prop(context.scene, "lod_slider", text="") + +#register the panel with blender +modules = [ L1960_PT_tools, + MESH_OT_add_auto_cube_projection, + MESH_OT_add_modifier_to_mesh, + MESH_OT_fix_material_names, + MESH_OT_prepare_lods_decimate +] + +def register(): + for mod in modules: + bpy.utils.register_class(mod) + + bpy.types.Scene.lod_slider = bpy.props.IntProperty(name="LOD Number", default=3, min=0, max=10) + +def unregister(): + for mod in modules: + bpy.utils.unregister_class(mod) + + del bpy.types.Scene.lod_slider + +if __name__== "__main__": + register() \ No newline at end of file diff --git a/Blender/_Source/L1960_Tools_1_6_0/CubeProjection.py b/Blender/_Source/L1960_Tools_1_6_0/CubeProjection.py new file mode 100644 index 0000000..c586c48 --- /dev/null +++ b/Blender/_Source/L1960_Tools_1_6_0/CubeProjection.py @@ -0,0 +1,94 @@ +import bpy +from math import pi + +L1960_Arr_PlainData = [ + ["Proj_Empty_01", (0, 0, 2), (0, 0, 0)], + ["Proj_Empty_02", (2, 0, 0), ((pi * 90 / 180), 0, (pi * 90 / 180))], + ["Proj_Empty_03", (0, 2, 0), ((pi * 90 / 180), 0, (pi * 180 / 180))], + ["Proj_Empty_04", (0, 0, -2), ((pi * 180 / 180), 0, 0)], + ["Proj_Empty_05", (-2, 0, 0), ((pi * 90 / 180), 0, (pi * -90 / 180))], + ["Proj_Empty_06", (0, -2, 0), ((pi * 90 / 180), 0, 0)] +] + +class MESH_OT_add_auto_cube_projection(bpy.types.Operator): + """Check Empty´s for projecting, if not existing create new one´s""" + + bl_idname = "mesh.add_auto_cube_projection" + bl_label = "Add Plain_Axes to scene" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + + scene = bpy.context.scene + oldSelection = bpy.context.selected_objects + oldActive = bpy.context.active_object + + for EmptyData in L1960_Arr_PlainData: + + EmptyName = EmptyData[0] + EmptyLocation = EmptyData[1] + EmptyRotation = EmptyData[2] + + if not scene.objects.get(EmptyName): + bpy.ops.object.empty_add(type='PLAIN_AXES', align='WORLD', location=EmptyLocation, scale=(1, 1, 1), rotation=EmptyRotation) + empty = bpy.context.active_object + empty.name = EmptyName + empty.hide_select = True + empty.hide_set(True) + + #Change back to old selection and select old active + for obj in oldSelection: + obj.select_set(True) + bpy.context.view_layer.objects.active = oldActive + + self.report({'INFO'}, 'Added/Fixed Emptys for Projection to Scene') + return {"FINISHED"} + +class MESH_OT_add_modifier_to_mesh(bpy.types.Operator): + """Add Modifier to selected Mesh´s and prepare UV-Maps""" + + bl_idname = "mesh.add_modifier_to_mesh" + bl_label = "Add Modifier to selected Mesh" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + + newModifierName = "CubeTexModifier" + Arr_obj = bpy.context.selected_objects + if len(Arr_obj) < 1: + self.report({'WARNING'}, 'Select a mesh to add the UVProject-Modifier') + return {"CANCELLED"} + + empty_objs = [emp_obj for emp_obj in bpy.context.scene.objects if emp_obj.name.startswith("Proj_Empty")] + if len(empty_objs) < 6: + self.report({'WARNING'}, 'Create/Recreate projectors, they need to be set up first!') + return {"CANCELLED"}; + + for obj in Arr_obj: + + if obj.data.uv_layers.get("UVMap"): + obj.data.uv_layers['UVMap'].name = 'UVMap0' + + if not obj.data.uv_layers.get("UVMap0"): + obj.data.uv_layers.new(name = 'UVMap0') + + if not obj.data.uv_layers.get("UVMap1"): + obj.data.uv_layers.new(name = 'UVMap1') + + + if obj.type == "MESH" and newModifierName not in obj.modifiers: + obj.modifiers.new(type='UV_PROJECT', name=newModifierName) + mod = obj.modifiers[newModifierName] + mod.uv_layer = "UVMap1" + mod.projector_count = 6 + + i = 0 + for p in mod.projectors: + p.object = bpy.data.objects[L1960_Arr_PlainData[i][0]] + i = i+1 + else: + self.report({'INFO'}, 'UVProject-Modifier allready set') + return {"FINISHED"} + + self.report({'INFO'}, 'Added UVProject-Modifier to mesh') + return {"FINISHED"} \ No newline at end of file diff --git a/Blender/_Source/L1960_Tools_1_6_0/FixMaterials.py b/Blender/_Source/L1960_Tools_1_6_0/FixMaterials.py new file mode 100644 index 0000000..b398704 --- /dev/null +++ b/Blender/_Source/L1960_Tools_1_6_0/FixMaterials.py @@ -0,0 +1,65 @@ +import bpy + +def replace_material(bad_mat, good_mat): + bad_mat.user_remap(good_mat) + bpy.data.materials.remove(bad_mat) + + +def get_duplicate_materials(og_material): + + common_name = og_material.name + + if common_name[-3:].isnumeric(): + common_name = common_name[:-4] + + duplicate_materials = [] + + for material in bpy.data.materials: + if material is not og_material: + name = material.name + if name[-3:].isnumeric() and name[-4] == ".": + name = name[:-4] + + if name == common_name: + duplicate_materials.append(material) + + text = "{} duplicate materials found" + print(text.format(len(duplicate_materials))) + + return duplicate_materials + + +def remove_all_duplicate_materials(): + i = 0 + while i < len(bpy.data.materials): + + og_material = bpy.data.materials[i] + + print("og material: " + og_material.name) + + # get duplicate materials + duplicate_materials = get_duplicate_materials(og_material) + + # replace all duplicates + for duplicate_material in duplicate_materials: + replace_material(duplicate_material, og_material) + + # adjust name to no trailing numbers + if og_material.name[-3:].isnumeric() and og_material.name[-4] == ".": + og_material.name = og_material.name[:-4] + + i = i+1 + +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_duplicate_materials() + + self.report({'INFO'}, 'All duplicated Materials fixed') + return {"FINISHED"} \ No newline at end of file diff --git a/Blender/_Source/L1960_Tools_1_6_0/PrepareLods.py b/Blender/_Source/L1960_Tools_1_6_0/PrepareLods.py new file mode 100644 index 0000000..ef61f03 --- /dev/null +++ b/Blender/_Source/L1960_Tools_1_6_0/PrepareLods.py @@ -0,0 +1,40 @@ +import bpy + +class MESH_OT_prepare_lods_decimate(bpy.types.Operator): + """Copy current Mesh and apply decimate Modifier""" + + bl_idname = "mesh.prepare_lods_decimate" + bl_label = "Copy current Mesh and apply decimate Modifier" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + + #Selected Mesh + obj = bpy.context.active_object + + if obj not in bpy.context.selected_objects or obj.type != "MESH": + self.report({'WARNING'}, 'Select a Mesh to continue') + return {"CANCELLED"} + + if not obj.name[:-1].endswith('LOD'): + obj.name = obj.name + '_LOD0' + + LODnumber = context.scene.lod_slider #Get from Slider + startLODcount = int(obj.name[-1]) + endLODcount = startLODcount + LODnumber + + for i in range (startLODcount + 1, endLODcount): + new_obj = obj.copy() + new_obj.data = obj.data.copy() + new_obj.name = obj.name[:-1] + str(i) + bpy.context.collection.objects.link(new_obj) + + for t in range (startLODcount, i): + newModifierName = 'LOD_Decimate_' + str(t) + new_obj.modifiers.new(type='DECIMATE', name=newModifierName) + mod = new_obj.modifiers[newModifierName] + mod.ratio = 0.49 + mod.use_collapse_triangulate = True + + self.report({'INFO'}, 'LOD´s created') + return {"FINISHED"} \ No newline at end of file diff --git a/Blender/_Source/L1960_Tools_1_6_0/__init__.py b/Blender/_Source/L1960_Tools_1_6_0/__init__.py new file mode 100644 index 0000000..a5eea70 --- /dev/null +++ b/Blender/_Source/L1960_Tools_1_6_0/__init__.py @@ -0,0 +1,104 @@ +bl_info = { + "name": "L1960 Tools", + "author": "Prodeath21", + "version": (1, 6, 0), + "blender": (2, 80, 0), + "location": "3D Viewport > Sidebar > 1960Life category", + "description": "Set´s up the Projection-Modifier automatically and add´s in the Emptys if not allready created.", + "category": "Object", +} + +# ---------------------------------------------- +# Import modules +# ---------------------------------------------- +if "bpy" in locals(): + import imp + imp.reload(CubeProjection) + imp.reload(FixMaterials) + imp.reload(PrepareLods) + print("L1960 Tools: Reloaded multifiles") +else: + from . import CubeProjection + from . import FixMaterials + from . import PrepareLods + +import bpy + +from . CubeProjection import MESH_OT_add_auto_cube_projection, MESH_OT_add_modifier_to_mesh +from . FixMaterials import MESH_OT_fix_material_names +from . PrepareLods import MESH_OT_prepare_lods_decimate + +class L1960_PT_tools(bpy.types.Panel): + pass + #where to add the panel + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + + #add labels + bl_label = "1960-Life Tools" + bl_category = "1960-Life" + + def draw(self, context): + """define the layout of the panel""" + box = self.layout.box() + # UV-Project helper + box.label(text="UV-Projection") + row = box.row() + row.operator("mesh.add_auto_cube_projection", text="Set up Projectors") + row = box.row() + row.operator("mesh.add_modifier_to_mesh", text="Add Modifier to Mesh") + self.layout.separator() + box = self.layout.box() + # Materials helper + box.label(text="Materials") + row = box.row() + row.operator("mesh.fix_material_names", text="Fix Material Name´s") + self.layout.separator() + box = self.layout.box() + # Generate LODs + box.label(text="LOD´s") + row = box.row() + row.operator("mesh.prepare_lods_decimate", text="Create LOD´s") + box.prop(context.scene, "lod_slider", text="LOD Number") + ############################### + # Enfusion Blender Tools Linked + box = self.layout.box() + box.label(text="EBT Linked") + row = box.row() + row.operator("view3d.ebt_sort", text="Sort Objects") + # colliders setup is allowed in both OBJECT and EDIT mode + row = box.row() + row.operator("view3d.ebt_colliders_setup", text=" Colliders Setup") + row = box.row() + # Light Setup + row.operator("view3d.ebt_setup_light", text=" Light Setup") + row = box.row() + col = row.column(align=True) + # Update Materials + col.operator("scene.ebt_update_enf_materials",) + row = box.row() + col = row.column(align=True) + + +#register the panel with blender +modules = [ L1960_PT_tools, + MESH_OT_add_auto_cube_projection, + MESH_OT_add_modifier_to_mesh, + MESH_OT_fix_material_names, + MESH_OT_prepare_lods_decimate +] + +def register(): + for mod in modules: + bpy.utils.register_class(mod) + + bpy.types.Scene.lod_slider = bpy.props.IntProperty(name="LOD Number", default=3, min=0, max=10) + +def unregister(): + for mod in modules: + bpy.utils.unregister_class(mod) + + del bpy.types.Scene.lod_slider + +if __name__== "__main__": + register() \ No newline at end of file