| 
									
										
										
										
											2025-01-22 16:18:30 +01:00
										 |  |  | import bpy, math, time | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from . import cache | 
					
						
							|  |  |  | from .. utility import * | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def assemble(): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     configure_world() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     configure_lights() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     configure_meshes() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def init(self, prev_container): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     store_existing(prev_container) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     set_settings() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     configure_world() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     configure_lights() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     configure_meshes(self) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     print("Config mesh catch omitted: REMEMBER TO SET IT BACK NAXELA") | 
					
						
							|  |  |  |     # try: | 
					
						
							|  |  |  |     #     configure_meshes(self) | 
					
						
							|  |  |  |     # except Exception as e: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #     print("An error occured during mesh configuration. See error below:") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #     print(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #     if not bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |     #         print("Turn on verbose mode to get more detail.") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def configure_world(): | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def configure_lights(): | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def configure_meshes(self): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |         print("Configuring meshes: Start") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |         print("Configuring meshes: Material restore") | 
					
						
							|  |  |  |     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) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |         print("Configuring meshes: Material rename check") | 
					
						
							|  |  |  |     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 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) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     iterNum = 0 | 
					
						
							|  |  |  |     currentIterNum = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     scene = bpy.context.scene | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |         print("Object: Setting UV, converting modifiers and prepare channels") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #OBJECT: Set UV, CONVERT AND PREPARE | 
					
						
							|  |  |  |     for obj in bpy.context.scene.objects: | 
					
						
							|  |  |  |         if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             hidden = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             #We check if the object is hidden | 
					
						
							|  |  |  |             if obj.hide_get(): | 
					
						
							|  |  |  |                 hidden = True | 
					
						
							|  |  |  |             if obj.hide_viewport: | 
					
						
							|  |  |  |                 hidden = True | 
					
						
							|  |  |  |             if obj.hide_render: | 
					
						
							|  |  |  |                 hidden = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             #We check if the object's collection is hidden | 
					
						
							|  |  |  |             collections = obj.users_collection | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for collection in collections: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if collection.hide_viewport: | 
					
						
							|  |  |  |                     hidden = True | 
					
						
							|  |  |  |                 if collection.hide_render: | 
					
						
							|  |  |  |                     hidden = True | 
					
						
							|  |  |  |                      | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     if collection.name in bpy.context.scene.view_layers[0].layer_collection.children: | 
					
						
							|  |  |  |                         if bpy.context.scene.view_layers[0].layer_collection.children[collection.name].hide_viewport: | 
					
						
							|  |  |  |                             hidden = True | 
					
						
							|  |  |  |                 except: | 
					
						
							|  |  |  |                     print("Error: Could not find collection: " + collection.name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             #Additional check for zero poly meshes | 
					
						
							|  |  |  |             mesh = obj.data | 
					
						
							|  |  |  |             if (len(mesh.polygons)) < 1: | 
					
						
							|  |  |  |                 print("Found an object with zero polygons. Skipping object: " + obj.name) | 
					
						
							|  |  |  |                 obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use and not hidden: | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |                 print("Preparing: UV initiation for object: " + obj.name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if len(obj.data.vertex_colors) < 1: | 
					
						
							|  |  |  |                     obj.data.vertex_colors.new(name="TLM") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if scene.TLM_SceneProperties.tlm_reset_uv: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     uv_layers = obj.data.uv_layers | 
					
						
							|  |  |  |                     uv_channel = "UVMap_Lightmap" | 
					
						
							|  |  |  |                     for uvlayer in uv_layers: | 
					
						
							|  |  |  |                         if uvlayer.name == uv_channel: | 
					
						
							|  |  |  |                             uv_layers.remove(uvlayer) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if scene.TLM_SceneProperties.tlm_apply_on_unwrap: | 
					
						
							|  |  |  |                     if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                         print("Applying transform to: " + obj.name) | 
					
						
							|  |  |  |                     bpy.context.view_layer.objects.active = obj | 
					
						
							|  |  |  |                     obj.select_set(True) | 
					
						
							|  |  |  |                     bpy.ops.object.transform_apply(location=False, rotation=True, scale=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if scene.TLM_SceneProperties.tlm_apply_modifiers: | 
					
						
							|  |  |  |                     if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                         print("Applying modifiers to: " + obj.name) | 
					
						
							|  |  |  |                     bpy.context.view_layer.objects.active = obj | 
					
						
							|  |  |  |                     obj.select_set(True) | 
					
						
							|  |  |  |                     bpy.ops.object.convert(target='MESH') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 for slot in obj.material_slots: | 
					
						
							|  |  |  |                     material = slot.material | 
					
						
							|  |  |  |                     skipIncompatibleMaterials(material) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 obj.hide_select = False #Remember to toggle this back | 
					
						
							|  |  |  |                 for slot in obj.material_slots: | 
					
						
							|  |  |  |                     if "." + slot.name + '_Original' in bpy.data.materials: | 
					
						
							|  |  |  |                         if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                             print("The material: " + slot.name + " shifted to " + "." + slot.name + '_Original') | 
					
						
							|  |  |  |                         slot.material = bpy.data.materials["." + slot.name + '_Original'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #ATLAS UV PROJECTING | 
					
						
							|  |  |  |     print("PREPARE: ATLAS") | 
					
						
							|  |  |  |     for atlasgroup in scene.TLM_AtlasList: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         print("Adding UV Projection for Atlas group: " + atlasgroup.name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         atlas = atlasgroup.name | 
					
						
							|  |  |  |         atlas_items = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bpy.ops.object.select_all(action='DESELECT') | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         #Atlas: Set UV, CONVERT AND PREPARE | 
					
						
							|  |  |  |         for obj in bpy.context.scene.objects: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if obj.TLM_ObjectProperties.tlm_atlas_pointer == atlasgroup.name: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 hidden = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 #We check if the object is hidden | 
					
						
							|  |  |  |                 if obj.hide_get(): | 
					
						
							|  |  |  |                     hidden = True | 
					
						
							|  |  |  |                 if obj.hide_viewport: | 
					
						
							|  |  |  |                     hidden = True | 
					
						
							|  |  |  |                 if obj.hide_render: | 
					
						
							|  |  |  |                     hidden = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 #We check if the object's collection is hidden | 
					
						
							|  |  |  |                 collections = obj.users_collection | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 for collection in collections: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if collection.hide_viewport: | 
					
						
							|  |  |  |                         hidden = True | 
					
						
							|  |  |  |                     if collection.hide_render: | 
					
						
							|  |  |  |                         hidden = True | 
					
						
							|  |  |  |                          | 
					
						
							|  |  |  |                     try: | 
					
						
							|  |  |  |                         if collection.name in bpy.context.scene.view_layers[0].layer_collection.children: | 
					
						
							|  |  |  |                             if bpy.context.scene.view_layers[0].layer_collection.children[collection.name].hide_viewport: | 
					
						
							|  |  |  |                                 hidden = True | 
					
						
							|  |  |  |                     except: | 
					
						
							|  |  |  |                         print("Error: Could not find collection: " + collection.name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA" and not hidden: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     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" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if not uv_channel in uv_layers: | 
					
						
							|  |  |  |                         if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                             print("UV map created for object: " + obj.name) | 
					
						
							|  |  |  |                         uvmap = uv_layers.new(name=uv_channel) | 
					
						
							|  |  |  |                         uv_layers.active_index = len(uv_layers) - 1 | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         print("Existing UV map found for object: " + obj.name) | 
					
						
							|  |  |  |                         for i in range(0, len(uv_layers)): | 
					
						
							|  |  |  |                             if uv_layers[i].name == 'UVMap_Lightmap': | 
					
						
							|  |  |  |                                 uv_layers.active_index = i | 
					
						
							|  |  |  |                                 break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     atlas_items.append(obj) | 
					
						
							|  |  |  |                     obj.select_set(True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if atlasgroup.tlm_atlas_lightmap_unwrap_mode == "SmartProject": | 
					
						
							|  |  |  |                     if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                         print("Atlasgroup Smart Project for: " + str(atlas_items)) | 
					
						
							|  |  |  |                     for obj in atlas_items: | 
					
						
							|  |  |  |                         print("Applying Smart Project to: ") | 
					
						
							|  |  |  |                         print(obj.name + ": Active UV: " + obj.data.uv_layers[obj.data.uv_layers.active_index].name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if len(atlas_items) > 0: | 
					
						
							|  |  |  |                         bpy.context.view_layer.objects.active = atlas_items[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     bpy.ops.object.mode_set(mode='EDIT') | 
					
						
							|  |  |  |                     bpy.ops.mesh.select_all(action='SELECT') | 
					
						
							|  |  |  |                     #API changes in 2.91 causes errors: | 
					
						
							|  |  |  |                     if (2, 91, 0) > bpy.app.version: | 
					
						
							|  |  |  |                         bpy.ops.uv.smart_project(angle_limit=45.0, island_margin=obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin, user_area_weight=1.0, use_aspect=True, stretch_to_bounds=False) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         angle = math.radians(45.0) | 
					
						
							|  |  |  |                         bpy.ops.uv.smart_project(angle_limit=angle, island_margin=obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin, area_weight=1.0, correct_aspect=True, scale_to_bounds=False) | 
					
						
							|  |  |  |                     bpy.ops.mesh.select_all(action='DESELECT') | 
					
						
							|  |  |  |                     bpy.ops.object.mode_set(mode='OBJECT') | 
					
						
							|  |  |  |                     print("Smart project done.") | 
					
						
							|  |  |  |                 elif atlasgroup.tlm_atlas_lightmap_unwrap_mode == "Lightmap": | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     bpy.ops.object.mode_set(mode='EDIT') | 
					
						
							|  |  |  |                     bpy.ops.uv.lightmap_pack('EXEC_SCREEN', PREF_CONTEXT='ALL_FACES', PREF_MARGIN_DIV=atlasgroup.tlm_atlas_unwrap_margin) | 
					
						
							|  |  |  |                     bpy.ops.mesh.select_all(action='DESELECT') | 
					
						
							|  |  |  |                     bpy.ops.object.mode_set(mode='OBJECT') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 elif atlasgroup.tlm_atlas_lightmap_unwrap_mode == "Xatlas": | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                         print("Using Xatlas on Atlas Group: " + atlas) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     for obj in atlas_items: | 
					
						
							|  |  |  |                         obj.select_set(True) | 
					
						
							|  |  |  |                     if len(atlas_items) > 0: | 
					
						
							|  |  |  |                         bpy.context.view_layer.objects.active = atlas_items[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     bpy.ops.object.mode_set(mode='EDIT') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     bpy.ops.object.mode_set(mode='OBJECT') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                         print("Copied Existing UV Map for Atlas Group: " + atlas) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if atlasgroup.tlm_use_uv_packer: | 
					
						
							|  |  |  |                     bpy.ops.object.select_all(action='DESELECT') | 
					
						
							|  |  |  |                     for obj in atlas_items: | 
					
						
							|  |  |  |                         obj.select_set(True) | 
					
						
							|  |  |  |                     if len(atlas_items) > 0: | 
					
						
							|  |  |  |                         bpy.context.view_layer.objects.active = atlas_items[0] | 
					
						
							|  |  |  |                     bpy.ops.object.mode_set(mode='EDIT') | 
					
						
							|  |  |  |                     bpy.ops.mesh.select_all(action='SELECT') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     bpy.context.scene.UVPackerProps.uvp_padding = atlasgroup.tlm_uv_packer_padding | 
					
						
							|  |  |  |                     bpy.context.scene.UVPackerProps.uvp_engine = atlasgroup.tlm_uv_packer_packing_engine | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     #print(x) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     print("!!!!!!!!!!!!!!!!!!!!! Using UV Packer on: " + obj.name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if uv_layers.active == "UVMap_Lightmap": | 
					
						
							|  |  |  |                         print("YES") | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         print("NO") | 
					
						
							|  |  |  |                         uv_layers.active_index = len(uv_layers) - 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if uv_layers.active == "UVMap_Lightmap": | 
					
						
							|  |  |  |                         print("YES") | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         print("NO") | 
					
						
							|  |  |  |                         uv_layers.active_index = len(uv_layers) - 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     bpy.ops.uvpackeroperator.packbtn() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     # if bpy.context.scene.UVPackerProps.uvp_engine == "OP0": | 
					
						
							|  |  |  |                     #     time.sleep(1) | 
					
						
							|  |  |  |                     # else: | 
					
						
							|  |  |  |                     #     time.sleep(2) | 
					
						
							|  |  |  |                     time.sleep(2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     #FIX THIS! MAKE A SEPARATE CALL. THIS IS A THREADED ASYNC | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     bpy.ops.mesh.select_all(action='DESELECT') | 
					
						
							|  |  |  |                     bpy.ops.object.mode_set(mode='OBJECT') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     #print(x) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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: | 
					
						
							|  |  |  |                 iterNum = iterNum + 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #OBJECT UV PROJECTING | 
					
						
							|  |  |  |     print("PREPARE: OBJECTS") | 
					
						
							|  |  |  |     for obj in bpy.context.scene.objects: | 
					
						
							|  |  |  |         if obj.name in bpy.context.view_layer.objects: #Possible fix for view layer error | 
					
						
							|  |  |  |             if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 hidden = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 #We check if the object is hidden | 
					
						
							|  |  |  |                 if obj.hide_get(): | 
					
						
							|  |  |  |                     hidden = True | 
					
						
							|  |  |  |                 if obj.hide_viewport: | 
					
						
							|  |  |  |                     hidden = True | 
					
						
							|  |  |  |                 if obj.hide_render: | 
					
						
							|  |  |  |                     hidden = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 #We check if the object's collection is hidden | 
					
						
							|  |  |  |                 collections = obj.users_collection | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 for collection in collections: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if collection.hide_viewport: | 
					
						
							|  |  |  |                         hidden = True | 
					
						
							|  |  |  |                     if collection.hide_render: | 
					
						
							|  |  |  |                         hidden = True | 
					
						
							|  |  |  |                          | 
					
						
							|  |  |  |                     try: | 
					
						
							|  |  |  |                         if collection.name in bpy.context.scene.view_layers[0].layer_collection.children: | 
					
						
							|  |  |  |                             if bpy.context.scene.view_layers[0].layer_collection.children[collection.name].hide_viewport: | 
					
						
							|  |  |  |                                 hidden = True | 
					
						
							|  |  |  |                     except: | 
					
						
							|  |  |  |                         print("Error: Could not find collection: " + collection.name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use and not hidden: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     objWasHidden = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     #For some reason, a Blender bug might prevent invisible objects from being smart projected | 
					
						
							|  |  |  |                     #We will turn the object temporarily visible | 
					
						
							|  |  |  |                     obj.hide_viewport = False | 
					
						
							|  |  |  |                     obj.hide_set(False) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     currentIterNum = currentIterNum + 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     #Configure selection | 
					
						
							|  |  |  |                     bpy.ops.object.select_all(action='DESELECT') | 
					
						
							|  |  |  |                     bpy.context.view_layer.objects.active = obj | 
					
						
							|  |  |  |                     obj.select_set(True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     obs = bpy.context.view_layer.objects | 
					
						
							|  |  |  |                     active = obs.active | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     #Provide material if none exists | 
					
						
							|  |  |  |                     print("Preprocessing material for: " + obj.name) | 
					
						
							|  |  |  |                     preprocess_material(obj, scene) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     #UV Layer management here | 
					
						
							|  |  |  |                     if not obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA": | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         print("Managing layer for Obj: " + obj.name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         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" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         if not uv_channel in uv_layers: | 
					
						
							|  |  |  |                             if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                                 print("UV map created for obj: " + obj.name) | 
					
						
							|  |  |  |                             uvmap = uv_layers.new(name=uv_channel) | 
					
						
							|  |  |  |                             uv_layers.active_index = len(uv_layers) - 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             #If lightmap | 
					
						
							|  |  |  |                             if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "Lightmap": | 
					
						
							|  |  |  |                                 bpy.ops.uv.lightmap_pack('EXEC_SCREEN', PREF_CONTEXT='ALL_FACES', PREF_MARGIN_DIV=obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin) | 
					
						
							|  |  |  |                              | 
					
						
							|  |  |  |                             #If smart project | 
					
						
							|  |  |  |                             elif obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "SmartProject": | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                 if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                                     print("Smart Project B") | 
					
						
							|  |  |  |                                 bpy.ops.object.select_all(action='DESELECT') | 
					
						
							|  |  |  |                                 obj.select_set(True) | 
					
						
							|  |  |  |                                 bpy.ops.object.mode_set(mode='EDIT') | 
					
						
							|  |  |  |                                 bpy.ops.mesh.select_all(action='SELECT') | 
					
						
							|  |  |  |                                 #API changes in 2.91 causes errors: | 
					
						
							|  |  |  |                                 if (2, 91, 0) > bpy.app.version: | 
					
						
							|  |  |  |                                     bpy.ops.uv.smart_project(angle_limit=45.0, island_margin=obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin, user_area_weight=1.0, use_aspect=True, stretch_to_bounds=False) | 
					
						
							|  |  |  |                                 else: | 
					
						
							|  |  |  |                                     angle = math.radians(45.0) | 
					
						
							|  |  |  |                                     bpy.ops.uv.smart_project(angle_limit=angle, island_margin=obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin, area_weight=1.0, correct_aspect=True, scale_to_bounds=False) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                 bpy.ops.mesh.select_all(action='DESELECT') | 
					
						
							|  |  |  |                                 bpy.ops.object.mode_set(mode='OBJECT') | 
					
						
							|  |  |  |                              | 
					
						
							|  |  |  |                             elif obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "Xatlas": | 
					
						
							|  |  |  |                                  | 
					
						
							|  |  |  |                                 Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             elif obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA": | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                 if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                                     print("ATLAS GROUP: " + obj.TLM_ObjectProperties.tlm_atlas_pointer) | 
					
						
							|  |  |  |                                  | 
					
						
							|  |  |  |                             else: #if copy existing | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                 if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                                     print("Copied Existing UV Map for object: " + obj.name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         if obj.TLM_ObjectProperties.tlm_use_uv_packer: | 
					
						
							|  |  |  |                             bpy.ops.object.select_all(action='DESELECT') | 
					
						
							|  |  |  |                             obj.select_set(True) | 
					
						
							|  |  |  |                             bpy.context.view_layer.objects.active = obj | 
					
						
							|  |  |  |                             bpy.ops.object.mode_set(mode='EDIT') | 
					
						
							|  |  |  |                             bpy.ops.mesh.select_all(action='SELECT') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             bpy.context.scene.UVPackerProps.uvp_padding = obj.TLM_ObjectProperties.tlm_uv_packer_padding | 
					
						
							|  |  |  |                             bpy.context.scene.UVPackerProps.uvp_engine = obj.TLM_ObjectProperties.tlm_uv_packer_packing_engine | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             #print(x) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             print("!!!!!!!!!!!!!!!!!!!!! Using UV Packer on: " + obj.name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             if uv_layers.active == "UVMap_Lightmap": | 
					
						
							|  |  |  |                                 print("YES") | 
					
						
							|  |  |  |                             else: | 
					
						
							|  |  |  |                                 print("NO") | 
					
						
							|  |  |  |                                 uv_layers.active_index = len(uv_layers) - 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             if uv_layers.active == "UVMap_Lightmap": | 
					
						
							|  |  |  |                                 print("YES") | 
					
						
							|  |  |  |                             else: | 
					
						
							|  |  |  |                                 print("NO") | 
					
						
							|  |  |  |                                 uv_layers.active_index = len(uv_layers) - 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             bpy.ops.uvpackeroperator.packbtn() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             if bpy.context.scene.UVPackerProps.uvp_engine == "OP0": | 
					
						
							|  |  |  |                                 time.sleep(1) | 
					
						
							|  |  |  |                             else: | 
					
						
							|  |  |  |                                 time.sleep(2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             #FIX THIS! MAKE A SEPARATE CALL. THIS IS A THREADED ASYNC | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             bpy.ops.mesh.select_all(action='DESELECT') | 
					
						
							|  |  |  |                             bpy.ops.object.mode_set(mode='OBJECT') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             #print(x) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         else: | 
					
						
							|  |  |  |                             if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                                 print("Existing UV map found for obj: " + obj.name) | 
					
						
							|  |  |  |                             for i in range(0, len(uv_layers)): | 
					
						
							|  |  |  |                                 if uv_layers[i].name == uv_channel: | 
					
						
							|  |  |  |                                     uv_layers.active_index = i | 
					
						
							|  |  |  |                                     break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     #print(x) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     #Sort out nodes | 
					
						
							|  |  |  |                     for slot in obj.material_slots: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         nodetree = slot.material.node_tree | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         outputNode = nodetree.nodes[0] #Presumed to be material output node | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         if(outputNode.type != "OUTPUT_MATERIAL"): | 
					
						
							|  |  |  |                             for node in nodetree.nodes: | 
					
						
							|  |  |  |                                 if node.type == "OUTPUT_MATERIAL": | 
					
						
							|  |  |  |                                     outputNode = node | 
					
						
							|  |  |  |                                     break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         mainNode = outputNode.inputs[0].links[0].from_node | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         if mainNode.type not in ['BSDF_PRINCIPLED','BSDF_DIFFUSE','GROUP']: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             #TODO! FIND THE PRINCIPLED PBR | 
					
						
							|  |  |  |                             self.report({'INFO'}, "The primary material node is not supported. Seeking first principled.") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             if len(find_node_by_type(nodetree.nodes, Node_Types.pbr_node)) > 0:  | 
					
						
							|  |  |  |                                 mainNode = find_node_by_type(nodetree.nodes, Node_Types.pbr_node)[0] | 
					
						
							|  |  |  |                             else: | 
					
						
							|  |  |  |                                 self.report({'INFO'}, "No principled found. Seeking diffuse") | 
					
						
							|  |  |  |                                 if len(find_node_by_type(nodetree.nodes, Node_Types.diffuse)) > 0:  | 
					
						
							|  |  |  |                                     mainNode = find_node_by_type(nodetree.nodes, Node_Types.diffuse)[0] | 
					
						
							|  |  |  |                                 else: | 
					
						
							|  |  |  |                                     self.report({'INFO'}, "No supported nodes. Continuing anyway.") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         if mainNode.type == 'GROUP': | 
					
						
							|  |  |  |                             if mainNode.node_tree != "Leenkx PBR": | 
					
						
							|  |  |  |                                 if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                                     print("The material group is not supported!") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-28 02:06:48 +00:00
										 |  |  |                         if (mainNode.type == "ShaderNodeMix"): | 
					
						
							| 
									
										
										
										
											2025-01-22 16:18:30 +01:00
										 |  |  |                             if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                                 print("Mix shader found") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             #Skip for now | 
					
						
							|  |  |  |                             slot.material.TLM_ignore = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         if (mainNode.type == "BSDF_PRINCIPLED"): | 
					
						
							|  |  |  |                             if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                                 print("BSDF_Principled") | 
					
						
							|  |  |  |                             if scene.TLM_EngineProperties.tlm_directional_mode == "None": | 
					
						
							|  |  |  |                                 if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                                     print("Directional mode") | 
					
						
							|  |  |  |                                 if not len(mainNode.inputs[22].links) == 0: | 
					
						
							|  |  |  |                                     if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                                         print("NOT LEN 0") | 
					
						
							|  |  |  |                                     ninput = mainNode.inputs[22].links[0] | 
					
						
							|  |  |  |                                     noutput = mainNode.inputs[22].links[0].from_node | 
					
						
							|  |  |  |                                     nodetree.links.remove(noutput.outputs[0].links[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             #Clamp metallic | 
					
						
							|  |  |  |                             if bpy.context.scene.TLM_SceneProperties.tlm_metallic_clamp == "limit": | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                 MainMetNodeSocket = mainNode.inputs.get("Metallic") | 
					
						
							|  |  |  |                                 if not len(MainMetNodeSocket.links) == 0: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                     print("Creating new clamp node") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                     nodes = nodetree.nodes | 
					
						
							|  |  |  |                                     MetClampNode = nodes.new('ShaderNodeClamp') | 
					
						
							|  |  |  |                                     MetClampNode.location = (-200,150) | 
					
						
							|  |  |  |                                     MetClampNode.inputs[2].default_value = 0.9 | 
					
						
							|  |  |  |                                     minput = mainNode.inputs.get("Metallic").links[0] #Metal input socket | 
					
						
							|  |  |  |                                     moutput = mainNode.inputs.get("Metallic").links[0].from_socket #Output socket | 
					
						
							|  |  |  |                                      | 
					
						
							|  |  |  |                                     nodetree.links.remove(minput) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                     nodetree.links.new(moutput, MetClampNode.inputs[0]) #minput node to clamp node | 
					
						
							|  |  |  |                                     nodetree.links.new(MetClampNode.outputs[0], MainMetNodeSocket) #clamp node to metinput | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                 elif mainNode.type == "PRINCIPLED_BSDF" and MainMetNodeSocket.links[0].from_node.type == "CLAMP": | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                 else: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                     print("New clamp node NOT made") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                     if mainNode.inputs[4].default_value > 0.9: | 
					
						
							|  |  |  |                                         mainNode.inputs[4].default_value = 0.9 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             elif bpy.context.scene.TLM_SceneProperties.tlm_metallic_clamp == "zero": | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                 MainMetNodeSocket = mainNode.inputs[4] | 
					
						
							|  |  |  |                                 if not len(MainMetNodeSocket.links) == 0: | 
					
						
							|  |  |  |                                     nodes = nodetree.nodes | 
					
						
							|  |  |  |                                     MetClampNode = nodes.new('ShaderNodeClamp') | 
					
						
							|  |  |  |                                     MetClampNode.location = (-200,150) | 
					
						
							|  |  |  |                                     MetClampNode.inputs[2].default_value = 0.0 | 
					
						
							|  |  |  |                                     minput = mainNode.inputs[4].links[0] #Metal input socket | 
					
						
							|  |  |  |                                     moutput = mainNode.inputs[4].links[0].from_socket #Output socket | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                     nodetree.links.remove(minput) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                     nodetree.links.new(moutput, MetClampNode.inputs[0]) #minput node to clamp node | 
					
						
							|  |  |  |                                     nodetree.links.new(MetClampNode.outputs[0], MainMetNodeSocket) #clamp node to metinput | 
					
						
							|  |  |  |                                 else: | 
					
						
							|  |  |  |                                     mainNode.inputs[4].default_value = 0.0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             else: #Skip | 
					
						
							|  |  |  |                                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         if (mainNode.type == "BSDF_DIFFUSE"): | 
					
						
							|  |  |  |                             if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                                 print("BSDF_Diffuse") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         # if (mainNode.type == "BSDF_DIFFUSE"): | 
					
						
							|  |  |  |                         #     if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |                         #         print("BSDF_Diffuse") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     #TODO FIX THIS PART! | 
					
						
							|  |  |  |                     #THIS IS USED IN CASES WHERE FOR SOME REASON THE USER FORGETS TO CONNECT SOMETHING INTO THE OUTPUT MATERIAL | 
					
						
							|  |  |  |                     for slot in obj.material_slots: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         nodetree = bpy.data.materials[slot.name].node_tree | 
					
						
							|  |  |  |                         nodes = nodetree.nodes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         #First search to get the first output material type | 
					
						
							|  |  |  |                         for node in nodetree.nodes: | 
					
						
							|  |  |  |                             if node.type == "OUTPUT_MATERIAL": | 
					
						
							|  |  |  |                                 mainNode = node | 
					
						
							|  |  |  |                                 break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         #Fallback to get search | 
					
						
							|  |  |  |                         if not mainNode.type == "OUTPUT_MATERIAL": | 
					
						
							|  |  |  |                             mainNode = nodetree.nodes.get("Material Output") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         #Last resort to first node in list | 
					
						
							|  |  |  |                         if not mainNode.type == "OUTPUT_MATERIAL": | 
					
						
							|  |  |  |                             mainNode = nodetree.nodes[0].inputs[0].links[0].from_node | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     #     for node in nodes: | 
					
						
							|  |  |  |                     #         if "LM" in node.name: | 
					
						
							|  |  |  |                     #             nodetree.links.new(node.outputs[0], mainNode.inputs[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     #     for node in nodes: | 
					
						
							|  |  |  |                     #         if "Lightmap" in node.name: | 
					
						
							|  |  |  |                     #                 nodes.remove(node) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def preprocess_material(obj, scene): | 
					
						
							|  |  |  |     if len(obj.material_slots) == 0: | 
					
						
							|  |  |  |         single = False | 
					
						
							|  |  |  |         number = 0 | 
					
						
							|  |  |  |         while single == False: | 
					
						
							|  |  |  |             matname = obj.name + ".00" + str(number) | 
					
						
							|  |  |  |             if matname in bpy.data.materials: | 
					
						
							|  |  |  |                 single = False | 
					
						
							|  |  |  |                 number = number + 1 | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 mat = bpy.data.materials.new(name=matname) | 
					
						
							|  |  |  |                 mat.use_nodes = True | 
					
						
							|  |  |  |                 obj.data.materials.append(mat) | 
					
						
							|  |  |  |                 single = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #We copy the existing material slots to an ordered array, which corresponds to the slot index | 
					
						
							|  |  |  |     matArray = [] | 
					
						
							|  |  |  |     for slot in obj.material_slots: | 
					
						
							|  |  |  |         matArray.append(slot.name) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     obj["TLM_PrevMatArray"] = matArray | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #We check and safeguard against NoneType | 
					
						
							|  |  |  |     for slot in obj.material_slots: | 
					
						
							|  |  |  |         if slot.material is None: | 
					
						
							|  |  |  |             matName = obj.name + ".00" + str(0) | 
					
						
							|  |  |  |             bpy.data.materials.new(name=matName) | 
					
						
							|  |  |  |             slot.material = bpy.data.materials[matName] | 
					
						
							|  |  |  |             slot.material.use_nodes = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for slot in obj.material_slots: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         cache.backup_material_copy(slot) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         mat = slot.material | 
					
						
							|  |  |  |         if mat.users > 1: | 
					
						
							|  |  |  |                 copymat = mat.copy() | 
					
						
							|  |  |  |                 slot.material = copymat | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #SOME ATLAS EXCLUSION HERE? | 
					
						
							|  |  |  |     ob = obj | 
					
						
							|  |  |  |     for slot in ob.material_slots: | 
					
						
							|  |  |  |         #If temporary material already exists | 
					
						
							|  |  |  |         if slot.material.name.endswith('_temp'): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         n = slot.material.name + '_' + ob.name + '_temp' | 
					
						
							|  |  |  |         if not n in bpy.data.materials: | 
					
						
							|  |  |  |             slot.material = slot.material.copy() | 
					
						
							|  |  |  |         slot.material.name = n | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #Add images for baking | 
					
						
							|  |  |  |     img_name = obj.name + '_baked' | 
					
						
							|  |  |  |     #Resolution is object lightmap resolution divided by global scaler | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if scene.TLM_EngineProperties.tlm_setting_supersample == "2x": | 
					
						
							|  |  |  |         supersampling_scale = 2 | 
					
						
							|  |  |  |     elif scene.TLM_EngineProperties.tlm_setting_supersample == "4x": | 
					
						
							|  |  |  |         supersampling_scale = 4 | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         supersampling_scale = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA" and obj.TLM_ObjectProperties.tlm_atlas_pointer != ""): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         atlas_image_name = obj.TLM_ObjectProperties.tlm_atlas_pointer + "_baked" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         res = int(scene.TLM_AtlasList[obj.TLM_ObjectProperties.tlm_atlas_pointer].tlm_atlas_lightmap_resolution) / int(scene.TLM_EngineProperties.tlm_resolution_scale) * int(supersampling_scale) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         #If image not in bpy.data.images or if size changed, make a new image | 
					
						
							|  |  |  |         if atlas_image_name not in bpy.data.images or bpy.data.images[atlas_image_name].size[0] != res or bpy.data.images[atlas_image_name].size[1] != res: | 
					
						
							|  |  |  |             img = bpy.data.images.new(img_name, int(res), int(res), alpha=True, float_buffer=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             num_pixels = len(img.pixels) | 
					
						
							|  |  |  |             result_pixel = list(img.pixels) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for i in range(0,num_pixels,4): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if scene.TLM_SceneProperties.tlm_override_bg_color: | 
					
						
							|  |  |  |                     result_pixel[i+0] = scene.TLM_SceneProperties.tlm_override_color[0] | 
					
						
							|  |  |  |                     result_pixel[i+1] = scene.TLM_SceneProperties.tlm_override_color[1] | 
					
						
							|  |  |  |                     result_pixel[i+2] = scene.TLM_SceneProperties.tlm_override_color[2] | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     result_pixel[i+0] = 0.0 | 
					
						
							|  |  |  |                     result_pixel[i+1] = 0.0 | 
					
						
							|  |  |  |                     result_pixel[i+2] = 0.0 | 
					
						
							|  |  |  |                     result_pixel[i+3] = 1.0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             img.pixels = result_pixel | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             img.name = atlas_image_name | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             img = bpy.data.images[atlas_image_name] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for slot in obj.material_slots: | 
					
						
							|  |  |  |             mat = slot.material | 
					
						
							|  |  |  |             mat.use_nodes = True | 
					
						
							|  |  |  |             nodes = mat.node_tree.nodes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if "Baked Image" in nodes: | 
					
						
							|  |  |  |                 img_node = nodes["Baked Image"] | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 img_node = nodes.new('ShaderNodeTexImage') | 
					
						
							|  |  |  |                 img_node.name = 'Baked Image' | 
					
						
							|  |  |  |                 img_node.location = (100, 100) | 
					
						
							|  |  |  |                 img_node.image = img | 
					
						
							|  |  |  |             img_node.select = True | 
					
						
							|  |  |  |             nodes.active = img_node | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         #We need to save this file first in Blender 3.3 due to new filmic option? | 
					
						
							|  |  |  |         image = img | 
					
						
							|  |  |  |         saveDir = os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_EngineProperties.tlm_lightmap_savedir) | 
					
						
							|  |  |  |         bakemap_path = os.path.join(saveDir, image.name) | 
					
						
							|  |  |  |         filepath_ext = ".hdr" | 
					
						
							|  |  |  |         image.filepath_raw = bakemap_path + filepath_ext | 
					
						
							|  |  |  |         image.file_format = "HDR" | 
					
						
							|  |  |  |         if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |             print("Saving to: " + image.filepath_raw) | 
					
						
							|  |  |  |         image.save() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         res = int(obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution) / int(scene.TLM_EngineProperties.tlm_resolution_scale) * int(supersampling_scale) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         #If image not in bpy.data.images or if size changed, make a new image | 
					
						
							|  |  |  |         if img_name not in bpy.data.images or bpy.data.images[img_name].size[0] != res or bpy.data.images[img_name].size[1] != res: | 
					
						
							|  |  |  |             img = bpy.data.images.new(img_name, int(res), int(res), alpha=True, float_buffer=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             num_pixels = len(img.pixels) | 
					
						
							|  |  |  |             result_pixel = list(img.pixels) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for i in range(0,num_pixels,4): | 
					
						
							|  |  |  |                 if scene.TLM_SceneProperties.tlm_override_bg_color: | 
					
						
							|  |  |  |                     result_pixel[i+0] = scene.TLM_SceneProperties.tlm_override_color[0] | 
					
						
							|  |  |  |                     result_pixel[i+1] = scene.TLM_SceneProperties.tlm_override_color[1] | 
					
						
							|  |  |  |                     result_pixel[i+2] = scene.TLM_SceneProperties.tlm_override_color[2] | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     result_pixel[i+0] = 0.0 | 
					
						
							|  |  |  |                     result_pixel[i+1] = 0.0 | 
					
						
							|  |  |  |                     result_pixel[i+2] = 0.0 | 
					
						
							|  |  |  |                     result_pixel[i+3] = 1.0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             img.pixels = result_pixel | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             img.name = img_name | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             img = bpy.data.images[img_name] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for slot in obj.material_slots: | 
					
						
							|  |  |  |             mat = slot.material | 
					
						
							|  |  |  |             mat.use_nodes = True | 
					
						
							|  |  |  |             nodes = mat.node_tree.nodes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if "Baked Image" in nodes: | 
					
						
							|  |  |  |                 img_node = nodes["Baked Image"] | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 img_node = nodes.new('ShaderNodeTexImage') | 
					
						
							|  |  |  |                 img_node.name = 'Baked Image' | 
					
						
							|  |  |  |                 img_node.location = (100, 100) | 
					
						
							|  |  |  |                 img_node.image = img | 
					
						
							|  |  |  |             img_node.select = True | 
					
						
							|  |  |  |             nodes.active = img_node | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         #We need to save this file first in Blender 3.3 due to new filmic option? | 
					
						
							|  |  |  |         image = img | 
					
						
							|  |  |  |         saveDir = os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_EngineProperties.tlm_lightmap_savedir) | 
					
						
							|  |  |  |         bakemap_path = os.path.join(saveDir, image.name) | 
					
						
							|  |  |  |         filepath_ext = ".hdr" | 
					
						
							|  |  |  |         image.filepath_raw = bakemap_path + filepath_ext | 
					
						
							|  |  |  |         image.file_format = "HDR" | 
					
						
							|  |  |  |         if bpy.context.scene.TLM_SceneProperties.tlm_verbose: | 
					
						
							|  |  |  |             print("Saving to: " + image.filepath_raw) | 
					
						
							|  |  |  |         image.save() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def set_settings(): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     scene = bpy.context.scene | 
					
						
							|  |  |  |     cycles = scene.cycles | 
					
						
							|  |  |  |     scene.render.engine = "CYCLES" | 
					
						
							|  |  |  |     sceneProperties = scene.TLM_SceneProperties | 
					
						
							|  |  |  |     engineProperties = scene.TLM_EngineProperties | 
					
						
							|  |  |  |     cycles.device = scene.TLM_EngineProperties.tlm_mode | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     print(bpy.app.version) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-28 02:06:48 +00:00
										 |  |  |     if bpy.app.version[0] == 3 or byp.app.version[0] == 4: | 
					
						
							| 
									
										
										
										
											2025-01-22 16:18:30 +01:00
										 |  |  |         if cycles.device == "GPU": | 
					
						
							|  |  |  |             scene.cycles.tile_size = 256 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             scene.cycles.tile_size = 32 | 
					
						
							|  |  |  |     else:     | 
					
						
							|  |  |  |         if cycles.device == "GPU": | 
					
						
							|  |  |  |             scene.render.tile_x = 256 | 
					
						
							|  |  |  |             scene.render.tile_y = 256 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             scene.render.tile_x = 32 | 
					
						
							|  |  |  |             scene.render.tile_y = 32 | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     if engineProperties.tlm_quality == "0": | 
					
						
							|  |  |  |         cycles.samples = 32 | 
					
						
							|  |  |  |         cycles.max_bounces = 1 | 
					
						
							|  |  |  |         cycles.diffuse_bounces = 1 | 
					
						
							|  |  |  |         cycles.glossy_bounces = 1 | 
					
						
							|  |  |  |         cycles.transparent_max_bounces = 1 | 
					
						
							|  |  |  |         cycles.transmission_bounces = 1 | 
					
						
							|  |  |  |         cycles.volume_bounces = 1 | 
					
						
							|  |  |  |         cycles.caustics_reflective = False | 
					
						
							|  |  |  |         cycles.caustics_refractive = False | 
					
						
							|  |  |  |     elif engineProperties.tlm_quality == "1": | 
					
						
							|  |  |  |         cycles.samples = 64 | 
					
						
							|  |  |  |         cycles.max_bounces = 2 | 
					
						
							|  |  |  |         cycles.diffuse_bounces = 2 | 
					
						
							|  |  |  |         cycles.glossy_bounces = 2 | 
					
						
							|  |  |  |         cycles.transparent_max_bounces = 2 | 
					
						
							|  |  |  |         cycles.transmission_bounces = 2 | 
					
						
							|  |  |  |         cycles.volume_bounces = 2 | 
					
						
							|  |  |  |         cycles.caustics_reflective = False | 
					
						
							|  |  |  |         cycles.caustics_refractive = False | 
					
						
							|  |  |  |     elif engineProperties.tlm_quality == "2": | 
					
						
							|  |  |  |         cycles.samples = 512 | 
					
						
							|  |  |  |         cycles.max_bounces = 2 | 
					
						
							|  |  |  |         cycles.diffuse_bounces = 2 | 
					
						
							|  |  |  |         cycles.glossy_bounces = 2 | 
					
						
							|  |  |  |         cycles.transparent_max_bounces = 2 | 
					
						
							|  |  |  |         cycles.transmission_bounces = 2 | 
					
						
							|  |  |  |         cycles.volume_bounces = 2 | 
					
						
							|  |  |  |         cycles.caustics_reflective = False | 
					
						
							|  |  |  |         cycles.caustics_refractive = False | 
					
						
							|  |  |  |     elif engineProperties.tlm_quality == "3": | 
					
						
							|  |  |  |         cycles.samples = 1024 | 
					
						
							|  |  |  |         cycles.max_bounces = 256 | 
					
						
							|  |  |  |         cycles.diffuse_bounces = 256 | 
					
						
							|  |  |  |         cycles.glossy_bounces = 256 | 
					
						
							|  |  |  |         cycles.transparent_max_bounces = 256 | 
					
						
							|  |  |  |         cycles.transmission_bounces = 256 | 
					
						
							|  |  |  |         cycles.volume_bounces = 256 | 
					
						
							|  |  |  |         cycles.caustics_reflective = False | 
					
						
							|  |  |  |         cycles.caustics_refractive = False | 
					
						
							|  |  |  |     elif engineProperties.tlm_quality == "4": | 
					
						
							|  |  |  |         cycles.samples = 2048 | 
					
						
							|  |  |  |         cycles.max_bounces = 512 | 
					
						
							|  |  |  |         cycles.diffuse_bounces = 512 | 
					
						
							|  |  |  |         cycles.glossy_bounces = 512 | 
					
						
							|  |  |  |         cycles.transparent_max_bounces = 512 | 
					
						
							|  |  |  |         cycles.transmission_bounces = 512 | 
					
						
							|  |  |  |         cycles.volume_bounces = 512 | 
					
						
							|  |  |  |         cycles.caustics_reflective = True | 
					
						
							|  |  |  |         cycles.caustics_refractive = True | 
					
						
							|  |  |  |     else: #Custom | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def store_existing(prev_container): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     scene = bpy.context.scene | 
					
						
							|  |  |  |     cycles = scene.cycles | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     selected = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for obj in bpy.context.scene.objects: | 
					
						
							|  |  |  |         if obj.select_get(): | 
					
						
							|  |  |  |             selected.append(obj.name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     prev_container["settings"] = [ | 
					
						
							|  |  |  |         cycles.samples, | 
					
						
							|  |  |  |         cycles.max_bounces, | 
					
						
							|  |  |  |         cycles.diffuse_bounces, | 
					
						
							|  |  |  |         cycles.glossy_bounces, | 
					
						
							|  |  |  |         cycles.transparent_max_bounces, | 
					
						
							|  |  |  |         cycles.transmission_bounces, | 
					
						
							|  |  |  |         cycles.volume_bounces, | 
					
						
							|  |  |  |         cycles.caustics_reflective, | 
					
						
							|  |  |  |         cycles.caustics_refractive, | 
					
						
							|  |  |  |         cycles.device, | 
					
						
							|  |  |  |         scene.render.engine, | 
					
						
							|  |  |  |         bpy.context.view_layer.objects.active, | 
					
						
							|  |  |  |         selected, | 
					
						
							|  |  |  |         [scene.render.resolution_x, scene.render.resolution_y] | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def skipIncompatibleMaterials(material): | 
					
						
							|  |  |  |     node_tree = material.node_tree | 
					
						
							|  |  |  |     nodes = material.node_tree.nodes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #ADD OR MIX SHADER? CUSTOM/GROUP? | 
					
						
							|  |  |  |     #IF Principled has emissive or transparency? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SkipMatList = ["EMISSION", | 
					
						
							|  |  |  |                     "BSDF_TRANSPARENT", | 
					
						
							|  |  |  |                     "BACKGROUND",  | 
					
						
							|  |  |  |                     "BSDF_HAIR", | 
					
						
							|  |  |  |                     "BSDF_HAIR_PRINCIPLED", | 
					
						
							|  |  |  |                     "HOLDOUT", | 
					
						
							|  |  |  |                     "PRINCIPLED_VOLUME", | 
					
						
							|  |  |  |                     "BSDF_REFRACTION", | 
					
						
							|  |  |  |                     "EEVEE_SPECULAR", | 
					
						
							|  |  |  |                     "BSDF_TRANSLUCENT", | 
					
						
							|  |  |  |                     "VOLUME_ABSORPTION", | 
					
						
							|  |  |  |                     "VOLUME_SCATTER"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #Find output node | 
					
						
							|  |  |  |     outputNode = nodes[0] | 
					
						
							|  |  |  |     if(outputNode.type != "OUTPUT_MATERIAL"): | 
					
						
							|  |  |  |         for node in node_tree.nodes: | 
					
						
							|  |  |  |             if node.type == "OUTPUT_MATERIAL": | 
					
						
							|  |  |  |                 outputNode = node | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #Find mainnode | 
					
						
							|  |  |  |     mainNode = outputNode.inputs[0].links[0].from_node | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if mainNode.type in SkipMatList: | 
					
						
							|  |  |  |         material.TLM_ignore = True | 
					
						
							|  |  |  |         print("Ignored material: " + material.name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def packUVPack(): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pass |