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 nodesmain
parent
6624c45228
commit
c58654a7e1
|
@ -14,6 +14,11 @@ Activate / deactivate layer opacity according to prefix
|
|||
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
|
||||
|
||||
- added: autobuild set each gp objects data to single user
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import bpy
|
||||
import re
|
||||
from math import isclose
|
||||
from itertools import groupby
|
||||
from . import fn
|
||||
from . import gen_vlayer
|
||||
|
||||
|
@ -114,6 +115,126 @@ def merge_layers(rlayers, obname=None, active=None, disconnect=True, color=None)
|
|||
|
||||
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):
|
||||
bl_idname = "gp.merge_viewlayers_to_active"
|
||||
bl_label = "Merge selected layers view_layers"
|
||||
|
@ -145,6 +266,21 @@ class GPEXP_OT_merge_viewlayers_to_active(bpy.types.Operator):
|
|||
self.report(*ret)
|
||||
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):
|
||||
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_merge_selected_dopesheet_layers,# unused
|
||||
GPEXP_OT_merge_selected_viewlayer_nodes,
|
||||
GPEXP_OT_merge_preview_ouput,
|
||||
)
|
||||
|
||||
def register():
|
||||
|
|
|
@ -2,7 +2,7 @@ bl_info = {
|
|||
"name": "GP Render",
|
||||
"description": "Organise export of gp layers through compositor output",
|
||||
"author": "Samuel Bernou",
|
||||
"version": (1, 2, 3),
|
||||
"version": (1, 3, 0),
|
||||
"blender": (2, 93, 0),
|
||||
"location": "View3D",
|
||||
"warning": "",
|
||||
|
|
13
fn.py
13
fn.py
|
@ -182,9 +182,16 @@ def set_settings(scene=None, aa=True):
|
|||
|
||||
# output (fast write settings since this is just to delete afterwards...)
|
||||
scene.render.filepath = f'//render/preview/{scene.name}/preview_'
|
||||
scene.render.image_settings.file_format = 'JPEG'
|
||||
scene.render.image_settings.color_mode = 'RGB'
|
||||
scene.render.image_settings.quality = 0
|
||||
im_settings = scene.render.image_settings
|
||||
# im_settings.file_format = 'JPEG'
|
||||
# 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):
|
||||
'''Change scene AA settings and commute AA nodes according to toggle'''
|
||||
|
|
4
ui.py
4
ui.py
|
@ -117,6 +117,10 @@ class GPEXP_PT_gp_node_ui(Panel):
|
|||
subcol = col.column()
|
||||
subcol.enabled = bool(ct)
|
||||
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
|
||||
# col.operator('gp.number_outputs', icon='LINENUMBERS_ON', text='Renumber all outputs').mode = 'ALL'
|
||||
|
||||
|
|
Loading…
Reference in New Issue