stacked preview in composite output

1.3.0

- added: Preview with a combined alpha over of all render layer available
- added: button to clear preview nodes
main
pullusb 2023-04-04 11:09:00 +02:00
parent 6624c45228
commit c58654a7e1
5 changed files with 158 additions and 5 deletions

View File

@ -14,6 +14,11 @@ Activate / deactivate layer opacity according to prefix
Activate / deactivate all masks using MA layers Activate / deactivate all masks using MA layers
--> -->
1.3.0
- added: Preview with a combined alpha over of all render layer available
- added: button to clear preview nodes
1.2.3 1.2.3
- added: autobuild set each gp objects data to single user - added: autobuild set each gp objects data to single user

View File

@ -1,6 +1,7 @@
import bpy import bpy
import re import re
from math import isclose from math import isclose
from itertools import groupby
from . import fn from . import fn
from . import gen_vlayer from . import gen_vlayer
@ -114,6 +115,126 @@ def merge_layers(rlayers, obname=None, active=None, disconnect=True, color=None)
return ng, out return ng, out
def merge_compositor_preview(context=None, clear=False):
'''Merge all active render layer with alpha over.location[0]+450, ng.location[1]+50), width=600)
Create a dedicated node group and connect to compositor output
return tuple(merge nodegroup, compositor out)
'''
context = context or bpy.context
node_tree = context.scene.node_tree
nodes = node_tree.nodes
links = node_tree.links
## identify all duplicated render layer and remove them, then recreate the preview
for n in reversed(nodes):
if n.type in ('R_LAYERS', 'GROUP') and n.get('is_preview'):
nodes.remove(n)
ng_name = f'merge_NG_preview'
## clear unused nodes groups duplication
fn.clear_nodegroup(ng_name, full_clear=True)
if clear:
## Restore to jpg out ?
# im_settings = context.scene.render.image_settings
# im_settings.file_format = 'JPEG'
# im_settings.color_mode = 'RGB'
# im_settings.quality = 0
return
## Get all RL node per object block (node frames), sort object by name (should a)
all_rlayers = [n for n in nodes if n.type == 'R_LAYERS']
all_rlayers.sort(key=lambda x: x.label, reverse=True)
## ! All at once doe not work, need to separate by individual object first
# all_rlayers.sort(key=lambda x: (x.label, -fn.real_loc(x).y))
## Sort all render layer by object (either by start name or by frames)
## sort order within by order in layer stack (check -n.location.y or associated gp object)
grps = groupby(all_rlayers, key=lambda x : x.label.split(' /')[0])
rlayers_groups = {k : sorted(list(grp), key=lambda x: x.location.y, reverse=True) for k, grp in grps if k}
# Debug prints
# for ob_key_name, rl_group in rlayers_groups.items():
# print(ob_key_name)
# for n in rl_group:
# print(f'- {n.label}')
# print()
# print('Done')
## Recreate the render layer nodes duplicated at the side of the frames
pos_x = 2400
pos_y = 30
offset_y = 180
comp_list = []
for k, rl_group in rlayers_groups.items():
for rl in rl_group:
comp = nodes.new('CompositorNodeRLayers')
comp['is_preview'] = 1
comp.label = rl.label # f'.{rl.label}'
comp.name = f'.{rl.name}'
comp.scene = rl.scene
comp.layer = rl.layer
comp.color = rl.color
comp.use_custom_color = True
comp.width = rl.width
comp.show_preview = False
comp.location = (pos_x, pos_y)
comp_list.append(comp)
pos_y -= offset_y
### Create the nodegroup for clean alpha over merge
## Need a unique nodegroup name, increment name while nodegroup exists
# while bpy.data.node_groups.get(ng_name): # nodes.get(ng_name)
# if not re.search(r'(\d+)$', ng_name):
# ng_name += '_02' # if not ending with a number add _02
# ng_name = re.sub(r'(\d+)(?!.*\d)', lambda x: str(int(x.group(1))+1).zfill(len(x.group(1))), ng_name)
print(f'Create preview merge nodegroup {ng_name}')
ngroup = bpy.data.node_groups.new(ng_name, 'CompositorNodeTree')
ng = fn.create_node('CompositorNodeGroup', tree=node_tree, location=(3000, 0), width=400)
ng.node_tree = ngroup
ng.name = ngroup.name
ng['is_preview'] = 1
fn.create_node('NodeGroupInput', tree=ngroup, location=(-600,0))
fn.create_node('NodeGroupOutput', tree=ngroup, location=(1000,0))
# Create inputs and links to node_group
for rln in comp_list:
rln.outputs['Image']
sockin = ng.inputs.new('NodeSocketColor', rln.layer)
sockin = ng.inputs[-1]
links.new(rln.outputs['Image'], sockin)
fn.nodegroup_merge_inputs(ng.node_tree)
ng.update()
# Create composite out (if needed) and connect
composite_out = next((n for n in nodes if n.type == 'COMPOSITE'), None)
if not composite_out:
composite_out = fn.create_node('CompositorNodeComposite', tree=node_tree, location=(ng.location[0]+450, ng.location[1]+50), width=140)
composite_out.use_alpha = True
links.new(ng.outputs[0], composite_out.inputs[0])
im_settings = context.scene.render.image_settings
# im_settings.file_format = 'JPEG'
# im_settings.color_mode = 'RGB'
# im_settings.quality = 0
im_settings.file_format = 'OPEN_EXR'
im_settings.color_mode = 'RGBA'
im_settings.color_depth = '16'
im_settings.exr_codec = 'ZIP'
return ng, composite_out
class GPEXP_OT_merge_viewlayers_to_active(bpy.types.Operator): class GPEXP_OT_merge_viewlayers_to_active(bpy.types.Operator):
bl_idname = "gp.merge_viewlayers_to_active" bl_idname = "gp.merge_viewlayers_to_active"
bl_label = "Merge selected layers view_layers" bl_label = "Merge selected layers view_layers"
@ -145,6 +266,21 @@ class GPEXP_OT_merge_viewlayers_to_active(bpy.types.Operator):
self.report(*ret) self.report(*ret)
return {"FINISHED"} return {"FINISHED"}
class GPEXP_OT_merge_preview_ouput(bpy.types.Operator):
bl_idname = "gp.merge_preview_ouput"
bl_label = "Merge Preview Output"
bl_description = "Merge all active render layers to an output"
bl_options = {"REGISTER"}
# @classmethod
# def poll(cls, context):
# return True
clear : bpy.props.BoolProperty(default=False, options={'SKIP_SAVE'})
def execute(self, context):
merge_compositor_preview(context=context, clear=self.clear)
return {"FINISHED"}
class GPEXP_OT_auto_merge_adjacent_prefix(bpy.types.Operator): class GPEXP_OT_auto_merge_adjacent_prefix(bpy.types.Operator):
bl_idname = "gpexp.auto_merge_adjacent_prefix" bl_idname = "gpexp.auto_merge_adjacent_prefix"
@ -285,6 +421,7 @@ GPEXP_OT_merge_viewlayers_to_active,
GPEXP_OT_auto_merge_adjacent_prefix, GPEXP_OT_auto_merge_adjacent_prefix,
GPEXP_OT_merge_selected_dopesheet_layers,# unused GPEXP_OT_merge_selected_dopesheet_layers,# unused
GPEXP_OT_merge_selected_viewlayer_nodes, GPEXP_OT_merge_selected_viewlayer_nodes,
GPEXP_OT_merge_preview_ouput,
) )
def register(): def register():

View File

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

15
fn.py
View File

@ -182,9 +182,16 @@ def set_settings(scene=None, aa=True):
# output (fast write settings since this is just to delete afterwards...) # output (fast write settings since this is just to delete afterwards...)
scene.render.filepath = f'//render/preview/{scene.name}/preview_' scene.render.filepath = f'//render/preview/{scene.name}/preview_'
scene.render.image_settings.file_format = 'JPEG' im_settings = scene.render.image_settings
scene.render.image_settings.color_mode = 'RGB' # im_settings.file_format = 'JPEG'
scene.render.image_settings.quality = 0 # im_settings.color_mode = 'RGB'
# im_settings.quality = 0
## Same as output nodes
im_settings.file_format = 'OPEN_EXR'
im_settings.color_mode = 'RGBA'
im_settings.color_depth = '16'
im_settings.exr_codec = 'ZIP'
def scene_aa(scene=None, toggle=True): def scene_aa(scene=None, toggle=True):
'''Change scene AA settings and commute AA nodes according to toggle''' '''Change scene AA settings and commute AA nodes according to toggle'''
@ -1702,4 +1709,4 @@ def clean_mats_duplication(ob, skip_different_materials=True):
if diff_ct: if diff_ct:
print(f'{diff_ct} mat skipped >> same name but different color settings!') print(f'{diff_ct} mat skipped >> same name but different color settings!')
# return ('INFO', f'{diff_ct} mat skipped >> same name but different color settings!') # return ('INFO', f'{diff_ct} mat skipped >> same name but different color settings!')

4
ui.py
View File

@ -117,6 +117,10 @@ class GPEXP_PT_gp_node_ui(Panel):
subcol = col.column() subcol = col.column()
subcol.enabled = bool(ct) subcol.enabled = bool(ct)
subcol.operator('gp.number_outputs', icon='LINENUMBERS_ON', text=txt).mode = 'SELECTED' subcol.operator('gp.number_outputs', icon='LINENUMBERS_ON', text=txt).mode = 'SELECTED'
row=layout.row(align=True)
row.operator('gp.merge_preview_ouput', icon='NODETREE', text='Set Preview')
row.operator('gp.merge_preview_ouput', icon='X', text='').clear = True
# subcol.operator('gp.normalize_outnames', icon='SYNTAX_OFF', text=f'Normalize Paths {ct} Selected Ouptut') # not ready # subcol.operator('gp.normalize_outnames', icon='SYNTAX_OFF', text=f'Normalize Paths {ct} Selected Ouptut') # not ready
# col.operator('gp.number_outputs', icon='LINENUMBERS_ON', text='Renumber all outputs').mode = 'ALL' # col.operator('gp.number_outputs', icon='LINENUMBERS_ON', text='Renumber all outputs').mode = 'ALL'