mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merge pull request #951 from pypeclub/3.0/arnold-referenced-aovs
Maya: Handling Arnold referenced AOVs - Pype 3
This commit is contained in:
commit
8b1897a020
3 changed files with 78 additions and 104 deletions
|
|
@ -29,8 +29,8 @@ Attributes:
|
|||
token in image prefixes.
|
||||
RENDERER_NAMES (dict): Renderer names mapping between reported name and
|
||||
*human readable* name.
|
||||
ImagePrefixes (dict): Mapping between renderers and their respective
|
||||
image prefix atrribute names.
|
||||
IMAGE_PREFIXES (dict): Mapping between renderers and their respective
|
||||
image prefix attribute names.
|
||||
|
||||
Todo:
|
||||
Determine `multipart` from render instance.
|
||||
|
|
@ -78,7 +78,7 @@ RENDERER_NAMES = {
|
|||
}
|
||||
|
||||
# not sure about the renderman image prefix
|
||||
ImagePrefixes = {
|
||||
IMAGE_PREFIXES = {
|
||||
"mentalray": "defaultRenderGlobals.imageFilePrefix",
|
||||
"vray": "vraySettings.fileNamePrefix",
|
||||
"arnold": "defaultRenderGlobals.imageFilePrefix",
|
||||
|
|
@ -123,22 +123,22 @@ class ExpectedFiles:
|
|||
if renderer.lower() == "arnold":
|
||||
return self._get_files(ExpectedFilesArnold(layer,
|
||||
self._render_instance))
|
||||
elif renderer.lower() == "vray":
|
||||
if renderer.lower() == "vray":
|
||||
return self._get_files(ExpectedFilesVray(
|
||||
layer, self._render_instance))
|
||||
elif renderer.lower() == "redshift":
|
||||
if renderer.lower() == "redshift":
|
||||
return self._get_files(ExpectedFilesRedshift(
|
||||
layer, self._render_instance))
|
||||
elif renderer.lower() == "mentalray":
|
||||
if renderer.lower() == "mentalray":
|
||||
return self._get_files(ExpectedFilesMentalray(
|
||||
layer, self._render_instance))
|
||||
elif renderer.lower() == "renderman":
|
||||
if renderer.lower() == "renderman":
|
||||
return self._get_files(ExpectedFilesRenderman(
|
||||
layer, self._render_instance))
|
||||
else:
|
||||
raise UnsupportedRendererException(
|
||||
"unsupported {}".format(renderer)
|
||||
)
|
||||
|
||||
raise UnsupportedRendererException(
|
||||
"unsupported {}".format(renderer)
|
||||
)
|
||||
|
||||
def _get_files(self, renderer):
|
||||
files = renderer.get_files()
|
||||
|
|
@ -169,9 +169,9 @@ class AExpectedFiles:
|
|||
@abstractmethod
|
||||
def get_aovs(self):
|
||||
"""To be implemented by renderer class."""
|
||||
pass
|
||||
|
||||
def sanitize_camera_name(self, camera):
|
||||
@staticmethod
|
||||
def sanitize_camera_name(camera):
|
||||
"""Sanitize camera name.
|
||||
|
||||
Remove Maya illegal characters from camera name.
|
||||
|
|
@ -187,8 +187,7 @@ class AExpectedFiles:
|
|||
test_camera_01
|
||||
|
||||
"""
|
||||
sanitized = re.sub('[^0-9a-zA-Z_]+', '_', camera)
|
||||
return sanitized
|
||||
return re.sub('[^0-9a-zA-Z_]+', '_', camera)
|
||||
|
||||
def get_renderer_prefix(self):
|
||||
"""Return prefix for specific renderer.
|
||||
|
|
@ -201,12 +200,12 @@ class AExpectedFiles:
|
|||
Raises:
|
||||
:exc:`UnsupportedRendererException`: If we requested image
|
||||
prefix for renderer we know nothing about.
|
||||
See :data:`ImagePrefixes` for mapping of renderers and
|
||||
See :data:`IMAGE_PREFIXES` for mapping of renderers and
|
||||
image prefixes.
|
||||
|
||||
"""
|
||||
try:
|
||||
file_prefix = cmds.getAttr(ImagePrefixes[self.renderer])
|
||||
file_prefix = cmds.getAttr(IMAGE_PREFIXES[self.renderer])
|
||||
except KeyError:
|
||||
raise UnsupportedRendererException(
|
||||
"Unsupported renderer {}".format(self.renderer)
|
||||
|
|
@ -218,62 +217,32 @@ class AExpectedFiles:
|
|||
# ____________________/ ____________________________________________/
|
||||
# 1 - get scene name /__________________/
|
||||
# ____________________/
|
||||
scene_dir, scene_basename = os.path.split(cmds.file(q=True, loc=True))
|
||||
_, scene_basename = os.path.split(cmds.file(q=True, loc=True))
|
||||
scene_name, _ = os.path.splitext(scene_basename)
|
||||
|
||||
# ______________________________________________
|
||||
# ____________________/ ____________________________________________/
|
||||
# 2 - detect renderer /__________________/
|
||||
# ____________________/
|
||||
renderer = self.renderer
|
||||
|
||||
# ________________________________________________
|
||||
# __________________/ ______________________________________________/
|
||||
# 3 - image prefix /__________________/
|
||||
# __________________/
|
||||
file_prefix = self.get_renderer_prefix()
|
||||
|
||||
if not file_prefix:
|
||||
raise RuntimeError("Image prefix not set")
|
||||
|
||||
default_ext = cmds.getAttr("defaultRenderGlobals.imfPluginKey")
|
||||
|
||||
# ________________________________________________
|
||||
# __________________/ ______________________________________________/
|
||||
# 4 - get renderable cameras_____________/
|
||||
# __________________/
|
||||
|
||||
# if we have <camera> token in prefix path we'll expect output for
|
||||
# every renderable camera in layer.
|
||||
|
||||
renderable_cameras = self.get_renderable_cameras()
|
||||
# ________________________________________________
|
||||
# __________________/ ______________________________________________/
|
||||
# 5 - get AOVs /____________________/
|
||||
# __________________/
|
||||
|
||||
enabled_aovs = self.get_aovs()
|
||||
|
||||
layer_name = self.layer
|
||||
if self.layer.startswith("rs_"):
|
||||
layer_name = self.layer[3:]
|
||||
start_frame = int(self.get_render_attribute("startFrame"))
|
||||
end_frame = int(self.get_render_attribute("endFrame"))
|
||||
frame_step = int(self.get_render_attribute("byFrameStep"))
|
||||
padding = int(self.get_render_attribute("extensionPadding"))
|
||||
|
||||
scene_data = {
|
||||
"frameStart": start_frame,
|
||||
"frameEnd": end_frame,
|
||||
"frameStep": frame_step,
|
||||
"padding": padding,
|
||||
"cameras": renderable_cameras,
|
||||
"frameStart": int(self.get_render_attribute("startFrame")),
|
||||
"frameEnd": int(self.get_render_attribute("endFrame")),
|
||||
"frameStep": int(self.get_render_attribute("byFrameStep")),
|
||||
"padding": int(self.get_render_attribute("extensionPadding")),
|
||||
# if we have <camera> token in prefix path we'll expect output for
|
||||
# every renderable camera in layer.
|
||||
"cameras": self.get_renderable_cameras(),
|
||||
"sceneName": scene_name,
|
||||
"layerName": layer_name,
|
||||
"renderer": renderer,
|
||||
"defaultExt": default_ext,
|
||||
"renderer": self.renderer,
|
||||
"defaultExt": cmds.getAttr("defaultRenderGlobals.imfPluginKey"),
|
||||
"filePrefix": file_prefix,
|
||||
"enabledAOVs": enabled_aovs,
|
||||
"enabledAOVs": self.get_aovs(),
|
||||
}
|
||||
return scene_data
|
||||
|
||||
|
|
@ -296,9 +265,9 @@ class AExpectedFiles:
|
|||
file_prefix = re.sub(regex, value, file_prefix)
|
||||
|
||||
for frame in range(
|
||||
int(layer_data["frameStart"]),
|
||||
int(layer_data["frameEnd"]) + 1,
|
||||
int(layer_data["frameStep"]),
|
||||
int(layer_data["frameStart"]),
|
||||
int(layer_data["frameEnd"]) + 1,
|
||||
int(layer_data["frameStep"]),
|
||||
):
|
||||
expected_files.append(
|
||||
"{}.{}.{}".format(
|
||||
|
|
@ -331,9 +300,9 @@ class AExpectedFiles:
|
|||
|
||||
aov_files = []
|
||||
for frame in range(
|
||||
int(layer_data["frameStart"]),
|
||||
int(layer_data["frameEnd"]) + 1,
|
||||
int(layer_data["frameStep"]),
|
||||
int(layer_data["frameStart"]),
|
||||
int(layer_data["frameEnd"]) + 1,
|
||||
int(layer_data["frameStep"]),
|
||||
):
|
||||
aov_files.append(
|
||||
"{}.{}.{}".format(
|
||||
|
|
@ -388,14 +357,13 @@ class AExpectedFiles:
|
|||
|
||||
renderable_cameras = []
|
||||
for cam in cam_parents:
|
||||
renderable = False
|
||||
if self.maya_is_true(cmds.getAttr("{}.renderable".format(cam))):
|
||||
renderable = True
|
||||
renderable_cameras.append(cam)
|
||||
|
||||
return renderable_cameras
|
||||
|
||||
def maya_is_true(self, attr_val):
|
||||
@staticmethod
|
||||
def maya_is_true(attr_val):
|
||||
"""Whether a Maya attr evaluates to True.
|
||||
|
||||
When querying an attribute value from an ambiguous object the
|
||||
|
|
@ -411,12 +379,13 @@ class AExpectedFiles:
|
|||
"""
|
||||
if isinstance(attr_val, types.BooleanType):
|
||||
return attr_val
|
||||
elif isinstance(attr_val, (types.ListType, types.GeneratorType)):
|
||||
if isinstance(attr_val, (types.ListType, types.GeneratorType)):
|
||||
return any(attr_val)
|
||||
else:
|
||||
return bool(attr_val)
|
||||
|
||||
def get_layer_overrides(self, attr, layer):
|
||||
return bool(attr_val)
|
||||
|
||||
@staticmethod
|
||||
def get_layer_overrides(attr):
|
||||
"""Get overrides for attribute on given render layer.
|
||||
|
||||
Args:
|
||||
|
|
@ -491,8 +460,8 @@ class ExpectedFilesArnold(AExpectedFiles):
|
|||
enabled_aovs = []
|
||||
try:
|
||||
if not (
|
||||
cmds.getAttr("defaultArnoldRenderOptions.aovMode")
|
||||
and not cmds.getAttr("defaultArnoldDriver.mergeAOVs") # noqa: W503, E501
|
||||
cmds.getAttr("defaultArnoldRenderOptions.aovMode")
|
||||
and not cmds.getAttr("defaultArnoldDriver.mergeAOVs") # noqa: W503, E501
|
||||
):
|
||||
# AOVs are merged in mutli-channel file
|
||||
self.multipart = True
|
||||
|
|
@ -508,7 +477,14 @@ class ExpectedFilesArnold(AExpectedFiles):
|
|||
# AOVs are set to be rendered separately. We should expect
|
||||
# <RenderPass> token in path.
|
||||
|
||||
ai_aovs = [n for n in cmds.ls(type="aiAOV")]
|
||||
# handle aovs from references
|
||||
use_ref_aovs = self.render_instance.data.get(
|
||||
"useReferencedAovs", False) or False
|
||||
|
||||
ai_aovs = cmds.ls(type="aiAOV")
|
||||
if not use_ref_aovs:
|
||||
ref_aovs = cmds.ls(type="aiAOV", referencedNodes=True)
|
||||
ai_aovs = list(set(ai_aovs) - set(ref_aovs))
|
||||
|
||||
for aov in ai_aovs:
|
||||
enabled = self.maya_is_true(cmds.getAttr("{}.enabled".format(aov)))
|
||||
|
|
@ -523,7 +499,7 @@ class ExpectedFilesArnold(AExpectedFiles):
|
|||
raise AOVError(msg)
|
||||
|
||||
for override in self.get_layer_overrides(
|
||||
"{}.enabled".format(aov), self.layer
|
||||
"{}.enabled".format(aov)
|
||||
):
|
||||
enabled = self.maya_is_true(override)
|
||||
if enabled:
|
||||
|
|
@ -567,7 +543,7 @@ class ExpectedFilesVray(AExpectedFiles):
|
|||
"""Override to get vray specific extension."""
|
||||
layer_data = super(ExpectedFilesVray, self)._get_layer_data()
|
||||
default_ext = cmds.getAttr("vraySettings.imageFormatStr")
|
||||
if default_ext == "exr (multichannel)" or default_ext == "exr (deep)":
|
||||
if default_ext in ["exr (multichannel)", "exr (deep)"]:
|
||||
default_ext = "exr"
|
||||
layer_data["defaultExt"] = default_ext
|
||||
layer_data["padding"] = cmds.getAttr("vraySettings.fileNamePadding")
|
||||
|
|
@ -587,11 +563,11 @@ class ExpectedFilesVray(AExpectedFiles):
|
|||
# remove 'beauty' from filenames as vray doesn't output it
|
||||
update = {}
|
||||
if layer_data.get("enabledAOVs"):
|
||||
for aov, seq in expected_files[0].items():
|
||||
for aov, seqs in expected_files[0].items():
|
||||
if aov.startswith("beauty"):
|
||||
new_list = []
|
||||
for f in seq:
|
||||
new_list.append(f.replace("_beauty", ""))
|
||||
for seq in seqs:
|
||||
new_list.append(seq.replace("_beauty", ""))
|
||||
update[aov] = new_list
|
||||
|
||||
expected_files[0].update(update)
|
||||
|
|
@ -609,8 +585,8 @@ class ExpectedFilesVray(AExpectedFiles):
|
|||
try:
|
||||
# really? do we set it in vray just by selecting multichannel exr?
|
||||
if (
|
||||
cmds.getAttr("vraySettings.imageFormatStr")
|
||||
== "exr (multichannel)" # noqa: W503
|
||||
cmds.getAttr("vraySettings.imageFormatStr")
|
||||
== "exr (multichannel)" # noqa: W503
|
||||
):
|
||||
# AOVs are merged in mutli-channel file
|
||||
self.multipart = True
|
||||
|
|
@ -624,7 +600,7 @@ class ExpectedFilesVray(AExpectedFiles):
|
|||
return enabled_aovs
|
||||
|
||||
default_ext = cmds.getAttr("vraySettings.imageFormatStr")
|
||||
if default_ext == "exr (multichannel)" or default_ext == "exr (deep)":
|
||||
if default_ext in ["exr (multichannel)", "exr (deep)"]:
|
||||
default_ext = "exr"
|
||||
|
||||
# add beauty as default
|
||||
|
|
@ -634,7 +610,7 @@ class ExpectedFilesVray(AExpectedFiles):
|
|||
|
||||
# handle aovs from references
|
||||
use_ref_aovs = self.render_instance.data.get(
|
||||
"vrayUseReferencedAovs", False) or False
|
||||
"useReferencedAovs", False) or False
|
||||
|
||||
# this will have list of all aovs no matter if they are coming from
|
||||
# reference or not.
|
||||
|
|
@ -650,18 +626,18 @@ class ExpectedFilesVray(AExpectedFiles):
|
|||
for aov in vr_aovs:
|
||||
enabled = self.maya_is_true(cmds.getAttr("{}.enabled".format(aov)))
|
||||
for override in self.get_layer_overrides(
|
||||
"{}.enabled".format(aov), "rs_{}".format(self.layer)
|
||||
"{}.enabled".format(aov)
|
||||
):
|
||||
enabled = self.maya_is_true(override)
|
||||
|
||||
if enabled:
|
||||
# todo: find how vray set format for AOVs
|
||||
enabled_aovs.append(
|
||||
(self._get_vray_aov_name(aov), default_ext))
|
||||
|
||||
return enabled_aovs
|
||||
|
||||
def _get_vray_aov_name(self, node):
|
||||
@staticmethod
|
||||
def _get_vray_aov_name(node):
|
||||
"""Get AOVs name from Vray.
|
||||
|
||||
Args:
|
||||
|
|
@ -762,8 +738,8 @@ class ExpectedFilesRedshift(AExpectedFiles):
|
|||
if aov[0].lower() == "cryptomatte":
|
||||
aov_name = aov[0]
|
||||
expected_files.append(
|
||||
{aov_name: self._generate_single_file_sequence(
|
||||
layer_data, aov_name=aov_name)})
|
||||
{aov_name: self._generate_single_file_sequence(layer_data)}
|
||||
)
|
||||
|
||||
return expected_files
|
||||
|
||||
|
|
@ -778,7 +754,7 @@ class ExpectedFilesRedshift(AExpectedFiles):
|
|||
|
||||
try:
|
||||
if self.maya_is_true(
|
||||
cmds.getAttr("redshiftOptions.exrForceMultilayer")
|
||||
cmds.getAttr("redshiftOptions.exrForceMultilayer")
|
||||
):
|
||||
# AOVs are merged in mutli-channel file
|
||||
self.multipart = True
|
||||
|
|
@ -794,13 +770,13 @@ class ExpectedFilesRedshift(AExpectedFiles):
|
|||
default_ext = self.ext_mapping[
|
||||
cmds.getAttr("redshiftOptions.imageFormat")
|
||||
]
|
||||
rs_aovs = [n for n in cmds.ls(type="RedshiftAOV")]
|
||||
rs_aovs = cmds.ls(type="RedshiftAOV", referencedNodes=False)
|
||||
|
||||
# todo: find out how to detect multichannel exr for redshift
|
||||
for aov in rs_aovs:
|
||||
enabled = self.maya_is_true(cmds.getAttr("{}.enabled".format(aov)))
|
||||
for override in self.get_layer_overrides(
|
||||
"{}.enabled".format(aov), self.layer
|
||||
"{}.enabled".format(aov)
|
||||
):
|
||||
enabled = self.maya_is_true(override)
|
||||
|
||||
|
|
@ -809,7 +785,7 @@ class ExpectedFilesRedshift(AExpectedFiles):
|
|||
# is in the list of AOVs that renderer cannot (or will not)
|
||||
# merge into final exr.
|
||||
if self.maya_is_true(
|
||||
cmds.getAttr("redshiftOptions.exrForceMultilayer")
|
||||
cmds.getAttr("redshiftOptions.exrForceMultilayer")
|
||||
):
|
||||
if cmds.getAttr("%s.name" % aov) in self.unmerged_aovs:
|
||||
enabled_aovs.append(
|
||||
|
|
@ -821,7 +797,7 @@ class ExpectedFilesRedshift(AExpectedFiles):
|
|||
)
|
||||
|
||||
if self.maya_is_true(
|
||||
cmds.getAttr("redshiftOptions.exrForceMultilayer")
|
||||
cmds.getAttr("redshiftOptions.exrForceMultilayer")
|
||||
):
|
||||
# AOVs are merged in mutli-channel file
|
||||
self.multipart = True
|
||||
|
|
@ -859,7 +835,7 @@ class ExpectedFilesRenderman(AExpectedFiles):
|
|||
|
||||
enabled = self.maya_is_true(cmds.getAttr("{}.enable".format(aov)))
|
||||
for override in self.get_layer_overrides(
|
||||
"{}.enable".format(aov), self.layer
|
||||
"{}.enable".format(aov)
|
||||
):
|
||||
enabled = self.maya_is_true(override)
|
||||
|
||||
|
|
@ -908,6 +884,7 @@ class ExpectedFilesMentalray(AExpectedFiles):
|
|||
:exc:`UnimplementedRendererException`: as it is not implemented.
|
||||
|
||||
"""
|
||||
super(ExpectedFilesMentalray, self).__init__(layer, render_instance)
|
||||
raise UnimplementedRendererException("Mentalray not implemented")
|
||||
|
||||
def get_aovs(self):
|
||||
|
|
@ -923,8 +900,6 @@ class ExpectedFilesMentalray(AExpectedFiles):
|
|||
class AOVError(Exception):
|
||||
"""Custom exception for determining AOVs."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class UnsupportedRendererException(Exception):
|
||||
"""Custom exception.
|
||||
|
|
@ -932,13 +907,9 @@ class UnsupportedRendererException(Exception):
|
|||
Raised when requesting data from unsupported renderer.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class UnimplementedRendererException(Exception):
|
||||
"""Custom exception.
|
||||
|
||||
Raised when requesting data from renderer that is not implemented yet.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ class CreateRender(avalon.maya.Creator):
|
|||
self.data["tilesX"] = 2
|
||||
self.data["tilesY"] = 2
|
||||
self.data["convertToScanline"] = False
|
||||
self.data["vrayUseReferencedAovs"] = False
|
||||
self.data["useReferencedAovs"] = False
|
||||
# Disable for now as this feature is not working yet
|
||||
# self.data["assScene"] = False
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"""Collect render data.
|
||||
|
||||
This collector will go through render layers in maya and prepare all data
|
||||
needed to create instances and their representations for submition and
|
||||
needed to create instances and their representations for submission and
|
||||
publishing on farm.
|
||||
|
||||
Requires:
|
||||
|
|
@ -248,8 +248,11 @@ class CollectMayaRender(pyblish.api.ContextPlugin):
|
|||
"tilesX": render_instance.data.get("tilesX") or 2,
|
||||
"tilesY": render_instance.data.get("tilesY") or 2,
|
||||
"priority": render_instance.data.get("priority"),
|
||||
"convertToScanline": render_instance.data.get("convertToScanline") or False, # noqa: E501
|
||||
"vrayUseReferencedAovs": render_instance.data.get("vrayUseReferencedAovs") or False # noqa: E501
|
||||
"convertToScanline": render_instance.data.get(
|
||||
"convertToScanline") or False,
|
||||
"useReferencedAovs": render_instance.data.get(
|
||||
"useReferencedAovs") or render_instance.data.get(
|
||||
"vrayUseReferencedAovs") or False
|
||||
}
|
||||
|
||||
if self.sync_workfile_version:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue