Skip to content

Commit

Permalink
Merge pull request #10 from ynput/enhancement/usd_workflow_implement_…
Browse files Browse the repository at this point in the history
…render_targets

Houdini: Support different render targets for usdrender product
  • Loading branch information
BigRoy authored Jun 18, 2024
2 parents e2bfa41 + 35aae03 commit da1ae21
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,19 @@ class CreateUSDRender(plugin.HoudiniCreator):
icon = "magic"
description = "Create USD Render"

split_render = True
default_renderer = "Karma CPU"
# Default render target
render_target = "farm_split"

def create(self, product_name, instance_data, pre_create_data):
import hou # noqa

# Transfer settings from pre create to instance
creator_attributes = instance_data.setdefault(
"creator_attributes", dict())

for key in ["render_target", "review"]:
if key in pre_create_data:
creator_attributes[key] = pre_create_data[key]

# TODO: Support creation in /stage if wanted by user
# pre_create_data["parent"] = "/stage"
Expand Down Expand Up @@ -67,7 +75,7 @@ def create(self, product_name, instance_data, pre_create_data):
if self.selected_nodes:
parms["loppath"] = self.selected_nodes[0].path()

if pre_create_data.get("split_render", self.split_render):
if pre_create_data.get("render_target") == "farm_split":
# Do not trigger the husk render, only trigger the USD export
parms["runcommand"] = False
# By default, the render ROP writes out the render file to a
Expand Down Expand Up @@ -103,6 +111,30 @@ def create(self, product_name, instance_data, pre_create_data):
to_lock = ["productType", "id"]
self.lock_parameters(instance_node, to_lock)

def get_instance_attr_defs(self):
"""get instance attribute definitions.
Attributes defined in this method are exposed in
publish tab in the publisher UI.
"""

render_target_items = {
"local": "Local machine rendering",
"local_no_render": "Use existing frames (local)",
"farm": "Farm Rendering",
"farm_split": "Farm Rendering - Split export & render jobs",
}

return [
BoolDef("review",
label="Review",
tooltip="Mark as reviewable",
default=True),
EnumDef("render_target",
items=render_target_items,
label="Render target",
default=self.render_target)
]

def get_pre_create_attr_defs(self):

# Retrieve available renderers and convert default renderer to
Expand All @@ -123,12 +155,11 @@ def get_pre_create_attr_defs(self):
default_renderer = None

attrs = super(CreateUSDRender, self).get_pre_create_attr_defs()
return attrs + [
attrs += [
EnumDef("renderer",
label="Renderer",
default=default_renderer,
items=renderer_plugin_to_display_name),
BoolDef("split_render",
label="Split export and render jobs",
default=self.split_render),
]

return attrs + self.get_instance_attr_defs()
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ class CollectFarmInstances(plugin.HoudiniInstancePlugin):
"karma_rop",
"redshift_rop",
"arnold_rop",
"vray_rop"]
"vray_rop",
"usdrender"]

targets = ["local", "remote"]
label = "Collect farm instances"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ class CollectLocalRenderInstances(plugin.HoudiniInstancePlugin):
"karma_rop",
"redshift_rop",
"arnold_rop",
"vray_rop"]
"vray_rop",
"usdrender"]

label = "Collect local render instances"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ class CollectRenderProducts(plugin.HoudiniInstancePlugin):
"""

label = "Collect Render Products"
order = pyblish.api.CollectorOrder + 0.4
# This plugin should run after CollectUsdRender
# and, before CollectLocalRenderInstances
order = pyblish.api.CollectorOrder + 0.04
families = ["usdrender"]

def process(self, instance):
Expand Down Expand Up @@ -135,8 +137,15 @@ def replace(match):
instance.data["files"] = filenames
instance.data.setdefault("expectedFiles", []).append(files_by_product)

# Farm Publishing add review logic expects this key to exist and
# be True if render is a multipart Exr.
# otherwise it will most probably fail the AOV filter as multipartExr
# files mostly don't include aov name in the file path.
# Assume multipartExr is 'True' as long as we have one AOV.
instance.data["multipartExr"] = len(files_by_product) <= 1

def get_aov_identifier(self, render_product):
"""Return the AOV identfier for a Render Product
"""Return the AOV identifier for a Render Product
A Render Product does not really define what 'AOV' it is, it
defines the product name (output path) and the render vars to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ class CollectReviewableInstances(plugin.HoudiniInstancePlugin):
"karma_rop",
"redshift_rop",
"arnold_rop",
"vray_rop"]
"vray_rop",
"usdrender"]

def process(self, instance):
creator_attribute = instance.data["creator_attributes"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,7 @@ def process(self, instance):

rop = hou.node(instance.data.get("instance_node"))

# Store whether we are splitting the render job in an export + render
split_render = not rop.parm("runcommand").eval()
instance.data["splitRender"] = split_render
if split_render:
if instance.data["splitRender"]:
# USD file output
lop_output = evalParmNoFrame(
rop, "lopoutput", pad_character="#"
Expand Down Expand Up @@ -78,8 +75,6 @@ def replace_to_f(match):
if "$F" not in export_file:
instance.data["splitRenderFrameDependent"] = False

instance.data["farm"] = True # always submit to farm

# update the colorspace data
colorspace_data = get_color_management_preferences()
instance.data["colorspaceConfig"] = colorspace_data["config"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,20 @@ class ExtractRender(plugin.HoudiniExtractorPlugin):
"karma_rop",
"redshift_rop",
"arnold_rop",
"vray_rop"]
"vray_rop",
"usdrender"]

def process(self, instance):
creator_attribute = instance.data["creator_attributes"]
product_type = instance.data["productType"]
rop_node = hou.node(instance.data.get("instance_node"))

# TODO: This section goes against pyblish concepts where
# pyblish plugins should change the state of the scene.
# However, in ayon publisher tool users can have options and
# these options should some how synced with the houdini nodes.
# More info: https://github.com/ynput/ayon-core/issues/417

# Align split parameter value on rop node to the render target.
if instance.data["splitRender"]:
if product_type == "arnold_rop":
Expand All @@ -32,6 +39,8 @@ def process(self, instance):
rop_node.setParms({"RS_archive_enable": 1})
elif product_type == "vray_rop":
rop_node.setParms({"render_export_mode": "2"})
elif product_type == "usdrender":
rop_node.setParms({"runcommand": 0})
else:
if product_type == "arnold_rop":
rop_node.setParms({"ar_ass_export_enable": 0})
Expand All @@ -41,6 +50,8 @@ def process(self, instance):
rop_node.setParms({"RS_archive_enable": 0})
elif product_type == "vray_rop":
rop_node.setParms({"render_export_mode": "1"})
elif product_type == "usdrender":
rop_node.setParms({"runcommand": 1})

if instance.data.get("farm"):
self.log.debug("Render should be processed on farm, skipping local render.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ def process(self, instance):
)
render_chunk_size = submission_data.get("chunk", 1)
export_chunk_size = submission_data.get("export_chunk", 1)
usd_file_per_frame = "$F" in instance.data["ifdFile"]
usd_file_per_frame = (
instance.data["creator_attributes"].get("render_target") == "farm_split"
and
"$F" in instance.data["ifdFile"]
)
frame_start_handle = instance.data["frameStartHandle"]
frame_end_handle = instance.data["frameEndHandle"]
num_frames = frame_end_handle - frame_start_handle + 1
Expand Down

0 comments on commit da1ae21

Please sign in to comment.