exclude layer buttons
1.3.5 - added: button to exclude viewlayers and nodes by selection or by hided layersmain
parent
bc5a046bec
commit
352027ad8c
|
@ -14,6 +14,10 @@ Activate / deactivate layer opacity according to prefix
|
|||
Activate / deactivate all masks using MA layers
|
||||
-->
|
||||
|
||||
1.3.5
|
||||
|
||||
- added: button to exclude viewlayers and nodes by selection or by hided layers
|
||||
|
||||
1.3.4
|
||||
|
||||
- added: multi object merge
|
||||
|
|
|
@ -26,7 +26,8 @@ class GPEXP_OT_mute_toggle_output_nodes(bpy.types.Operator):
|
|||
class GPEXP_OT_number_outputs(bpy.types.Operator):
|
||||
bl_idname = "gp.number_outputs"
|
||||
bl_label = "Number Outputs"
|
||||
bl_description = "(Re)Number the outputs to have ordered file by name in export directories\nCtrl+Clic : Delete numbering"
|
||||
bl_description = "(Re)Number the outputs to have ordered file by name in export directories\
|
||||
\nCtrl+Clic : Delete numbering"
|
||||
bl_options = {"REGISTER"}
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -274,6 +274,85 @@ class GPEXP_OT_merge_viewlayers_to_active(bpy.types.Operator):
|
|||
self.report(*ret)
|
||||
return {"FINISHED"}
|
||||
|
||||
class GPEXP_OT_remove_viewlayer_on_selected(bpy.types.Operator):
|
||||
bl_idname = "gp.remove_viewlayer_on_selected"
|
||||
bl_label = "Exclude Viewlayer"
|
||||
bl_description = "Set exclude view layers on selected gp layers\
|
||||
\nRemove associated nodes in Render scene nodetree\
|
||||
\nCtrl + Click : Affect selected GP objects, not only active"
|
||||
bl_options = {"REGISTER"}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.object and context.object.type == 'GPENCIL'
|
||||
|
||||
# multi_object : bpy.props.BoolProperty(default=True, options={'SKIP_SAVE'})
|
||||
remove_all_hidden : bpy.props.BoolProperty(default=False, options={'SKIP_SAVE'})
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, properties) -> str:
|
||||
if properties.remove_all_hidden:
|
||||
return "Set HIDDEN gp layers to 'exclude' viewlayers\
|
||||
\nremoving associated nodes in Render scene nodetree\
|
||||
\nCtrl + Click : Affect selected GP objects, else only active"
|
||||
else:
|
||||
return "Set SELECTED gp layers to 'exclude' viewlayers\
|
||||
\nremoving associated nodes in Render scene nodetree\
|
||||
\nCtrl + Click : Affect selected GP objects, else only active"
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.multi_object = event.ctrl
|
||||
return self.execute(context)
|
||||
|
||||
def execute(self, context):
|
||||
ob = context.object
|
||||
|
||||
## Force use of render scene (?)
|
||||
rd_scn = bpy.data.scenes.get('Render')
|
||||
if not rd_scn:
|
||||
self.report({'ERROR'}, 'No render scene found')
|
||||
return {'CANCELLED'}
|
||||
|
||||
if self.remove_all_hidden:
|
||||
if self.multi_object:
|
||||
layers = [l for ob in context.selected_objects if ob.type == 'GPENCIL' for l in ob.data.layers if l.hide]
|
||||
else:
|
||||
layers = [l for l in ob.data.layers if l.select]
|
||||
|
||||
else:
|
||||
if self.multi_object:
|
||||
layers = [l for ob in context.selected_objects if ob.type == 'GPENCIL' for l in ob.data.layers if l.select]
|
||||
else:
|
||||
layers = [l for l in ob.data.layers if l.select]
|
||||
|
||||
if not layers:
|
||||
self.report({'ERROR'}, 'Some layers need to be selected to exclude render viewlayer')
|
||||
return {'CANCELLED'}
|
||||
|
||||
layers = list(set(layers))
|
||||
|
||||
## Prepare report / prints in console
|
||||
exclude_message = ['Layer list set to exclude:']
|
||||
print('\nLayer list to exclude:')
|
||||
for l in layers:
|
||||
vl_name = l.viewlayer_render if l.viewlayer_render else 'None'
|
||||
mess = f'{l.id_data.name}: {l.info} (previous: {vl_name})'
|
||||
print(mess)
|
||||
exclude_message.append(mess)
|
||||
|
||||
view_layers = [rd_scn.view_layers.get(l.viewlayer_render) for l in layers\
|
||||
if l.viewlayer_render and rd_scn.view_layers.get(l.viewlayer_render)]
|
||||
|
||||
## remove nodes associated with those viewlayers
|
||||
fn.remove_nodes_by_viewlayer(view_layers, scene=rd_scn)
|
||||
|
||||
## Set selected those layer viewlayer exclude
|
||||
for l in layers:
|
||||
l.viewlayer_render = fn.get_view_layer('exclude').name
|
||||
|
||||
fn.show_message_box(exclude_message)
|
||||
return {"FINISHED"}
|
||||
|
||||
class GPEXP_OT_merge_preview_ouput(bpy.types.Operator):
|
||||
bl_idname = "gp.merge_preview_ouput"
|
||||
bl_label = "Merge Preview Output"
|
||||
|
@ -429,6 +508,7 @@ GPEXP_OT_merge_viewlayers_to_active,
|
|||
GPEXP_OT_auto_merge_adjacent_prefix,
|
||||
GPEXP_OT_merge_selected_dopesheet_layers,# unused
|
||||
GPEXP_OT_merge_selected_viewlayer_nodes,
|
||||
GPEXP_OT_remove_viewlayer_on_selected,
|
||||
GPEXP_OT_merge_preview_ouput,
|
||||
)
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ bl_info = {
|
|||
"name": "GP Render",
|
||||
"description": "Organise export of gp layers through compositor output",
|
||||
"author": "Samuel Bernou",
|
||||
"version": (1, 3, 4),
|
||||
"version": (1, 3, 5),
|
||||
"blender": (2, 93, 0),
|
||||
"location": "View3D",
|
||||
"warning": "",
|
||||
|
|
Binary file not shown.
73
fn.py
73
fn.py
|
@ -410,32 +410,18 @@ def get_frames_bbox(node_tree):
|
|||
|
||||
return frames_bbox
|
||||
|
||||
|
||||
## -- nodes helper functions
|
||||
|
||||
def merge_gplayer_viewlayers(ob=None, act=None, layers=None):
|
||||
'''ob is not needed if active and layers are passed'''
|
||||
if ob is None:
|
||||
ob = bpy.context.object
|
||||
if act is None:
|
||||
act = ob.data.layers.active
|
||||
if layers is None:
|
||||
layers = [l for l in ob.data.layers if l.select and l != act]
|
||||
def remove_nodes_by_viewlayer(viewlayer_list, scene=None):
|
||||
'''Take a list of viewlayer and optionaly a scene to target nodetree
|
||||
remove nodes related to this viewlayer in nodetree
|
||||
'''
|
||||
|
||||
rd_scn = bpy.data.scenes.get('Render')
|
||||
if not rd_scn:
|
||||
return ({'ERROR'}, 'Viewlayers needs to be generated first!')
|
||||
scene = scene or bpy.context.scene
|
||||
|
||||
if not act.viewlayer_render:
|
||||
return ({'ERROR'}, f'Active layer {act.info} has no viewlayer assigned')
|
||||
vl_names = [v.name for v in viewlayer_list]
|
||||
|
||||
# list layers and viewlayers
|
||||
vls = [rd_scn.view_layers.get(l.viewlayer_render) for l in layers
|
||||
if l.viewlayer_render and l.viewlayer_render != act.viewlayer_render and rd_scn.view_layers.get(l.viewlayer_render)]
|
||||
|
||||
vl_names = [v.name for v in vls]
|
||||
|
||||
for n in reversed(rd_scn.node_tree.nodes):
|
||||
for n in reversed(scene.node_tree.nodes):
|
||||
if n.type == 'R_LAYERS' and n.layer in vl_names:
|
||||
for lnk in n.outputs[0].links:
|
||||
grp = lnk.to_node
|
||||
|
@ -468,20 +454,49 @@ def merge_gplayer_viewlayers(ob=None, act=None, layers=None):
|
|||
ngroup.outputs.remove(ngroup.outputs[i])
|
||||
break
|
||||
|
||||
# remove render_layer node
|
||||
rd_scn.node_tree.nodes.remove(n)
|
||||
# Remove render_layer node
|
||||
scene.node_tree.nodes.remove(n)
|
||||
|
||||
# assign view layer from active to selected
|
||||
def merge_gplayer_viewlayers(ob=None, act=None, layers=None):
|
||||
'''ob is not needed if active and layers are passed'''
|
||||
if ob is None:
|
||||
ob = bpy.context.object
|
||||
if act is None:
|
||||
act = ob.data.layers.active
|
||||
if layers is None:
|
||||
layers = [l for l in ob.data.layers if l.select and l != act]
|
||||
|
||||
if act is None:
|
||||
return ({'ERROR'}, 'Active layer not found. Should be active layer on active object!')
|
||||
|
||||
rd_scn = bpy.data.scenes.get('Render')
|
||||
if not rd_scn:
|
||||
return ({'ERROR'}, 'Viewlayers needs to be generated first!')
|
||||
|
||||
if not act.viewlayer_render:
|
||||
return ({'ERROR'}, f'Active layer {act.info} has no viewlayer assigned')
|
||||
|
||||
# list layers and viewlayers
|
||||
vls = [rd_scn.view_layers.get(l.viewlayer_render) for l in layers
|
||||
if l.viewlayer_render and l.viewlayer_render != act.viewlayer_render and rd_scn.view_layers.get(l.viewlayer_render)]
|
||||
|
||||
# Remove viewlayer related nodes
|
||||
remove_nodes_by_viewlayer(vls, rd_scn)
|
||||
|
||||
# Assign view layer from active to selected
|
||||
for l in layers:
|
||||
l.viewlayer_render = act.viewlayer_render
|
||||
|
||||
## delete unused_vl
|
||||
## Delete unused viewlayers ()
|
||||
|
||||
# used_vl_name = [n.layer for n in rd_scn.node_tree.nodes if n.type == 'R_LAYERS' and n.layer]
|
||||
used_vl_name = [n.layer for n in rd_scn.node_tree.nodes if n.type == 'R_LAYERS' and n.layer]
|
||||
for vl in vls:
|
||||
rd_scn.view_layers.remove(vl)
|
||||
# if not vl.name in used_vl_name:
|
||||
# rd_scn.view_layers.remove(vl)
|
||||
# rd_scn.view_layers.remove(vl)
|
||||
if vl.name == 'exclude':
|
||||
# keep exclude
|
||||
continue
|
||||
if not vl.name in used_vl_name:
|
||||
rd_scn.view_layers.remove(vl)
|
||||
|
||||
def group_adjacent_layer_prefix_rlayer(ob, excluded_prefix=[], first_name=True):
|
||||
'''Set viewlayer and renderlayers by Gp layer adjacent prefix
|
||||
|
|
3
ui.py
3
ui.py
|
@ -213,6 +213,9 @@ class GPEXP_PT_gp_dopesheet_ui(Panel):
|
|||
row.enabled= ct > 1
|
||||
|
||||
col.operator('gpexp.auto_merge_adjacent_prefix', icon='SELECT_EXTEND')
|
||||
row = col.row(align=True)
|
||||
row.operator('gp.remove_viewlayer_on_selected', text=f'Exclude {ct} layers', icon='X').remove_all_hidden = False
|
||||
row.operator('gp.remove_viewlayer_on_selected', text='', icon='HIDE_ON').remove_all_hidden = True
|
||||
|
||||
## all and objects
|
||||
layout.separator()
|
||||
|
|
Loading…
Reference in New Issue