partial autobuild
1.1.0 - added: `autobuild` button (partial auto-buildfor now) - added: make sent object selectedmain
parent
e086eb4050
commit
10c279c315
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
|
|
||||||
<!-- TODO
|
<!-- TODO
|
||||||
- need to let use choose output settings
|
- need to let user choose output settings
|
||||||
|
|
||||||
if objects has multiple user without being linked in render scene :
|
if objects has multiple user without being linked in render scene :
|
||||||
duplicate the object insteat of linking
|
duplicate the object insteat of linking
|
||||||
|
@ -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.1.0
|
||||||
|
|
||||||
|
- added: `autobuild` button (partial auto-buildfor now)
|
||||||
|
- added: make sent object selected
|
||||||
|
|
||||||
1.0.3
|
1.0.3
|
||||||
|
|
||||||
- fixed: Send to render layer compatibility with blender 3.4
|
- fixed: Send to render layer compatibility with blender 3.4
|
||||||
|
|
|
@ -75,17 +75,19 @@ class GPEXP_OT_render_auto_build(bpy.types.Operator):
|
||||||
if (render_wkspace := bpy.data.workspaces.get('GP Render')):
|
if (render_wkspace := bpy.data.workspaces.get('GP Render')):
|
||||||
context.window.workspace = render_wkspace
|
context.window.workspace = render_wkspace
|
||||||
else:
|
else:
|
||||||
render_wkspace_filepath = Path(bpy.utils.user_resource('SCRIPTS'), 'startup', 'GP', 'startup.blend')
|
render_wkspace_filepath = Path(bpy.utils.user_resource('SCRIPTS'), 'startup', 'bl_app_templates_user', 'GP', 'startup.blend')
|
||||||
|
print('render workspace', render_wkspace_filepath.exists())
|
||||||
ret = bpy.ops.workspace.append_activate(idname='GP Render', filepath=str(render_wkspace_filepath))
|
ret = bpy.ops.workspace.append_activate(idname='GP Render', filepath=str(render_wkspace_filepath))
|
||||||
|
print('ret: ', ret)
|
||||||
if ret != {'FINISHED'}:
|
if ret != {'FINISHED'}:
|
||||||
# Fallback to workspace template shipped with addon (TODO : add template blend file in addon)
|
# Fallback to workspace template shipped with addon (TODO : add template blend file in addon)
|
||||||
render_wkspace_filepath = Path(__file__).parent / 'workspaces' / 'startup.blend'
|
render_wkspace_filepath = Path(__file__).parent / 'workspaces' / 'startup.blend'
|
||||||
ret = bpy.ops.workspace.append_activate(idname='GP Render', filepath=str(render_wkspace_filepath))
|
ret = bpy.ops.workspace.append_activate(idname='GP Render', filepath=str(render_wkspace_filepath))
|
||||||
|
if ret != {'FINISHED'}:
|
||||||
|
print('No GP render workspace available')
|
||||||
|
|
||||||
## Group all adjacent layer type
|
## Group all adjacent layer type
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Renumber File outputs
|
## Renumber File outputs
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,73 @@ def merge_layers(rlayers, obname=None, active=None, disconnect=True, color=None)
|
||||||
|
|
||||||
return ng, out
|
return ng, out
|
||||||
|
|
||||||
|
def merge_gplayer_viewlayers(ob, act=None, layers=None):
|
||||||
|
if act is None:
|
||||||
|
act = ob.data.layers.active
|
||||||
|
if layers is None:
|
||||||
|
layers = [l for l in ob.data.layers if l.select and l != act]
|
||||||
|
|
||||||
|
rd_scn = bpy.data.scenes.get('Render')
|
||||||
|
if not rd_scn:
|
||||||
|
return ({'ERROR'}, 'Viewlayers needs to be generated first!')
|
||||||
|
|
||||||
|
if not act.viewlayer_render:
|
||||||
|
return ({'ERROR'}, f'Active layer {act.info} has no viewlayer assigned')
|
||||||
|
|
||||||
|
# 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)]
|
||||||
|
|
||||||
|
vl_names = [v.name for v in vls]
|
||||||
|
|
||||||
|
for n in reversed(rd_scn.node_tree.nodes):
|
||||||
|
if n.type == 'R_LAYERS' and n.layer in vl_names:
|
||||||
|
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)
|
||||||
|
|
||||||
|
# remove input and output from group
|
||||||
|
# grp.inputs.remove(sockin) # do not clear inside !!
|
||||||
|
# grp.outputs.remove(sockout) # do not clear inside !!
|
||||||
|
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])
|
||||||
|
break
|
||||||
|
for i in range(len(grp.outputs))[::-1]:
|
||||||
|
if grp.outputs[i].name == sockout.name:
|
||||||
|
ngroup.outputs.remove(ngroup.outputs[i])
|
||||||
|
break
|
||||||
|
|
||||||
|
# remove render_layer node
|
||||||
|
rd_scn.node_tree.nodes.remove(n)
|
||||||
|
|
||||||
|
# assign view layer from active to selected
|
||||||
|
for l in layers:
|
||||||
|
l.viewlayer_render = act.viewlayer_render
|
||||||
|
|
||||||
|
## delete unused_vl
|
||||||
|
|
||||||
|
# used_vl_name = [n.layer for n in rd_scn.node_tree.nodes if n.type == 'R_LAYERS' and n.layer]
|
||||||
|
for vl in vls:
|
||||||
|
rd_scn.view_layers.remove(vl)
|
||||||
|
# if not vl.name in used_vl_name:
|
||||||
|
# rd_scn.view_layers.remove(vl)
|
||||||
|
|
||||||
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"
|
||||||
|
@ -130,69 +197,19 @@ class GPEXP_OT_merge_viewlayers_to_active(bpy.types.Operator):
|
||||||
act = ob.data.layers.active
|
act = ob.data.layers.active
|
||||||
layers = [l for l in ob.data.layers if l.select and l != act]
|
layers = [l for l in ob.data.layers if l.select and l != act]
|
||||||
|
|
||||||
if not act.viewlayer_render:
|
## Tested in func
|
||||||
self.report({'ERROR'}, f'Active layer {act.info} has no viewlayer assigned')
|
# rd_scn = bpy.data.scenes.get('Render')
|
||||||
return {'CANCELLED'}
|
# if not rd_scn:
|
||||||
|
# self.report({'ERROR'}, 'Viewlayers needs to be generated first!')
|
||||||
|
# return {'CANCELLED'}
|
||||||
|
|
||||||
rd_scn = bpy.data.scenes.get('Render')
|
# if not act.viewlayer_render:
|
||||||
if not rd_scn:
|
# self.report({'ERROR'}, f'Active layer {act.info} has no viewlayer assigned')
|
||||||
self.report({'ERROR'}, 'Viewlayers needs to be generated first!')
|
# return {'CANCELLED'}
|
||||||
return {'CANCELLED'}
|
|
||||||
|
|
||||||
# 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)]
|
|
||||||
|
|
||||||
vl_names = [v.name for v in vls]
|
|
||||||
|
|
||||||
for n in reversed(rd_scn.node_tree.nodes):
|
|
||||||
if n.type == 'R_LAYERS' and n.layer in vl_names:
|
|
||||||
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)
|
|
||||||
|
|
||||||
# remove input and output from group
|
|
||||||
# grp.inputs.remove(sockin) # do not clear inside !!
|
|
||||||
# grp.outputs.remove(sockout) # do not clear inside !!
|
|
||||||
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])
|
|
||||||
break
|
|
||||||
for i in range(len(grp.outputs))[::-1]:
|
|
||||||
if grp.outputs[i].name == sockout.name:
|
|
||||||
ngroup.outputs.remove(ngroup.outputs[i])
|
|
||||||
break
|
|
||||||
|
|
||||||
# remove render_layer node
|
|
||||||
rd_scn.node_tree.nodes.remove(n)
|
|
||||||
|
|
||||||
# assign view layer from active to selected
|
ret = merge_gplayer_viewlayers(ob, act=act, layers=layers)
|
||||||
for l in layers:
|
if isinstance(ret, tuple):
|
||||||
l.viewlayer_render = act.viewlayer_render
|
self.report(*ret)
|
||||||
|
|
||||||
## delete unused_vl
|
|
||||||
|
|
||||||
# used_vl_name = [n.layer for n in rd_scn.node_tree.nodes if n.type == 'R_LAYERS' and n.layer]
|
|
||||||
for vl in vls:
|
|
||||||
rd_scn.view_layers.remove(vl)
|
|
||||||
# if not vl.name in used_vl_name:
|
|
||||||
# rd_scn.view_layers.remove(vl)
|
|
||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
class GPEXP_OT_merge_selected_dopesheet_layers(bpy.types.Operator):
|
class GPEXP_OT_merge_selected_dopesheet_layers(bpy.types.Operator):
|
||||||
|
|
|
@ -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, 0, 2),
|
"version": (1, 1, 0),
|
||||||
"blender": (2, 93, 0),
|
"blender": (2, 93, 0),
|
||||||
"location": "View3D",
|
"location": "View3D",
|
||||||
"warning": "",
|
"warning": "",
|
||||||
|
|
|
@ -234,7 +234,17 @@ def get_set_viewlayer_from_gp(ob, l, scene=None):
|
||||||
# ob.data = ob.data.copy() # create duplicate (this will also affect the one in original scene !!!)
|
# ob.data = ob.data.copy() # create duplicate (this will also affect the one in original scene !!!)
|
||||||
scene.collection.objects.link(ob)
|
scene.collection.objects.link(ob)
|
||||||
ob.hide_viewport = ob.hide_render = False
|
ob.hide_viewport = ob.hide_render = False
|
||||||
|
|
||||||
|
## set object active in default viewlayer
|
||||||
|
|
||||||
|
# if (avl := scene.view_layers.get('ViewLayer')):
|
||||||
|
# # This select the object in source scene
|
||||||
|
# avl.objects.active = ob
|
||||||
|
# # avl.objects.active.select_set(True)
|
||||||
|
nob = scene.collection.objects.get(ob.name)
|
||||||
|
if nob:
|
||||||
|
nob.select_set(True)
|
||||||
|
|
||||||
# create viewlayer
|
# create viewlayer
|
||||||
vl_name = f'{ob.name} / {l.info}'
|
vl_name = f'{ob.name} / {l.info}'
|
||||||
vl = fn.get_view_layer(vl_name, scene=scene)
|
vl = fn.get_view_layer(vl_name, scene=scene)
|
||||||
|
|
3
ui.py
3
ui.py
|
@ -174,8 +174,7 @@ class GPEXP_PT_gp_dopesheet_ui(Panel):
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
|
|
||||||
## TODO: add auto-build
|
layout.operator('gp_export.render_auto_build')
|
||||||
# layout.operator('gp_export.render_auto_build')
|
|
||||||
if context.object:
|
if context.object:
|
||||||
layout.label(text=f'Object: {context.object.name}')
|
layout.label(text=f'Object: {context.object.name}')
|
||||||
if context.object.data.users > 1:
|
if context.object.data.users > 1:
|
||||||
|
|
Loading…
Reference in New Issue