import bpy from . import fn class GPEXP_OT_reconnect_render_layer(bpy.types.Operator): bl_idname = "gp.reconnect_render_layer" bl_label = "Reconnect Render Layer" bl_description = "Reconnect 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): node_tree = context.scene.node_tree nodes = node_tree.nodes changed = [] for n in nodes: if not n.select or not n.type == 'R_LAYERS': continue if not ' / ' in n.layer: continue if n.outputs[0].is_linked: # already connected continue # get namme obname = n.layer.split()[0] grp_name = f'NG_{obname}' # get nodegroup grp = nodes.get(grp_name) if not grp: print(f'{n.name} Node group not found : {n.layer} !-> {grp_name}') continue inp = grp.inputs.get(n.layer) if not inp: print(f'{n.name} no inputs name "{n.layer}" in group {grp_name}') continue # reconnect node_tree.links.new(n.outputs[0], inp) changed.append(f'{n.name} ({n.layer}) to {grp_name}') if changed: self.report({'INFO'}, f'{len(changed)} nodes reconnected') else: self.report({'WARNING'}, f'Could not reconnect, see console') 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(): for cls in classes: bpy.utils.register_class(cls) def unregister(): for cls in reversed(classes): bpy.utils.unregister_class(cls)