1313bl_info = {
1414 "name" : "Automated LOD Generation Tool" ,
1515 "author" : "Nico Breycha" ,
16- "version" : (0 , 0 , 3 ),
16+ "version" : (0 , 0 , 4 ),
1717 "blender" : (4 , 0 , 0 ),
1818 "location" : "View3D > Sidebar > Tool Tab" ,
1919 "description" : "Combines the Operator from all the other plugins." ,
@@ -26,13 +26,48 @@ class OBJECT_OT_lod_pipeline(bpy.types.Operator):
2626 bl_label = COMB_LABEL
2727
2828 def execute (self , context ):
29- def _select_all_except_original ():
30- """Select all objects except the original mesh."""
31- for _obj in bpy .data .objects :
32- if _obj != original_mesh :
29+ def import_and_prepare_original_mesh (filepath , rotation_correction , keep_original_name = False ):
30+ # Get list of existing objects before import
31+ existing_objects = set (bpy .data .objects )
32+
33+ # Import the model
34+ bpy .ops .wm .obj_import (filepath = filepath )
35+
36+ # Get the list of new objects
37+ imported_objects = [_obj for _obj in bpy .data .objects if _obj not in existing_objects ]
38+
39+ # Deselect all
40+ bpy .ops .object .select_all (action = 'DESELECT' )
41+
42+ # If it's multiple meshes, join them into one.
43+ for _obj in imported_objects :
44+ if _obj .type == 'MESH' :
3345 _obj .select_set (True )
34- else :
35- _obj .select_set (False )
46+ bpy .context .view_layer .objects .active = _obj
47+
48+ bpy .ops .object .join ()
49+ bpy .ops .object .transform_apply (location = True , rotation = True , scale = True )
50+
51+ # Apply rotation correction if needed
52+ _obj = bpy .context .active_object
53+
54+ if rotation_correction [0 ] != 0 :
55+ _obj .rotation_euler [0 ] = math .radians (rotation_correction [0 ])
56+ if rotation_correction [1 ] != 0 :
57+ _obj .rotation_euler [1 ] = math .radians (rotation_correction [1 ])
58+ if rotation_correction [2 ] != 0 :
59+ _obj .rotation_euler [2 ] = math .radians (rotation_correction [2 ])
60+
61+ bpy .ops .object .transform_apply (location = True , rotation = True , scale = True )
62+
63+ # Rename the original mesh
64+ imported_mesh = bpy .context .active_object
65+
66+ if not keep_original_name :
67+ imported_mesh .name = "original_mesh"
68+ imported_mesh .data .name = "original_mesh"
69+
70+ return imported_mesh
3671
3772 clear_scene ()
3873
@@ -94,65 +129,24 @@ def _select_all_except_original():
94129 context .scene .baker_settings .texture_margin = baker_settings_comb .texture_margin
95130 context .scene .baker_settings .save_path = baker_settings_comb .save_path
96131
97- # Import Model
98- bpy .ops .wm .obj_import (filepath = import_fp_comb )
99-
100- bpy .ops .object .select_all (action = 'DESELECT' )
101-
102- # If its multiple meshes, join them into one.
103- for obj in bpy .data .objects :
104- if obj .type == 'MESH' :
105- obj .select_set (True )
106- bpy .context .view_layer .objects .active = obj
107-
108- bpy .ops .object .join ()
109- bpy .ops .object .transform_apply (location = True , rotation = True , scale = True )
110-
111- # Apply rotation correction if needed
112- obj = bpy .context .active_object
113-
114- if rot_correction_comb [0 ] != 0 :
115- obj .rotation_euler [0 ] = math .radians (rot_correction_comb [0 ])
116- if rot_correction_comb [1 ] != 0 :
117- obj .rotation_euler [1 ] = math .radians (rot_correction_comb [1 ])
118- if rot_correction_comb [2 ] != 0 :
119- obj .rotation_euler [2 ] = math .radians (rot_correction_comb [2 ])
120-
121- bpy .ops .object .transform_apply (location = True , rotation = True , scale = True )
122-
123-
124- # Rename the original mesh. We will use it later for baking.
125- original_mesh = bpy .context .active_object
126- orig_name = original_mesh .name
127- original_mesh .name = "original_mesh"
128- original_mesh .data .name = "original_mesh"
129- context .scene .baker_settings .highpoly_mesh_name = original_mesh .name
130-
131- # Create a copy for the mesh we will work on.
132- bpy .ops .object .duplicate ()
133- working_mesh = bpy .context .active_object
134- working_mesh .name = orig_name
135- working_mesh .data .name = orig_name
132+ working_mesh = import_and_prepare_original_mesh (import_fp_comb , rot_correction_comb , keep_original_name = True )
136133
137134 # Make sure only the working mesh is selected.
138135 bpy .ops .object .select_all (action = 'DESELECT' )
139136 working_mesh .select_set (True )
140137 bpy .context .view_layer .objects .active = working_mesh
141138
142139 # Execute Operators
143- print ("Starting Cleanup" )
144140 launch_operator_by_name (CLEANUP_IDNAME )
145141
146- print ("Starting Slicing" )
147142 launch_operator_by_name (SLICE_IDNAME )
148143
149-
150144 # Ensure Target Polycount set by the user as intial polycount.
151- parts = []
145+ parts = set ()
152146
153147 for obj in bpy .data .objects :
154- if obj != original_mesh :
155- parts .append (obj )
148+ if obj . type == "MESH" :
149+ parts .add (obj )
156150
157151 # Clamp part count to not exceed initial reduction count.
158152 target_part_pc = initial_reduction_comb / num_of_modules_comb
@@ -165,34 +159,42 @@ def _select_all_except_original():
165159 vg = vertex_group_from_outer_boundary (part )
166160 decimate_object (part , perc_red , iterations = 1 , vg_name = vg )
167161
168- _select_all_except_original ()
162+ for part in parts :
163+ part .select_set (True )
169164
170165 launch_operator_by_name (LOD_IDNAME )
171166
172- _select_all_except_original ()
167+ objects_to_bake = {obj for obj in bpy .data .objects if obj .type == "MESH" }
168+
169+ for obj in objects_to_bake :
170+ obj .select_set (True )
173171
174172 launch_operator_by_name (UNWRAP_IDNAME )
175173
176- # Save .blend File after Unwrap.
177- blend_file_path = os .path .join (export_fp_comb , "bake_scene.blend" )
178- bpy .ops .wm .save_as_mainfile (filepath = blend_file_path , check_existing = False , compress = True )
174+ original_mesh = import_and_prepare_original_mesh (import_fp_comb , rot_correction_comb , keep_original_name = False )
175+ context .scene .baker_settings .highpoly_mesh_name = original_mesh .name
179176
180- _select_all_except_original ()
177+ for obj in objects_to_bake :
178+ obj .vertex_groups .clear () # Clear a little non-relevant data along the way.
179+ obj .select_set (True )
181180
182181 launch_operator_by_name (BAKE_IDNAME )
183182
183+ # Remove the original mesh from the scene before export.
184+ original_mesh .select_set (True )
185+ bpy .ops .object .delete ()
186+
184187 # Export newly created objects.
185- for obj in bpy .data .objects :
186- if obj .type == 'MESH' and obj != original_mesh :
187- # Deselect all objects
188- bpy .ops .object .select_all (action = 'DESELECT' )
188+ for obj in objects_to_bake :
189+ # Deselect all objects
190+ bpy .ops .object .select_all (action = 'DESELECT' )
189191
190- # Select the object to export
191- obj .select_set (True )
192- bpy .context .view_layer .objects .active = obj
192+ # Select the object to export
193+ obj .select_set (True )
194+ bpy .context .view_layer .objects .active = obj
193195
194- export_path = os .path .join (export_fp_comb , obj .name + '.obj' )
195- bpy .ops .wm .obj_export (filepath = export_path , export_selected_objects = True )
196+ export_path = os .path .join (export_fp_comb , obj .name + '.obj' )
197+ bpy .ops .wm .obj_export (filepath = export_path , export_selected_objects = True )
196198
197199 # Restore Operator Properties
198200 context .scene .initial_reduction = restore_dict ["initial_reduction" ]
@@ -209,7 +211,7 @@ def _select_all_except_original():
209211 context .scene .baker_settings .texture_margin = restore_dict ["baker_settings" ].texture_margin
210212 context .scene .baker_settings .save_path = restore_dict ["baker_settings" ].save_path
211213
212- # Save .blend File
214+ blend_file_path = os . path . join ( export_fp_comb , "cleaned_scene.blend" )
213215 bpy .ops .wm .save_as_mainfile (filepath = blend_file_path , check_existing = False , compress = True )
214216
215217 self .report ({'INFO' }, "Export completed successfully." )
0 commit comments