Added BlenderWorkbench customized script

Changed some lines of code in a existing script od the Blender Workbench addon to:
- fix a bug when importing textures into Blender from Workbench wich ends in a crash
- Added the ability to ignore dummyvolumes from BI on texture import into Blender.
This commit is contained in:
ProDeath21
2024-08-29 20:45:09 +02:00
parent 5e62f1d81d
commit 41024bd8ad
34 changed files with 0 additions and 0 deletions

View File

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

View File

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

View File

@@ -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()

View File

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

View File

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

View File

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

View File

@@ -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()

View File

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

View File

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

View File

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

View File

@@ -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()

View File

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

View File

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

View File

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

View File

@@ -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()

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

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

View File

@@ -0,0 +1,48 @@
import bpy
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)

View File

@@ -0,0 +1,128 @@
import bpy
import os
### GENRATE MLOD ###
plugin_dir = bpy.utils.user_resource('SCRIPTS')
plugin_path = "addons\L1960Tools"
L1960_path = os.path.join(plugin_dir, plugin_path)
colorpalettes = [
"ColorPalette_01.png",
"ColorPalette_02.png"
]
enum_palettes = []
for file in colorpalettes:
enum_palettes.append((file, file[:-4], "Select " + file[:-4] + " for MLOD"))
class EnumColorPalettes(bpy.types.PropertyGroup):
mlod_enum_selection: bpy.props.EnumProperty(
name="Color Palettes for MLOD",
items=enum_palettes,
description="Choose a palette",
default=0
)
class MESH_OT_set_up_mlod(bpy.types.Operator):
"""Set´s up a material to be used for MLOD´s"""
bl_idname = "mesh.set_up_mlod"
bl_label = "Set´s up a material to be used for MLOD´s"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
#Load Color Palettes
self.import_palettes_textures()
#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"}
arr_layers = obj.data.uv_layers
if not arr_layers.get("MLOD") or len(arr_layers) > 1:
for uv_layer in reversed(arr_layers):
arr_layers.remove(uv_layer)
arr_layers.new(name = 'MLOD')
texture_filepath = os.path.join(L1960_path, colorpalettes[1])
if not len(obj.data.materials) == 0:
obj.data.materials.clear()
palette_enum_selection = context.scene.color_palettes.mlod_enum_selection
mlod_material_name = "MLOD_" + palette_enum_selection[:-4]
if not bpy.data.materials.get(mlod_material_name):
material = bpy.data.materials.new(name=mlod_material_name)
material.use_nodes = True
bsdf_node = material.node_tree.nodes["Principled BSDF"]
texImage = material.node_tree.nodes.new('ShaderNodeTexImage')
texImage.image = bpy.data.images.get(palette_enum_selection)
material.node_tree.links.new(bsdf_node.inputs['Base Color'], texImage.outputs['Color'])
obj.data.materials.append(bpy.data.materials.get(mlod_material_name))
self.report({'INFO'}, 'Mesh configured like MLOD')
return {"FINISHED"}
def import_palettes_textures(self):
for image_name in colorpalettes:
texture_name = image_name.split(".")[0]
if texture_name not in bpy.data.textures:
texture = bpy.data.textures.new(name=texture_name, type='IMAGE')
else:
texture = bpy.data.textures.get(texture_name)
if image_name not in bpy.data.images:
image = bpy.data.images.load(os.path.join(L1960_path, image_name))
else:
image = bpy.data.images.get(image_name)
texture.image = image
### PREPARE LODS ###
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"}

View File

@@ -0,0 +1,113 @@
bl_info = {
"name": "L1960 Tools",
"author": "Prodeath21",
"version": (1, 7, 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(Materials)
imp.reload(PrepareLods)
print("L1960 Tools: Reloaded multifiles")
else:
from . import CubeProjection
from . import Materials
from . import PrepareLods
import bpy
from . CubeProjection import MESH_OT_add_auto_cube_projection, MESH_OT_add_modifier_to_mesh
from . Materials import MESH_OT_fix_material_names
from . PrepareLods import MESH_OT_prepare_lods_decimate, MESH_OT_set_up_mlod, EnumColorPalettes
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()
# Materials helper
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()
# Generate LODs
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="Amount")
box = self.layout.box()
box.prop(context.scene.color_palettes, "mlod_enum_selection", expand=True)
row = box.row()
row.operator("mesh.set_up_mlod", text="Set up MLOD")
self.layout.separator()
###############################
# 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,
MESH_OT_set_up_mlod,
EnumColorPalettes
]
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)
bpy.types.Scene.color_palettes = bpy.props.PointerProperty(type=EnumColorPalettes)
def unregister():
for mod in modules:
bpy.utils.unregister_class(mod)
del bpy.types.Scene.lod_slider
del bpy.types.Scene.color_palettes
if __name__== "__main__":
register()

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

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

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

View File

@@ -0,0 +1,128 @@
import bpy
import os
### GENRATE MLOD ###
plugin_dir = bpy.utils.user_resource('SCRIPTS')
plugin_path = "addons\L1960Tools"
L1960_path = os.path.join(plugin_dir, plugin_path)
colorpalettes = [
"ColorPalette_01.png",
"ColorPalette_02.png"
]
enum_palettes = []
for file in colorpalettes:
enum_palettes.append((file, file[:-4], "Select " + file[:-4] + " for MLOD"))
class EnumColorPalettes(bpy.types.PropertyGroup):
mlod_enum_selection: bpy.props.EnumProperty(
name="Color Palettes for MLOD",
items=enum_palettes,
description="Choose a palette",
default=0
)
class MESH_OT_set_up_mlod(bpy.types.Operator):
"""Set´s up a material to be used for MLOD´s"""
bl_idname = "mesh.set_up_mlod"
bl_label = "Set´s up a material to be used for MLOD´s"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
#Load Color Palettes
self.import_palettes_textures()
#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"}
arr_layers = obj.data.uv_layers
if not arr_layers.get("MLOD") or len(arr_layers) > 1:
for uv_layer in reversed(arr_layers):
arr_layers.remove(uv_layer)
arr_layers.new(name = 'MLOD')
texture_filepath = os.path.join(L1960_path, colorpalettes[1])
if not len(obj.data.materials) == 0:
obj.data.materials.clear()
palette_enum_selection = context.scene.color_palettes.mlod_enum_selection
mlod_material_name = "MLOD_" + palette_enum_selection[:-4]
if not bpy.data.materials.get(mlod_material_name):
material = bpy.data.materials.new(name=mlod_material_name)
material.use_nodes = True
bsdf_node = material.node_tree.nodes["Principled BSDF"]
texImage = material.node_tree.nodes.new('ShaderNodeTexImage')
texImage.image = bpy.data.images.get(palette_enum_selection)
material.node_tree.links.new(bsdf_node.inputs['Base Color'], texImage.outputs['Color'])
obj.data.materials.append(bpy.data.materials.get(mlod_material_name))
self.report({'INFO'}, 'Mesh configured like MLOD')
return {"FINISHED"}
def import_palettes_textures(self):
for image_name in colorpalettes:
texture_name = image_name.split(".")[0]
if texture_name not in bpy.data.textures:
texture = bpy.data.textures.new(name=texture_name, type='IMAGE')
else:
texture = bpy.data.textures.get(texture_name)
if image_name not in bpy.data.images:
image = bpy.data.images.load(os.path.join(L1960_path, image_name))
else:
image = bpy.data.images.get(image_name)
texture.image = image
### PREPARE LODS ###
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"}

View File

@@ -0,0 +1,122 @@
bl_info = {
"name": "L1960 Tools",
"author": "Prodeath21",
"version": (1, 8, 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(Helper)
imp.reload(PrepareLods)
print("L1960 Tools: Reloaded multifiles")
else:
from . import CubeProjection
from . import Helper
from . import PrepareLods
import bpy
from . CubeProjection import MESH_OT_add_auto_cube_projection, MESH_OT_add_modifier_to_mesh
from . Helper import MESH_OT_fix_material_names, MESH_OT_group_objects_in_collections, MESH_OT_fix_naming_conventions, MESH_OT_generate_empty_for_mesh
from . PrepareLods import MESH_OT_prepare_lods_decimate, MESH_OT_set_up_mlod, EnumColorPalettes
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()
# Helpers
box = self.layout.box()
box.label(text="Various Helper")
row = box.row()
row.operator("mesh.fix_material_names", text="Fix Material Name´s")
row = box.row()
row.operator("mesh.group_objects_in_collections", text="Group to Collections")
row = box.row()
row.operator("mesh.fix_naming_convention", text="Fix Naming Convention")
row = box.row()
row.operator("mesh.generate_empty_for_mesh", text="Generate Empty")
self.layout.separator()
# Generate LODs
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="Amount")
box = self.layout.box()
box.prop(context.scene.color_palettes, "mlod_enum_selection", expand=True)
row = box.row()
row.operator("mesh.set_up_mlod", text="Set up MLOD")
self.layout.separator()
###############################
# 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_group_objects_in_collections,
MESH_OT_fix_naming_conventions,
MESH_OT_generate_empty_for_mesh,
MESH_OT_prepare_lods_decimate,
MESH_OT_set_up_mlod,
EnumColorPalettes
]
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)
bpy.types.Scene.color_palettes = bpy.props.PointerProperty(type=EnumColorPalettes)
def unregister():
for mod in modules:
bpy.utils.unregister_class(mod)
del bpy.types.Scene.lod_slider
del bpy.types.Scene.color_palettes
if __name__== "__main__":
register()