From 86ff90dad71e55f66ebc0d54b0c20a279c9f9080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Tue, 15 Dec 2020 18:58:52 +0100 Subject: [PATCH 1/4] handle referenced AOVs --- pype/hosts/maya/expected_files.py | 67 ++++++++++++------- pype/plugins/maya/create/create_render.py | 1 + pype/plugins/maya/publish/collect_render.py | 5 +- .../publish/validate_vray_referenced_aovs.py | 50 ++++++++++++++ 4 files changed, 98 insertions(+), 25 deletions(-) create mode 100644 pype/plugins/maya/publish/validate_vray_referenced_aovs.py diff --git a/pype/hosts/maya/expected_files.py b/pype/hosts/maya/expected_files.py index a2ddec16401..174876db4e6 100644 --- a/pype/hosts/maya/expected_files.py +++ b/pype/hosts/maya/expected_files.py @@ -32,6 +32,9 @@ ImagePrefixes (dict): Mapping between renderers and their respective image prefix atrribute names. +Todo: + Determine `multipart` from render instance. + """ import types @@ -94,6 +97,10 @@ class ExpectedFiles: multipart = False + def __init__(self, render_instance): + """Constructor.""" + self._render_instance = render_instance + def get(self, renderer, layer): """Get expected files for given renderer and render layer. @@ -114,15 +121,20 @@ def get(self, renderer, layer): renderSetup.instance().switchToLayerUsingLegacyName(layer) if renderer.lower() == "arnold": - return self._get_files(ExpectedFilesArnold(layer)) + return self._get_files(ExpectedFilesArnold(layer, + self._render_instance)) elif renderer.lower() == "vray": - return self._get_files(ExpectedFilesVray(layer)) + return self._get_files(ExpectedFilesVray( + layer, self._render_instance)) elif renderer.lower() == "redshift": - return self._get_files(ExpectedFilesRedshift(layer)) + return self._get_files(ExpectedFilesRedshift( + layer, self._render_instance)) elif renderer.lower() == "mentalray": - return self._get_files(ExpectedFilesMentalray(layer)) + return self._get_files(ExpectedFilesMentalray( + layer, self._render_instance)) elif renderer.lower() == "renderman": - return self._get_files(ExpectedFilesRenderman(layer)) + return self._get_files(ExpectedFilesRenderman( + layer, self._render_instance)) else: raise UnsupportedRendererException( "unsupported {}".format(renderer) @@ -149,9 +161,10 @@ class AExpectedFiles: layer = None multipart = False - def __init__(self, layer): + def __init__(self, layer, render_instance): """Constructor.""" self.layer = layer + self.render_instance = render_instance @abstractmethod def get_aovs(self): @@ -460,9 +473,9 @@ class ExpectedFilesArnold(AExpectedFiles): "maya": "", } - def __init__(self, layer): + def __init__(self, layer, render_instance): """Constructor.""" - super(ExpectedFilesArnold, self).__init__(layer) + super(ExpectedFilesArnold, self).__init__(layer, render_instance) self.renderer = "arnold" def get_aovs(self): @@ -531,9 +544,9 @@ def get_aovs(self): class ExpectedFilesVray(AExpectedFiles): """Expected files for V-Ray renderer.""" - def __init__(self, layer): + def __init__(self, layer, render_instance): """Constructor.""" - super(ExpectedFilesVray, self).__init__(layer) + super(ExpectedFilesVray, self).__init__(layer, render_instance) self.renderer = "vray" def get_renderer_prefix(self): @@ -615,14 +628,22 @@ def get_aovs(self): default_ext = "exr" # filter all namespace prefixed AOVs - they are pulled in from - # references and are not rendered. - vr_aovs = [ - n - for n in cmds.ls( - type=["VRayRenderElement", "VRayRenderElementSet"] - ) - if len(n.split(":")) == 1 - ] + # references. Or leave them alone, based on preferences on render + # instance. + ref_aovs = self.render_instance.data.get( + "vrayUseReferencedAovs", False) or False + + if ref_aovs: + vr_aovs = cmds.ls( + type=["VRayRenderElement", "VRayRenderElementSet"]) + else: + vr_aovs = [ + n + for n in cmds.ls( + type=["VRayRenderElement", "VRayRenderElementSet"] + ) + if len(n.split(":")) == 1 + ] for aov in vr_aovs: enabled = self.maya_is_true(cmds.getAttr("{}.enabled".format(aov))) @@ -696,9 +717,9 @@ class ExpectedFilesRedshift(AExpectedFiles): ext_mapping = ["iff", "exr", "tif", "png", "tga", "jpg"] - def __init__(self, layer): + def __init__(self, layer, render_instance): """Construtor.""" - super(ExpectedFilesRedshift, self).__init__(layer) + super(ExpectedFilesRedshift, self).__init__(layer, render_instance) self.renderer = "redshift" def get_renderer_prefix(self): @@ -815,9 +836,9 @@ class ExpectedFilesRenderman(AExpectedFiles): This is very rudimentary and needs more love and testing. """ - def __init__(self, layer): + def __init__(self, layer, render_instance): """Constructor.""" - super(ExpectedFilesRenderman, self).__init__(layer) + super(ExpectedFilesRenderman, self).__init__(layer, render_instance) self.renderer = "renderman" def get_aovs(self): @@ -880,7 +901,7 @@ def get_files(self): class ExpectedFilesMentalray(AExpectedFiles): """Skeleton unimplemented class for Mentalray renderer.""" - def __init__(self, layer): + def __init__(self, layer, render_instance): """Constructor. Raises: diff --git a/pype/plugins/maya/create/create_render.py b/pype/plugins/maya/create/create_render.py index fa0e2691260..5a4f8f9dcbe 100644 --- a/pype/plugins/maya/create/create_render.py +++ b/pype/plugins/maya/create/create_render.py @@ -189,6 +189,7 @@ def _create_render_settings(self): self.data["tilesX"] = 2 self.data["tilesY"] = 2 self.data["convertToScanline"] = False + self.data["vrayUseReferencedAovs"] = False # Disable for now as this feature is not working yet # self.data["assScene"] = False diff --git a/pype/plugins/maya/publish/collect_render.py b/pype/plugins/maya/publish/collect_render.py index 3dde3b15923..08534731201 100644 --- a/pype/plugins/maya/publish/collect_render.py +++ b/pype/plugins/maya/publish/collect_render.py @@ -149,7 +149,7 @@ def process(self, context): # return all expected files for all cameras and aovs in given # frame range - ef = ExpectedFiles() + ef = ExpectedFiles(render_instance) exp_files = ef.get(renderer, layer_name) self.log.info("multipart: {}".format(ef.multipart)) assert exp_files, "no file names were generated, this is bug" @@ -248,7 +248,8 @@ def process(self, context): "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 + "convertToScanline": render_instance.data.get("convertToScanline") or False, # noqa: E501 + "vrayUseReferencedAovs": render_instance.data.get("vrayUseReferencedAovs") or False # noqa: E501 } if self.sync_workfile_version: diff --git a/pype/plugins/maya/publish/validate_vray_referenced_aovs.py b/pype/plugins/maya/publish/validate_vray_referenced_aovs.py new file mode 100644 index 00000000000..923cb06263f --- /dev/null +++ b/pype/plugins/maya/publish/validate_vray_referenced_aovs.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +"""Validate if there are AOVs pulled from references.""" +import pyblish.api +import pype.api + +from maya import cmds + +import pype.hosts.maya.action + + +class ValidateVrayReferencedAOVs(pyblish.api.InstancePlugin): + """Validate whether the V-Ray Render Elements (AOVs) include references. + + This will check if there are AOVs pulled from references. If + `Vray Use Referenced Aovs` is checked on render instance, u must add those + manually to Render Elements as Pype will expect them to be rendered. + + """ + + order = pyblish.api.ValidatorOrder + label = 'VRay Referenced AOVs' + hosts = ['maya'] + families = ['renderlayer'] + actions = [pype.hosts.maya.action.SelectInvalidAction] + + def process(self, instance): + """Plugin main entry point.""" + if instance.data.get("renderer") != "vray": + # If not V-Ray ignore.. + return + + if not instance.data.get("vrayUseReferencedAovs"): + self.get_invalid(instance) + + @classmethod + def get_invalid(cls, instance): + """Find referenced AOVs in scene.""" + # those aovs with namespace prefix are coming from references + ref_aovs = [ + n for n in + cmds.ls(type=["VRayRenderElement", "VRayRenderElementSet"]) + if len(n.split(":")) > 1 + ] + + if ref_aovs: + cls.log.warning( + "Scene contain referenced AOVs: {}".format(ref_aovs)) + + # Return the instance itself + return ref_aovs From 5e8aca606ca36eefe0cadb65309de4f8ed85a89f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Tue, 15 Dec 2020 19:09:05 +0100 Subject: [PATCH 2/4] better check for referenced AOVs --- pype/hosts/maya/expected_files.py | 12 ++++-------- .../maya/publish/validate_vray_referenced_aovs.py | 11 +++++------ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/pype/hosts/maya/expected_files.py b/pype/hosts/maya/expected_files.py index 174876db4e6..9dd10e573ec 100644 --- a/pype/hosts/maya/expected_files.py +++ b/pype/hosts/maya/expected_files.py @@ -635,15 +635,11 @@ def get_aovs(self): if ref_aovs: vr_aovs = cmds.ls( - type=["VRayRenderElement", "VRayRenderElementSet"]) + type=["VRayRenderElement", "VRayRenderElementSet"]) or [] else: - vr_aovs = [ - n - for n in cmds.ls( - type=["VRayRenderElement", "VRayRenderElementSet"] - ) - if len(n.split(":")) == 1 - ] + vr_aovs = cmds.ls( + type=["VRayRenderElement", "VRayRenderElementSet"], + referencedNodes=False) or [] for aov in vr_aovs: enabled = self.maya_is_true(cmds.getAttr("{}.enabled".format(aov))) diff --git a/pype/plugins/maya/publish/validate_vray_referenced_aovs.py b/pype/plugins/maya/publish/validate_vray_referenced_aovs.py index 923cb06263f..0c1a5f552a2 100644 --- a/pype/plugins/maya/publish/validate_vray_referenced_aovs.py +++ b/pype/plugins/maya/publish/validate_vray_referenced_aovs.py @@ -35,12 +35,11 @@ def process(self, instance): @classmethod def get_invalid(cls, instance): """Find referenced AOVs in scene.""" - # those aovs with namespace prefix are coming from references - ref_aovs = [ - n for n in - cmds.ls(type=["VRayRenderElement", "VRayRenderElementSet"]) - if len(n.split(":")) > 1 - ] + + if cmds.getAttr("vraySettings.relements_usereferenced") == 0: + ref_aovs = cmds.ls( + type=["VRayRenderElement", "VRayRenderElementSet"], + referencedNodes=True) or [] if ref_aovs: cls.log.warning( From 6fb3cfafdd92b8c63187cd64912bd87f8ef19e54 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 16 Dec 2020 18:44:04 +0100 Subject: [PATCH 3/4] repair action for validator, skip unwanted referenced aovs --- pype/hosts/maya/expected_files.py | 21 +++--- .../publish/validate_vray_referenced_aovs.py | 73 +++++++++++++++---- 2 files changed, 69 insertions(+), 25 deletions(-) diff --git a/pype/hosts/maya/expected_files.py b/pype/hosts/maya/expected_files.py index 9dd10e573ec..07b3f94aa04 100644 --- a/pype/hosts/maya/expected_files.py +++ b/pype/hosts/maya/expected_files.py @@ -627,19 +627,20 @@ def get_aovs(self): if default_ext == "exr (multichannel)" or default_ext == "exr (deep)": default_ext = "exr" - # filter all namespace prefixed AOVs - they are pulled in from - # references. Or leave them alone, based on preferences on render - # instance. - ref_aovs = self.render_instance.data.get( + # handle aovs from references + use_ref_aovs = self.render_instance.data.get( "vrayUseReferencedAovs", False) or False - if ref_aovs: - vr_aovs = cmds.ls( - type=["VRayRenderElement", "VRayRenderElementSet"]) or [] - else: - vr_aovs = cmds.ls( + # this will have list of all aovs no matter if they are coming from + # reference or not. + vr_aovs = cmds.ls( + type=["VRayRenderElement", "VRayRenderElementSet"]) or [] + if not use_ref_aovs: + ref_aovs = cmds.ls( type=["VRayRenderElement", "VRayRenderElementSet"], - referencedNodes=False) or [] + referencedNodes=True) or [] + # get difference + vr_aovs = list(set(vr_aovs) - set(ref_aovs)) for aov in vr_aovs: enabled = self.maya_is_true(cmds.getAttr("{}.enabled".format(aov))) diff --git a/pype/plugins/maya/publish/validate_vray_referenced_aovs.py b/pype/plugins/maya/publish/validate_vray_referenced_aovs.py index 0c1a5f552a2..67d5ed558cb 100644 --- a/pype/plugins/maya/publish/validate_vray_referenced_aovs.py +++ b/pype/plugins/maya/publish/validate_vray_referenced_aovs.py @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- """Validate if there are AOVs pulled from references.""" import pyblish.api -import pype.api - +import types from maya import cmds import pype.hosts.maya.action @@ -21,7 +20,7 @@ class ValidateVrayReferencedAOVs(pyblish.api.InstancePlugin): label = 'VRay Referenced AOVs' hosts = ['maya'] families = ['renderlayer'] - actions = [pype.hosts.maya.action.SelectInvalidAction] + actions = [pype.api.RepairContextAction] def process(self, instance): """Plugin main entry point.""" @@ -29,21 +28,65 @@ def process(self, instance): # If not V-Ray ignore.. return + ref_aovs = cmds.ls( + type=["VRayRenderElement", "VRayRenderElementSet"], + referencedNodes=True) + ref_aovs_enabled = ValidateVrayReferencedAOVs.maya_is_true( + cmds.getAttr("vraySettings.relements_usereferenced")) + if not instance.data.get("vrayUseReferencedAovs"): - self.get_invalid(instance) + if ref_aovs_enabled and ref_aovs: + self.log.warning(( + "Referenced AOVs are enabled in Vray " + "Render Settings and are detected in scene, but " + "Pype render instance option for referenced AOVs is " + "disabled. Those AOVs will be rendered but not published " + "by Pype." + )) + self.log.warning(", ".join(ref_aovs)) + else: + if not ref_aovs: + self.log.warning(( + "Use of referenced AOVs enabled but there are none " + "in the scene." + )) + if not ref_aovs_enabled: + self.log.error(( + "'Use referenced' not enabled in Vray Render Settings." + )) + raise AssertionError("Invalid render settings") @classmethod - def get_invalid(cls, instance): - """Find referenced AOVs in scene.""" + def repair(cls, context): + + vray_settings = cmds.ls(type="VRaySettingsNode") + if not vray_settings: + node = cmds.createNode("VRaySettingsNode") + else: + node = vray_settings[0] + + cmds.setAttr("{}.relements_usereferenced".format(node), True) + + + + @staticmethod + def maya_is_true(attr_val): + """Whether a Maya attr evaluates to True. + + When querying an attribute value from an ambiguous object the + Maya API will return a list of values, which need to be properly + handled to evaluate properly. - if cmds.getAttr("vraySettings.relements_usereferenced") == 0: - ref_aovs = cmds.ls( - type=["VRayRenderElement", "VRayRenderElementSet"], - referencedNodes=True) or [] + Args: + attr_val (mixed): Maya attribute to be evaluated as bool. - if ref_aovs: - cls.log.warning( - "Scene contain referenced AOVs: {}".format(ref_aovs)) + Returns: + bool: cast Maya attribute to Pythons boolean value. - # Return the instance itself - return ref_aovs + """ + if isinstance(attr_val, types.BooleanType): + return attr_val + elif isinstance(attr_val, (types.ListType, types.GeneratorType)): + return any(attr_val) + else: + return bool(attr_val) From 183058a6c4e836b5601399e89e0dd98198a12d55 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 16 Dec 2020 18:46:41 +0100 Subject: [PATCH 4/4] shut the hound up --- pype/plugins/maya/publish/validate_vray_referenced_aovs.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pype/plugins/maya/publish/validate_vray_referenced_aovs.py b/pype/plugins/maya/publish/validate_vray_referenced_aovs.py index 67d5ed558cb..120677021de 100644 --- a/pype/plugins/maya/publish/validate_vray_referenced_aovs.py +++ b/pype/plugins/maya/publish/validate_vray_referenced_aovs.py @@ -58,7 +58,7 @@ def process(self, instance): @classmethod def repair(cls, context): - + """Repair action.""" vray_settings = cmds.ls(type="VRaySettingsNode") if not vray_settings: node = cmds.createNode("VRaySettingsNode") @@ -67,8 +67,6 @@ def repair(cls, context): cmds.setAttr("{}.relements_usereferenced".format(node), True) - - @staticmethod def maya_is_true(attr_val): """Whether a Maya attr evaluates to True.