From 373ed201d323718b182ae851ab8d820b01984077 Mon Sep 17 00:00:00 2001 From: pullusb Date: Wed, 23 Jul 2025 14:30:44 +0200 Subject: [PATCH] Added global checks to popup and then launch individual checks 0.5.1 --- operators/__init__.py | 2 + operators/scene_checker.py | 74 +++++++++++++++++++------------ operators/simplify_conflicts.py | 4 ++ operators/visibility_conflicts.py | 12 ++++- ui.py | 31 +++++++++---- 5 files changed, 84 insertions(+), 39 deletions(-) diff --git a/operators/__init__.py b/operators/__init__.py index 591fa71..b8f9b17 100755 --- a/operators/__init__.py +++ b/operators/__init__.py @@ -4,6 +4,7 @@ from . import ( outputs_search_and_replace, visibility_conflicts, simplify_conflicts, + scene_checker, ) mods = ( @@ -12,6 +13,7 @@ mods = ( outputs_search_and_replace, visibility_conflicts, simplify_conflicts, + scene_checker, ) def register(): diff --git a/operators/scene_checker.py b/operators/scene_checker.py index 169a76a..4dba42b 100644 --- a/operators/scene_checker.py +++ b/operators/scene_checker.py @@ -1,7 +1,8 @@ import bpy - +from bpy.types import Operator from .. import fn from .simplify_conflicts import list_simplify_affected_objects +from .visibility_conflicts import get_viewlayer_collections_with_visiblity_conflict ## WIP : checker operator to perform all check at once (sometimes a limited version of the check) to expose useful solving operators. @@ -9,20 +10,19 @@ from .simplify_conflicts import list_simplify_affected_objects class RT_OT_scene_checker(Operator): bl_idname = "rt.scene_checker" - bl_label = "Check Scene " + bl_label = "Check Scene For Render Issues" bl_description = "Check / correct some aspect of the scene and objects, properties, etc. and report" bl_options = {"REGISTER"} - ## List of possible actions calls : - # set scene res - # set scene percentage at 100: - # Disabled animation - # Objects visibility conflict - # Objects modifiers visibility conflict + ## checkes and possible actions calls : + # list_object_visibility_conflicts + # list_modifier_visibility + # list_collection_visibility_conflicts + # list_object_affected_by_simplify - apply_fixes : bpy.props.BoolProperty(name="Apply Fixes", default=False, - description="Apply possible fixes instead of just listing (pop the list again in fix mode)", - options={'SKIP_SAVE'}) + # apply_fixes : bpy.props.BoolProperty(name="Apply Fixes", default=False, + # description="Apply possible fixes instead of just listing (pop the list again in fix mode)", + # options={'SKIP_SAVE'}) def invoke(self, context, event): self.ctrl = event.ctrl @@ -30,7 +30,7 @@ class RT_OT_scene_checker(Operator): def execute(self, context): problems = [] - + print('-- Scene Checks --') ## Old method : Apply fixes based on pref (inverted by ctrl key) # # If Ctrl is pressed, invert behavior (invert boolean) # apply ^= self.ctrl @@ -49,7 +49,7 @@ class RT_OT_scene_checker(Operator): viz_ct += 1 print(f'{o.name} : viewlayer {hv} - viewport {vp} - render {rd}') if viz_ct: - problems.append(['rt.list_object_visibility_conflicts', f'{viz_ct} objects visibility conflicts (details in console)', 'OBJECT_DATAMODE']) + problems.append(['rt.list_object_visibility_conflicts', f'{viz_ct} objects visibility conflicts', 'OBJECT_DATAMODE']) ## GP modifiers visibility conflict mod_viz_ct = 0 @@ -61,33 +61,44 @@ class RT_OT_scene_checker(Operator): mod_viz_ct += 1 print(f'{o.name} - modifier {m.name}: viewport {vp} != render {rd}') if mod_viz_ct: - problems.append(['rt.list_modifier_visibility', f'{mod_viz_ct} modifiers visibility conflicts (details in console)', 'MODIFIER_DATA']) + problems.append(['rt.list_modifier_visibility', f'{mod_viz_ct} modifiers visibility conflicts', 'MODIFIER_DATA']) ## Collection - # TODO: add check for collection visibility conflicts - - + if conflicts := get_viewlayer_collections_with_visiblity_conflict(context): + print('\nCollection visibility conflicts:') + for vc in conflicts: + vl = 'Yes' if vc.hide_viewport else 'No' + vp = 'Yes' if vc.collection.hide_viewport else 'No' + rd = 'Yes' if vc.collection.hide_render else 'No' + print(f'{vc.name}: viewlayer {vl} - viewport {vp} - render {rd}') + problems.append(['rt.list_collection_visibility_conflicts', f'{len(conflicts)} collections visibility conflicts', 'GROUP']) ## Simplify affected object - if context.scene.render.use_simplify and list_simplify_affected_objects(context): - problems.append(['rt.list_object_affected_by_simplify', 'Some objects are affected by simplify (details in console)', 'MOD_SIMPLIFY']) + if context.scene.render.use_simplify and (conflicts := list_simplify_affected_objects(context)): + print('\nSimplify affected objects:') + # Conflict list model : [[obj, [{type: "SUBSURF", ..}, {..}], icon], ..] + for item_l in conflicts: + print(f'{item_l[0].name} : {[m.get("type", "issue") for m in item_l[1]]}') + problems.append(['rt.list_object_affected_by_simplify', f'{len(conflicts)} objects affected by simplify', 'MOD_SIMPLIFY']) #### --- print fix/problems report if problems: print('===File check===') - for p in problems: - if isinstance(p, str): - print(p) - else: - print(p[0]) + ## List checks + # for p in problems: + # if isinstance(p, str): + # print(p) + # else: + # print(p[0]) - if not self.apply_fixes: - ## button to call the operator again with apply_fixes set to True - problems.append(['OPERATOR', 'gp.file_checker', 'Apply Fixes', 'FORWARD', {'apply_fixes': True}]) + # if not self.apply_fixes: + # ## button to call the operator again with apply_fixes set to True + # problems.append(['OPERATOR', 'gp.file_checker', 'Apply Fixes', 'FORWARD', {'apply_fixes': True}]) # Show in viewport - title = "Changed Settings" if apply else "Checked Settings (nothing changed)" + # title = "Changed Settings" if apply else "Checked Settings (nothing changed)" + title = "Visibility checks report (details in console)" fn.show_message_box(problems, _title = title, _icon = 'INFO') else: self.report({'INFO'}, 'All good') @@ -97,4 +108,9 @@ class RT_OT_scene_checker(Operator): # endregion -# RT_OT_scene_checker, +def register(): + bpy.utils.register_class(RT_OT_scene_checker) + + +def unregister(): + bpy.utils.unregister_class(RT_OT_scene_checker) diff --git a/operators/simplify_conflicts.py b/operators/simplify_conflicts.py index 02287bc..8665712 100644 --- a/operators/simplify_conflicts.py +++ b/operators/simplify_conflicts.py @@ -8,6 +8,10 @@ from bpy.props import (BoolProperty, StringProperty) def list_simplify_affected_objects(context): + """Return a list of object affected by simplify + return : [[obj, [{type: "SUBSURF", ..}, {..}], icon], ..] + """ + ob_list = [] # Get simplify settings render = context.scene.render diff --git a/operators/visibility_conflicts.py b/operators/visibility_conflicts.py index b6ba3ef..a4b24d4 100644 --- a/operators/visibility_conflicts.py +++ b/operators/visibility_conflicts.py @@ -345,6 +345,14 @@ def get_collection_children_recursive(col, cols=None) -> list: cols = get_collection_children_recursive(sub, cols) return cols +def get_viewlayer_collections_with_visiblity_conflict(context): + '''return viewlayer collections with visibility conflicts between hide in viewlayer, hide viewport and hide render''' + vcols = get_collection_children_recursive(context.view_layer.layer_collection) + vcols = list(set(vcols)) # ensure no duplicates + + ## Store collection with conflicts + return [vc for vc in vcols if not (vc.hide_viewport == vc.collection.hide_viewport == vc.collection.hide_render)] + class RT_OT_list_collection_visibility_conflicts(Operator): bl_idname = "rt.list_collection_visibility_conflicts" bl_label = "List Collection Visibility Conflicts" @@ -364,12 +372,12 @@ class RT_OT_list_collection_visibility_conflicts(Operator): def invoke(self, context, event): ## get all viewlayer collections + + self.conflict_collections = get_viewlayer_collections_with_visiblity_conflict(context) vcols = get_collection_children_recursive(context.view_layer.layer_collection) vcols = list(set(vcols)) # ensure no duplicates ## Store collection with conflicts - # layer_collection.is_visible against render visibility ? - ## Do not list currently excluded collections self.conflict_collections = [vc for vc in vcols if not (vc.hide_viewport == vc.collection.hide_viewport == vc.collection.hide_render)] self.included_collection = [vc for vc in self.conflict_collections if not vc.exclude] self.excluded_collection = [vc for vc in self.conflict_collections if vc.exclude] diff --git a/ui.py b/ui.py index 64576fc..2060117 100755 --- a/ui.py +++ b/ui.py @@ -14,13 +14,17 @@ class RT_PT_render_toolbox_ui(Panel): layout.operator("rt.create_output_layers", icon="NODE") layout.operator("rt.outputs_search_and_replace", text='Search and replace outputs', icon="BORDERMOVE") -class RT_PT_visibility_check(Panel): - bl_space_type = "NODE_EDITOR" +# Base panel for drawing +class RT_PT_visibility_check_ui_base(bpy.types.Panel): + bl_space_type = "VIEW_3D" bl_region_type = "UI" - bl_category = "Render" # Wrangler + bl_category = "View" bl_label = "Visibility Checks" - # bl_parent_id = "RT_PT_render_toolbox_ui" - # bl_options = {'DEFAULT_CLOSED'} + bl_options = {'DEFAULT_CLOSED'} + + def draw_header_preset(self, context): + layout = self.layout + layout.operator('rt.scene_checker', text="", icon='CHECKMARK') #, depress=True def draw(self, context): layout = self.layout @@ -31,14 +35,24 @@ class RT_PT_visibility_check(Panel): layout.operator("rt.list_modifier_visibility", text="List Modifiers Visibility Conflicts", icon="MODIFIER") layout.operator("rt.list_collection_visibility_conflicts", text="List Collections Visibility Conflicts", icon="OUTLINER_COLLECTION") - + layout.separator() layout.operator("rt.list_object_affected_by_simplify", text="List Object Affected By Simplify", icon="MOD_SIMPLIFY") +class RT_PT_visibility_check_ui_viewport(RT_PT_visibility_check_ui_base): + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_category = "View" + +class RT_PT_visibility_check_ui_node(RT_PT_visibility_check_ui_base): + bl_space_type = 'NODE_EDITOR' + # bl_parent_id = "RT_PT_render_toolbox_ui" + bl_region_type = 'UI' + bl_category = "Render" # Wrangler ? ## Unused, only exposed in Create output panel class RT_PT_output_template(Panel): - bl_space_type = "NODE_EDITOR" + bl_space_type = "3D_VIEW" bl_region_type = "UI" bl_category = "Render" # Wrangler bl_label = "File Output Templates" @@ -65,8 +79,9 @@ class RT_PT_output_template(Panel): classes = ( RT_PT_render_toolbox_ui, + RT_PT_visibility_check_ui_viewport, + RT_PT_visibility_check_ui_node # RT_PT_output_template, - RT_PT_visibility_check, ) def register():