Initial code for collection confo operator
This commit is contained in:
parent
ffd0fcf90c
commit
22e97d63ca
47
fn.py
47
fn.py
@ -305,7 +305,7 @@ def connect_to_file_output(node_list, file_out=None, base_path='', excludes=None
|
|||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
|
|
||||||
# region Utilities
|
# region Collections
|
||||||
|
|
||||||
def get_collection_children_recursive(col, cols=None) -> list:
|
def get_collection_children_recursive(col, cols=None) -> list:
|
||||||
'''return a list of all the child collections
|
'''return a list of all the child collections
|
||||||
@ -319,6 +319,51 @@ def get_collection_children_recursive(col, cols=None) -> list:
|
|||||||
cols = get_collection_children_recursive(sub, cols)
|
cols = get_collection_children_recursive(sub, cols)
|
||||||
return cols
|
return cols
|
||||||
|
|
||||||
|
def get_view_layer_collection(col, vl_col=None, view_layer=None):
|
||||||
|
'''return viewlayer collection from collection
|
||||||
|
col: the collection to get viewlayer collection from
|
||||||
|
view_layer (viewlayer, optional) : viewlayer to search in, if not passed, use active viewlayer
|
||||||
|
|
||||||
|
'''
|
||||||
|
if vl_col is None:
|
||||||
|
if view_layer:
|
||||||
|
vl_col = view_layer.layer_collection
|
||||||
|
else:
|
||||||
|
vl_col = bpy.context.view_layer.layer_collection
|
||||||
|
for sub in vl_col.children:
|
||||||
|
if sub.collection == col:
|
||||||
|
return sub
|
||||||
|
if len(sub.children):
|
||||||
|
c = get_view_layer_collection(col, sub)
|
||||||
|
if c is not None:
|
||||||
|
return c
|
||||||
|
|
||||||
|
def get_parents_cols(col, root=None, scene=None, cols=None):
|
||||||
|
'''Return a list of parents collections of passed col
|
||||||
|
root : Pass a collection to search in (recursive)
|
||||||
|
Else search in master collection
|
||||||
|
scene: scene to search in (active scene if not passed)
|
||||||
|
cols: used internally by the function to collect results
|
||||||
|
'''
|
||||||
|
if cols is None:
|
||||||
|
cols = []
|
||||||
|
|
||||||
|
if root == None:
|
||||||
|
scn = scene or bpy.context.scene
|
||||||
|
root=scn.collection
|
||||||
|
|
||||||
|
for sub in root.children:
|
||||||
|
if sub == col:
|
||||||
|
cols.append(root)
|
||||||
|
|
||||||
|
if len(sub.children):
|
||||||
|
cols = get_parents_cols(col, root=sub, cols=cols)
|
||||||
|
return cols
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
# region utilities
|
||||||
|
|
||||||
def set_properties_editor_tab(tab, skip_if_exists=True):
|
def set_properties_editor_tab(tab, skip_if_exists=True):
|
||||||
'''Take a tab name and apply it to properties editor
|
'''Take a tab name and apply it to properties editor
|
||||||
tab: identifier of the tab, possible name in:
|
tab: identifier of the tab, possible name in:
|
||||||
|
@ -4,7 +4,7 @@ from . import (
|
|||||||
outputs_search_and_replace,
|
outputs_search_and_replace,
|
||||||
visibility_conflicts,
|
visibility_conflicts,
|
||||||
simplify_conflicts,
|
simplify_conflicts,
|
||||||
# conform_collection_hierarchy,
|
conform_collection_hierarchy,
|
||||||
scene_checker,
|
scene_checker,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ mods = (
|
|||||||
outputs_search_and_replace,
|
outputs_search_and_replace,
|
||||||
visibility_conflicts,
|
visibility_conflicts,
|
||||||
simplify_conflicts,
|
simplify_conflicts,
|
||||||
# conform_collection_hierarchy,
|
conform_collection_hierarchy,
|
||||||
scene_checker,
|
scene_checker,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
180
operators/conform_collection_hierarchy.py
Normal file
180
operators/conform_collection_hierarchy.py
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
import bpy
|
||||||
|
from bpy.types import Operator
|
||||||
|
from bpy.props import (BoolProperty,
|
||||||
|
EnumProperty,
|
||||||
|
PointerProperty,
|
||||||
|
CollectionProperty,
|
||||||
|
StringProperty)
|
||||||
|
from .. import fn
|
||||||
|
|
||||||
|
def collection_search_callback(self, context, edit_text):
|
||||||
|
"""Search callback for collection names"""
|
||||||
|
## second arg is not displayed, can be and empty string...
|
||||||
|
return [(c.name, str(c.session_uid)) for c in bpy.context.scene.collection.children_recursive if edit_text.lower() in c.name.lower()]
|
||||||
|
|
||||||
|
class RT_OT_conform_collection_hierarchy(Operator):
|
||||||
|
bl_idname = "rt.conform_collection_hierarchy"
|
||||||
|
bl_label = "Conform Collection Hierarchy"
|
||||||
|
bl_description = "Chek and conform collection visibility hierarchy settings\
|
||||||
|
\nCan affect collection, objects or both"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
|
||||||
|
hierarchy_type: EnumProperty(
|
||||||
|
name="Hierarchy Type",
|
||||||
|
description="Choose whether to conform object hierarchy or collection hierarchy",
|
||||||
|
items=[
|
||||||
|
('COLLECTION', "Collection Hierarchy", "Conform collection hierarchy")
|
||||||
|
('OBJECT', "Object Hierarchy", "Conform object hierarchy"),
|
||||||
|
],
|
||||||
|
default='COLLECTION'
|
||||||
|
)
|
||||||
|
|
||||||
|
target_collection: StringProperty(
|
||||||
|
name="Target Collecton",
|
||||||
|
description="Collection to target", # or object name # (useful for excluded collections)
|
||||||
|
default="",
|
||||||
|
search=collection_search_callback
|
||||||
|
## basic collection fetch:
|
||||||
|
# search=lambda self, context, edit_text: [(c.name, '') for c in bpy.context.scene.collection.children_recursive if edit_text.lower() in c.name.lower()]
|
||||||
|
)
|
||||||
|
|
||||||
|
affect_target: EnumProperty(
|
||||||
|
name="Affect Target",
|
||||||
|
description="Choose whether to affect collections, objects, or both",
|
||||||
|
items=[
|
||||||
|
('COLLECTION', "Collection", "Affect collections only"),
|
||||||
|
('OBJECT', "Object", "Affect objects only"),
|
||||||
|
('BOTH', "Both", "Affect both collections and objects")
|
||||||
|
],
|
||||||
|
default='BOTH'
|
||||||
|
)
|
||||||
|
|
||||||
|
## Common object and collection
|
||||||
|
|
||||||
|
conform_selectability: BoolProperty(
|
||||||
|
name="Hide Select State",
|
||||||
|
description="Conform hide select select",
|
||||||
|
default=True
|
||||||
|
)
|
||||||
|
|
||||||
|
conform_viewlayer: BoolProperty(
|
||||||
|
name="Hide in Viewlayer State",
|
||||||
|
description="Conform viewlayer temporary hide",
|
||||||
|
default=True
|
||||||
|
)
|
||||||
|
|
||||||
|
conform_viewport: BoolProperty(
|
||||||
|
name="Disable in Viewports State",
|
||||||
|
description="Conform the monitor icon (global viewport disable)",
|
||||||
|
default=True
|
||||||
|
)
|
||||||
|
|
||||||
|
conform_render: BoolProperty(
|
||||||
|
name="Disable in Renders State",
|
||||||
|
description="Conform the camera icon (render visibility)",
|
||||||
|
default=True
|
||||||
|
)
|
||||||
|
|
||||||
|
## Specific to collections
|
||||||
|
|
||||||
|
conform_exclude: BoolProperty(
|
||||||
|
name="Exclude View Layer State",
|
||||||
|
description="Conform the exclude from view layer",
|
||||||
|
default=True
|
||||||
|
)
|
||||||
|
|
||||||
|
conform_holdout: BoolProperty(
|
||||||
|
name="Holdout State",
|
||||||
|
description="Conform Collection Holdout State",
|
||||||
|
default=True
|
||||||
|
)
|
||||||
|
|
||||||
|
conform_use_indirect: BoolProperty(
|
||||||
|
name="Indirect Only State",
|
||||||
|
description="Conform Collection Indirect Only",
|
||||||
|
default=True
|
||||||
|
)
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
return context.window_manager.invoke_props_dialog(self, width=400)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
# if self.hierarchy_type == 'COLLECTION':
|
||||||
|
layout.prop(self, "Get Collection by name")
|
||||||
|
layout.prop(self, "affect_target", text="Target Items")
|
||||||
|
|
||||||
|
# layout.prop(self, "target_name", text="Target Collection")
|
||||||
|
## Works with 'children' (root hierarchy), but not with 'children_recursive'
|
||||||
|
# layout.prop_search(self, "target_name", bpy.context.scene.collection, "children", text="Target Collection")
|
||||||
|
|
||||||
|
target_collection = None
|
||||||
|
if not self.target_collection:
|
||||||
|
target_collection = context.collection
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.target_collection:
|
||||||
|
layout.label(text="Select a collection or search by name", icon='INFO')
|
||||||
|
return
|
||||||
|
|
||||||
|
root_col = next((c for c in context.scene.collection.children_recursive if c.name == target_collection), None)
|
||||||
|
|
||||||
|
if not root_col:
|
||||||
|
layout.label(text=f"Error: Collection '{target_collection}' not found", icon='ERROR')
|
||||||
|
return
|
||||||
|
|
||||||
|
vlc_root = fn.get_view_layer_collection(root_col)
|
||||||
|
if not vlc_root:
|
||||||
|
layout.label(text=f"Error: Viewlayer Collection '{target_collection}' not found", icon='ERROR')
|
||||||
|
return
|
||||||
|
|
||||||
|
## TODO: Show current state of the selected root collection
|
||||||
|
col = layout.column(align=True)
|
||||||
|
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.prop(vlc_root, "exclude", text="", emboss=False)
|
||||||
|
row.prop(root_col, "hide_select", text="", emboss=False)
|
||||||
|
row.prop(vlc_root, "hide_viewport", text="", emboss=False)
|
||||||
|
row.prop(root_col, "hide_viewport", text="", emboss=False)
|
||||||
|
row.prop(root_col, "hide_render", text="", emboss=False)
|
||||||
|
row.prop(vlc_root, "holdout", text="", emboss=False)
|
||||||
|
row.prop(vlc_root, "indirect_only", text="", emboss=False)
|
||||||
|
|
||||||
|
col = layout.column(align=True)
|
||||||
|
col.label(text="Parameter To Conform:")
|
||||||
|
row = col.row(align=True)
|
||||||
|
## Same order, greyout unused options
|
||||||
|
collec_row = row.row(align=True)
|
||||||
|
collec_row.prop(self, "conform_exclude", text="", icon='CHECKBOX_HLT') # Exclude from View Layer
|
||||||
|
collec_row.active = self.affect_target != 'OBJECT'
|
||||||
|
|
||||||
|
## Object and collections
|
||||||
|
row.prop(self, "conform_selectability", text="", icon='RESTRICT_SELECT_OFF') # Hide Select
|
||||||
|
row.prop(self, "conform_viewlayer", text="", icon='HIDE_OFF') # Hide in current viewlayer (eye)
|
||||||
|
row.prop(self, "conform_viewport", text="", icon='RESTRICT_VIEW_OFF') # Disable in Viewports
|
||||||
|
row.prop(self, "conform_render", text="", icon='RESTRICT_RENDER_OFF') # Disable in Renders
|
||||||
|
|
||||||
|
## Specific to collections
|
||||||
|
collec_row = row.row(align=True)
|
||||||
|
collec_row.prop(self, "conform_holdout", text="", icon='HOLDOUT_OFF') # Holdout
|
||||||
|
collec_row.prop(self, "conform_use_indirect", text="", icon='INDIRECT_ONLY_OFF') # Indirect Only
|
||||||
|
collec_row.active = self.affect_target != 'OBJECT'
|
||||||
|
|
||||||
|
## TODO: Show live wich object / collection are affected by the conformation action when executed.
|
||||||
|
|
||||||
|
sub_vlc = fn.get_collection_children_recursive(vlc_root)
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
|
||||||
|
def register():
|
||||||
|
bpy.utils.register_class(RT_OT_conform_collection_hierarchy)
|
||||||
|
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
bpy.utils.unregister_class(RT_OT_conform_collection_hierarchy)
|
55
ui.py
55
ui.py
@ -50,37 +50,50 @@ class RT_PT_visibility_check_ui_node(RT_PT_visibility_check_ui_base):
|
|||||||
bl_region_type = 'UI'
|
bl_region_type = 'UI'
|
||||||
bl_category = "Render" # Wrangler ?
|
bl_category = "Render" # Wrangler ?
|
||||||
|
|
||||||
## Unused, only exposed in Create output panel
|
class RT_PT_conformation_ui(bpy.types.Panel):
|
||||||
class RT_PT_output_template(Panel):
|
bl_space_type = "VIEW_3D"
|
||||||
bl_space_type = "3D_VIEW"
|
|
||||||
bl_region_type = "UI"
|
bl_region_type = "UI"
|
||||||
bl_category = "Render" # Wrangler
|
bl_category = "View"
|
||||||
bl_label = "File Output Templates"
|
bl_label = "Conformation"
|
||||||
bl_parent_id = "RT_PT_render_toolbox_ui"
|
bl_options = {'DEFAULT_CLOSED'}
|
||||||
# bl_options = {'DEFAULT_CLOSED'}
|
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
settings = context.scene.render_toolbox
|
layout.operator("rt.conform_collection_hierarchy",
|
||||||
|
text="Conform Collection Hierarchy", icon="OUTLINER_COLLECTION")
|
||||||
col = layout.column(align=True)
|
|
||||||
col.label(text='Single file:')
|
|
||||||
col.prop(settings, "default_base_path", text="Base Path")
|
|
||||||
col.prop(settings, "default_file_slot", text="File Slot")
|
|
||||||
|
|
||||||
col.separator()
|
|
||||||
col = layout.column(align=True)
|
|
||||||
col.label(text='Multilayers:')
|
|
||||||
col.prop(settings, "default_multilayer_base_path", text="Base Path")
|
|
||||||
col.prop(settings, "default_multilayer_name", text="Layer Name")
|
|
||||||
|
|
||||||
## Handle separate tech passes names ?
|
## Unused, only exposed in Create output panel
|
||||||
|
# class RT_PT_output_template(Panel):
|
||||||
|
# bl_space_type = "3D_VIEW"
|
||||||
|
# bl_region_type = "UI"
|
||||||
|
# bl_category = "Render" # Wrangler
|
||||||
|
# bl_label = "File Output Templates"
|
||||||
|
# bl_parent_id = "RT_PT_render_toolbox_ui"
|
||||||
|
# # bl_options = {'DEFAULT_CLOSED'}
|
||||||
|
|
||||||
|
# def draw(self, context):
|
||||||
|
# layout = self.layout
|
||||||
|
# settings = context.scene.render_toolbox
|
||||||
|
|
||||||
|
# col = layout.column(align=True)
|
||||||
|
# col.label(text='Single file:')
|
||||||
|
# col.prop(settings, "default_base_path", text="Base Path")
|
||||||
|
# col.prop(settings, "default_file_slot", text="File Slot")
|
||||||
|
|
||||||
|
# col.separator()
|
||||||
|
# col = layout.column(align=True)
|
||||||
|
# col.label(text='Multilayers:')
|
||||||
|
# col.prop(settings, "default_multilayer_base_path", text="Base Path")
|
||||||
|
# col.prop(settings, "default_multilayer_name", text="Layer Name")
|
||||||
|
|
||||||
|
# ## Handle separate tech passes names ?
|
||||||
|
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
RT_PT_render_toolbox_ui,
|
RT_PT_render_toolbox_ui,
|
||||||
RT_PT_visibility_check_ui_viewport,
|
RT_PT_visibility_check_ui_viewport,
|
||||||
RT_PT_visibility_check_ui_node
|
RT_PT_visibility_check_ui_node,
|
||||||
|
RT_PT_conformation_ui,
|
||||||
# RT_PT_output_template,
|
# RT_PT_output_template,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user