diff --git a/openpype/hosts/maya/api/lib_renderproducts.py b/openpype/hosts/maya/api/lib_renderproducts.py index 4983109d58d..e8e4b9aaef7 100644 --- a/openpype/hosts/maya/api/lib_renderproducts.py +++ b/openpype/hosts/maya/api/lib_renderproducts.py @@ -180,6 +180,7 @@ def __init__(self, layer, render_instance): self.layer = layer self.render_instance = render_instance self.multipart = False + self.aov_separator = render_instance.data.get("aovSeparator", "_") # Initialize self.layer_data = self._get_layer_data() @@ -676,7 +677,7 @@ def get_renderer_prefix(self): """ prefix = super(RenderProductsVray, self).get_renderer_prefix() - prefix = "{}.".format(prefix) + prefix = "{}{}".format(prefix, self.aov_separator) return prefix def _get_layer_data(self): diff --git a/openpype/hosts/maya/plugins/create/create_render.py b/openpype/hosts/maya/plugins/create/create_render.py index 4fd4b9d9862..85919d11665 100644 --- a/openpype/hosts/maya/plugins/create/create_render.py +++ b/openpype/hosts/maya/plugins/create/create_render.py @@ -21,6 +21,7 @@ from openpype.modules import ModulesManager from avalon.api import Session +from avalon.api import CreatorError class CreateRender(plugin.Creator): @@ -81,13 +82,21 @@ class CreateRender(plugin.Creator): } _image_prefixes = { - 'mentalray': 'maya///_', + 'mentalray': 'maya///{aov_separator}', # noqa 'vray': 'maya///', - 'arnold': 'maya///_', - 'renderman': 'maya///_', - 'redshift': 'maya///_' + 'arnold': 'maya///{aov_separator}', # noqa + 'renderman': 'maya///{aov_separator}', + 'redshift': 'maya///{aov_separator}' # noqa } + _aov_chars = { + "dot": ".", + "dash": "-", + "underscore": "_" + } + + _project_settings = None + def __init__(self, *args, **kwargs): """Constructor.""" super(CreateRender, self).__init__(*args, **kwargs) @@ -95,12 +104,24 @@ def __init__(self, *args, **kwargs): if not deadline_settings["enabled"]: self.deadline_servers = {} return - project_settings = get_project_settings(Session["AVALON_PROJECT"]) + self._project_settings = get_project_settings( + Session["AVALON_PROJECT"]) + + # project_settings/maya/create/CreateRender/aov_separator + try: + self.aov_separator = self._aov_chars[( + self._project_settings["maya"] + ["create"] + ["CreateRender"] + ["aov_separator"] + )] + except KeyError: + self.aov_separator = "_" + try: default_servers = deadline_settings["deadline_urls"] project_servers = ( - project_settings["deadline"] - ["deadline_servers"] + self._project_settings["deadline"]["deadline_servers"] ) self.deadline_servers = { k: default_servers[k] @@ -409,8 +430,10 @@ def _set_default_renderer_settings(self, renderer): renderer (str): Renderer name. """ + prefix = self._image_prefixes[renderer] + prefix = prefix.replace("{aov_separator}", self.aov_separator) cmds.setAttr(self._image_prefix_nodes[renderer], - self._image_prefixes[renderer], + prefix, type="string") asset = get_asset() @@ -446,37 +469,37 @@ def _set_default_renderer_settings(self, renderer): self._set_global_output_settings() - @staticmethod - def _set_renderer_option(renderer_node, arg=None, value=None): - # type: (str, str, str) -> str - """Set option on renderer node. - - If renderer settings node doesn't exists, it is created first. - - Args: - renderer_node (str): Renderer name. - arg (str, optional): Argument name. - value (str, optional): Argument value. - - Returns: - str: Renderer settings node. - - """ - settings = cmds.ls(type=renderer_node) - result = settings[0] if settings else cmds.createNode(renderer_node) - cmds.setAttr(arg.format(result), value) - return result - def _set_vray_settings(self, asset): # type: (dict) -> None """Sets important settings for Vray.""" - node = self._set_renderer_option( - "VRaySettingsNode", "{}.fileNameRenderElementSeparator", "_" - ) + settings = cmds.ls(type="VRaySettingsNode") + node = settings[0] if settings else cmds.createNode("VRaySettingsNode") + + # set separator + # set it in vray menu + if cmds.optionMenuGrp("vrayRenderElementSeparator", exists=True, + q=True): + items = cmds.optionMenuGrp( + "vrayRenderElementSeparator", ill=True, query=True) + separators = [cmds.menuItem(i, label=True, query=True) for i in items] # noqa: E501 + try: + sep_idx = separators.index(self.aov_separator) + except ValueError: + raise CreatorError( + "AOV character {} not in {}".format( + self.aov_separator, separators)) + + cmds.optionMenuGrp( + "vrayRenderElementSeparator", sl=sep_idx + 1, edit=True) + cmds.setAttr( + "{}.fileNameRenderElementSeparator".format(node), + self.aov_separator, + type="string" + ) # set format to exr cmds.setAttr( - "{}.imageFormatStr".format(node), 5) + "{}.imageFormatStr".format(node), "exr", type="string") # animType cmds.setAttr( diff --git a/openpype/hosts/maya/plugins/publish/collect_render.py b/openpype/hosts/maya/plugins/publish/collect_render.py index 59f931c84e7..580d459a907 100644 --- a/openpype/hosts/maya/plugins/publish/collect_render.py +++ b/openpype/hosts/maya/plugins/publish/collect_render.py @@ -62,6 +62,12 @@ class CollectMayaRender(pyblish.api.ContextPlugin): label = "Collect Render Layers" sync_workfile_version = False + _aov_chars = { + "dot": ".", + "dash": "-", + "underscore": "_" + } + def process(self, context): """Entry point to collector.""" render_instance = None @@ -167,6 +173,18 @@ def process(self, context): if renderer.startswith("renderman"): renderer = "renderman" + try: + aov_separator = self._aov_chars[( + context.data["project_settings"] + ["create"] + ["CreateRender"] + ["aov_separator"] + )] + except KeyError: + aov_separator = "_" + + render_instance.data["aovSeparator"] = aov_separator + # return all expected files for all cameras and aovs in given # frame range layer_render_products = get_layer_render_products( @@ -267,6 +285,17 @@ def process(self, context): self.log.info(full_exp_files) self.log.info("collecting layer: {}".format(layer_name)) # Get layer specific settings, might be overrides + + try: + aov_separator = self._aov_chars[( + context.data["project_settings"] + ["create"] + ["CreateRender"] + ["aov_separator"] + )] + except KeyError: + aov_separator = "_" + data = { "subset": expected_layer_name, "attachTo": attach_to, @@ -308,7 +337,8 @@ def process(self, context): "convertToScanline") or False, "useReferencedAovs": render_instance.data.get( "useReferencedAovs") or render_instance.data.get( - "vrayUseReferencedAovs") or False + "vrayUseReferencedAovs") or False, + "aovSeparator": aov_separator } if deadline_url: diff --git a/openpype/hosts/maya/plugins/publish/validate_rendersettings.py b/openpype/hosts/maya/plugins/publish/validate_rendersettings.py index 65ddacfc573..6079d34fbe6 100644 --- a/openpype/hosts/maya/plugins/publish/validate_rendersettings.py +++ b/openpype/hosts/maya/plugins/publish/validate_rendersettings.py @@ -55,13 +55,19 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): ImagePrefixTokens = { - 'arnold': 'maya///_', + 'arnold': 'maya///{aov_separator}', # noqa 'redshift': 'maya///', 'vray': 'maya///', - 'renderman': '_..' + 'renderman': '{aov_separator}..' # noqa } - redshift_AOV_prefix = "/_" + _aov_chars = { + "dot": ".", + "dash": "-", + "underscore": "_" + } + + redshift_AOV_prefix = "/{aov_separator}" # noqa: E501 # WARNING: There is bug? in renderman, translating token # to something left behind mayas default image prefix. So instead @@ -107,6 +113,9 @@ def get_invalid(cls, instance): anim_override = lib.get_attr_in_layer("defaultRenderGlobals.animation", layer=layer) + + prefix = prefix.replace( + "{aov_separator}", instance.data.get("aovSeparator", "_")) if not anim_override: invalid = True cls.log.error("Animation needs to be enabled. Use the same " @@ -138,12 +147,16 @@ def get_invalid(cls, instance): else: node = vray_settings[0] - if cmds.getAttr( - "{}.fileNameRenderElementSeparator".format(node)) != "_": - invalid = False + scene_sep = cmds.getAttr( + "{}.fileNameRenderElementSeparator".format(node)) + if scene_sep != instance.data.get("aovSeparator", "_"): cls.log.error("AOV separator is not set correctly.") + invalid = True if renderer == "redshift": + redshift_AOV_prefix = cls.redshift_AOV_prefix.replace( + "{aov_separator}", instance.data.get("aovSeparator", "_") + ) if re.search(cls.R_AOV_TOKEN, prefix): invalid = True cls.log.error(("Do not use AOV token [ {} ] - " @@ -155,7 +168,7 @@ def get_invalid(cls, instance): for aov in rs_aovs: aov_prefix = cmds.getAttr("{}.filePrefix".format(aov)) # check their image prefix - if aov_prefix != cls.redshift_AOV_prefix: + if aov_prefix != redshift_AOV_prefix: cls.log.error(("AOV ({}) image prefix is not set " "correctly {} != {}").format( cmds.getAttr("{}.name".format(aov)), @@ -181,7 +194,7 @@ def get_invalid(cls, instance): file_prefix = cmds.getAttr("rmanGlobals.imageFileFormat") dir_prefix = cmds.getAttr("rmanGlobals.imageOutputDir") - if file_prefix.lower() != cls.ImagePrefixTokens[renderer].lower(): + if file_prefix.lower() != prefix.lower(): invalid = True cls.log.error("Wrong image prefix [ {} ]".format(file_prefix)) @@ -198,18 +211,20 @@ def get_invalid(cls, instance): cls.log.error("Wrong image prefix [ {} ] - " "You can't use '' token " "with merge AOVs turned on".format(prefix)) - else: - if not re.search(cls.R_AOV_TOKEN, prefix): - invalid = True - cls.log.error("Wrong image prefix [ {} ] - " - "doesn't have: '' or " - "token".format(prefix)) + elif not re.search(cls.R_AOV_TOKEN, prefix): + invalid = True + cls.log.error("Wrong image prefix [ {} ] - " + "doesn't have: '' or " + "token".format(prefix)) # prefix check - if prefix.lower() != cls.ImagePrefixTokens[renderer].lower(): + default_prefix = cls.ImagePrefixTokens[renderer] + default_prefix = default_prefix.replace( + "{aov_separator}", instance.data.get("aovSeparator", "_")) + if prefix.lower() != default_prefix.lower(): cls.log.warning("warning: prefix differs from " "recommended {}".format( - cls.ImagePrefixTokens[renderer])) + default_prefix)) if padding != cls.DEFAULT_PADDING: invalid = True @@ -257,9 +272,14 @@ def get_invalid(cls, instance): @classmethod def repair(cls, instance): - renderer = instance.data['renderer'] layer_node = instance.data['setMembers'] + redshift_AOV_prefix = cls.redshift_AOV_prefix.replace( + "{aov_separator}", instance.data.get("aovSeparator", "_") + ) + default_prefix = cls.ImagePrefixTokens[renderer].replace( + "{aov_separator}", instance.data.get("aovSeparator", "_") + ) with lib.renderlayer(layer_node): default = lib.RENDER_ATTRS['default'] @@ -270,7 +290,7 @@ def repair(cls, instance): node = render_attrs["node"] prefix_attr = render_attrs["prefix"] - fname_prefix = cls.ImagePrefixTokens[renderer] + fname_prefix = default_prefix cmds.setAttr("{}.{}".format(node, prefix_attr), fname_prefix, type="string") @@ -281,7 +301,7 @@ def repair(cls, instance): else: # renderman handles stuff differently cmds.setAttr("rmanGlobals.imageFileFormat", - cls.ImagePrefixTokens[renderer], + default_prefix, type="string") cmds.setAttr("rmanGlobals.imageOutputDir", cls.RendermanDirPrefix, @@ -294,10 +314,13 @@ def repair(cls, instance): else: node = vray_settings[0] + cmds.optionMenuGrp("vrayRenderElementSeparator", + v=instance.data.get("aovSeparator", "_")) cmds.setAttr( "{}.fileNameRenderElementSeparator".format( node), - "_" + instance.data.get("aovSeparator", "_"), + type="string" ) if renderer == "redshift": @@ -306,7 +329,7 @@ def repair(cls, instance): for aov in rs_aovs: # fix AOV prefixes cmds.setAttr( - "{}.filePrefix".format(aov), cls.redshift_AOV_prefix) + "{}.filePrefix".format(aov), redshift_AOV_prefix) # fix AOV file format default_ext = cmds.getAttr( "redshiftOptions.imageFormat", asString=True) diff --git a/openpype/modules/default_modules/deadline/plugins/publish/submit_publish_job.py b/openpype/modules/default_modules/deadline/plugins/publish/submit_publish_job.py index 6b077498194..cdd936b9169 100644 --- a/openpype/modules/default_modules/deadline/plugins/publish/submit_publish_job.py +++ b/openpype/modules/default_modules/deadline/plugins/publish/submit_publish_job.py @@ -104,7 +104,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): families = ["render.farm", "prerender.farm", "renderlayer", "imagesequence", "vrayscene"] - aov_filter = {"maya": [r".*(?:\.|_)*([Bb]eauty)(?:\.|_)*.*"], + aov_filter = {"maya": [r".*(?:[\._-])*([Bb]eauty)(?:[\.|_])*.*"], "aftereffects": [r".*"], # for everything from AE "harmony": [r".*"], # for everything from AE "celaction": [r".*"]} diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index 689d6418ba8..73c75ef3ee3 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -42,7 +42,8 @@ "enabled": true, "defaults": [ "Main" - ] + ], + "aov_separator": "underscore" }, "CreateAnimation": { "enabled": true, diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_create.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_create.json index 44a35af7c1d..e50357cc40c 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_create.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_create.json @@ -46,6 +46,18 @@ "key": "defaults", "label": "Default Subsets", "object_type": "text" + }, + { + "key": "aov_separator", + "label": "AOV Separator character", + "type": "enum", + "multiselection": false, + "default": "underscore", + "enum_items": [ + {"dash": "- (dash)"}, + {"underscore": "_ (underscore)"}, + {"dot": ". (dot)"} + ] } ] }, diff --git a/tools/run_mongo.ps1 b/tools/run_mongo.ps1 index 32f6cfed173..f6fa37207da 100644 --- a/tools/run_mongo.ps1 +++ b/tools/run_mongo.ps1 @@ -113,7 +113,7 @@ $port = 2707 # path to database $dbpath = (Get-Item $openpype_root).parent.FullName + "\mongo_db_data" -$preferred_version = "4.0" +$preferred_version = "5.0" $mongoPath = Find-Mongo $preferred_version Write-Host ">>> " -NoNewLine -ForegroundColor Green