import bpy, os, time, blf, webbrowser, platform, numpy, bmesh import math, subprocess, multiprocessing from .. utility import utility from .. utility import build from .. utility.cycles import cache from .. network import server def setObjectLightmapByWeight(minimumRes, maximumRes, objWeight): availableResolutions = [32,64,128,256,512,1024,2048,4096,8192] minRes = minimumRes minResIdx = availableResolutions.index(minRes) maxRes = maximumRes maxResIdx = availableResolutions.index(maxRes) exampleWeight = objWeight if minResIdx == maxResIdx: pass else: increment = 1.0/(maxResIdx-minResIdx) assortedRange = [] for a in numpy.arange(0.0, 1.0, increment): assortedRange.append(round(a, 2)) assortedRange.append(1.0) nearestWeight = min(assortedRange, key=lambda x:abs(x - exampleWeight)) return (availableResolutions[assortedRange.index(nearestWeight) + minResIdx]) class TLM_BuildLightmaps(bpy.types.Operator): bl_idname = "tlm.build_lightmaps" bl_label = "Build Lightmaps" bl_description = "Build Lightmaps" bl_options = {'REGISTER', 'UNDO'} def modal(self, context, event): #Add progress bar from 0.15 print("MODAL") return {'PASS_THROUGH'} def invoke(self, context, event): if not bpy.app.background: build.prepare_build(self, False) else: print("Running in background mode. Contextual operator not available. Use command 'thelightmapper.addon.build.prepare_build()'") return {'RUNNING_MODAL'} def cancel(self, context): pass def draw_callback_px(self, context, event): pass class TLM_CleanLightmaps(bpy.types.Operator): bl_idname = "tlm.clean_lightmaps" bl_label = "Clean Lightmaps" bl_description = "Clean Lightmaps" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): scene = context.scene filepath = bpy.data.filepath dirpath = os.path.join(os.path.dirname(bpy.data.filepath), scene.TLM_EngineProperties.tlm_lightmap_savedir) if not bpy.context.scene.TLM_SceneProperties.tlm_keep_baked_files: if os.path.isdir(dirpath): for file in os.listdir(dirpath): os.remove(os.path.join(dirpath + "/" + file)) for obj in bpy.context.scene.objects: if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects: if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use: cache.backup_material_restore(obj) for obj in bpy.context.scene.objects: if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects: if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use: cache.backup_material_rename(obj) for obj in bpy.context.scene.objects: if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects: if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use: for vertex_layer in obj.data.vertex_colors: if vertex_layer.name == "TLM": obj.data.vertex_colors.remove(vertex_layer) for mat in bpy.data.materials: if mat.users < 1: bpy.data.materials.remove(mat) for mat in bpy.data.materials: if mat.name.startswith("."): if "_Original" in mat.name: bpy.data.materials.remove(mat) for image in bpy.data.images: if image.name.endswith("_baked"): bpy.data.images.remove(image, do_unlink=True) for obj in bpy.context.scene.objects: if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects: if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use: if obj.TLM_ObjectProperties.tlm_postpack_object: atlas = obj.TLM_ObjectProperties.tlm_postatlas_pointer atlas_resize = False for atlasgroup in scene.TLM_PostAtlasList: if atlasgroup.name == atlas: atlas_resize = True if atlas_resize: bpy.ops.object.select_all(action='DESELECT') obj.select_set(True) bpy.context.view_layer.objects.active = obj uv_layers = obj.data.uv_layers if not obj.TLM_ObjectProperties.tlm_use_default_channel: uv_channel = obj.TLM_ObjectProperties.tlm_uv_channel else: uv_channel = "UVMap_Lightmap" for i in range(0, len(uv_layers)): if uv_layers[i].name == uv_channel: uv_layers.active_index = i break bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='SELECT') bpy.ops.uv.select_all(action='SELECT') bpy.ops.uv.pack_islands(rotate=False, margin=0.001) bpy.ops.uv.select_all(action='DESELECT') bpy.ops.mesh.select_all(action='DESELECT') bpy.ops.object.mode_set(mode='OBJECT') if bpy.context.scene.TLM_SceneProperties.tlm_verbose: print("Resized for obj: " + obj.name) if "Lightmap" in obj: del obj["Lightmap"] if bpy.context.scene.TLM_SceneProperties.tlm_repartition_on_clean: mats = bpy.data.materials for obj in bpy.context.scene.objects: if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects: if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use: print("Repartitioning materials") for slt in obj.material_slots: print("Repartitioning material: " + str(slt.name)) part = slt.name.rpartition('.') if part[2].isnumeric() and part[0] in mats: slt.material = mats.get(part[0]) for slt in obj.material_slots: if slt.name.endswith(tuple(["001","002","003","004","005","006","007","008","009"])): #Do regex instead if not slt.name[:-4] in mats: slt.material.name = slt.name[:-4] return {'FINISHED'} class TLM_ExploreLightmaps(bpy.types.Operator): bl_idname = "tlm.explore_lightmaps" bl_label = "Explore Lightmaps" bl_description = "Explore Lightmaps" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): scene = context.scene cycles = scene.cycles if not bpy.data.is_saved: self.report({'INFO'}, "Please save your file first") return {"CANCELLED"} filepath = bpy.data.filepath dirpath = os.path.join(os.path.dirname(bpy.data.filepath), scene.TLM_EngineProperties.tlm_lightmap_savedir) if platform.system() != "Linux": if os.path.isdir(dirpath): webbrowser.open('file://' + dirpath) else: os.mkdir(dirpath) webbrowser.open('file://' + dirpath) else: if os.path.isdir(dirpath): os.system('xdg-open "%s"' % dirpath) #webbrowser.open('file://' + dirpath) else: os.mkdir(dirpath) os.system('xdg-open "%s"' % dirpath) #webbrowser.open('file://' + dirpath) return {'FINISHED'} class TLM_EnableSet(bpy.types.Operator): """Enable for set""" bl_idname = "tlm.enable_set" bl_label = "Enable for set" bl_description = "Enable for set" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): scene = context.scene weightList = {} #ObjName : [Dimension,Weight] max = 0 if bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Scene": for obj in bpy.context.scene.objects: if obj.type == "MESH": print("Enabling for scene: " + obj.name) bpy.context.view_layer.objects.active = obj obj.select_set(True) bpy.ops.object.transform_apply(location=False, rotation=True, scale=True) obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = True obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode = bpy.context.scene.TLM_SceneProperties.tlm_mesh_lightmap_unwrap_mode obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin = bpy.context.scene.TLM_SceneProperties.tlm_mesh_unwrap_margin obj.TLM_ObjectProperties.tlm_postpack_object = bpy.context.scene.TLM_SceneProperties.tlm_postpack_object if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA": obj.TLM_ObjectProperties.tlm_atlas_pointer = bpy.context.scene.TLM_SceneProperties.tlm_atlas_pointer obj.TLM_ObjectProperties.tlm_postatlas_pointer = bpy.context.scene.TLM_SceneProperties.tlm_postatlas_pointer if bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Single": obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution = scene.TLM_SceneProperties.tlm_mesh_lightmap_resolution elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Dimension": obj_dimensions = obj.dimensions.x * obj.dimensions.y * obj.dimensions.z weightList[obj.name] = [obj_dimensions, 0] if obj_dimensions > max: max = obj_dimensions elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Surface": bm = bmesh.new() bm.from_mesh(obj.data) area = sum(f.calc_area() for f in bm.faces) weightList[obj.name] = [area, 0] if area > max: max = area elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Volume": bm = bmesh.new() bm.from_mesh(obj.data) volume = float( bm.calc_volume()) weightList[obj.name] = [volume, 0] if volume > max: max = volume elif bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Selection": for obj in bpy.context.selected_objects: if obj.type == "MESH": print("Enabling for selection: " + obj.name) bpy.context.view_layer.objects.active = obj obj.select_set(True) bpy.ops.object.transform_apply(location=False, rotation=True, scale=True) obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = True obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode = bpy.context.scene.TLM_SceneProperties.tlm_mesh_lightmap_unwrap_mode obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin = bpy.context.scene.TLM_SceneProperties.tlm_mesh_unwrap_margin obj.TLM_ObjectProperties.tlm_postpack_object = bpy.context.scene.TLM_SceneProperties.tlm_postpack_object if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA": obj.TLM_ObjectProperties.tlm_atlas_pointer = bpy.context.scene.TLM_SceneProperties.tlm_atlas_pointer obj.TLM_ObjectProperties.tlm_postatlas_pointer = bpy.context.scene.TLM_SceneProperties.tlm_postatlas_pointer if bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Single": obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution = scene.TLM_SceneProperties.tlm_mesh_lightmap_resolution elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Dimension": obj_dimensions = obj.dimensions.x * obj.dimensions.y * obj.dimensions.z weightList[obj.name] = [obj_dimensions, 0] if obj_dimensions > max: max = obj_dimensions elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Surface": bm = bmesh.new() bm.from_mesh(obj.data) area = sum(f.calc_area() for f in bm.faces) weightList[obj.name] = [area, 0] if area > max: max = area elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Volume": bm = bmesh.new() bm.from_mesh(obj.data) volume = float( bm.calc_volume()) weightList[obj.name] = [volume, 0] if volume > max: max = volume else: #Enabled for obj in bpy.context.scene.objects: if obj.type == "MESH": if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use: print("Enabling for designated: " + obj.name) bpy.context.view_layer.objects.active = obj obj.select_set(True) bpy.ops.object.transform_apply(location=False, rotation=True, scale=True) obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = True obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode = bpy.context.scene.TLM_SceneProperties.tlm_mesh_lightmap_unwrap_mode obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin = bpy.context.scene.TLM_SceneProperties.tlm_mesh_unwrap_margin obj.TLM_ObjectProperties.tlm_postpack_object = bpy.context.scene.TLM_SceneProperties.tlm_postpack_object if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA": obj.TLM_ObjectProperties.tlm_atlas_pointer = bpy.context.scene.TLM_SceneProperties.tlm_atlas_pointer obj.TLM_ObjectProperties.tlm_postatlas_pointer = bpy.context.scene.TLM_SceneProperties.tlm_postatlas_pointer if bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Single": obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution = scene.TLM_SceneProperties.tlm_mesh_lightmap_resolution elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Dimension": obj_dimensions = obj.dimensions.x * obj.dimensions.y * obj.dimensions.z weightList[obj.name] = [obj_dimensions, 0] if obj_dimensions > max: max = obj_dimensions elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Surface": bm = bmesh.new() bm.from_mesh(obj.data) area = sum(f.calc_area() for f in bm.faces) weightList[obj.name] = [area, 0] if area > max: max = area elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Volume": bm = bmesh.new() bm.from_mesh(obj.data) volume = float( bm.calc_volume()) weightList[obj.name] = [volume, 0] if volume > max: max = volume if bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Scene": for obj in bpy.context.scene.objects: if obj.type == "MESH": if bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight != "Single": for key in weightList: weightList[obj.name][1] = weightList[obj.name][0] / max a = setObjectLightmapByWeight(int(bpy.context.scene.TLM_SceneProperties.tlm_resolution_min), int(bpy.context.scene.TLM_SceneProperties.tlm_resolution_max), weightList[obj.name][1]) print(str(a) + "/" + str(weightList[obj.name][1])) print("Scale: " + str(weightList[obj.name][0])) print("Obj: " + obj.name) obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution = str(a) elif bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Selection": for obj in bpy.context.selected_objects: if obj.type == "MESH": if bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight != "Single": for key in weightList: weightList[obj.name][1] = weightList[obj.name][0] / max a = setObjectLightmapByWeight(int(bpy.context.scene.TLM_SceneProperties.tlm_resolution_min), int(bpy.context.scene.TLM_SceneProperties.tlm_resolution_max), weightList[obj.name][1]) print(str(a) + "/" + str(weightList[obj.name][1])) print("Scale: " + str(weightList[obj.name][0])) print("Obj: " + obj.name) obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution = str(a) else: #Enabled for obj in bpy.context.scene.objects: if obj.type == "MESH": if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use: if bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight != "Single": for key in weightList: weightList[obj.name][1] = weightList[obj.name][0] / max a = setObjectLightmapByWeight(int(bpy.context.scene.TLM_SceneProperties.tlm_resolution_min), int(bpy.context.scene.TLM_SceneProperties.tlm_resolution_max), weightList[obj.name][1]) print(str(a) + "/" + str(weightList[obj.name][1])) print("Scale: " + str(weightList[obj.name][0])) print("Obj: " + obj.name) print("") obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution = str(a) return{'FINISHED'} class TLM_DisableSelection(bpy.types.Operator): """Disable for set""" bl_idname = "tlm.disable_selection" bl_label = "Disable for set" bl_description = "Disable for selection" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): scene = context.scene weightList = {} #ObjName : [Dimension,Weight] max = 0 if bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Scene": for obj in bpy.context.scene.objects: if obj.type == "MESH": obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = False elif bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Selection": for obj in bpy.context.selected_objects: if obj.type == "MESH": obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = False else: #Enabled for obj in bpy.context.scene.objects: if obj.type == "MESH": if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use: obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = False return{'FINISHED'} class TLM_RemoveLightmapUV(bpy.types.Operator): """Remove Lightmap UV for set""" bl_idname = "tlm.remove_uv_selection" bl_label = "Remove Lightmap UV" bl_description = "Remove Lightmap UV for set" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): if bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Scene": for obj in bpy.context.scene.objects: if obj.type == "MESH": uv_layers = obj.data.uv_layers if not obj.TLM_ObjectProperties.tlm_use_default_channel: uv_channel = obj.TLM_ObjectProperties.tlm_uv_channel else: uv_channel = "UVMap_Lightmap" for uvlayer in uv_layers: if uvlayer.name == uv_channel: uv_layers.remove(uvlayer) elif bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Selection": for obj in bpy.context.selected_objects: if obj.type == "MESH": uv_layers = obj.data.uv_layers if not obj.TLM_ObjectProperties.tlm_use_default_channel: uv_channel = obj.TLM_ObjectProperties.tlm_uv_channel else: uv_channel = "UVMap_Lightmap" for uvlayer in uv_layers: if uvlayer.name == uv_channel: uv_layers.remove(uvlayer) else: #Enabled for obj in bpy.context.scene.objects: if obj.type == "MESH": if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use: uv_layers = obj.data.uv_layers if not obj.TLM_ObjectProperties.tlm_use_default_channel: uv_channel = obj.TLM_ObjectProperties.tlm_uv_channel else: uv_channel = "UVMap_Lightmap" for uvlayer in uv_layers: if uvlayer.name == uv_channel: uv_layers.remove(uvlayer) return{'FINISHED'} class TLM_SelectLightmapped(bpy.types.Operator): """Select all objects for lightmapping""" bl_idname = "tlm.select_lightmapped_objects" bl_label = "Select lightmap objects" bl_description = "Remove Lightmap UV for selection" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): for obj in bpy.context.scene.objects: if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects: if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use: obj.select_set(True) return{'FINISHED'} class TLM_GroupListNewItem(bpy.types.Operator): # Add a new item to the list bl_idname = "tlm_grouplist.new_item" bl_label = "Add a new lightmap group" bl_description = "Create a new lightmap group" def execute(self, context): scene = context.scene scene.TLM_GroupList.add() scene.TLM_GroupListItem = len(scene.TLM_GroupList) - 1 scene.TLM_GroupList[len(scene.TLM_GroupList) - 1].name = "LightmapGroup" class TLM_AtlasListNewItem(bpy.types.Operator): # Add a new item to the list bl_idname = "tlm_atlaslist.new_item" bl_label = "Add a new item" bl_description = "Create a new AtlasGroup" def execute(self, context): scene = context.scene scene.TLM_AtlasList.add() scene.TLM_AtlasListItem = len(scene.TLM_AtlasList) - 1 scene.TLM_AtlasList[len(scene.TLM_AtlasList) - 1].name = "AtlasGroup" return{'FINISHED'} class TLM_PostAtlasListNewItem(bpy.types.Operator): # Add a new item to the list bl_idname = "tlm_postatlaslist.new_item" bl_label = "Add a new item" bl_description = "Create a new AtlasGroup" bl_description = "" def execute(self, context): scene = context.scene scene.TLM_PostAtlasList.add() scene.TLM_PostAtlasListItem = len(scene.TLM_PostAtlasList) - 1 scene.TLM_PostAtlasList[len(scene.TLM_PostAtlasList) - 1].name = "AtlasGroup" return{'FINISHED'} class TLM_AtlastListDeleteItem(bpy.types.Operator): # Delete the selected item from the list bl_idname = "tlm_atlaslist.delete_item" bl_label = "Deletes an item" bl_description = "Delete an AtlasGroup" @classmethod def poll(self, context): """ Enable if there's something in the list """ scene = context.scene return len(scene.TLM_AtlasList) > 0 def execute(self, context): scene = context.scene list = scene.TLM_AtlasList index = scene.TLM_AtlasListItem for obj in bpy.context.scene.objects: atlasName = scene.TLM_AtlasList[index].name if obj.TLM_ObjectProperties.tlm_atlas_pointer == atlasName: obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode = "SmartProject" list.remove(index) if index > 0: index = index - 1 scene.TLM_AtlasListItem = index return{'FINISHED'} class TLM_PostAtlastListDeleteItem(bpy.types.Operator): # Delete the selected item from the list bl_idname = "tlm_postatlaslist.delete_item" bl_label = "Deletes an item" bl_description = "Delete an AtlasGroup" @classmethod def poll(self, context): """ Enable if there's something in the list """ scene = context.scene return len(scene.TLM_PostAtlasList) > 0 def execute(self, context): scene = context.scene list = scene.TLM_PostAtlasList index = scene.TLM_PostAtlasListItem for obj in bpy.context.scene.objects: atlasName = scene.TLM_PostAtlasList[index].name if obj.TLM_ObjectProperties.tlm_atlas_pointer == atlasName: obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode = "SmartProject" list.remove(index) if index > 0: index = index - 1 scene.TLM_PostAtlasListItem = index return{'FINISHED'} class TLM_AtlasListMoveItem(bpy.types.Operator): # Move an item in the list bl_idname = "tlm_atlaslist.move_item" bl_label = "Move an item in the list" bl_description = "Move an item in the list" direction: bpy.props.EnumProperty( items=( ('UP', 'Up', ""), ('DOWN', 'Down', ""),)) def move_index(self): # Move index of an item render queue while clamping it scene = context.scene index = scene.TLM_AtlasListItem list_length = len(scene.TLM_AtlasList) - 1 new_index = 0 if self.direction == 'UP': new_index = index - 1 elif self.direction == 'DOWN': new_index = index + 1 new_index = max(0, min(new_index, list_length)) scene.TLM_AtlasList.move(index, new_index) scene.TLM_AtlasListItem = new_index def execute(self, context): scene = context.scene list = scene.TLM_AtlasList index = scene.TLM_AtlasListItem if self.direction == 'DOWN': neighbor = index + 1 self.move_index() elif self.direction == 'UP': neighbor = index - 1 self.move_index() else: return{'CANCELLED'} return{'FINISHED'} class TLM_PostAtlasListMoveItem(bpy.types.Operator): # Move an item in the list bl_idname = "tlm_postatlaslist.move_item" bl_label = "Move an item in the list" bl_description = "Move an item in the list" direction: bpy.props.EnumProperty( items=( ('UP', 'Up', ""), ('DOWN', 'Down', ""),)) def move_index(self): # Move index of an item render queue while clamping it scene = context.scene index = scene.TLM_PostAtlasListItem list_length = len(scene.TLM_PostAtlasList) - 1 new_index = 0 if self.direction == 'UP': new_index = index - 1 elif self.direction == 'DOWN': new_index = index + 1 new_index = max(0, min(new_index, list_length)) scene.TLM_PostAtlasList.move(index, new_index) scene.TLM_PostAtlasListItem = new_index def execute(self, context): scene = context.scene list = scene.TLM_PostAtlasList index = scene.TLM_PostAtlasListItem if self.direction == 'DOWN': neighbor = index + 1 self.move_index() elif self.direction == 'UP': neighbor = index - 1 self.move_index() else: return{'CANCELLED'} return{'FINISHED'} class TLM_StartServer(bpy.types.Operator): bl_idname = "tlm.start_server" bl_label = "Start Network Server" bl_description = "Start Network Server" bl_options = {'REGISTER', 'UNDO'} def modal(self, context, event): #Add progress bar from 0.15 print("MODAL") return {'PASS_THROUGH'} def invoke(self, context, event): server.startServer() return {'RUNNING_MODAL'} class TLM_BuildEnvironmentProbes(bpy.types.Operator): bl_idname = "tlm.build_environmentprobe" bl_label = "Build Environment Probes" bl_description = "Build all environment probes from reflection cubemaps" bl_options = {'REGISTER', 'UNDO'} def invoke(self, context, event): for obj in bpy.context.scene.objects: if obj.type == "LIGHT_PROBE": if obj.data.type == "CUBEMAP": cam_name = "EnvPCam_" + obj.name camera = bpy.data.cameras.new(cam_name) camobj_name = "EnvPCamera_" + obj.name cam_obj = bpy.data.objects.new(camobj_name, camera) bpy.context.collection.objects.link(cam_obj) cam_obj.location = obj.location camera.angle = math.radians(90) prevResx = bpy.context.scene.render.resolution_x prevResy = bpy.context.scene.render.resolution_y prevCam = bpy.context.scene.camera prevEngine = bpy.context.scene.render.engine bpy.context.scene.camera = cam_obj bpy.context.scene.render.engine = bpy.context.scene.TLM_SceneProperties.tlm_environment_probe_engine bpy.context.scene.render.resolution_x = int(bpy.context.scene.TLM_SceneProperties.tlm_environment_probe_resolution) bpy.context.scene.render.resolution_y = int(bpy.context.scene.TLM_SceneProperties.tlm_environment_probe_resolution) savedir = os.path.dirname(bpy.data.filepath) directory = os.path.join(savedir, "Probes") t = 90 inverted = bpy.context.scene.TLM_SceneProperties.tlm_invert_direction if inverted: positions = { "xp" : (math.radians(t), 0, math.radians(0)), "zp" : (math.radians(t), 0, math.radians(t)), "xm" : (math.radians(t), 0, math.radians(t*2)), "zm" : (math.radians(t), 0, math.radians(-t)), "yp" : (math.radians(t*2), 0, math.radians(t)), "ym" : (0, 0, math.radians(t)) } else: positions = { "xp" : (math.radians(t), 0, math.radians(t*2)), "zp" : (math.radians(t), 0, math.radians(-t)), "xm" : (math.radians(t), 0, math.radians(0)), "zm" : (math.radians(t), 0, math.radians(t)), "yp" : (math.radians(t*2), 0, math.radians(-t)), "ym" : (0, 0, math.radians(-t)) } cam = cam_obj image_settings = bpy.context.scene.render.image_settings image_settings.file_format = "HDR" image_settings.color_depth = '32' for val in positions: cam.rotation_euler = positions[val] filename = os.path.join(directory, val) + "_" + camobj_name + ".hdr" bpy.context.scene.render.filepath = filename print("Writing out: " + val) bpy.ops.render.render(write_still=True) cmft_path = bpy.path.abspath(os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_SceneProperties.tlm_cmft_path)) output_file_irr = camobj_name + ".hdr" posx = directory + "/" + "xp_" + camobj_name + ".hdr" negx = directory + "/" + "xm_" + camobj_name + ".hdr" posy = directory + "/" + "yp_" + camobj_name + ".hdr" negy = directory + "/" + "ym_" + camobj_name + ".hdr" posz = directory + "/" + "zp_" + camobj_name + ".hdr" negz = directory + "/" + "zm_" + camobj_name + ".hdr" output = directory + "/" + camobj_name if platform.system() == 'Windows': envpipe = [cmft_path, '--inputFacePosX', posx, '--inputFaceNegX', negx, '--inputFacePosY', posy, '--inputFaceNegY', negy, '--inputFacePosZ', posz, '--inputFaceNegZ', negz, '--output0', output, '--output0params', 'hdr,rgbe,latlong'] else: envpipe = [cmft_path + '--inputFacePosX' + posx + '--inputFaceNegX' + negx + '--inputFacePosY' + posy + '--inputFaceNegY' + negy + '--inputFacePosZ' + posz + '--inputFaceNegZ' + negz + '--output0' + output + '--output0params' + 'hdr,rgbe,latlong'] if bpy.context.scene.TLM_SceneProperties.tlm_verbose: print("Calling CMFT with:" + str(envpipe)) if bpy.context.scene.TLM_SceneProperties.tlm_create_spherical: subprocess.call(envpipe, shell=True) input2 = output + ".hdr" output2 = directory + "/" + camobj_name if platform.system() == 'Windows': envpipe2 = [cmft_path, '--input', input2, '--filter', 'shcoeffs', '--outputNum', '1', '--output0', output2] else: envpipe2 = [cmft_path + '--input' + input2 + '-filter' + 'shcoeffs' + '--outputNum' + '1' + '--output0' + output2] if bpy.context.scene.TLM_SceneProperties.tlm_write_sh: subprocess.call(envpipe2, shell=True) if bpy.context.scene.TLM_SceneProperties.tlm_write_radiance: use_opencl = 'false' cpu_count = 2 # 4096 = 256 face # 2048 = 128 face # 1024 = 64 face target_w = int(512) face_size = target_w / 8 if target_w == 2048: mip_count = 9 elif target_w == 1024: mip_count = 8 else: mip_count = 7 output_file_rad = directory + "/" + camobj_name + "_rad.hdr" if platform.system() == 'Windows': envpipe3 = [ cmft_path, '--input', input2, '--filter', 'radiance', '--dstFaceSize', str(face_size), '--srcFaceSize', str(face_size), '--excludeBase', 'false', # '--mipCount', str(mip_count), '--glossScale', '8', '--glossBias', '3', '--lightingModel', 'blinnbrdf', '--edgeFixup', 'none', '--numCpuProcessingThreads', str(cpu_count), '--useOpenCL', use_opencl, '--clVendor', 'anyGpuVendor', '--deviceType', 'gpu', '--deviceIndex', '0', '--generateMipChain', 'true', '--inputGammaNumerator', '1.0', '--inputGammaDenominator', '1.0', '--outputGammaNumerator', '1.0', '--outputGammaDenominator', '1.0', '--outputNum', '1', '--output0', output_file_rad, '--output0params', 'hdr,rgbe,latlong' ] subprocess.call(envpipe3) else: envpipe3 = cmft_path + \ ' --input "' + input2 + '"' + \ ' --filter radiance' + \ ' --dstFaceSize ' + str(face_size) + \ ' --srcFaceSize ' + str(face_size) + \ ' --excludeBase false' + \ ' --glossScale 8' + \ ' --glossBias 3' + \ ' --lightingModel blinnbrdf' + \ ' --edgeFixup none' + \ ' --numCpuProcessingThreads ' + str(cpu_count) + \ ' --useOpenCL ' + use_opencl + \ ' --clVendor anyGpuVendor' + \ ' --deviceType gpu' + \ ' --deviceIndex 0' + \ ' --generateMipChain true' + \ ' --inputGammaNumerator ' + '1.0' + \ ' --inputGammaDenominator 1.0' + \ ' --outputGammaNumerator 1.0' + \ ' --outputGammaDenominator 1.0' + \ ' --outputNum 1' + \ ' --output0 "' + output_file_rad + '"' + \ ' --output0params hdr,rgbe,latlong' subprocess.call([envpipe3], shell=True) for obj in bpy.context.scene.objects: obj.select_set(False) cam_obj.select_set(True) bpy.ops.object.delete() bpy.context.scene.render.resolution_x = prevResx bpy.context.scene.render.resolution_y = prevResy bpy.context.scene.camera = prevCam bpy.context.scene.render.engine = prevEngine print("Finished building environment probes") return {'RUNNING_MODAL'} class TLM_CleanBuildEnvironmentProbes(bpy.types.Operator): bl_idname = "tlm.clean_environmentprobe" bl_label = "Clean Environment Probes" bl_description = "Clean Environment Probes" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): scene = context.scene savedir = os.path.dirname(bpy.data.filepath) dirpath = os.path.join(savedir, "Probes") if os.path.isdir(dirpath): for file in os.listdir(dirpath): os.remove(os.path.join(dirpath + "/" + file)) return {'FINISHED'} class TLM_MergeAdjacentActors(bpy.types.Operator): bl_idname = "tlm.merge_adjacent_actors" bl_label = "Merge adjacent actors" bl_description = "Merges the adjacent faces/vertices of selected objects" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): scene = context.scene return {'FINISHED'} class TLM_PrepareUVMaps(bpy.types.Operator): bl_idname = "tlm.prepare_uvmaps" bl_label = "Prepare UV maps" bl_description = "Prepare UV lightmaps for selected objects" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): scene = context.scene return {'FINISHED'} class TLM_LoadLightmaps(bpy.types.Operator): bl_idname = "tlm.load_lightmaps" bl_label = "Load Lightmaps" bl_description = "Load lightmaps from selected folder" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): scene = context.scene utility.transfer_load() print("Transfer finished") build.finish_assemble(self, 1, 1) return {'FINISHED'} class TLM_ToggleTexelDensity(bpy.types.Operator): bl_idname = "tlm.toggle_texel_density" bl_label = "Toggle Texel Density" bl_description = "Toggle visualize lightmap texel density for selected objects" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): scene = context.scene for obj in bpy.context.selected_objects: if obj.type == "MESH": uv_layers = obj.data.uv_layers #if the object has a td_vis in the uv maps, toggle off #else toggle on if obj.TLM_ObjectProperties.tlm_use_default_channel: for i in range(0, len(uv_layers)): if uv_layers[i].name == 'UVMap_Lightmap': uv_layers.active_index = i break else: for i in range(0, len(uv_layers)): if uv_layers[i].name == obj.TLM_ObjectProperties.tlm_uv_channel: uv_layers.active_index = i break #filepath = r"C:\path\to\image.png" #img = bpy.data.images.load(filepath) for area in bpy.context.screen.areas: if area.type == 'VIEW_3D': space_data = area.spaces.active bpy.ops.screen.area_dupli('INVOKE_DEFAULT') new_window = context.window_manager.windows[-1] area = new_window.screen.areas[-1] area.type = 'VIEW_3D' #bg = space_data.background_images.new() print(bpy.context.object) bpy.ops.object.bake_td_uv_to_vc() #bg.image = img break #set active uv_layer to print("TLM_Viz_Toggle") return {'FINISHED'} class TLM_DisableSpecularity(bpy.types.Operator): bl_idname = "tlm.disable_specularity" bl_label = "Disable specularity" bl_description = "Disables specularity from set" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): if bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Scene": for obj in bpy.context.scene.objects: if obj.type == "MESH": for slot in obj.material_slots: mat = slot.material if mat.node_tree: for node in mat.node_tree.nodes: if node.type == "BSDF_PRINCIPLED": for inp in node.inputs: if inp.name == "Specular": inp.default_value = 0.0 if inp.links and bpy.context.scene.TLM_SceneProperties.tlm_remove_met_spec_link: mat.node_tree.links.remove(inp.links[0]) elif bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Selection": for obj in bpy.context.selected_objects: if obj.type == "MESH": for slot in obj.material_slots: mat = slot.material if mat.node_tree: for node in mat.node_tree.nodes: if node.type == "BSDF_PRINCIPLED": for inp in node.inputs: if inp.name == "Specular": inp.default_value = 0.0 if inp.links and bpy.context.scene.TLM_SceneProperties.tlm_remove_met_spec_link: mat.node_tree.links.remove(inp.links[0]) else: #Enabled for obj in bpy.context.scene.objects: if obj.type == "MESH": if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use: for slot in obj.material_slots: mat = slot.material if mat.node_tree: for node in mat.node_tree.nodes: if node.type == "BSDF_PRINCIPLED": for inp in node.inputs: if inp.name == "Specular": inp.default_value = 0.0 if inp.links and bpy.context.scene.TLM_SceneProperties.tlm_remove_met_spec_link: mat.node_tree.links.remove(inp.links[0]) return{'FINISHED'} class TLM_DisableMetallic(bpy.types.Operator): bl_idname = "tlm.disable_metallic" bl_label = "Disable metallic" bl_description = "Disables metallic from set" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): if bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Scene": for obj in bpy.context.scene.objects: if obj.type == "MESH": for slot in obj.material_slots: mat = slot.material for node in mat.node_tree.nodes: if node.type == "BSDF_PRINCIPLED": for inp in node.inputs: if inp.name == "Metallic": inp.default_value = 0.0 if inp.links and bpy.context.scene.TLM_SceneProperties.tlm_remove_met_spec_link: mat.node_tree.links.remove(inp.links[0]) elif bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Selection": for obj in bpy.context.selected_objects: if obj.type == "MESH": for slot in obj.material_slots: mat = slot.material for node in mat.node_tree.nodes: if node.type == "BSDF_PRINCIPLED": for inp in node.inputs: if inp.name == "Metallic": inp.default_value = 0.0 if inp.links and bpy.context.scene.TLM_SceneProperties.tlm_remove_met_spec_link: mat.node_tree.links.remove(inp.links[0]) else: #Enabled for obj in bpy.context.scene.objects: if obj.type == "MESH": if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use: for slot in obj.material_slots: mat = slot.material for node in mat.node_tree.nodes: if node.type == "BSDF_PRINCIPLED": for inp in node.inputs: if inp.name == "Metallic": inp.default_value = 0.0 if inp.links and bpy.context.scene.TLM_SceneProperties.tlm_remove_met_spec_link: mat.node_tree.links.remove(inp.links[0]) return{'FINISHED'} class TLM_RemoveEmptyImages(bpy.types.Operator): bl_idname = "tlm.remove_empty_images" bl_label = "Remove Empty Images" bl_description = "Removes empty images from scene materials" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): for mat in bpy.data.materials: nodetree = mat.node_tree if nodetree: for node in nodetree.nodes: if node.name == "Baked Image": print(node.name) nodetree.nodes.remove(node) return{'FINISHED'} class TLM_PostAtlasSpecialsMenu(bpy.types.Menu): bl_label = "Lightmap" bl_idname = "TLM_MT_PostAtlasListSpecials" def draw(self, context): layout = self.layout layout.operator("tlm.add_collections_post") layout.operator("tlm.add_selected_collections_post") class TLM_AddCollectionsPost(bpy.types.Operator): bl_idname = "tlm.add_collections_post" bl_label = "Add collections" bl_description = "Adds all collections to atlases" bl_options = {'REGISTER', 'UNDO'} resolution : bpy.props.EnumProperty( items = [('32', '32', 'TODO'), ('64', '64', 'TODO'), ('128', '128', 'TODO'), ('256', '256', 'TODO'), ('512', '512', 'TODO'), ('1024', '1024', 'TODO'), ('2048', '2048', 'TODO'), ('4096', '4096', 'TODO'), ('8192', '8192', 'TODO')], name = "Atlas Lightmap Resolution", description="Atlas lightmap resolution", default='256') unwrap_modes = [('Lightmap', 'Lightmap', 'Use Blender Lightmap Pack algorithm'), ('SmartProject', 'Smart Project', 'Use Blender Smart Project algorithm')] if "blender_xatlas" in bpy.context.preferences.addons.keys(): unwrap_modes.append(('Xatlas', 'Xatlas', 'Use Xatlas addon packing algorithm')) unwrap : bpy.props.EnumProperty( items = unwrap_modes, name = "Unwrap Mode", description="Atlas unwrapping method", default='SmartProject') margin : bpy.props.FloatProperty( name="Unwrap Margin", default=0.1, min=0.0, max=1.0, subtype='FACTOR') @classmethod def poll(cls, context): return True def execute(self, context): for collection in bpy.context.scene.collection.children: #Add a new atlas with collection name #Traverse before adding scene = bpy.context.scene scene.TLM_PostAtlasList.add() scene.TLM_PostAtlasListItem = len(scene.TLM_PostAtlasList) - 1 scene.TLM_PostAtlasList[len(scene.TLM_PostAtlasList) - 1].name = collection.name scene.TLM_PostAtlasList[collection.name].tlm_atlas_lightmap_unwrap_mode = self.unwrap scene.TLM_PostAtlasList[collection.name].tlm_atlas_lightmap_resolution = self.resolution scene.TLM_PostAtlasList[collection.name].tlm_atlas_unwrap_margin = self.margin for obj in collection.objects: if obj.type == "MESH": obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = True obj.TLM_ObjectProperties.tlm_postpack_object = True obj.TLM_ObjectProperties.tlm_postatlas_pointer = collection.name return{'FINISHED'} def invoke(self, context, event): return context.window_manager.invoke_props_dialog(self) def draw(self, context): row = self.layout row.prop(self, "unwrap", text="Unwrap mode") row.prop(self, "resolution", text="Resolution") row.prop(self, "margin", text="Margin") class TLM_AddSelectedCollectionsPost(bpy.types.Operator): bl_idname = "tlm.add_selected_collections_post" bl_label = "Add selected collections" bl_description = "Add the collections of the selected objects" bl_options = {'REGISTER', 'UNDO'} resolution : bpy.props.EnumProperty( items = [('32', '32', 'TODO'), ('64', '64', 'TODO'), ('128', '128', 'TODO'), ('256', '256', 'TODO'), ('512', '512', 'TODO'), ('1024', '1024', 'TODO'), ('2048', '2048', 'TODO'), ('4096', '4096', 'TODO'), ('8192', '8192', 'TODO')], name = "Atlas Lightmap Resolution", description="Atlas lightmap resolution", default='256') unwrap_modes = [('Lightmap', 'Lightmap', 'Use Blender Lightmap Pack algorithm'), ('SmartProject', 'Smart Project', 'Use Blender Smart Project algorithm')] if "blender_xatlas" in bpy.context.preferences.addons.keys(): unwrap_modes.append(('Xatlas', 'Xatlas', 'Use Xatlas addon packing algorithm')) unwrap : bpy.props.EnumProperty( items = unwrap_modes, name = "Unwrap Mode", description="Atlas unwrapping method", default='SmartProject') margin : bpy.props.FloatProperty( name="Unwrap Margin", default=0.1, min=0.0, max=1.0, subtype='FACTOR') @classmethod def poll(cls, context): return True def execute(self, context): collections = [] for obj in bpy.context.selected_objects: obj_collection = obj.users_collection[0] if obj_collection.name not in collections: collections.append(obj_collection.name) print("Collections:" + str(collections)) for collection in bpy.context.scene.collection.children: if collection.name in collections: #Add a new atlas with collection name #Traverse before adding scene = bpy.context.scene scene.TLM_PostAtlasList.add() scene.TLM_PostAtlasListItem = len(scene.TLM_PostAtlasList) - 1 scene.TLM_PostAtlasList[len(scene.TLM_PostAtlasList) - 1].name = collection.name scene.TLM_PostAtlasList[collection.name].tlm_atlas_lightmap_unwrap_mode = self.unwrap scene.TLM_PostAtlasList[collection.name].tlm_atlas_lightmap_resolution = self.resolution scene.TLM_PostAtlasList[collection.name].tlm_atlas_unwrap_margin = self.margin for obj in collection.objects: if obj.type == "MESH": obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = True obj.TLM_ObjectProperties.tlm_postpack_object = True obj.TLM_ObjectProperties.tlm_postatlas_pointer = collection.name return{'FINISHED'} def invoke(self, context, event): return context.window_manager.invoke_props_dialog(self) def draw(self, context): row = self.layout row.prop(self, "unwrap", text="Unwrap mode") row.prop(self, "resolution", text="Resolution") row.prop(self, "margin", text="Margin") class TLM_AtlasSpecialsMenu(bpy.types.Menu): bl_label = "Lightmap" bl_idname = "TLM_MT_AtlasListSpecials" def draw(self, context): layout = self.layout layout.operator("tlm.add_collections") layout.operator("tlm.add_selected_collections") class TLM_AddCollections(bpy.types.Operator): bl_idname = "tlm.add_collections" bl_label = "Add all collections" bl_description = "Adds all collections to atlases" bl_options = {'REGISTER', 'UNDO'} resolution : bpy.props.EnumProperty( items = [('32', '32', 'TODO'), ('64', '64', 'TODO'), ('128', '128', 'TODO'), ('256', '256', 'TODO'), ('512', '512', 'TODO'), ('1024', '1024', 'TODO'), ('2048', '2048', 'TODO'), ('4096', '4096', 'TODO'), ('8192', '8192', 'TODO')], name = "Atlas Lightmap Resolution", description="Atlas lightmap resolution", default='256') unwrap_modes = [('Lightmap', 'Lightmap', 'Use Blender Lightmap Pack algorithm'), ('SmartProject', 'Smart Project', 'Use Blender Smart Project algorithm'), ('Copy', 'Copy existing', 'Use the existing UV channel')] if "blender_xatlas" in bpy.context.preferences.addons.keys(): unwrap_modes.append(('Xatlas', 'Xatlas', 'Use Xatlas addon packing algorithm')) unwrap : bpy.props.EnumProperty( items = unwrap_modes, name = "Unwrap Mode", description="Atlas unwrapping method", default='SmartProject') margin : bpy.props.FloatProperty( name="Unwrap Margin", default=0.1, min=0.0, max=1.0, subtype='FACTOR') @classmethod def poll(cls, context): return True def execute(self, context): for collection in bpy.context.scene.collection.children: #Add a new atlas with collection name #Traverse before adding scene = bpy.context.scene scene.TLM_AtlasList.add() scene.TLM_AtlasListItem = len(scene.TLM_AtlasList) - 1 scene.TLM_AtlasList[len(scene.TLM_AtlasList) - 1].name = collection.name scene.TLM_AtlasList[collection.name].tlm_atlas_lightmap_unwrap_mode = self.unwrap scene.TLM_AtlasList[collection.name].tlm_atlas_lightmap_resolution = self.resolution scene.TLM_AtlasList[collection.name].tlm_atlas_unwrap_margin = self.margin for obj in collection.objects: if obj.type == "MESH": obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = True obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode = "AtlasGroupA" obj.TLM_ObjectProperties.tlm_atlas_pointer = collection.name return{'FINISHED'} def invoke(self, context, event): return context.window_manager.invoke_props_dialog(self) def draw(self, context): row = self.layout row.prop(self, "unwrap", text="Unwrap mode") row.prop(self, "resolution", text="Resolution") row.prop(self, "margin", text="Margin") class TLM_AddSelectedCollections(bpy.types.Operator): bl_idname = "tlm.add_selected_collections" bl_label = "Add the collections of the selected objects" bl_description = "Add the collections of the selected objects" bl_options = {'REGISTER', 'UNDO'} resolution : bpy.props.EnumProperty( items = [('32', '32', 'TODO'), ('64', '64', 'TODO'), ('128', '128', 'TODO'), ('256', '256', 'TODO'), ('512', '512', 'TODO'), ('1024', '1024', 'TODO'), ('2048', '2048', 'TODO'), ('4096', '4096', 'TODO'), ('8192', '8192', 'TODO')], name = "Atlas Lightmap Resolution", description="Atlas lightmap resolution", default='256') unwrap_modes = [('Lightmap', 'Lightmap', 'Use Blender Lightmap Pack algorithm'), ('SmartProject', 'Smart Project', 'Use Blender Smart Project algorithm'), ('Copy', 'Copy existing', 'Use the existing UV channel')] if "blender_xatlas" in bpy.context.preferences.addons.keys(): unwrap_modes.append(('Xatlas', 'Xatlas', 'Use Xatlas addon packing algorithm')) unwrap : bpy.props.EnumProperty( items = unwrap_modes, name = "Unwrap Mode", description="Atlas unwrapping method", default='SmartProject') margin : bpy.props.FloatProperty( name="Unwrap Margin", default=0.1, min=0.0, max=1.0, subtype='FACTOR') @classmethod def poll(cls, context): return True def execute(self, context): collections = [] for obj in bpy.context.selected_objects: obj_collection = obj.users_collection[0] if obj_collection.name not in collections: collections.append(obj_collection.name) print("Collections:" + str(collections)) for collection in bpy.context.scene.collection.children: if collection.name in collections: #Add a new atlas with collection name #Traverse before adding scene = bpy.context.scene scene.TLM_AtlasList.add() scene.TLM_AtlasListItem = len(scene.TLM_AtlasList) - 1 scene.TLM_AtlasList[len(scene.TLM_AtlasList) - 1].name = collection.name scene.TLM_AtlasList[collection.name].tlm_atlas_lightmap_unwrap_mode = self.unwrap scene.TLM_AtlasList[collection.name].tlm_atlas_lightmap_resolution = self.resolution scene.TLM_AtlasList[collection.name].tlm_atlas_unwrap_margin = self.margin for obj in collection.objects: if obj.type == "MESH": obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = True obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode = "AtlasGroupA" obj.TLM_ObjectProperties.tlm_atlas_pointer = collection.name return{'FINISHED'} def invoke(self, context, event): return context.window_manager.invoke_props_dialog(self) def draw(self, context): row = self.layout row.prop(self, "unwrap", text="Unwrap mode") row.prop(self, "resolution", text="Resolution") row.prop(self, "margin", text="Margin") #Atlas disable objects class TLM_Reset(bpy.types.Operator): bl_idname = "tlm.reset" bl_label = "Resets all UI and settings" bl_description = "Reset UI and objects" bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): return True def execute(self, context): self.report({'INFO'}, "YES!") return {'FINISHED'} def invoke(self, context, event): return context.window_manager.invoke_confirm(self, event) # class TLM_Reset2(bpy.types.Operator): # bl_idname = "tlm.reset2" # bl_label = "Do you really want to do that?" # bl_options = {'REGISTER', 'INTERNAL'} # prop1: bpy.props.BoolProperty() # prop2: bpy.props.BoolProperty() # @classmethod # def poll(cls, context): # return True # def execute(self, context): # self.report({'INFO'}, "YES!") # return {'FINISHED'} # def invoke(self, context, event): # return context.window_manager.invoke_props_dialog(self) # def draw(self, context): # row = self.layout # row.prop(self, "prop1", text="Property A") # row.prop(self, "prop2", text="Property B") def TLM_DoubleResolution(): pass def TLM_HalfResolution(): pass def TLM_DivideLMGroups(): pass class TLM_CalcTexDex(bpy.types.Operator): bl_idname = "tlm.calctexdex" bl_label = "Calculate Texel Density" bl_description = "Calculates Texel Density of selected object" bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): return True def execute(self, context): return {'FINISHED'} class TLM_AddGLTFNode(bpy.types.Operator): bl_idname = "tlm.add_gltf_node" bl_label = "Add GLTF Node" bl_description = "Add to GLTF node to active material and connect lightmap if present" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): scene = context.scene cycles = scene.cycles material = bpy.context.active_object.active_material nodes = material.node_tree.nodes # create group data gltf_settings = bpy.data.node_groups.get('glTF Settings') if gltf_settings is None: bpy.data.node_groups.new('glTF Settings', 'ShaderNodeTree') # add group to node tree gltf_settings_node = nodes.get('glTF Settings') if gltf_settings_node is None: gltf_settings_node = nodes.new('ShaderNodeGroup') gltf_settings_node.name = 'glTF Settings' gltf_settings_node.node_tree = bpy.data.node_groups['glTF Settings'] # create group inputs if gltf_settings_node.inputs.get('Occlusion') is None: gltf_settings_node.inputs.new('NodeSocketFloat','Occlusion') #return gltf_settings_node return {'FINISHED'} class TLM_ShiftMultiplyLinks(bpy.types.Operator): bl_idname = "tlm.shift_multiply_links" bl_label = "Shift multiply links" bl_description = "Shift multiply links for active material" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): scene = context.scene cycles = scene.cycles material = bpy.context.active_object.active_material nodes = material.node_tree.nodes LM_Node = nodes.get("TLM_Lightmap") Multi_Node = nodes.get("Lightmap_Multiplication") Base_Node = nodes.get("Lightmap_BasecolorNode_A") material.node_tree.links.remove(LM_Node.outputs[0].links[0]) material.node_tree.links.remove(Base_Node.outputs[0].links[0]) material.node_tree.links.new(LM_Node.outputs[0], Multi_Node.inputs[2]) material.node_tree.links.new(Base_Node.outputs[0], Multi_Node.inputs[1]) return {'FINISHED'}