mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-02 08:54:53 +01:00
[Automated] Merged develop into main
This commit is contained in:
commit
7caf3fc9e7
10 changed files with 285 additions and 221 deletions
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
|
@ -35,6 +35,7 @@ body:
|
|||
label: Version
|
||||
description: What version are you running? Look to OpenPype Tray
|
||||
options:
|
||||
- 3.18.7-nightly.5
|
||||
- 3.18.7-nightly.4
|
||||
- 3.18.7-nightly.3
|
||||
- 3.18.7-nightly.2
|
||||
|
|
@ -134,7 +135,6 @@ body:
|
|||
- 3.15.11-nightly.1
|
||||
- 3.15.10
|
||||
- 3.15.10-nightly.2
|
||||
- 3.15.10-nightly.1
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ from pathlib import Path
|
|||
|
||||
import bpy
|
||||
|
||||
from openpype import AYON_SERVER_ENABLED
|
||||
from openpype.settings import get_project_settings
|
||||
from openpype.pipeline import get_current_project_name
|
||||
|
||||
|
|
@ -47,6 +48,22 @@ def get_multilayer(settings):
|
|||
["multilayer_exr"])
|
||||
|
||||
|
||||
def get_renderer(settings):
|
||||
"""Get renderer from blender settings."""
|
||||
|
||||
return (settings["blender"]
|
||||
["RenderSettings"]
|
||||
["renderer"])
|
||||
|
||||
|
||||
def get_compositing(settings):
|
||||
"""Get compositing from blender settings."""
|
||||
|
||||
return (settings["blender"]
|
||||
["RenderSettings"]
|
||||
["compositing"])
|
||||
|
||||
|
||||
def get_render_product(output_path, name, aov_sep):
|
||||
"""
|
||||
Generate the path to the render product. Blender interprets the `#`
|
||||
|
|
@ -91,66 +108,121 @@ def set_render_format(ext, multilayer):
|
|||
image_settings.file_format = "TIFF"
|
||||
|
||||
|
||||
def set_render_passes(settings):
|
||||
aov_list = (settings["blender"]
|
||||
["RenderSettings"]
|
||||
["aov_list"])
|
||||
|
||||
custom_passes = (settings["blender"]
|
||||
["RenderSettings"]
|
||||
["custom_passes"])
|
||||
def set_render_passes(settings, renderer):
|
||||
aov_list = set(settings["blender"]["RenderSettings"]["aov_list"])
|
||||
custom_passes = settings["blender"]["RenderSettings"]["custom_passes"]
|
||||
|
||||
# Common passes for both renderers
|
||||
vl = bpy.context.view_layer
|
||||
|
||||
# Data Passes
|
||||
vl.use_pass_combined = "combined" in aov_list
|
||||
vl.use_pass_z = "z" in aov_list
|
||||
vl.use_pass_mist = "mist" in aov_list
|
||||
vl.use_pass_normal = "normal" in aov_list
|
||||
|
||||
# Light Passes
|
||||
vl.use_pass_diffuse_direct = "diffuse_light" in aov_list
|
||||
vl.use_pass_diffuse_color = "diffuse_color" in aov_list
|
||||
vl.use_pass_glossy_direct = "specular_light" in aov_list
|
||||
vl.use_pass_glossy_color = "specular_color" in aov_list
|
||||
vl.eevee.use_pass_volume_direct = "volume_light" in aov_list
|
||||
vl.use_pass_emit = "emission" in aov_list
|
||||
vl.use_pass_environment = "environment" in aov_list
|
||||
vl.use_pass_shadow = "shadow" in aov_list
|
||||
vl.use_pass_ambient_occlusion = "ao" in aov_list
|
||||
|
||||
cycles = vl.cycles
|
||||
# Cryptomatte Passes
|
||||
vl.use_pass_cryptomatte_object = "cryptomatte_object" in aov_list
|
||||
vl.use_pass_cryptomatte_material = "cryptomatte_material" in aov_list
|
||||
vl.use_pass_cryptomatte_asset = "cryptomatte_asset" in aov_list
|
||||
|
||||
cycles.denoising_store_passes = "denoising" in aov_list
|
||||
cycles.use_pass_volume_direct = "volume_direct" in aov_list
|
||||
cycles.use_pass_volume_indirect = "volume_indirect" in aov_list
|
||||
if renderer == "BLENDER_EEVEE":
|
||||
# Eevee exclusive passes
|
||||
eevee = vl.eevee
|
||||
|
||||
# Light Passes
|
||||
vl.use_pass_shadow = "shadow" in aov_list
|
||||
eevee.use_pass_volume_direct = "volume_light" in aov_list
|
||||
|
||||
# Effects Passes
|
||||
eevee.use_pass_bloom = "bloom" in aov_list
|
||||
eevee.use_pass_transparent = "transparent" in aov_list
|
||||
|
||||
# Cryptomatte Passes
|
||||
vl.use_pass_cryptomatte_accurate = "cryptomatte_accurate" in aov_list
|
||||
elif renderer == "CYCLES":
|
||||
# Cycles exclusive passes
|
||||
cycles = vl.cycles
|
||||
|
||||
# Data Passes
|
||||
vl.use_pass_position = "position" in aov_list
|
||||
vl.use_pass_vector = "vector" in aov_list
|
||||
vl.use_pass_uv = "uv" in aov_list
|
||||
cycles.denoising_store_passes = "denoising" in aov_list
|
||||
vl.use_pass_object_index = "object_index" in aov_list
|
||||
vl.use_pass_material_index = "material_index" in aov_list
|
||||
cycles.pass_debug_sample_count = "sample_count" in aov_list
|
||||
|
||||
# Light Passes
|
||||
vl.use_pass_diffuse_indirect = "diffuse_indirect" in aov_list
|
||||
vl.use_pass_glossy_indirect = "specular_indirect" in aov_list
|
||||
vl.use_pass_transmission_direct = "transmission_direct" in aov_list
|
||||
vl.use_pass_transmission_indirect = "transmission_indirect" in aov_list
|
||||
vl.use_pass_transmission_color = "transmission_color" in aov_list
|
||||
cycles.use_pass_volume_direct = "volume_light" in aov_list
|
||||
cycles.use_pass_volume_indirect = "volume_indirect" in aov_list
|
||||
cycles.use_pass_shadow_catcher = "shadow" in aov_list
|
||||
|
||||
aovs_names = [aov.name for aov in vl.aovs]
|
||||
for cp in custom_passes:
|
||||
cp_name = cp[0]
|
||||
cp_name = cp["attribute"] if AYON_SERVER_ENABLED else cp[0]
|
||||
if cp_name not in aovs_names:
|
||||
aov = vl.aovs.add()
|
||||
aov.name = cp_name
|
||||
else:
|
||||
aov = vl.aovs[cp_name]
|
||||
aov.type = cp[1].get("type", "VALUE")
|
||||
aov.type = (cp["value"]
|
||||
if AYON_SERVER_ENABLED else cp[1].get("type", "VALUE"))
|
||||
|
||||
return aov_list, custom_passes
|
||||
return list(aov_list), custom_passes
|
||||
|
||||
|
||||
def set_node_tree(output_path, name, aov_sep, ext, multilayer):
|
||||
def _create_aov_slot(name, aov_sep, slots, rpass_name, multi_exr, output_path):
|
||||
filename = f"{name}{aov_sep}{rpass_name}.####"
|
||||
slot = slots.new(rpass_name if multi_exr else filename)
|
||||
filepath = str(output_path / filename.lstrip("/"))
|
||||
|
||||
return slot, filepath
|
||||
|
||||
|
||||
def set_node_tree(
|
||||
output_path, render_product, name, aov_sep, ext, multilayer, compositing
|
||||
):
|
||||
# Set the scene to use the compositor node tree to render
|
||||
bpy.context.scene.use_nodes = True
|
||||
|
||||
tree = bpy.context.scene.node_tree
|
||||
|
||||
# Get the Render Layers node
|
||||
rl_node = None
|
||||
comp_layer_type = "CompositorNodeRLayers"
|
||||
output_type = "CompositorNodeOutputFile"
|
||||
compositor_type = "CompositorNodeComposite"
|
||||
|
||||
# Get the Render Layer, Composite and the previous output nodes
|
||||
render_layer_node = None
|
||||
composite_node = None
|
||||
old_output_node = None
|
||||
for node in tree.nodes:
|
||||
if node.bl_idname == "CompositorNodeRLayers":
|
||||
rl_node = node
|
||||
if node.bl_idname == comp_layer_type:
|
||||
render_layer_node = node
|
||||
elif node.bl_idname == compositor_type:
|
||||
composite_node = node
|
||||
elif node.bl_idname == output_type and "AYON" in node.name:
|
||||
old_output_node = node
|
||||
if render_layer_node and composite_node and old_output_node:
|
||||
break
|
||||
|
||||
# If there's not a Render Layers node, we create it
|
||||
if not rl_node:
|
||||
rl_node = tree.nodes.new("CompositorNodeRLayers")
|
||||
if not render_layer_node:
|
||||
render_layer_node = tree.nodes.new(comp_layer_type)
|
||||
|
||||
# Get the enabled output sockets, that are the active passes for the
|
||||
# render.
|
||||
|
|
@ -158,48 +230,81 @@ def set_node_tree(output_path, name, aov_sep, ext, multilayer):
|
|||
exclude_sockets = ["Image", "Alpha", "Noisy Image"]
|
||||
passes = [
|
||||
socket
|
||||
for socket in rl_node.outputs
|
||||
for socket in render_layer_node.outputs
|
||||
if socket.enabled and socket.name not in exclude_sockets
|
||||
]
|
||||
|
||||
# Remove all output nodes
|
||||
for node in tree.nodes:
|
||||
if node.bl_idname == "CompositorNodeOutputFile":
|
||||
tree.nodes.remove(node)
|
||||
|
||||
# Create a new output node
|
||||
output = tree.nodes.new("CompositorNodeOutputFile")
|
||||
output = tree.nodes.new(output_type)
|
||||
|
||||
image_settings = bpy.context.scene.render.image_settings
|
||||
output.format.file_format = image_settings.file_format
|
||||
|
||||
slots = None
|
||||
|
||||
# In case of a multilayer exr, we don't need to use the output node,
|
||||
# because the blender render already outputs a multilayer exr.
|
||||
if ext == "exr" and multilayer:
|
||||
output.layer_slots.clear()
|
||||
return []
|
||||
multi_exr = ext == "exr" and multilayer
|
||||
slots = output.layer_slots if multi_exr else output.file_slots
|
||||
output.base_path = render_product if multi_exr else str(output_path)
|
||||
|
||||
output.file_slots.clear()
|
||||
output.base_path = str(output_path)
|
||||
slots.clear()
|
||||
|
||||
aov_file_products = []
|
||||
|
||||
old_links = {
|
||||
link.from_socket.name: link for link in tree.links
|
||||
if link.to_node == old_output_node}
|
||||
|
||||
# Create a new socket for the beauty output
|
||||
pass_name = "rgba" if multi_exr else "beauty"
|
||||
slot, _ = _create_aov_slot(
|
||||
name, aov_sep, slots, pass_name, multi_exr, output_path)
|
||||
tree.links.new(render_layer_node.outputs["Image"], slot)
|
||||
|
||||
if compositing:
|
||||
# Create a new socket for the composite output
|
||||
pass_name = "composite"
|
||||
comp_socket, filepath = _create_aov_slot(
|
||||
name, aov_sep, slots, pass_name, multi_exr, output_path)
|
||||
aov_file_products.append(("Composite", filepath))
|
||||
|
||||
# For each active render pass, we add a new socket to the output node
|
||||
# and link it
|
||||
for render_pass in passes:
|
||||
filepath = f"{name}{aov_sep}{render_pass.name}.####"
|
||||
for rpass in passes:
|
||||
slot, filepath = _create_aov_slot(
|
||||
name, aov_sep, slots, rpass.name, multi_exr, output_path)
|
||||
aov_file_products.append((rpass.name, filepath))
|
||||
|
||||
output.file_slots.new(filepath)
|
||||
# If the rpass was not connected with the old output node, we connect
|
||||
# it with the new one.
|
||||
if not old_links.get(rpass.name):
|
||||
tree.links.new(rpass, slot)
|
||||
|
||||
filename = str(output_path / filepath.lstrip("/"))
|
||||
for link in list(old_links.values()):
|
||||
# Check if the socket is still available in the new output node.
|
||||
socket = output.inputs.get(link.to_socket.name)
|
||||
# If it is, we connect it with the new output node.
|
||||
if socket:
|
||||
tree.links.new(link.from_socket, socket)
|
||||
# Then, we remove the old link.
|
||||
tree.links.remove(link)
|
||||
|
||||
aov_file_products.append((render_pass.name, filename))
|
||||
# If there's a composite node, we connect its input with the new output
|
||||
if compositing and composite_node:
|
||||
for link in tree.links:
|
||||
if link.to_node == composite_node:
|
||||
tree.links.new(link.from_socket, comp_socket)
|
||||
break
|
||||
|
||||
node_input = output.inputs[-1]
|
||||
if old_output_node:
|
||||
output.location = old_output_node.location
|
||||
tree.nodes.remove(old_output_node)
|
||||
|
||||
tree.links.new(render_pass, node_input)
|
||||
output.name = "AYON File Output"
|
||||
output.label = "AYON File Output"
|
||||
|
||||
return aov_file_products
|
||||
return [] if multi_exr else aov_file_products
|
||||
|
||||
|
||||
def imprint_render_settings(node, data):
|
||||
|
|
@ -228,17 +333,23 @@ def prepare_rendering(asset_group):
|
|||
aov_sep = get_aov_separator(settings)
|
||||
ext = get_image_format(settings)
|
||||
multilayer = get_multilayer(settings)
|
||||
renderer = get_renderer(settings)
|
||||
compositing = get_compositing(settings)
|
||||
|
||||
set_render_format(ext, multilayer)
|
||||
aov_list, custom_passes = set_render_passes(settings)
|
||||
bpy.context.scene.render.engine = renderer
|
||||
aov_list, custom_passes = set_render_passes(settings, renderer)
|
||||
|
||||
output_path = Path.joinpath(dirpath, render_folder, file_name)
|
||||
|
||||
render_product = get_render_product(output_path, name, aov_sep)
|
||||
aov_file_product = set_node_tree(
|
||||
output_path, name, aov_sep, ext, multilayer)
|
||||
output_path, render_product, name, aov_sep,
|
||||
ext, multilayer, compositing)
|
||||
|
||||
bpy.context.scene.render.filepath = render_product
|
||||
# Clear the render filepath, so that the output is handled only by the
|
||||
# output node in the compositor.
|
||||
bpy.context.scene.render.filepath = ""
|
||||
|
||||
render_settings = {
|
||||
"render_folder": render_folder,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
"""Create render."""
|
||||
import bpy
|
||||
|
||||
from openpype.lib import version_up
|
||||
from openpype.hosts.blender.api import plugin
|
||||
from openpype.hosts.blender.api.render_lib import prepare_rendering
|
||||
from openpype.hosts.blender.api.workio import save_file
|
||||
|
||||
|
||||
class CreateRenderlayer(plugin.BaseCreator):
|
||||
|
|
@ -37,6 +39,7 @@ class CreateRenderlayer(plugin.BaseCreator):
|
|||
# settings. Even the validator to check that the file is saved will
|
||||
# detect the file as saved, even if it isn't. The only solution for
|
||||
# now it is to force the file to be saved.
|
||||
bpy.ops.wm.save_as_mainfile(filepath=bpy.data.filepath)
|
||||
filepath = version_up(bpy.data.filepath)
|
||||
save_file(filepath, copy=False)
|
||||
|
||||
return collection
|
||||
|
|
|
|||
|
|
@ -28,15 +28,27 @@ class ValidateDeadlinePublish(pyblish.api.InstancePlugin,
|
|||
def process(self, instance):
|
||||
if not self.is_active(instance.data):
|
||||
return
|
||||
|
||||
tree = bpy.context.scene.node_tree
|
||||
output_type = "CompositorNodeOutputFile"
|
||||
output_node = None
|
||||
# Remove all output nodes that inlcude "AYON" in the name.
|
||||
# There should be only one.
|
||||
for node in tree.nodes:
|
||||
if node.bl_idname == output_type and "AYON" in node.name:
|
||||
output_node = node
|
||||
break
|
||||
if not output_node:
|
||||
raise PublishValidationError(
|
||||
"No output node found in the compositor tree."
|
||||
)
|
||||
filepath = bpy.data.filepath
|
||||
file = os.path.basename(filepath)
|
||||
filename, ext = os.path.splitext(file)
|
||||
if filename not in bpy.context.scene.render.filepath:
|
||||
if filename not in output_node.base_path:
|
||||
raise PublishValidationError(
|
||||
"Render output folder "
|
||||
"doesn't match the blender scene name! "
|
||||
"Use Repair action to "
|
||||
"fix the folder file path."
|
||||
"Render output folder doesn't match the blender scene name! "
|
||||
"Use Repair action to fix the folder file path."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
|
|
|||
|
|
@ -321,7 +321,6 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin,
|
|||
|
||||
return deadline_publish_job_id
|
||||
|
||||
|
||||
def process(self, instance):
|
||||
# type: (pyblish.api.Instance) -> None
|
||||
"""Process plugin.
|
||||
|
|
@ -338,151 +337,6 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin,
|
|||
self.log.debug("Skipping local instance.")
|
||||
return
|
||||
|
||||
data = instance.data.copy()
|
||||
context = instance.context
|
||||
self.context = context
|
||||
self.anatomy = instance.context.data["anatomy"]
|
||||
|
||||
asset = data.get("asset") or context.data["asset"]
|
||||
subset = data.get("subset")
|
||||
|
||||
start = instance.data.get("frameStart")
|
||||
if start is None:
|
||||
start = context.data["frameStart"]
|
||||
|
||||
end = instance.data.get("frameEnd")
|
||||
if end is None:
|
||||
end = context.data["frameEnd"]
|
||||
|
||||
handle_start = instance.data.get("handleStart")
|
||||
if handle_start is None:
|
||||
handle_start = context.data["handleStart"]
|
||||
|
||||
handle_end = instance.data.get("handleEnd")
|
||||
if handle_end is None:
|
||||
handle_end = context.data["handleEnd"]
|
||||
|
||||
fps = instance.data.get("fps")
|
||||
if fps is None:
|
||||
fps = context.data["fps"]
|
||||
|
||||
if data.get("extendFrames", False):
|
||||
start, end = self._extend_frames(
|
||||
asset,
|
||||
subset,
|
||||
start,
|
||||
end,
|
||||
data["overrideExistingFrame"])
|
||||
|
||||
try:
|
||||
source = data["source"]
|
||||
except KeyError:
|
||||
source = context.data["currentFile"]
|
||||
|
||||
success, rootless_path = (
|
||||
self.anatomy.find_root_template_from_path(source)
|
||||
)
|
||||
if success:
|
||||
source = rootless_path
|
||||
|
||||
else:
|
||||
# `rootless_path` is not set to `source` if none of roots match
|
||||
self.log.warning((
|
||||
"Could not find root path for remapping \"{}\"."
|
||||
" This may cause issues."
|
||||
).format(source))
|
||||
|
||||
family = "render"
|
||||
if ("prerender" in instance.data["families"] or
|
||||
"prerender.farm" in instance.data["families"]):
|
||||
family = "prerender"
|
||||
families = [family]
|
||||
|
||||
# pass review to families if marked as review
|
||||
do_not_add_review = False
|
||||
if data.get("review"):
|
||||
families.append("review")
|
||||
elif data.get("review") is False:
|
||||
self.log.debug("Instance has review explicitly disabled.")
|
||||
do_not_add_review = True
|
||||
|
||||
instance_skeleton_data = {
|
||||
"family": family,
|
||||
"subset": subset,
|
||||
"families": families,
|
||||
"asset": asset,
|
||||
"frameStart": start,
|
||||
"frameEnd": end,
|
||||
"handleStart": handle_start,
|
||||
"handleEnd": handle_end,
|
||||
"frameStartHandle": start - handle_start,
|
||||
"frameEndHandle": end + handle_end,
|
||||
"comment": instance.data["comment"],
|
||||
"fps": fps,
|
||||
"source": source,
|
||||
"extendFrames": data.get("extendFrames"),
|
||||
"overrideExistingFrame": data.get("overrideExistingFrame"),
|
||||
"pixelAspect": data.get("pixelAspect", 1),
|
||||
"resolutionWidth": data.get("resolutionWidth", 1920),
|
||||
"resolutionHeight": data.get("resolutionHeight", 1080),
|
||||
"multipartExr": data.get("multipartExr", False),
|
||||
"jobBatchName": data.get("jobBatchName", ""),
|
||||
"useSequenceForReview": data.get("useSequenceForReview", True),
|
||||
# map inputVersions `ObjectId` -> `str` so json supports it
|
||||
"inputVersions": list(map(str, data.get("inputVersions", []))),
|
||||
"colorspace": instance.data.get("colorspace"),
|
||||
"stagingDir_persistent": instance.data.get(
|
||||
"stagingDir_persistent", False
|
||||
)
|
||||
}
|
||||
|
||||
# skip locking version if we are creating v01
|
||||
instance_version = instance.data.get("version") # take this if exists
|
||||
if instance_version != 1:
|
||||
instance_skeleton_data["version"] = instance_version
|
||||
|
||||
# transfer specific families from original instance to new render
|
||||
for item in self.families_transfer:
|
||||
if item in instance.data.get("families", []):
|
||||
instance_skeleton_data["families"] += [item]
|
||||
|
||||
# transfer specific properties from original instance based on
|
||||
# mapping dictionary `instance_transfer`
|
||||
for key, values in self.instance_transfer.items():
|
||||
if key in instance.data.get("families", []):
|
||||
for v in values:
|
||||
instance_skeleton_data[v] = instance.data.get(v)
|
||||
|
||||
# look into instance data if representations are not having any
|
||||
# which are having tag `publish_on_farm` and include them
|
||||
for repre in instance.data.get("representations", []):
|
||||
staging_dir = repre.get("stagingDir")
|
||||
if staging_dir:
|
||||
success, rootless_staging_dir = (
|
||||
self.anatomy.find_root_template_from_path(
|
||||
staging_dir
|
||||
)
|
||||
)
|
||||
if success:
|
||||
repre["stagingDir"] = rootless_staging_dir
|
||||
else:
|
||||
self.log.warning((
|
||||
"Could not find root path for remapping \"{}\"."
|
||||
" This may cause issues on farm."
|
||||
).format(staging_dir))
|
||||
repre["stagingDir"] = staging_dir
|
||||
|
||||
if "publish_on_farm" in repre.get("tags"):
|
||||
# create representations attribute of not there
|
||||
if "representations" not in instance_skeleton_data.keys():
|
||||
instance_skeleton_data["representations"] = []
|
||||
|
||||
instance_skeleton_data["representations"].append(repre)
|
||||
|
||||
instances = None
|
||||
assert data.get("expectedFiles"), ("Submission from old Pype version"
|
||||
" - missing expectedFiles")
|
||||
|
||||
anatomy = instance.context.data["anatomy"]
|
||||
|
||||
instance_skeleton_data = create_skeleton_instance(
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ class PostFtrackHook(PostLaunchHook):
|
|||
if key in already_tested:
|
||||
continue
|
||||
|
||||
value = value.lower()
|
||||
value = [i.lower() for i in value]
|
||||
if actual_status in value or "__any__" in value:
|
||||
if key != "__ignore__":
|
||||
next_status_name = key
|
||||
|
|
|
|||
|
|
@ -22,7 +22,9 @@
|
|||
"aov_separator": "underscore",
|
||||
"image_format": "exr",
|
||||
"multilayer_exr": true,
|
||||
"aov_list": [],
|
||||
"renderer": "CYCLES",
|
||||
"compositing": true,
|
||||
"aov_list": ["combined"],
|
||||
"custom_passes": []
|
||||
},
|
||||
"workfile_builder": {
|
||||
|
|
|
|||
|
|
@ -103,6 +103,22 @@
|
|||
"type": "label",
|
||||
"label": "Note: Multilayer EXR is only used when output format type set to EXR."
|
||||
},
|
||||
{
|
||||
"key": "renderer",
|
||||
"label": "Renderer",
|
||||
"type": "enum",
|
||||
"multiselection": false,
|
||||
"defaults": "CYCLES",
|
||||
"enum_items": [
|
||||
{"CYCLES": "Cycles"},
|
||||
{"BLENDER_EEVEE": "Eevee"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "compositing",
|
||||
"type": "boolean",
|
||||
"label": "Enable Compositing"
|
||||
},
|
||||
{
|
||||
"key": "aov_list",
|
||||
"label": "AOVs to create",
|
||||
|
|
@ -110,23 +126,38 @@
|
|||
"multiselection": true,
|
||||
"defaults": "empty",
|
||||
"enum_items": [
|
||||
{"empty": "< empty >"},
|
||||
{"combined": "Combined"},
|
||||
{"z": "Z"},
|
||||
{"mist": "Mist"},
|
||||
{"normal": "Normal"},
|
||||
{"diffuse_light": "Diffuse Light"},
|
||||
{"position": "Position (Cycles Only)"},
|
||||
{"vector": "Vector (Cycles Only)"},
|
||||
{"uv": "UV (Cycles Only)"},
|
||||
{"denoising": "Denoising Data (Cycles Only)"},
|
||||
{"object_index": "Object Index (Cycles Only)"},
|
||||
{"material_index": "Material Index (Cycles Only)"},
|
||||
{"sample_count": "Sample Count (Cycles Only)"},
|
||||
{"diffuse_light": "Diffuse Light/Direct"},
|
||||
{"diffuse_indirect": "Diffuse Indirect (Cycles Only)"},
|
||||
{"diffuse_color": "Diffuse Color"},
|
||||
{"specular_light": "Specular Light"},
|
||||
{"specular_color": "Specular Color"},
|
||||
{"volume_light": "Volume Light"},
|
||||
{"specular_light": "Specular (Glossy) Light/Direct"},
|
||||
{"specular_indirect": "Specular (Glossy) Indirect (Cycles Only)"},
|
||||
{"specular_color": "Specular (Glossy) Color"},
|
||||
{"transmission_light": "Transmission Light/Direct (Cycles Only)"},
|
||||
{"transmission_indirect": "Transmission Indirect (Cycles Only)"},
|
||||
{"transmission_color": "Transmission Color (Cycles Only)"},
|
||||
{"volume_light": "Volume Light/Direct"},
|
||||
{"volume_indirect": "Volume Indirect (Cycles Only)"},
|
||||
{"emission": "Emission"},
|
||||
{"environment": "Environment"},
|
||||
{"shadow": "Shadow"},
|
||||
{"shadow": "Shadow/Shadow Catcher"},
|
||||
{"ao": "Ambient Occlusion"},
|
||||
{"denoising": "Denoising"},
|
||||
{"volume_direct": "Direct Volumetric Scattering"},
|
||||
{"volume_indirect": "Indirect Volumetric Scattering"}
|
||||
{"bloom": "Bloom (Eevee Only)"},
|
||||
{"transparent": "Transparent (Eevee Only)"},
|
||||
{"cryptomatte_object": "Cryptomatte Object"},
|
||||
{"cryptomatte_material": "Cryptomatte Material"},
|
||||
{"cryptomatte_asset": "Cryptomatte Asset"},
|
||||
{"cryptomatte_accurate": "Cryptomatte Accurate Mode (Eevee Only)"}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,6 +23,13 @@ def image_format_enum():
|
|||
]
|
||||
|
||||
|
||||
def renderers_enum():
|
||||
return [
|
||||
{"value": "CYCLES", "label": "Cycles"},
|
||||
{"value": "BLENDER_EEVEE", "label": "Eevee"},
|
||||
]
|
||||
|
||||
|
||||
def aov_list_enum():
|
||||
return [
|
||||
{"value": "empty", "label": "< none >"},
|
||||
|
|
@ -30,18 +37,52 @@ def aov_list_enum():
|
|||
{"value": "z", "label": "Z"},
|
||||
{"value": "mist", "label": "Mist"},
|
||||
{"value": "normal", "label": "Normal"},
|
||||
{"value": "diffuse_light", "label": "Diffuse Light"},
|
||||
{"value": "position", "label": "Position (Cycles Only)"},
|
||||
{"value": "vector", "label": "Vector (Cycles Only)"},
|
||||
{"value": "uv", "label": "UV (Cycles Only)"},
|
||||
{"value": "denoising", "label": "Denoising Data (Cycles Only)"},
|
||||
{"value": "object_index", "label": "Object Index (Cycles Only)"},
|
||||
{"value": "material_index", "label": "Material Index (Cycles Only)"},
|
||||
{"value": "sample_count", "label": "Sample Count (Cycles Only)"},
|
||||
{"value": "diffuse_light", "label": "Diffuse Light/Direct"},
|
||||
{
|
||||
"value": "diffuse_indirect",
|
||||
"label": "Diffuse Indirect (Cycles Only)"
|
||||
},
|
||||
{"value": "diffuse_color", "label": "Diffuse Color"},
|
||||
{"value": "specular_light", "label": "Specular Light"},
|
||||
{"value": "specular_color", "label": "Specular Color"},
|
||||
{"value": "volume_light", "label": "Volume Light"},
|
||||
{"value": "specular_light", "label": "Specular (Glossy) Light/Direct"},
|
||||
{
|
||||
"value": "specular_indirect",
|
||||
"label": "Specular (Glossy) Indirect (Cycles Only)"
|
||||
},
|
||||
{"value": "specular_color", "label": "Specular (Glossy) Color"},
|
||||
{
|
||||
"value": "transmission_light",
|
||||
"label": "Transmission Light/Direct (Cycles Only)"
|
||||
},
|
||||
{
|
||||
"value": "transmission_indirect",
|
||||
"label": "Transmission Indirect (Cycles Only)"
|
||||
},
|
||||
{
|
||||
"value": "transmission_color",
|
||||
"label": "Transmission Color (Cycles Only)"
|
||||
},
|
||||
{"value": "volume_light", "label": "Volume Light/Direct"},
|
||||
{"value": "volume_indirect", "label": "Volume Indirect (Cycles Only)"},
|
||||
{"value": "emission", "label": "Emission"},
|
||||
{"value": "environment", "label": "Environment"},
|
||||
{"value": "shadow", "label": "Shadow"},
|
||||
{"value": "shadow", "label": "Shadow/Shadow Catcher"},
|
||||
{"value": "ao", "label": "Ambient Occlusion"},
|
||||
{"value": "denoising", "label": "Denoising"},
|
||||
{"value": "volume_direct", "label": "Direct Volumetric Scattering"},
|
||||
{"value": "volume_indirect", "label": "Indirect Volumetric Scattering"}
|
||||
{"value": "bloom", "label": "Bloom (Eevee Only)"},
|
||||
{"value": "transparent", "label": "Transparent (Eevee Only)"},
|
||||
{"value": "cryptomatte_object", "label": "Cryptomatte Object"},
|
||||
{"value": "cryptomatte_material", "label": "Cryptomatte Material"},
|
||||
{"value": "cryptomatte_asset", "label": "Cryptomatte Asset"},
|
||||
{
|
||||
"value": "cryptomatte_accurate",
|
||||
"label": "Cryptomatte Accurate Mode (Eevee Only)"
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -81,6 +122,14 @@ class RenderSettingsModel(BaseSettingsModel):
|
|||
multilayer_exr: bool = SettingsField(
|
||||
title="Multilayer (EXR)"
|
||||
)
|
||||
renderer: str = SettingsField(
|
||||
"CYCLES",
|
||||
title="Renderer",
|
||||
enum_resolver=renderers_enum
|
||||
)
|
||||
compositing: bool = SettingsField(
|
||||
title="Enable Compositing"
|
||||
)
|
||||
aov_list: list[str] = SettingsField(
|
||||
default_factory=list,
|
||||
enum_resolver=aov_list_enum,
|
||||
|
|
@ -102,6 +151,8 @@ DEFAULT_RENDER_SETTINGS = {
|
|||
"aov_separator": "underscore",
|
||||
"image_format": "exr",
|
||||
"multilayer_exr": True,
|
||||
"aov_list": [],
|
||||
"renderer": "CYCLES",
|
||||
"compositing": True,
|
||||
"aov_list": ["combined"],
|
||||
"custom_passes": []
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
__version__ = "0.1.5"
|
||||
__version__ = "0.1.6"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue