393 lines
16 KiB
Python
Executable File
393 lines
16 KiB
Python
Executable File
import bpy
|
|
|
|
from bpy.types import Panel
|
|
from . import fn
|
|
|
|
|
|
# region viewlayer layout
|
|
|
|
def viewlayer_layout(layout, scn):
|
|
for vl in scn.view_layers:
|
|
row = layout.row()
|
|
row.prop(vl, 'use', text=vl.name, icon='RESTRICT_RENDER_OFF' if vl.use else 'RESTRICT_RENDER_ON', emboss=False, toggle=0)
|
|
|
|
class RT_PT_viewlayers_ui(Panel):
|
|
bl_space_type = "NODE_EDITOR"
|
|
bl_region_type = "UI"
|
|
bl_label = "View Layers"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.label(text=f'{context.scene.name} :: View layers')
|
|
col = layout.column(align=True)
|
|
viewlayer_layout(col, context.scene)
|
|
|
|
class RT_PT_viewlayers_multi_ui(Panel):
|
|
bl_space_type = "NODE_EDITOR"
|
|
bl_region_type = "UI"
|
|
bl_label = "Multi View Layers"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.label(text=f'{len(bpy.data.scenes)} scenes view layers:')
|
|
for s in bpy.data.scenes:
|
|
col = layout.column()
|
|
# col.label(text=f'{s.name}:')
|
|
col.label(text=s.name)
|
|
viewlayer_layout(col, s)
|
|
layout.separator()
|
|
|
|
# region main panel
|
|
|
|
class RT_PT_render_toolbox_ui(Panel):
|
|
bl_space_type = "NODE_EDITOR"
|
|
bl_region_type = "UI"
|
|
bl_category = "Render" # Wrangler
|
|
bl_label = "Render Toolbox"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
## Scene infos recap
|
|
scn = context.scene
|
|
text = f'{scn.render.resolution_x}x{scn.render.resolution_y} @ {scn.render.fps} fps'
|
|
cam = context.scene.camera
|
|
if cam:
|
|
|
|
text = f'{cam.name} : {text}'
|
|
else:
|
|
text = f'No Camera ! : {text}'
|
|
|
|
box = layout.box()
|
|
col = box.column()
|
|
col.label(text=text, icon='SCENE_DATA') # VIEW_CAMERA
|
|
# col.label(text=f"{scn.render.fps} fps")
|
|
|
|
if scn.render.resolution_percentage != 100:
|
|
col.label(text='Percentage not 100%', icon='INFO')
|
|
col.prop(scn.render, 'resolution_percentage', text="Resolution Percentage")
|
|
percent = scn.render.resolution_percentage
|
|
col.label(text=f"{int(scn.render.resolution_x * percent / 100)}x{int(scn.render.resolution_y * percent / 100)}", icon='INFO')
|
|
if cam and cam.data.shift_x != 0 or cam.data.shift_y != 0:
|
|
col.label(text='Camera has Shift', icon='INFO')
|
|
# col.prop(cam.data, 'shift_x', text="Shift X")
|
|
# col.prop(cam.data, 'shift_y', text="Shift Y")
|
|
|
|
## viewlayer section
|
|
layout.label(text='View layers:')
|
|
ct = len([n for n in context.scene.node_tree.nodes if n.type == 'R_LAYERS' and n.select])
|
|
|
|
# col = layout.column(align=True)
|
|
# row=col.row(align=True)
|
|
col = layout.column(align=False)
|
|
row = col.row(align=True)
|
|
row.operator("wm.call_panel", text="View layers", icon='RENDERLAYERS').name = "RT_PT_viewlayers_ui"
|
|
row.operator("wm.call_panel", text="All View layers", icon='SCENE_DATA').name = "RT_PT_viewlayers_multi_ui"
|
|
|
|
# row=layout.row(align=True)
|
|
|
|
row1 = col.row(align=True)
|
|
row1.operator('rt.activate_only_selected_layers', text=f'Activate Only {ct} RenderLayer Nodes')
|
|
row1.enabled = ct > 0
|
|
|
|
exclude_count = len([vl for vl in scn.view_layers if not vl.use and vl.name not in {'exclude',}]) # 'View Layer',
|
|
if exclude_count:
|
|
# layout.label(text=f'{exclude_count} Excluded View Layers !')
|
|
layout.operator('rt.enable_all_viewlayers', text=f'Reactivate {exclude_count} Excluded View Layers')
|
|
|
|
# col = layout.column()
|
|
# col.label(text='Clean and updates:')
|
|
# col.operator('rt.clean_compo_tree', icon='BRUSHES_ALL', text='Clean Nodes') # NODE_CORNER
|
|
|
|
# region file output ui
|
|
class RT_PT_file_output_ui(bpy.types.Panel):
|
|
bl_space_type = "NODE_EDITOR"
|
|
bl_region_type = "UI"
|
|
bl_category = "Render"
|
|
bl_label = "File Output Manager"
|
|
# bl_parent_id = "RT_PT_render_toolbox_ui"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
col = layout.column()
|
|
col.operator("rt.create_output_layers", text='Create File Output', icon="NODE")
|
|
col.operator("rt.outputs_search_and_replace", text='Search And Replace Outputs', icon="BORDERMOVE")
|
|
|
|
col.separator()
|
|
col.operator('rt.set_output_node_format', icon='OUTPUT', text='Copy Output Format To Selected')
|
|
col.operator('rt.set_active_file_output_slot_to_composite', icon='OUTPUT', text='Active Slot To Composite')
|
|
|
|
layout.label(text='All Outputs:')
|
|
|
|
row=layout.row(align=True)
|
|
row.operator('rt.mute_toggle_output_nodes', icon='NODE_INSERT_ON', text='Mute').mute = True
|
|
row.operator('rt.mute_toggle_output_nodes', icon='NODE_INSERT_OFF', text='Unmute').mute = False
|
|
|
|
scn = context.scene
|
|
|
|
disabled_output = [n for n in scn.node_tree.nodes if n.type == 'OUTPUT_FILE' and n.mute]
|
|
if disabled_output:
|
|
output_ct = len([n for n in scn.node_tree.nodes if n.type == 'OUTPUT_FILE'])
|
|
layout.label(text=f'{len(disabled_output)}/{output_ct} Output Muted', icon='INFO')
|
|
|
|
col = layout.column()
|
|
|
|
## (re)number exports
|
|
ct = len([n for n in context.scene.node_tree.nodes if n.type == 'OUTPUT_FILE' and n.select])
|
|
txt = f'Renumber {ct} Selected Outputs'
|
|
subcol = col.column()
|
|
subcol.enabled = bool(ct)
|
|
|
|
row = subcol.row(align=True)
|
|
row.operator('rt.number_outputs', icon='LINENUMBERS_ON', text=txt).mode = 'SELECTED'
|
|
op = row.operator('rt.number_outputs', icon='X', text='')
|
|
op.mode = 'SELECTED'
|
|
op.clear = True
|
|
|
|
|
|
|
|
# region visibility ui
|
|
|
|
# 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 = "View"
|
|
bl_label = "Visibility Checks"
|
|
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
|
|
|
|
col = layout.column(align=True)
|
|
col .label(text="List Visibility Conflicts:") # , icon='HIDE_OFF'
|
|
row = col.row(align=True)
|
|
row.operator("rt.list_object_visibility_conflicts", text="Objects", icon="OBJECT_DATAMODE")
|
|
row.operator("rt.list_viewport_render_visibility", text="Viewport Vs Render") # , icon="OBJECT_DATAMODE"
|
|
col.operator("rt.list_modifier_visibility", text="Modifiers", icon="MODIFIER")
|
|
col.operator("rt.list_collection_visibility_conflicts", text="Collections", 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 ?
|
|
|
|
# region conformation ui
|
|
|
|
class RT_PT_conformation_ui(bpy.types.Panel):
|
|
bl_space_type = "VIEW_3D"
|
|
bl_region_type = "UI"
|
|
bl_category = "View"
|
|
bl_label = "Conformation"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
## Show properties for outliner conformation
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
# props = context.scene.render_toolbox_conform
|
|
props = context.view_layer.render_toolbox_conform
|
|
|
|
col = layout.column(align=True)
|
|
col.prop(props, "hierarchy_type", text="Work On") # , expand=True
|
|
# col.separator()
|
|
col.prop(props, "target_name", text="Search") # (Optional)
|
|
|
|
## Show current target
|
|
box = layout.box()
|
|
tgt_row = box.row()
|
|
|
|
if props.hierarchy_type == 'COLLECTION':
|
|
ref_collection = fn.get_target_collection(props.target_name, context)
|
|
if not ref_collection or ref_collection == context.scene.collection:
|
|
layout.label(text="Select a collection or search by name", icon='INFO')
|
|
if ref_collection == context.scene.collection:
|
|
layout.label(text="Cannot use the scene collection", icon='ERROR')
|
|
layout.label(text="An excluded collection collection cannot be active (use search)")
|
|
return
|
|
|
|
if not ref_collection:
|
|
layout.label(text=f"Error: Collection '{ref_collection.name}' not found", icon='ERROR')
|
|
return
|
|
|
|
ref_vlc = fn.get_view_layer_collection(ref_collection)
|
|
if not ref_vlc:
|
|
layout.label(text=f"Error: Viewlayer Collection '{ref_collection.name}' not found", icon='ERROR')
|
|
return
|
|
|
|
# tgt_row = layout.row(align=True)
|
|
# tgt_row.label(text="", icon='TRIA_RIGHT')
|
|
tgt_row.label(text=ref_collection.name, icon='OUTLINER_COLLECTION')
|
|
|
|
col = layout.column(align=False)
|
|
col.operator("rt.store_visibility_states", text='Store Target Hierarchy State', icon="DISK_DRIVE")
|
|
|
|
## Show current collection state (behave badly when changed, should be tweaked before)
|
|
# col = layout.column(align=True)
|
|
row = tgt_row.row(align=True)
|
|
row.prop(ref_vlc, "exclude", text="", emboss=False)
|
|
row.prop(ref_collection, "hide_select", text="", emboss=False)
|
|
row.prop(ref_vlc, "hide_viewport", text="", emboss=False)
|
|
row.prop(ref_collection, "hide_viewport", text="", emboss=False)
|
|
row.prop(ref_collection, "hide_render", text="", emboss=False)
|
|
row.prop(ref_vlc, "holdout", text="", emboss=False)
|
|
row.prop(ref_vlc, "indirect_only", text="", emboss=False)
|
|
|
|
layout.prop(props, "affect_target", text="Target Items")
|
|
layout.separator()
|
|
|
|
col = layout.column(align=True)
|
|
row = col.row(align=True)
|
|
row.label(text="To Conform:")
|
|
## Same order, greyout unused options
|
|
collec_row = row.row(align=True)
|
|
collec_row.prop(props, "conform_exclude", text="", icon='CHECKBOX_DEHLT' if ref_vlc.exclude else 'CHECKBOX_HLT') # Exclude from View Layer
|
|
collec_row.active = props.affect_target != 'OBJECT'
|
|
|
|
## Object and collections
|
|
row.prop(props, "conform_selectability", text="", icon='RESTRICT_SELECT_ON' if ref_collection.hide_select else 'RESTRICT_SELECT_OFF') # Hide Select
|
|
row.prop(props, "conform_viewlayer", text="", icon='HIDE_ON' if ref_vlc.hide_viewport else 'HIDE_OFF') # Hide in current viewlayer (eye)
|
|
row.prop(props, "conform_viewport", text="", icon='RESTRICT_VIEW_ON' if ref_collection.hide_viewport else 'RESTRICT_VIEW_OFF') # Disable in Viewports
|
|
row.prop(props, "conform_render", text="", icon='RESTRICT_RENDER_ON' if ref_collection.hide_render else 'RESTRICT_RENDER_OFF') # Disable in Renders
|
|
|
|
## Specific to collections
|
|
collec_row = row.row(align=True)
|
|
collec_row.prop(props, "conform_holdout", text="", icon='HOLDOUT_OFF') # Holdout
|
|
collec_row.prop(props, "conform_use_indirect", text="", icon='INDIRECT_ONLY_OFF') # Indirect Only
|
|
collec_row.active = props.affect_target != 'OBJECT'
|
|
|
|
else:
|
|
ref_obj = fn.get_target_object(props.target_name, context)
|
|
|
|
if not ref_obj:
|
|
layout.label(text="Make object active or search by name", icon='INFO')
|
|
return
|
|
|
|
# tgt_row = layout.row(align=True)
|
|
# tgt_row.label(text="", icon='TRIA_RIGHT')
|
|
tgt_row.label(text=ref_obj.name, icon='OBJECT_DATA')
|
|
|
|
if not ref_obj.children_recursive:
|
|
tgt_row.label(text="No Children", icon='ERROR')
|
|
return
|
|
|
|
layout.separator()
|
|
## Show current collection state (can behave badly when changed, should be tweaked before)
|
|
# col = layout.column(align=True)
|
|
row = tgt_row.row(align=True)
|
|
# row.label(text="Reference Object State:")
|
|
row.prop(ref_obj, "hide_select", text="", emboss=False)
|
|
# row.prop(props, "active_object_viewlayer_hide", text="", icon='HIDE_ON' if ref_obj.hide_get() else 'HIDE_OFF', emboss=False) # hack
|
|
row.label(text="", icon='HIDE_ON' if ref_obj.hide_get() else 'HIDE_OFF') # hack
|
|
row.prop(ref_obj, "hide_viewport", text="", emboss=False)
|
|
row.prop(ref_obj, "hide_render", text="", emboss=False)
|
|
|
|
layout.separator()
|
|
col = layout.column(align=True)
|
|
row = col.row(align=True)
|
|
row.label(text="To Conform:")
|
|
row.prop(props, "conform_selectability", text="", icon='RESTRICT_SELECT_ON' if ref_obj.hide_select else 'RESTRICT_SELECT_OFF') # Hide Select
|
|
row.prop(props, "conform_viewlayer", text="", icon='HIDE_ON' if ref_obj.hide_get() else 'HIDE_OFF') # Hide in current viewlayer (eye)
|
|
row.prop(props, "conform_viewport", text="", icon='RESTRICT_VIEW_ON' if ref_obj.hide_viewport else 'RESTRICT_VIEW_OFF') # Disable in Viewports
|
|
row.prop(props, "conform_render", text="", icon='RESTRICT_RENDER_ON' if ref_obj.hide_render else 'RESTRICT_RENDER_OFF') # Disable in Renders
|
|
|
|
|
|
layout.operator("rt.conform_collection_hierarchy",text="Conform Hierarchy", icon="CHECKMARK")
|
|
|
|
|
|
# region outliner state
|
|
|
|
class RT_PT_outliner_state_ui(bpy.types.Panel):
|
|
bl_space_type = "VIEW_3D"
|
|
bl_region_type = "UI"
|
|
bl_category = "View"
|
|
bl_label = "Outliner State"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
bl_parent_id = "RT_PT_conformation_ui"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
## Outliner state
|
|
|
|
## Scene
|
|
col = layout.column()
|
|
col.operator("rt.store_visibility_states", text='Store Whole Viewlayer State', icon="DISK_DRIVE").collection_name = "ALL-SCENE-COLLECTION"
|
|
stored_keys = context.scene.get('outliner_state', {}).keys()
|
|
if stored_keys and 'ALL' in stored_keys:
|
|
row = col.row(align=True)
|
|
row.operator("rt.apply_visibility_states", text=f"Restore Viewlayer State", icon="OUTLINER").collection_name = "ALL-SCENE-COLLECTION"
|
|
row.operator("rt.delete_visibility_states", text="", icon="TRASH").collection_name = 'ALL'
|
|
|
|
col = layout.column()
|
|
## Specific collection
|
|
if stored_keys:
|
|
col.label(text="Collections State:")
|
|
for key in stored_keys:
|
|
if key == 'ALL':
|
|
continue
|
|
row = col.row(align=True)
|
|
row.operator("rt.apply_visibility_states", text=f"Restore: {key}", icon="OUTLINER").collection_name = key
|
|
row.operator("rt.delete_visibility_states", text="", icon="TRASH").collection_name = key
|
|
|
|
## 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 = (
|
|
RT_PT_viewlayers_ui,
|
|
RT_PT_viewlayers_multi_ui,
|
|
RT_PT_render_toolbox_ui,
|
|
RT_PT_file_output_ui,
|
|
RT_PT_visibility_check_ui_viewport,
|
|
RT_PT_visibility_check_ui_node,
|
|
RT_PT_conformation_ui,
|
|
RT_PT_outliner_state_ui,
|
|
# RT_PT_output_template,
|
|
)
|
|
|
|
def register():
|
|
for cls in classes:
|
|
bpy.utils.register_class(cls)
|
|
|
|
def unregister():
|
|
for cls in reversed(classes):
|
|
bpy.utils.unregister_class(cls) |