viewlayer management and fixes

0.3.7

- fix: set render scene res at 100% at creation
- fix: exclude VL assignation
- feat: delete a render_layer (and add concerned gp layers to exclude)
- feat: reactivate all viewlayers
- feat: activate only selected viewlayer for fast re-render
- ui: rearrange + new buttons
main
Pullusb 2021-09-23 19:14:48 +02:00
parent e7621be9a8
commit a0a1647bf9
7 changed files with 194 additions and 18 deletions

View File

@ -14,23 +14,32 @@ Activate / deactivate layer opaticty according to prefix
Activate / deactivate all masks using MA layers
-->
0.3.7
- fix: set render scene res at 100% at creation
- fix: exclude VL assignation
- feat: delete a render_layer (and add concerned gp layers to exclude)
- feat: reactivate all viewlayers
- feat: activate only selected viewlayer for fast re-render
- ui: rearrange + new buttons
0.3.6
change: output settings switch from PNG to EXR
fix: set render scene output (preview) to jpeg fast to write
fix: correct copy output format ops
- change: output settings switch from PNG to EXR
- fix: set render scene output (preview) to jpeg fast to write
- fix: correct copy output format ops
0.3.5:
feat: set full opacity -> skip chosen prefix (MA by default)
- feat: set full opacity -> skip chosen prefix (MA by default)
0.3.4:
feat: swap cams button, code copied from `bg_plane_manager`
- feat: swap cams button, code copied from `bg_plane_manager`
0.3.3:
fix: norm name : lowercase first (else bad naming break prefix)
- fix: norm name : lowercase first (else bad naming break prefix)
0.3.2

View File

@ -26,8 +26,8 @@ class GPEXP_OT_add_layer_to_render(bpy.types.Operator):
for l in ob.data.layers:
if not l.select:
if not l.viewlayer_render:
# TODO : need to link, can reaise error if object is not linked in Render scene yet
l.viewlayer_render == fn.get_view_layer('exclude').name
# TODO : need to link, can raise error if object is not linked in Render scene yet
l.viewlayer_render = fn.get_view_layer('exclude').name
continue
gen_vlayer.get_set_viewlayer_from_gp(ob, l)

View File

@ -56,8 +56,88 @@ class GPEXP_OT_reconnect_render_layer(bpy.types.Operator):
return {"FINISHED"}
class GPEXP_OT_delete_render_layer(bpy.types.Operator):
bl_idname = "gp.delete_render_layer"
bl_label = "Delete Render Layer"
bl_description = "Delete selected render layers"
bl_options = {"REGISTER"}
@classmethod
def poll(cls, context):
return True
# mode : bpy.props.StringProperty(default='NORMAL', options={'SKIP_SAVE'})
def execute(self, context):
rd_scn = bpy.data.scenes.get('Render')
if not rd_scn:
self.report({'ERROR'}, 'Viewlayers needs to be generated first!')
return {'CANCELLED'}
nodes = rd_scn.node_tree.nodes
# 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)]
rlayers_nodes = [n for n in nodes if n.select and n.type == 'R_LAYERS']
vls = [rd_scn.view_layers.get(n.layer) for n in rlayers_nodes if rd_scn.view_layers.get(n.layer)]
vl_names = [v.name for v in vls]
## disable layers using those VL
for ob in [o for o in rd_scn.objects if o.type == 'GPENCIL']:
for l in ob.data.layers:
if l.viewlayer_render in vl_names:
l.viewlayer_render = fn.get_view_layer('exclude').name
for n in reversed(rlayers_nodes):
# Disconnect linked
for lnk in n.outputs[0].links:
grp = lnk.to_node
if grp.type != 'GROUP':
continue
if not grp.name.startswith('NG'):
continue
sockin = lnk.to_socket
sockout = grp.outputs.get(sockin.name)
if not sockout:
continue
for grplink in sockout.links:
if grplink.to_node.type != 'OUTPUT_FILE':
continue
fo_socket = grplink.to_socket
fo = grplink.to_node
fo.file_slots.remove(fo_socket)
inside_nodes = []
ngroup = grp.node_tree
for i in range(len(grp.inputs))[::-1]:
if grp.inputs[i].name == sockin.name:
ngroup.inputs.remove(ngroup.inputs[i])
gp_in_socket = ngroup.nodes['Group Input'].outputs[i]
for lnk in gp_in_socket.links:
inside_nodes += fn.all_connected_forward(lnk.to_node)
list(set(inside_nodes))
break
for i in range(len(grp.outputs))[::-1]:
if grp.outputs[i].name == sockout.name:
ngroup.outputs.remove(ngroup.outputs[i])
break
for sub_n in reversed(inside_nodes):
ngroup.nodes.remove(sub_n)
# remove render_layer node
rd_scn.node_tree.nodes.remove(n)
return {"FINISHED"}
classes=(
GPEXP_OT_reconnect_render_layer,
GPEXP_OT_delete_render_layer,
)
def register():

View File

@ -167,11 +167,54 @@ class GPEXP_OT_normalize_outnames(bpy.types.Operator):
return {"FINISHED"}
class GPEXP_OT_enable_all_viewlayers(bpy.types.Operator):
bl_idname = "gp.enable_all_viewlayers"
bl_label = "Enable All Viewlayers"
bl_description = "Enable all View layers except those named 'exclude' 'View Layer'"
bl_options = {"REGISTER"}
def execute(self, context):
rd_scn = bpy.data.scenes.get('Render')
if not rd_scn:
print('SKIP, no Render scene')
return {"CANCELLED"}
vl_list = [vl for vl in rd_scn.view_layers if not vl.use and vl.name not in {'View Layer', 'exclude'}]
for v in vl_list:
v.use = True
self.report({"INFO"}, f'{len(vl_list)} ViewLayers Reactivated')
return {"FINISHED"}
class GPEXP_OT_activate_only_selected_layers(bpy.types.Operator):
bl_idname = "gp.activate_only_selected_layers"
bl_label = "Activate Only Selected Layers"
bl_description = "Activate only selected node view layer , excluding all others"
bl_options = {"REGISTER"}
def execute(self, context):
rd_scn = bpy.data.scenes.get('Render')
if not rd_scn:
print('SKIP, no Render scene')
return {"CANCELLED"}
nodes = rd_scn.node_tree.nodes
rlayers_nodes = [n for n in nodes if n.select and n.type == 'R_LAYERS']
vls = [rd_scn.view_layers.get(n.layer) for n in rlayers_nodes if rd_scn.view_layers.get(n.layer)]
for v in rd_scn.view_layers:
v.use = v in vls
self.report({"INFO"}, f'Now only {len(vls)} viewlayer active (/{len(rd_scn.view_layers)})')
return {"FINISHED"}
classes=(
GPEXP_OT_mute_toggle_output_nodes,
GPEXP_OT_set_output_node_format,
GPEXP_OT_number_outputs,
GPEXP_OT_enable_all_viewlayers,
GPEXP_OT_activate_only_selected_layers,
# GPEXP_OT_normalize_outnames,
)

View File

@ -2,7 +2,7 @@ bl_info = {
"name": "GP Render",
"description": "Organise export of gp layers through compositor output",
"author": "Samuel Bernou",
"version": (0, 3, 6),
"version": (0, 3, 7),
"blender": (2, 93, 0),
"location": "View3D",
"warning": "",

19
fn.py
View File

@ -114,6 +114,8 @@ def set_settings(scene=None):
scene.render.film_transparent = True
scene.view_settings.view_transform = 'Standard'
scene.render.resolution_percentage = 100
# output (fast write settings since this is just to delete afterwards...)
scene.render.filepath = '//render/preview/preview_'
scene.render.image_settings.file_format = 'JPEG'
@ -370,6 +372,23 @@ def connect_to_group_input(n):
return val
return False
def all_connected_forward(n, nlist=[]):
'''return list of all forward connected nodes recursively (include passed nodes)'''
for o in n.outputs:
if o.is_linked:
for lnk in o.links:
if lnk.to_node.type == 'GROUP_OUTPUT':
if n not in nlist:
return nlist + [n]
else:
return nlist
else:
nlist = all_connected_forward(lnk.to_node, nlist)
if n in nlist:
return nlist
return nlist + [n]
def clear_nodegroup_content_if_disconnected(ngroup):
'''Get a nodegroup.node_tree
delete orphan nodes that are not connected from group input node

43
ui.py
View File

@ -2,7 +2,6 @@ import bpy
from bpy.types import Panel
# from .preferences import get_addon_prefs
# Node view panel
class GPEXP_PT_gp_node_ui(Panel):
bl_space_type = "NODE_EDITOR"
@ -28,19 +27,51 @@ class GPEXP_PT_gp_node_ui(Panel):
# if cam and cam_name == 'draw_cam':
# cam_name = f'{cam.parent.name} > {cam_name}'
row.operator("gp.swap_render_cams", text=text, icon='OUTLINER_OB_CAMERA')
# Live checks
if scn.render.resolution_percentage != 100:
layout.label(text='Res Percentage not 100%', icon='ERROR')
layout.prop(scn.render, 'resolution_percentage')
exclude_count = len([vl for vl in scn.view_layers if not vl.use and vl.name not in {'View Layer', 'exclude'}])
if exclude_count:
# layout.label(text=f'{exclude_count} Excluded View Layers !')
layout.operator('gp.enable_all_viewlayers', text=f'Reactivate {exclude_count} Excluded View Layers')
if not scn.use_nodes or not scn.node_tree:
return
layout.separator()
# TODO : add advanced bool checkbox to hide some options from the user
col = layout.column(align=True)
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)
col.operator('gp.activate_only_selected_layers', text=f'Activate Only {ct} Layer Nodes')
col.enabled = ct > 0
col = layout.column(align=True)
txt = f'Merge {ct} Layer Nodes'
col.operator('gp.merge_selected_viewlayer_nodes', icon='NODETREE', text=txt).disconnect = True
col.operator('gp.merge_selected_viewlayer_nodes', icon='NODETREE', text='Merge (keep connect)').disconnect = False
col.enabled = ct > 1
layout.separator()
col = layout.column()
subcol = col.column()
n = context.scene.node_tree.nodes.active
if n:
subcol.enabled = n and n.type == 'R_LAYERS' and not n.outputs[0].is_linked
else:
subcol.enabled = False
subcol.operator('gp.reconnect_render_layer', icon='ANIM', text=f'Reconnect {ct} Layer Node')
col.operator('gp.delete_render_layer', icon='TRACKING_CLEAR_FORWARDS', text=f'Delete {ct} Layer Node')
layout.separator()
layout.label(text='All Outputs:')
@ -53,14 +84,8 @@ class GPEXP_PT_gp_node_ui(Panel):
col=layout.column()
col.label(text='Clean and updates:')
row = col.row()
n = context.scene.node_tree.nodes.active
if n:
row.enabled = n and n.type == 'R_LAYERS' and not n.outputs[0].is_linked
else:
row.enabled = False
row.operator('gp.reconnect_render_layer', icon='ANIM', text='Reconnect')
col.separator()
col.operator('gp.clean_compo_tree', icon='BRUSHES_ALL', text='Clean Nodes') # NODE_CORNER