add env variable and prefs for tech passes split, and allow customization ofr tech passes split in popup
This commit is contained in:
parent
aa4293c7d7
commit
f95fe2eff7
@ -2,7 +2,7 @@ bl_info = {
|
|||||||
"name": "Render Toolbox",
|
"name": "Render Toolbox",
|
||||||
"description": "Setup outputs and perform cheks for rendering",
|
"description": "Setup outputs and perform cheks for rendering",
|
||||||
"author": "Samuel Bernou",
|
"author": "Samuel Bernou",
|
||||||
"version": (0, 8, 0),
|
"version": (1, 0, 0),
|
||||||
"blender": (4, 0, 0),
|
"blender": (4, 0, 0),
|
||||||
"location": "View3D",
|
"location": "View3D",
|
||||||
"warning": "",
|
"warning": "",
|
||||||
|
17
fn.py
17
fn.py
@ -7,6 +7,9 @@ from .constant import TECH_PASS_KEYWORDS
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def get_addon_prefs():
|
||||||
|
return bpy.context.preferences.addons[__package__].preferences
|
||||||
|
|
||||||
# region Manage nodes
|
# region Manage nodes
|
||||||
|
|
||||||
def real_loc(n):
|
def real_loc(n):
|
||||||
@ -208,7 +211,7 @@ def create_and_connect_file_output(node, outputs, file_out, out_name, base_path,
|
|||||||
|
|
||||||
|
|
||||||
def connect_to_file_output(node_list, file_out=None, base_path='', excludes=None, remap_names=None,
|
def connect_to_file_output(node_list, file_out=None, base_path='', excludes=None, remap_names=None,
|
||||||
file_format=None, split_tech_passes=False, tech_file_format=None, template=None):
|
file_format=None, tech_pass_names=None, tech_file_format=None, template=None):
|
||||||
"""Connect selected nodes output to file output(s)
|
"""Connect selected nodes output to file output(s)
|
||||||
if a file output is selected, add intputs on it
|
if a file output is selected, add intputs on it
|
||||||
|
|
||||||
@ -230,8 +233,12 @@ def connect_to_file_output(node_list, file_out=None, base_path='', excludes=None
|
|||||||
|
|
||||||
remap_names (dict, optionnal): List of output names to remap {node_name: {output_name: new_name}}.
|
remap_names (dict, optionnal): List of output names to remap {node_name: {output_name: new_name}}.
|
||||||
|
|
||||||
split_tech_passes (bool, optional): When True, create a separate file output for technical passes
|
tech_pass_names (list[str], optional): list of of socket names to set as separate file output for technical passes
|
||||||
Defaults to False.
|
Defaults to None
|
||||||
|
|
||||||
|
tech_file_format (dict, optionnal): converts each dictionary key into a file output format for tech passes
|
||||||
|
if not passed, will use file_format.
|
||||||
|
Defaults to None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list[bpy.types.CompositorNode]: All nodes created.
|
list[bpy.types.CompositorNode]: All nodes created.
|
||||||
@ -278,9 +285,9 @@ def connect_to_file_output(node_list, file_out=None, base_path='', excludes=None
|
|||||||
# Categorize outputs
|
# Categorize outputs
|
||||||
crypto_outputs = [o for o in all_outputs if 'crypto' in o.name.lower()]
|
crypto_outputs = [o for o in all_outputs if 'crypto' in o.name.lower()]
|
||||||
|
|
||||||
if split_tech_passes:
|
if tech_pass_names:
|
||||||
# Filter tech passes
|
# Filter tech passes
|
||||||
tech_outputs = [o for o in all_outputs if o.name.lower() in TECH_PASS_KEYWORDS] # any(keyword in o.name.lower() for keyword in TECH_PASS_KEYWORDS)]
|
tech_outputs = [o for o in all_outputs if o.name.lower() in tech_pass_names] # TECH_PASS_KEYWORDS
|
||||||
# Regular outputs (excluding crypto and tech passes)
|
# Regular outputs (excluding crypto and tech passes)
|
||||||
regular_outputs = [o for o in all_outputs if o not in crypto_outputs and o not in tech_outputs]
|
regular_outputs = [o for o in all_outputs if o not in crypto_outputs and o not in tech_outputs]
|
||||||
else:
|
else:
|
||||||
|
@ -282,8 +282,8 @@ class RT_OT_conform_collection_hierarchy(Operator):
|
|||||||
for _, v in affected_items_dict.items():
|
for _, v in affected_items_dict.items():
|
||||||
for item, attr_list in v.items():
|
for item, attr_list in v.items():
|
||||||
line = f'{item.name} : {", ".join(attr_list)}'
|
line = f'{item.name} : {", ".join(attr_list)}'
|
||||||
print(line)
|
print(line)
|
||||||
message.append(line)
|
message.append(line)
|
||||||
|
|
||||||
fn.show_message_box(
|
fn.show_message_box(
|
||||||
message=message,
|
message=message,
|
||||||
|
@ -7,9 +7,6 @@ from bpy.props import (StringProperty,
|
|||||||
EnumProperty,
|
EnumProperty,
|
||||||
CollectionProperty)
|
CollectionProperty)
|
||||||
|
|
||||||
from ..constant import TECH_PASS_KEYWORDS
|
|
||||||
|
|
||||||
|
|
||||||
class RT_OT_outputs_search_and_replace(bpy.types.Operator):
|
class RT_OT_outputs_search_and_replace(bpy.types.Operator):
|
||||||
bl_idname = "rt.outputs_search_and_replace"
|
bl_idname = "rt.outputs_search_and_replace"
|
||||||
bl_label = "Search And Replace Outputs Paths"
|
bl_label = "Search And Replace Outputs Paths"
|
||||||
|
@ -122,6 +122,7 @@ class RT_PG_selectable_prop(bpy.types.PropertyGroup):
|
|||||||
socket_name: StringProperty(name="Source socket Name") # Source socket name as reference
|
socket_name: StringProperty(name="Source socket Name") # Source socket name as reference
|
||||||
select: BoolProperty(name="Selected", default=True)
|
select: BoolProperty(name="Selected", default=True)
|
||||||
is_linked: BoolProperty(name="Linked", default=False)
|
is_linked: BoolProperty(name="Linked", default=False)
|
||||||
|
is_tech_pass: BoolProperty(name="Tech Pass", default=False)
|
||||||
# is_valid: BoolProperty(name="Valid", default=True)
|
# is_valid: BoolProperty(name="Valid", default=True)
|
||||||
|
|
||||||
## Specific to render layer nodes
|
## Specific to render layer nodes
|
||||||
@ -337,6 +338,14 @@ class RT_OT_create_output_layers(bpy.types.Operator):
|
|||||||
# self.blend_name = Path(self.blend_name).stem
|
# self.blend_name = Path(self.blend_name).stem
|
||||||
# self.version = fn.get_rightmost_number_in_string(self.blend_name)
|
# self.version = fn.get_rightmost_number_in_string(self.blend_name)
|
||||||
|
|
||||||
|
## tech_passes
|
||||||
|
prefs = fn.get_addon_prefs()
|
||||||
|
tech_passes_names = prefs.tech_passes_names
|
||||||
|
if prefs.use_env_technical_passes:
|
||||||
|
tech_passes_names = os.getenv('RENDERTOOLBOX_TECH_PASSES', prefs.tech_passes_names)
|
||||||
|
|
||||||
|
tech_passes_names = [tp.strip().lower() for tp in tech_passes_names.split(',') if tp.strip()]
|
||||||
|
|
||||||
selected = [n for n in context.scene.node_tree.nodes if n.select and n.type != 'OUTPUT_FILE']
|
selected = [n for n in context.scene.node_tree.nodes if n.select and n.type != 'OUTPUT_FILE']
|
||||||
if not selected:
|
if not selected:
|
||||||
self.report({'ERROR'}, 'No render layer nodes selected')
|
self.report({'ERROR'}, 'No render layer nodes selected')
|
||||||
@ -382,6 +391,10 @@ class RT_OT_create_output_layers(bpy.types.Operator):
|
|||||||
item.is_linked = True
|
item.is_linked = True
|
||||||
item.select = False
|
item.select = False
|
||||||
|
|
||||||
|
if item.socket_name.lower() in tech_passes_names:
|
||||||
|
item.is_tech_pass = True
|
||||||
|
|
||||||
|
|
||||||
## Assign default template values (Disabled for now)
|
## Assign default template values (Disabled for now)
|
||||||
## TRIGGER update to firstly fill template slot/names
|
## TRIGGER update to firstly fill template slot/names
|
||||||
# self.template_file_slot = context.scene.render_toolbox.default_file_slot
|
# self.template_file_slot = context.scene.render_toolbox.default_file_slot
|
||||||
@ -401,7 +414,7 @@ class RT_OT_create_output_layers(bpy.types.Operator):
|
|||||||
self.scene_name = ref.scene.name
|
self.scene_name = ref.scene.name
|
||||||
self.view_layer_name = ref.layer
|
self.view_layer_name = ref.layer
|
||||||
self.final_base_path_template = ''
|
self.final_base_path_template = ''
|
||||||
return context.window_manager.invoke_props_dialog(self, width=500)
|
return context.window_manager.invoke_props_dialog(self, width=530)
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
@ -483,8 +496,12 @@ Possible variables:
|
|||||||
col.prop(self, 'exr_codec')
|
col.prop(self, 'exr_codec')
|
||||||
col.row().prop(self, 'color_depth', expand=True)
|
col.row().prop(self, 'color_depth', expand=True)
|
||||||
col.prop(self, 'split_tech_passes')
|
col.prop(self, 'split_tech_passes')
|
||||||
if self.split_tech_passes:
|
|
||||||
col.prop(self, 'tech_exr_codec', text='Tech Passes Codec')
|
row = col.row()
|
||||||
|
row.prop(self, 'tech_exr_codec', text='Tech Passes Codec')
|
||||||
|
row.active = self.split_tech_passes
|
||||||
|
# if self.split_tech_passes:
|
||||||
|
# col.prop(self, 'tech_exr_codec', text='Tech Passes Codec')
|
||||||
|
|
||||||
search_row = layout.row()
|
search_row = layout.row()
|
||||||
op = search_row.operator("rt.colprop_search_and_replace", icon='BORDERMOVE')
|
op = search_row.operator("rt.colprop_search_and_replace", icon='BORDERMOVE')
|
||||||
@ -520,6 +537,7 @@ Possible variables:
|
|||||||
col.label(text=display_node_name, icon='NODE_SEL')
|
col.label(text=display_node_name, icon='NODE_SEL')
|
||||||
|
|
||||||
row = col.row()
|
row = col.row()
|
||||||
|
row.active = item.select
|
||||||
if item.is_linked:
|
if item.is_linked:
|
||||||
row.label(text='', icon='LINKED') # NODETREE
|
row.label(text='', icon='LINKED') # NODETREE
|
||||||
else:
|
else:
|
||||||
@ -529,7 +547,7 @@ Possible variables:
|
|||||||
display_name = item.socket_name
|
display_name = item.socket_name
|
||||||
if 'crypto' in display_name.lower():
|
if 'crypto' in display_name.lower():
|
||||||
display_name = f'{display_name} -> 32bit output node'
|
display_name = f'{display_name} -> 32bit output node'
|
||||||
elif self.split_tech_passes and display_name.lower() in TECH_PASS_KEYWORDS:
|
elif self.split_tech_passes and item.is_tech_pass:
|
||||||
display_name = f'{display_name} -> Tech pass'
|
display_name = f'{display_name} -> Tech pass'
|
||||||
|
|
||||||
row.label(text=display_name)
|
row.label(text=display_name)
|
||||||
@ -546,6 +564,9 @@ Possible variables:
|
|||||||
elif self.name_type == 'template':
|
elif self.name_type == 'template':
|
||||||
row.prop(item, 'name_from_template', text='')
|
row.prop(item, 'name_from_template', text='')
|
||||||
|
|
||||||
|
if self.split_tech_passes:
|
||||||
|
row.prop(item, 'is_tech_pass', text='')
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
|
||||||
# Build exclude dict from selection
|
# Build exclude dict from selection
|
||||||
@ -560,6 +581,8 @@ Possible variables:
|
|||||||
# elif item.socket_name != item.name:
|
# elif item.socket_name != item.name:
|
||||||
# remap_names[item.socket_name] = item.name
|
# remap_names[item.socket_name] = item.name
|
||||||
|
|
||||||
|
tech_pass_names = []
|
||||||
|
|
||||||
if len(self.socket_collection):
|
if len(self.socket_collection):
|
||||||
for item in self.socket_collection:
|
for item in self.socket_collection:
|
||||||
final_name = item.name
|
final_name = item.name
|
||||||
@ -580,6 +603,9 @@ Possible variables:
|
|||||||
remap_names.setdefault(item.node_name, {})[item.socket_name] = final_name
|
remap_names.setdefault(item.node_name, {})[item.socket_name] = final_name
|
||||||
# remap_names[item.socket_name] = final_name
|
# remap_names[item.socket_name] = final_name
|
||||||
|
|
||||||
|
if self.split_tech_passes and item.is_tech_pass:
|
||||||
|
tech_pass_names.append(item.socket_name.lower())
|
||||||
|
|
||||||
## Handle default file format
|
## Handle default file format
|
||||||
file_ext = self.file_format
|
file_ext = self.file_format
|
||||||
if self.file_format == 'NONE':
|
if self.file_format == 'NONE':
|
||||||
@ -615,7 +641,7 @@ Possible variables:
|
|||||||
excludes=excludes,
|
excludes=excludes,
|
||||||
remap_names=remap_names,
|
remap_names=remap_names,
|
||||||
file_format=file_format,
|
file_format=file_format,
|
||||||
split_tech_passes=self.split_tech_passes,
|
tech_pass_names=tech_pass_names,
|
||||||
tech_file_format=tech_file_format,
|
tech_file_format=tech_file_format,
|
||||||
template=self.final_base_path_template)
|
template=self.final_base_path_template)
|
||||||
|
|
||||||
|
@ -18,11 +18,12 @@ from bpy.app.handlers import persistent
|
|||||||
class RT_prefs(bpy.types.AddonPreferences):
|
class RT_prefs(bpy.types.AddonPreferences):
|
||||||
bl_idname = __package__
|
bl_idname = __package__
|
||||||
|
|
||||||
|
## path templates
|
||||||
use_env_base_path_templates : BoolProperty(
|
use_env_base_path_templates : BoolProperty(
|
||||||
name="Use Environment Base Path Templates",
|
name="Use Environment Base Path Templates",
|
||||||
description="Use environmenet variables to set base path for file output templates\
|
description="Use environmenet variables to set base path for file output templates\
|
||||||
\nFollowing env variable are available:\
|
\nFollowing env variable are available:\
|
||||||
\nRENDERTOOLBOX_EXR_PATH_TEMPLATE fo single base path file output\
|
\nRENDERTOOLBOX_EXR_PATH_TEMPLATE for single base path file output\
|
||||||
\nRENDERTOOLBOX_MULTILAYER_PATH_TEMPLATE for multilayer base path file output",
|
\nRENDERTOOLBOX_MULTILAYER_PATH_TEMPLATE for multilayer base path file output",
|
||||||
default=True,
|
default=True,
|
||||||
)
|
)
|
||||||
@ -39,24 +40,74 @@ class RT_prefs(bpy.types.AddonPreferences):
|
|||||||
default="//render/{node_label}/{node_label}_",
|
default="//render/{node_label}/{node_label}_",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
## Tech passes
|
||||||
|
use_env_technical_passes : BoolProperty(
|
||||||
|
name="Use Environment Technical Passes",
|
||||||
|
description="Use environmenet variables to set the technical passes name:\
|
||||||
|
\nRENDERTOOLBOX_TECH_PASSES",
|
||||||
|
default=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
tech_passes_names : StringProperty(
|
||||||
|
name="Tech Passes Names",
|
||||||
|
description="Comma separated list of tech passes names to use for file output creation (Use lossless EXR 32bit)",
|
||||||
|
default="uv, normal, depth, position, vector, ao",
|
||||||
|
)
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
layout.use_property_split = True
|
layout.use_property_split = True
|
||||||
layout.use_property_decorate = False
|
layout.use_property_decorate = False
|
||||||
|
|
||||||
layout.prop(self, "use_env_base_path_templates", text="Use Environment Base Path Templates")
|
|
||||||
col = layout.column()
|
col = layout.column()
|
||||||
|
col.label(text="Output files path templates:")
|
||||||
|
col.prop(self, "use_env_base_path_templates", text="Use Environment Base Path Templates")
|
||||||
# col.active = not self.use_env_base_path_templates
|
# col.active = not self.use_env_base_path_templates
|
||||||
col.prop(self, "base_path_template", text="Base Path Template")
|
col.prop(self, "base_path_template", text="Base Path Template")
|
||||||
col.prop(self, "base_path_multilayer_template", text="Base Path Multilayer Template")
|
col.prop(self, "base_path_multilayer_template", text="Base Path Multilayer Template")
|
||||||
|
|
||||||
if self.use_env_base_path_templates:
|
if self.use_env_base_path_templates:
|
||||||
col.separator()
|
box=col.box()
|
||||||
col.label(text="Environment variables will override above templates if set", icon='INFO')
|
boxcol = box.column()
|
||||||
# col.label(text="RENDERTOOLBOX_EXR_PATH_TEMPLATE for single base path file output")
|
env_path_template = os.getenv('RENDERTOOLBOX_EXR_PATH_TEMPLATE')
|
||||||
# col.label(text="RENDERTOOLBOX_MULTILAYER_PATH_TEMPLATE for multilayer base path file output")
|
env_multi_template = os.getenv('RENDERTOOLBOX_MULTILAYER_PATH_TEMPLATE')
|
||||||
col.label(text='If environment variables are not found, preferences will be used instead')
|
|
||||||
|
|
||||||
|
if not env_path_template or not env_multi_template:
|
||||||
|
boxcol.label(text="Environment variables override above templates if set", icon='INFO')
|
||||||
|
|
||||||
|
if env_path_template or env_multi_template:
|
||||||
|
boxcol.label(text="Environment variables found:", icon='CHECKMARK')
|
||||||
|
|
||||||
|
if env_path_template:
|
||||||
|
boxcol.label(text=f"RENDERTOOLBOX_EXR_PATH_TEMPLATE:")
|
||||||
|
boxcol.label(text=env_path_template)
|
||||||
|
else:
|
||||||
|
boxcol.label(text="RENDERTOOLBOX_EXR_PATH_TEMPLATE env not found, using preferences ") # (single base path file output)
|
||||||
|
|
||||||
|
if env_multi_template:
|
||||||
|
boxcol.label(text=f"RENDERTOOLBOX_MULTILAYER_PATH_TEMPLATE:")
|
||||||
|
boxcol.label(text=env_multi_template)
|
||||||
|
else:
|
||||||
|
boxcol.label(text="RENDERTOOLBOX_MULTILAYER_PATH_TEMPLATE env not found, using preferences") # (multilayer base path file output)
|
||||||
|
|
||||||
|
layout.separator()
|
||||||
|
col = layout.column()
|
||||||
|
col.label(text="Default Separated Technical Passes:")
|
||||||
|
col.prop(self, "use_env_technical_passes", text="Use Environment Technical Passes")
|
||||||
|
|
||||||
|
col.prop(self, "tech_passes_names", text="Technical Passes Names", placeholder="e.g. uv, normal, depth, vector, ...")
|
||||||
|
if self.use_env_technical_passes:
|
||||||
|
box=col.box()
|
||||||
|
boxcol = box.column()
|
||||||
|
|
||||||
|
env_tech_pass = os.getenv('RENDERTOOLBOX_TECH_PASSES')
|
||||||
|
if env_tech_pass:
|
||||||
|
boxcol.label(text="Environment variable found:", icon='CHECKMARK')
|
||||||
|
boxcol.label(text=f"RENDERTOOLBOX_TECH_PASSES:")
|
||||||
|
boxcol.label(text=env_tech_pass)
|
||||||
|
else:
|
||||||
|
boxcol.label(text="Environment variable override tech passes names if set", icon='INFO')
|
||||||
|
boxcol.label(text='RENDERTOOLBOX_TECH_PASSES env not found, using preferences')
|
||||||
|
|
||||||
# region Handlers
|
# region Handlers
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user