import os import subprocess import bpy from ..Functions import (basic_functions, constants, image_functions, material_functions, node_functions, visibility_functions,object_functions) class GTT_VerifyMaterialsOperator(bpy.types.Operator): """Check for each visbile material if it has a PBR Shader so the GLTF Export works fine""" bl_idname = "object.verify_materials" bl_label = "Verify Materials" def execute(self, context): vis_mats = material_functions.get_all_visible_materials() for mat in vis_mats: check_ok = node_functions.check_pbr(self,mat) if not check_ok: self.report({'INFO'}, "No PBR Shader in " + mat.name) objects_in_scene = bpy.data.objects for obj in objects_in_scene: for slot in obj.material_slots: if slot.material is None: self.report({'INFO'}, "Empty Material Slot on " + obj.name) return {'FINISHED'} # ----------------------- LIGHTAP OPERATORS--------------------# class GTT_SelectLightmapObjectsOperator(bpy.types.Operator): """Select all Objects in the list that have the according lightmap attached to them. Makes it easy to rebake multiple Objects""" bl_idname = "object.select_lightmap_objects" bl_label = "Select Lightmap Objects" @classmethod def poll(cls, context): if context.scene.bake_settings.baking_groups == '-- Baking Groups --': return False return True def execute(self, context): C = context O = bpy.ops bake_settings = C.scene.bake_settings active_lightmap = bake_settings.baking_groups objects = [ob for ob in bpy.context.view_layer.objects if ob.visible_get()] O.object.select_all(action='DESELECT') for obj in objects: if obj.lightmap_name == active_lightmap or obj.ao_map_name == active_lightmap: C.view_layer.objects.active = obj obj.select_set(True) return {'FINISHED'} # ----------------------- TEXTURE OPERATORS--------------------# class GTT_GetMaterialByTextureOperator(bpy.types.Operator): bl_idname = "scene.select_mat_by_tex" bl_label = "Select Material By Texture" bl_description = "Selecting all materials in scene that use the selected texture" bl_options = {"REGISTER"} bpy.types.Scene.materials_found = [] @classmethod def poll(cls, context): D = bpy.data images = D.images display = True # image to index not found try: sel_image_texture = images[context.scene.texture_settings.texture_index] if sel_image_texture.name in ('Viewer Node', 'Render Result'): display = False except: display = False return display def execute(self, context): D = bpy.data images = D.images sel_image_texture = images[context.scene.texture_settings.texture_index] materials = D.materials # to print materials with current image texture materials_found = context.scene.materials_found materials_found.clear() for mat in materials: if hasattr(mat,"node_tree"): if hasattr(mat.node_tree,"nodes"): nodes = mat.node_tree.nodes tex_node_type = constants.Node_Types.image_texture tex_nodes = node_functions.get_nodes_by_type(nodes,tex_node_type) # if texture node in current node tree if len(tex_nodes) > 0: images = [node.image for node in tex_nodes] if sel_image_texture in images: materials_found.append(mat.name) object_functions.select_obj_by_mat(mat,self) return {"FINISHED"} class GTT_ScaleImageOperator(bpy.types.Operator): """Scale all Images on selected Material to specific resolution""" bl_idname = "image.scale_image" bl_label = "Scale Images" @classmethod def poll(cls, context): D = bpy.data images = D.images display = True # if operate on all textures is checked we don't need to get the index if context.scene.texture_settings.operate_on_all_textures: return True # image to index not found try: sel_image_texture = images[context.scene.texture_settings.texture_index] if sel_image_texture.name in ('Viewer Node','Render Result'): display = False except: display = False return display def invoke(self,context,event): D = bpy.data texture_settings = context.scene.texture_settings image_size = [int(context.scene.img_bake_size),int(context.scene.img_bake_size)] images_in_scene = D.images all_images = image_functions.get_all_images_in_ui_list() if texture_settings.operate_on_all_textures: for img in all_images: image_functions.scale_image(img,image_size) else: sel_image_texture = images_in_scene[texture_settings.texture_index] image_functions.scale_image(sel_image_texture,image_size) return {'FINISHED'} def modal(self, context, event): if event.type in {'RIGHTMOUSE', 'ESC'}: return {'CANCELLED'} return {'PASS_THROUGH'} # ----------------------- VIEW OPERATORS--------------------# class GTT_SwitchBakeMaterialOperator(bpy.types.Operator): """Switch to baked material""" bl_idname = "object.switch_bake_mat_operator" bl_label = "Baked Material" def execute(self, context): show_bake_material = True visibility_functions.switch_baked_material(show_bake_material,context.scene.affect) return {'FINISHED'} class GTT_SwitchOrgMaterialOperator(bpy.types.Operator): """Switch from baked to original material""" bl_idname = "object.switch_org_mat_operator" bl_label = "Org. Material" def execute(self, context): show_bake_material = False visibility_functions.switch_baked_material(show_bake_material,context.scene.affect) return {'FINISHED'} class GTT_PreviewBakeTextureOperator(bpy.types.Operator): """Connect baked texture to emission to see result""" bl_idname = "object.preview_bake_texture" bl_label = "Preview Bake Texture" connect : bpy.props.BoolProperty() def execute(self, context): context.scene.texture_settings.preview_bake_texture = self.connect visibility_functions.preview_bake_texture(self,context) return {'FINISHED'} class GTT_LightmapEmissionOperator(bpy.types.Operator): """Connect baked Lightmap to Emission input of Principled Shader""" bl_idname = "object.lightmap_to_emission" bl_label = "Lightmap to Emission" connect : bpy.props.BoolProperty() def execute(self, context): visibility_functions.lightmap_to_emission(self,context,self.connect) return {'FINISHED'} class GTT_PreviewLightmap(bpy.types.Operator): """Connect baked Lightmap to Base Color input of Principled Shader""" bl_idname = "object.preview_lightmap" bl_label = "Lightmap to Base Color" connect : bpy.props.BoolProperty() def execute(self, context): context.scene.texture_settings.preview_lightmap = self.connect visibility_functions.preview_lightmap(self,context) return {'FINISHED'} # ----------------------- UV OPERATORS--------------------# class GTT_AddUVOperator(bpy.types.Operator): """Add uv layer with layer name entered above""" bl_idname = "object.add_uv" bl_label = "Add UV to all selected objects" uv_name:bpy.props.StringProperty() def execute(self, context): sel_objects = context.selected_objects for obj in sel_objects: if obj.type != "MESH": continue uv_layers = obj.data.uv_layers if self.uv_name in uv_layers: print("UV Name already take, choose another one") continue uv_layers.new(name=self.uv_name) uv_layers.get(self.uv_name).active = True return {'FINISHED'} class GTT_RemoveUVOperator(bpy.types.Operator): """Delete all uv layers found in uv_slot entered above""" bl_idname = "object.remove_uv" bl_label = "Remove UV" uv_slot: bpy.props.IntProperty() def execute(self, context): sel_objects = context.selected_objects self.uv_slot -= 1 for obj in sel_objects: if obj.type != "MESH": continue uv_layers = obj.data.uv_layers if len(uv_layers) > self.uv_slot: uv_layers.remove(uv_layers[self.uv_slot]) return {'FINISHED'} class GTT_SetActiveUVOperator(bpy.types.Operator): """Set the acive uv to the slot entered above""" bl_idname = "object.set_active_uv" bl_label = "Set Active UV" uv_slot:bpy.props.IntProperty() def execute(self, context): sel_objects = context.selected_objects self.uv_slot -= 1 for obj in sel_objects: if obj.type != "MESH": continue uv_layers = obj.data.uv_layers if len(uv_layers) > self.uv_slot: uv_layers.active_index = self.uv_slot return {'FINISHED'} # ----------------------- CLEAN OPERATORS--------------------# # class CleanBakesOperator(bpy.types.Operator): class GTT_RemoveLightmapOperator(bpy.types.Operator): """Remove Lightmap and UV Node""" bl_idname = "material.clean_lightmap" bl_label = "Clean Lightmap" def execute(self, context): selected_objects = context.selected_objects bake_settings = context.scene.bake_settings all_materials = set() slots_array = [obj.material_slots for obj in selected_objects] for slots in slots_array: for slot in slots: all_materials.add(slot.material) for mat in all_materials: if mat is None: continue node_functions.remove_node(mat,bake_settings.texture_node_lightmap) node_functions.remove_node(mat,"Mulitply Lightmap") node_functions.remove_node(mat,"Second_UV") #remove lightmap flag for obj in selected_objects: obj.hasLightmap = False if obj.get('lightmap_name') is not None : del obj["lightmap_name"] return {'FINISHED'} class GTT_RemoveAOOperator(bpy.types.Operator): """Remove AO Node and clear baking flags on object""" bl_idname = "material.clean_ao_map" bl_label = "Clean AO map" def execute(self, context): # visibility_functions.switch_baked_material(False,"scene") bpy.ops.material.clean_materials() bake_settings = context.scene.bake_settings selected_objects = context.selected_objects all_materials = set() slots_array = [obj.material_slots for obj in selected_objects] for slots in slots_array: for slot in slots: all_materials.add(slot.material) for mat in all_materials: if mat is None: continue node_functions.remove_node(mat,bake_settings.texture_node_ao) node_functions.remove_node(mat,"glTF Settings") #remove flag for obj in selected_objects: if obj.get('ao_map_name') is not None : del obj["ao_map_name"] if obj.get('bake_version') is not None : del obj["bake_version"] return {'FINISHED'} class GTT_CleanTexturesOperator(bpy.types.Operator): """Remove unreferenced images""" bl_idname = "image.clean_textures" bl_label = "Clean Textures" def execute(self, context): for image in bpy.data.images: if not image.users or list(image.size) == [0,0]: bpy.data.images.remove(image) return {'FINISHED'} class GTT_CleanMaterialsOperator(bpy.types.Operator): """Clean materials with no users and remove empty material slots""" bl_idname = "material.clean_materials" bl_label = "Clean Materials" def execute(self, context): material_functions.clean_empty_materials() material_functions.clean_no_user_materials() material_functions.use_nodes() return {'FINISHED'} class GTT_CleanUnusedImagesOperator(bpy.types.Operator): """Clean all images from Hard Disk that are not used in scene""" bl_idname = "scene.clean_unused_images" bl_label = "Clean Images" bl_options = {"REGISTER"} @classmethod def poll(cls, context): return True def execute(self, context): images_in_folder = [] images_in_blender = bpy.data.images image_paths_in_blender = [] filePath = bpy.data.filepath path = os.path.dirname(filePath) + "\\textures" # find images on hard drive if os.path.exists(path): for path, subdirs, files in os.walk(path): for name in files: images_in_folder.append(path+"\\"+name) for img in images_in_blender: image_paths_in_blender.append(img.filepath) images_intersection = basic_functions.Intersection(image_paths_in_blender,images_in_folder) images_to_clean = basic_functions.Diff(images_in_folder,images_intersection) print("Deleting files :") for img in images_to_clean: os.remove(img) print(img) return {'FINISHED'} # ----------------------- FILE OPERATORS--------------------# class GTT_OpenTexturesFolderOperator(bpy.types.Operator): """Open Texture folder if it exists, bake or scale texture to create texture folder""" bl_idname = "scene.open_textures_folder" bl_label = "Open Folder" texture_path="\\textures\\" @classmethod def poll(self, context): filePath = bpy.data.filepath path = os.path.dirname(filePath) if os.path.exists(path + self.texture_path): return True return False def execute(self, context): filepath = bpy.data.filepath directory = os.path.dirname(filepath) + self.texture_path if filepath != "": subprocess.call("explorer " + directory, shell=True) else: self.report({'INFO'}, 'You need to save Blend file first !') return {"FINISHED"} class GOVIE_Open_Link_Operator(bpy.types.Operator): bl_idname = "scene.open_link" bl_label = "Open Website" bl_description = "Go to GOVIE Website" url : bpy.props.StringProperty(name="url") @classmethod def poll(cls, context): return True def execute(self, context): bpy.ops.wm.url_open(url=self.url) return {"FINISHED"}