Implemented AOVs rendering in deadline and publishing

This commit is contained in:
Simone Barbieri 2023-08-22 15:56:23 +01:00
parent eb1b5425de
commit 9f56721334
3 changed files with 122 additions and 25 deletions

View file

@ -0,0 +1,52 @@
import attr
import bpy
@attr.s
class LayerMetadata(object):
"""Data class for Render Layer metadata."""
frameStart = attr.ib()
frameEnd = attr.ib()
@attr.s
class RenderProduct(object):
"""Getting Colorspace as
Specific Render Product Parameter for submitting
publish job.
"""
colorspace = attr.ib() # colorspace
view = attr.ib()
productName = attr.ib(default=None)
class ARenderProduct(object):
def __init__(self):
"""Constructor."""
# Initialize
self.layer_data = self._get_layer_data()
self.layer_data.products = self.get_colorspace_data()
def _get_layer_data(self):
scene = bpy.context.scene
return LayerMetadata(
frameStart=int(scene.frame_start),
frameEnd=int(scene.frame_end),
)
def get_colorspace_data(self):
"""To be implemented by renderer class.
This should return a list of RenderProducts.
Returns:
list: List of RenderProduct
"""
return [
RenderProduct(
colorspace="sRGB",
view="ACES 1.0",
productName=""
)
]

View file

@ -12,10 +12,7 @@ from openpype.pipeline import (
from openpype.settings import (
get_project_settings,
)
from openpype.hosts.blender.api.ops import (
MainThreadItem,
execute_in_main_thread
)
from openpype.hosts.blender.api import colorspace
import pyblish.api
@ -73,12 +70,13 @@ class CollectBlenderRender(pyblish.api.InstancePlugin):
return render_product
@staticmethod
def generate_expected_files(
render_product, frame_start, frame_end, frame_step
def generate_expected_beauty(
render_product, frame_start, frame_end, frame_step, ext
):
"""Generate the expected files for the render product.
This returns a list of files that should be rendered. It replaces
the sequence of `#` with the frame number.
"""
Generate the expected files for the render product for the beauty
render. This returns a list of files that should be rendered. It
replaces the sequence of `#` with the frame number.
"""
path = os.path.dirname(render_product)
file = os.path.basename(render_product)
@ -87,9 +85,39 @@ class CollectBlenderRender(pyblish.api.InstancePlugin):
for frame in range(frame_start, frame_end + 1, frame_step):
frame_str = str(frame).rjust(4, "0")
expected_file = os.path.join(path, re.sub("#+", frame_str, file))
filename = re.sub("#+", frame_str, file)
expected_file = f"{os.path.join(path, filename)}.{ext}"
expected_files.append(expected_file.replace("\\", "/"))
return {
"beauty": expected_files
}
@staticmethod
def generate_expected_aovs(
aov_file_product, frame_start, frame_end, frame_step, ext
):
"""
Generate the expected files for the render product for the beauty
render. This returns a list of files that should be rendered. It
replaces the sequence of `#` with the frame number.
"""
expected_files = {}
for aov_name, aov_file in aov_file_product:
path = os.path.dirname(aov_file)
file = os.path.basename(aov_file)
aov_files = []
for frame in range(frame_start, frame_end + 1, frame_step):
frame_str = str(frame).rjust(4, "0")
filename = re.sub("#+", frame_str, file)
expected_file = f"{os.path.join(path, filename)}.{ext}"
aov_files.append(expected_file.replace("\\", "/"))
expected_files[aov_name] = aov_files
return expected_files
@staticmethod
@ -117,7 +145,7 @@ class CollectBlenderRender(pyblish.api.InstancePlugin):
elif ext == "tif":
image_settings.file_format = "TIFF"
def _create_context():
def _create_context(self):
context = bpy.context.copy()
win = bpy.context.window_manager.windows[0]
@ -132,7 +160,7 @@ class CollectBlenderRender(pyblish.api.InstancePlugin):
return context
def _set_node_tree(self, output_path, instance):
def set_node_tree(self, output_path, instance):
# Set the scene to use the compositor node tree to render
bpy.context.scene.use_nodes = True
@ -153,8 +181,9 @@ class CollectBlenderRender(pyblish.api.InstancePlugin):
# render.
# We also exclude some layers.
exclude_sockets = ["Image", "Alpha"]
passes = [
socket for socket in rl_node.outputs
passes = [
socket
for socket in rl_node.outputs
if socket.enabled and socket.name not in exclude_sockets
]
@ -182,11 +211,16 @@ class CollectBlenderRender(pyblish.api.InstancePlugin):
image_settings = bpy.context.scene.render.image_settings
output.format.file_format = image_settings.file_format
aov_file_products = []
# For each active render pass, we add a new socket to the output node
# and link it
for render_pass in passes:
bpy.ops.node.output_file_add_socket(
context, file_path=f"{instance.name}_{render_pass.name}.####")
filepath = f"{instance.name}_{render_pass.name}.####"
bpy.ops.node.output_file_add_socket(context, file_path=filepath)
aov_file_products.append(
(render_pass.name, os.path.join(output_path, filepath)))
node_input = output.inputs[-1]
@ -195,10 +229,7 @@ class CollectBlenderRender(pyblish.api.InstancePlugin):
# Restore the area type
area.ui_type = old_area_type
def set_node_tree(self, output_path, instance):
""" Run the creator on Blender main thread"""
mti = MainThreadItem(self._set_node_tree, output_path, instance)
execute_in_main_thread(mti)
return aov_file_products
@staticmethod
def set_render_camera(instance):
@ -230,7 +261,7 @@ class CollectBlenderRender(pyblish.api.InstancePlugin):
output_path = os.path.join(file_path, render_folder, file_name)
render_product = self.get_render_product(output_path, instance)
self.set_node_tree(output_path, instance)
aov_file_product = self.set_node_tree(output_path, instance)
# We set the render path, the format and the camera
bpy.context.scene.render.filepath = render_product
@ -245,9 +276,15 @@ class CollectBlenderRender(pyblish.api.InstancePlugin):
frame_handle_start = context.data["frameStartHandle"]
frame_handle_end = context.data["frameEndHandle"]
expected_files = self.generate_expected_files(
expected_beauty = self.generate_expected_beauty(
render_product, int(frame_start), int(frame_end),
int(bpy.context.scene.frame_step))
int(bpy.context.scene.frame_step), ext)
expected_aovs = self.generate_expected_aovs(
aov_file_product, int(frame_start), int(frame_end),
int(bpy.context.scene.frame_step), ext)
expected_files = expected_beauty | expected_aovs
instance.data.update({
"frameStart": frame_start,
@ -257,7 +294,14 @@ class CollectBlenderRender(pyblish.api.InstancePlugin):
"fps": context.data["fps"],
"byFrameStep": bpy.context.scene.frame_step,
"farm": True,
"expectedFiles": expected_files,
"expectedFiles": [expected_files],
# OCIO not currently implemented in Blender, but the following
# settings are required by the schema, so it is hardcoded.
# TODO: Implement OCIO in Blender
"colorspaceConfig": "",
"colorspaceDisplay": "sRGB",
"colorspaceView": "ACES 1.0 SDR-video",
"renderProducts": colorspace.ARenderProduct(),
})
self.log.info(f"data: {instance.data}")

View file

@ -163,7 +163,8 @@ class BlenderSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline):
if not expected_files:
raise RuntimeError("No Render Elements found!")
output_dir = os.path.dirname(expected_files[0])
first_file = next(iter_expected_files(expected_files))
output_dir = os.path.dirname(first_file)
instance.data["outputDir"] = output_dir
instance.data["toBeRenderedOn"] = "deadline"