diff --git a/pype/hosts/maya/api/expected_files.py b/pype/hosts/maya/api/expected_files.py index 0a234baef7..41463b53f8 100644 --- a/pype/hosts/maya/api/expected_files.py +++ b/pype/hosts/maya/api/expected_files.py @@ -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 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 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 # 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 diff --git a/pype/hosts/maya/plugins/create/create_render.py b/pype/hosts/maya/plugins/create/create_render.py index 0763b19c17..2fd9972721 100644 --- a/pype/hosts/maya/plugins/create/create_render.py +++ b/pype/hosts/maya/plugins/create/create_render.py @@ -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 diff --git a/pype/hosts/maya/plugins/publish/collect_render.py b/pype/hosts/maya/plugins/publish/collect_render.py index 208937320d..fdd77815cc 100644 --- a/pype/hosts/maya/plugins/publish/collect_render.py +++ b/pype/hosts/maya/plugins/publish/collect_render.py @@ -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: