info = { 'icon': 'TRIA_DOWN_BAR', 'description': 'Merge layers', } import fnmatch import glob import os import re from math import degrees, radians from os import listdir from os.path import basename, dirname, exists, isdir, isfile, join, splitext from pathlib import Path import bpy C = bpy.context D = bpy.data def random_color(alpha=False): import random if alpha: return (random.uniform(0,1), random.uniform(0,1), random.uniform(0,1), 1) return (random.uniform(0,1), random.uniform(0,1), random.uniform(0,1)) def create_node(type, tree=None, **kargs): tree = tree or bpy.context.scene.node_tree node = tree.nodes.new(type) for k,v in kargs.items(): setattr(node, k, v) return node def new_aa_node(tree): '''create AA node''' aa = create_node('CompositorNodeAntiAliasing', tree) # type = ANTIALIASING aa.threshold = 0.5 aa.contrast_limit = 0.5 aa.corner_rounding = 0.25 aa.hide = True return aa def get_render_scene(): render = bpy.data.scenes.get('Render') if not render: render = bpy.data.scenes.new('Render') render.use_nodes = True return render def merge_layers(rlayers, obname=None): print(f'Merging {len(rlayers)} layers') print('->', [r.layer for r in rlayers]) print() if not rlayers: return ('ERROR', 'No render layer sent to merge') ng = rlayers[0].outputs[0].links[0].to_node rlayers.sort(key=lambda x: x.location.y, reverse=True) # change colors of those nodes color = random_color() for n in rlayers: n.use_custom_color = True n.color = color # get inside socket (group input) from outside socket list (should be already ordered) ## by name # for i, inp in enumerate(ng.node_tree.inputs): # if inp.name == # by connection order socket_list = [] grp_sockets = [] for n in rlayers: if n.outputs[0].links[0].to_node != ng: print(f'Skip {n.layer}, connect to {n.outputs[0].links[0].to_node} instead of {ng.name}') continue sock_in = n.outputs[0].links[0].to_socket for i, s in enumerate(ng.inputs): if s == sock_in: print(i, s.name) socket_list.append(s) grp_sockets.append(ng.node_tree.nodes['Group Input'].outputs[i]) break # debug for inp, grps in zip(socket_list, grp_sockets): if inp.name != grps.name: print(f'\n! Problem ! : {inp.name}, {grps.name}') return ## # JUST CREATE ANOTHER GROUP NODE FOR THE MERGE ! ## def merge_selected_layers(): '''Merge command from selected GP layers''' ob = bpy.context.object layer_names = [l.info for l in ob.data.layers if l.select and not l.hide] print("layer_names", layer_names)#Dbg if len(layer_names) < 2: print(f'Should select multiple layers for merging') return render = bpy.data.scenes.get('Render') if render: nodes = render.node_tree.nodes clean_ob_name = bpy.path.clean_name(ob.name) rlayers = [] for l in layer_names: ## identifier is clean_name(ob.name).layer_name idname = f'{clean_ob_name}.{l}' # check the render layer that have a parent frame rlayer = [n for n in nodes if n.type == 'R_LAYERS' and n.layer == idname and n.parent] if not rlayer: # send to function to generate the rlayer and connect # rlayer = creation continue rlayers.append(rlayer) merge_layers(rlayers, obname=clean_ob_name) def merge_selected_render_layers(): '''Merge command from selected render layers nodes''' render = bpy.data.scenes.get('Render') if not render: print('No render scene') return nodes = render.node_tree.nodes selection = [n for n in nodes if n.select and n.type == 'R_LAYERS'] # should be from the same object: assert all(selection[0].layer.split('.')[0] == n.layer.split('.')[0] for n in selection), 'Not every nodes start with the same object' # obname = selection[0].layer.split('.')[0] merge_layers(selection) # merge_selected_layers() # function to merge from GP dopesheet merge_selected_render_layers() # function to merge from nodegroup