From d7b6582cd38f1dd5a74036778ad22bb36b0dc54e Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Fri, 24 Dec 2021 15:11:53 +0100 Subject: [PATCH 01/16] Fix Maya 2022 Python 3 compatibility: types.BooleanType and types.ListType don't exist in Py3+ --- .../hosts/maya/plugins/publish/validate_ass_relative_paths.py | 4 ++-- .../maya/plugins/publish/validate_vray_referenced_aovs.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_ass_relative_paths.py b/openpype/hosts/maya/plugins/publish/validate_ass_relative_paths.py index 3625d4ab32b..5fb9bd98b15 100644 --- a/openpype/hosts/maya/plugins/publish/validate_ass_relative_paths.py +++ b/openpype/hosts/maya/plugins/publish/validate_ass_relative_paths.py @@ -110,9 +110,9 @@ def maya_is_true(self, attr_val): Maya API will return a list of values, which need to be properly handled to evaluate properly. """ - if isinstance(attr_val, types.BooleanType): + if isinstance(attr_val, bool): return attr_val - elif isinstance(attr_val, (types.ListType, types.GeneratorType)): + elif isinstance(attr_val, (list, types.GeneratorType)): return any(attr_val) else: return bool(attr_val) diff --git a/openpype/hosts/maya/plugins/publish/validate_vray_referenced_aovs.py b/openpype/hosts/maya/plugins/publish/validate_vray_referenced_aovs.py index 6cfbd4049b9..7a48c29b7d5 100644 --- a/openpype/hosts/maya/plugins/publish/validate_vray_referenced_aovs.py +++ b/openpype/hosts/maya/plugins/publish/validate_vray_referenced_aovs.py @@ -82,9 +82,9 @@ def maya_is_true(attr_val): bool: cast Maya attribute to Pythons boolean value. """ - if isinstance(attr_val, types.BooleanType): + if isinstance(attr_val, bool): return attr_val - elif isinstance(attr_val, (types.ListType, types.GeneratorType)): + elif isinstance(attr_val, (list, types.GeneratorType)): return any(attr_val) else: return bool(attr_val) From cb99b0acf791c970aeef7c04c1f01487f8e9f260 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 28 Dec 2021 12:37:46 +0100 Subject: [PATCH 02/16] Ensure `server_aliases` is of type `list` instead of `dict_keys` in Py3+ This resolves an issue where otherwise `lib.imprint` will fail on `self.data` for this Creator plug-in --- openpype/hosts/maya/plugins/create/create_render.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/create/create_render.py b/openpype/hosts/maya/plugins/create/create_render.py index 85919d11665..9e94996734c 100644 --- a/openpype/hosts/maya/plugins/create/create_render.py +++ b/openpype/hosts/maya/plugins/create/create_render.py @@ -254,7 +254,7 @@ def _create_render_settings(self): # get pools pool_names = [] - self.server_aliases = self.deadline_servers.keys() + self.server_aliases = list(self.deadline_servers.keys()) self.data["deadlineServers"] = self.server_aliases self.data["suspendPublishJob"] = False self.data["review"] = True From 74cfde55ec44b70bbc8628e0b4762e114877f89c Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 28 Dec 2021 13:18:12 +0100 Subject: [PATCH 03/16] Fix `dict_keys` object is not subscriptable (Py3+) --- openpype/hosts/maya/plugins/publish/collect_render.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_render.py b/openpype/hosts/maya/plugins/publish/collect_render.py index ac1e495f080..745954e032c 100644 --- a/openpype/hosts/maya/plugins/publish/collect_render.py +++ b/openpype/hosts/maya/plugins/publish/collect_render.py @@ -234,13 +234,14 @@ def process(self, context): publish_meta_path = None for aov in exp_files: full_paths = [] - for file in aov[aov.keys()[0]]: + aov_first_key = list(aov.keys())[0] + for file in aov[aov_first_key]: full_path = os.path.join(workspace, default_render_file, file) full_path = full_path.replace("\\", "/") full_paths.append(full_path) publish_meta_path = os.path.dirname(full_path) - aov_dict[aov.keys()[0]] = full_paths + aov_dict[aov_first_key] = full_paths frame_start_render = int(self.get_render_attribute( "startFrame", layer=layer_name)) From d09065576421d207e2f3e2cb7ab7b80b36fae3a3 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 28 Dec 2021 14:52:59 +0100 Subject: [PATCH 04/16] Support OpenPype icon override in Maya Toolbox in Maya 2022+ - Also refactor import maya.cmds as `mc` to `cmds` to match with other code in the OpenPype code base --- openpype/hosts/maya/api/customize.py | 57 +++++++++++++++++----------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/openpype/hosts/maya/api/customize.py b/openpype/hosts/maya/api/customize.py index 84742626267..83f481f56e5 100644 --- a/openpype/hosts/maya/api/customize.py +++ b/openpype/hosts/maya/api/customize.py @@ -5,7 +5,7 @@ from functools import partial -import maya.cmds as mc +import maya.cmds as cmds import maya.mel as mel from avalon.maya import pipeline @@ -31,9 +31,9 @@ def override_component_mask_commands(): log.info("Installing override_component_mask_commands..") # Get all object mask buttons - buttons = mc.formLayout("objectMaskIcons", - query=True, - childArray=True) + buttons = cmds.formLayout("objectMaskIcons", + query=True, + childArray=True) # Skip the triangle list item buttons = [btn for btn in buttons if btn != "objPickMenuLayout"] @@ -44,14 +44,14 @@ def on_changed_callback(raw_command, state): # toggle the others based on whether any of the buttons # was remaining active after the toggle, if not then # enable all - if mc.getModifiers() == 4: # = CTRL + if cmds.getModifiers() == 4: # = CTRL state = True - active = [mc.iconTextCheckBox(btn, query=True, value=True) for btn - in buttons] + active = [cmds.iconTextCheckBox(btn, query=True, value=True) + for btn in buttons] if any(active): - mc.selectType(allObjects=False) + cmds.selectType(allObjects=False) else: - mc.selectType(allObjects=True) + cmds.selectType(allObjects=True) # Replace #1 with the current button state cmd = raw_command.replace(" #1", " {}".format(int(state))) @@ -64,13 +64,13 @@ def on_changed_callback(raw_command, state): # try to implement the fix. (This also allows us to # "uninstall" the behavior later) if btn not in COMPONENT_MASK_ORIGINAL: - original = mc.iconTextCheckBox(btn, query=True, cc=True) + original = cmds.iconTextCheckBox(btn, query=True, cc=True) COMPONENT_MASK_ORIGINAL[btn] = original # Assign the special callback original = COMPONENT_MASK_ORIGINAL[btn] new_fn = partial(on_changed_callback, original) - mc.iconTextCheckBox(btn, edit=True, cc=new_fn) + cmds.iconTextCheckBox(btn, edit=True, cc=new_fn) def override_toolbox_ui(): @@ -78,18 +78,29 @@ def override_toolbox_ui(): icons = resources.get_resource("icons") # Ensure the maya web icon on toolbox exists - web_button = "ToolBox|MainToolboxLayout|mayaWebButton" - if not mc.iconTextButton(web_button, query=True, exists=True): + maya_version = int(cmds.about(version=True)) + if maya_version >= 2022: + # Maya 2022+ has an updated toolbox with a different web + # button name and type + web_button = "ToolBox|MainToolboxLayout|mayaHomeToolboxButton" + button_fn = cmds.iconTextStaticLabel + else: + web_button = "ToolBox|MainToolboxLayout|mayaWebButton" + button_fn = cmds.iconTextButton + + if not button_fn(web_button, query=True, exists=True): + # Button does not exist + log.warning("Can't find Maya Home/Web button to override toolbox ui..") return - mc.iconTextButton(web_button, edit=True, visible=False) + button_fn(web_button, edit=True, visible=False) # real = 32, but 36 with padding - according to toolbox mel script icon_size = 36 parent = web_button.rsplit("|", 1)[0] # Ensure the parent is a formLayout - if not mc.objectTypeUI(parent) == "formLayout": + if not cmds.objectTypeUI(parent) == "formLayout": return # Create our controls @@ -106,7 +117,7 @@ def override_toolbox_ui(): if look_assigner is not None: controls.append( - mc.iconTextButton( + cmds.iconTextButton( "pype_toolbox_lookmanager", annotation="Look Manager", label="Look Manager", @@ -120,7 +131,7 @@ def override_toolbox_ui(): ) controls.append( - mc.iconTextButton( + cmds.iconTextButton( "pype_toolbox_workfiles", annotation="Work Files", label="Work Files", @@ -136,7 +147,7 @@ def override_toolbox_ui(): ) controls.append( - mc.iconTextButton( + cmds.iconTextButton( "pype_toolbox_loader", annotation="Loader", label="Loader", @@ -152,7 +163,7 @@ def override_toolbox_ui(): ) controls.append( - mc.iconTextButton( + cmds.iconTextButton( "pype_toolbox_manager", annotation="Inventory", label="Inventory", @@ -173,7 +184,7 @@ def override_toolbox_ui(): for i, control in enumerate(controls): previous = controls[i - 1] if i > 0 else web_button - mc.formLayout(parent, edit=True, - attachControl=[control, "bottom", 0, previous], - attachForm=([control, "left", 1], - [control, "right", 1])) + cmds.formLayout(parent, edit=True, + attachControl=[control, "bottom", 0, previous], + attachForm=([control, "left", 1], + [control, "right", 1])) From 7cc091054957a9bc3cd6cdcdac4963ddc899aeb1 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 28 Dec 2021 18:19:33 +0100 Subject: [PATCH 05/16] Python 3 compatibility + correctly find maketx.exe on Windows --- openpype/hosts/maya/api/lib.py | 9 ++++++++- openpype/hosts/maya/plugins/publish/extract_look.py | 8 +++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 52ebcaff649..6dc27b459d0 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -5,6 +5,7 @@ import platform import uuid import math +import sys import json import logging @@ -130,7 +131,13 @@ def float_round(num, places=0, direction=ceil): def pairwise(iterable): """s -> (s0,s1), (s2,s3), (s4, s5), ...""" a = iter(iterable) - return itertools.izip(a, a) + + if sys.version_info[0] == 2: + izip = itertools.izip + else: + izip = zip + + return izip(a, a) def unique(name): diff --git a/openpype/hosts/maya/plugins/publish/extract_look.py b/openpype/hosts/maya/plugins/publish/extract_look.py index 953539f65c9..3b3f17aa7f1 100644 --- a/openpype/hosts/maya/plugins/publish/extract_look.py +++ b/openpype/hosts/maya/plugins/publish/extract_look.py @@ -4,6 +4,7 @@ import sys import json import tempfile +import platform import contextlib import subprocess from collections import OrderedDict @@ -58,6 +59,11 @@ def maketx(source, destination, *args): from openpype.lib import get_oiio_tools_path maketx_path = get_oiio_tools_path("maketx") + + if platform.system().lower() == "windows": + # Ensure .exe extension + maketx_path += ".exe" + if not os.path.exists(maketx_path): print( "OIIO tool not found in {}".format(maketx_path)) @@ -212,7 +218,7 @@ def process(self, instance): self.log.info("Extract sets (%s) ..." % _scene_type) lookdata = instance.data["lookData"] relationships = lookdata["relationships"] - sets = relationships.keys() + sets = list(relationships.keys()) if not sets: self.log.info("No sets found") return From 4d7ff9d54274272c89ebd0438ac489b318037edd Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 30 Dec 2021 09:20:30 +0100 Subject: [PATCH 06/16] Fix `xrange` doesn't exist in Py3+ --- .../maya/plugins/publish/validate_mesh_overlapping_uvs.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openpype/hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py b/openpype/hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py index 57cf0803a49..c06f48f5be7 100644 --- a/openpype/hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py +++ b/openpype/hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py @@ -2,10 +2,16 @@ import openpype.api import openpype.hosts.maya.api.action import math +import sys import maya.api.OpenMaya as om import pymel.core as pm +if sys.version_info[0] != 2: + # Py3+ does not have `xrange` so we mimic it to allow to use it in Py2 + xrange = range + + class GetOverlappingUVs(object): def _createBoundingCircle(self, meshfn): From bd726f8966481af7bcebbb3011cc4bb36836c4cd Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 30 Dec 2021 09:23:46 +0100 Subject: [PATCH 07/16] Fix `xrange` doesn't exist in Py3+ (use `six` instead) --- .../maya/plugins/publish/validate_mesh_overlapping_uvs.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py b/openpype/hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py index c06f48f5be7..3c1bf3cddcd 100644 --- a/openpype/hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py +++ b/openpype/hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py @@ -6,10 +6,7 @@ import maya.api.OpenMaya as om import pymel.core as pm - -if sys.version_info[0] != 2: - # Py3+ does not have `xrange` so we mimic it to allow to use it in Py2 - xrange = range +from six.moves import xrange class GetOverlappingUVs(object): From cf9899b0385c2824ba97973b86bd4153a4e8b496 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 30 Dec 2021 14:19:59 +0100 Subject: [PATCH 08/16] Remove unused import of 'sys' --- .../hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py b/openpype/hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py index 3c1bf3cddcd..c4e823fcbad 100644 --- a/openpype/hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py +++ b/openpype/hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py @@ -2,7 +2,6 @@ import openpype.api import openpype.hosts.maya.api.action import math -import sys import maya.api.OpenMaya as om import pymel.core as pm From 2b36eea3258d4d1ba69d1d1a0a5864037fd89f24 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 30 Dec 2021 14:39:35 +0100 Subject: [PATCH 09/16] Avoid 'dict_keys' issue in Py3+ --- openpype/hosts/maya/plugins/publish/collect_look.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_look.py b/openpype/hosts/maya/plugins/publish/collect_look.py index d39750e917c..b6a76f1e218 100644 --- a/openpype/hosts/maya/plugins/publish/collect_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_look.py @@ -320,7 +320,7 @@ def collect(self, instance): # Collect file nodes used by shading engines (if we have any) files = [] - look_sets = sets.keys() + look_sets = list(sets.keys()) shader_attrs = [ "surfaceShader", "volumeShader", From fa77a4934909b529ad38b79f9fa176fac8913c29 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 4 Jan 2022 14:12:21 +0100 Subject: [PATCH 10/16] Simplify logic that falls back to first valid name. - This fixes an issue with Maya 2022.0 where the maya web button was not yet renamed - Tested in Maya 2019.3.1, Maya 2020.4 and Maya 2022.1 --- openpype/hosts/maya/api/customize.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/openpype/hosts/maya/api/customize.py b/openpype/hosts/maya/api/customize.py index 83f481f56e5..3ee9475035e 100644 --- a/openpype/hosts/maya/api/customize.py +++ b/openpype/hosts/maya/api/customize.py @@ -78,22 +78,22 @@ def override_toolbox_ui(): icons = resources.get_resource("icons") # Ensure the maya web icon on toolbox exists - maya_version = int(cmds.about(version=True)) - if maya_version >= 2022: - # Maya 2022+ has an updated toolbox with a different web - # button name and type - web_button = "ToolBox|MainToolboxLayout|mayaHomeToolboxButton" - button_fn = cmds.iconTextStaticLabel + button_names = [ + # Maya 2022.1+ with maya.cmds.iconTextStaticLabel + "ToolBox|MainToolboxLayout|mayaHomeToolboxButton", + # Older with maya.cmds.iconTextButton + "ToolBox|MainToolboxLayout|mayaWebButton" + ] + for name in button_names: + if cmds.control(name, query=True, exists=True): + web_button = name + break else: - web_button = "ToolBox|MainToolboxLayout|mayaWebButton" - button_fn = cmds.iconTextButton - - if not button_fn(web_button, query=True, exists=True): # Button does not exist log.warning("Can't find Maya Home/Web button to override toolbox ui..") return - button_fn(web_button, edit=True, visible=False) + cmds.control(web_button, edit=True, visible=False) # real = 32, but 36 with padding - according to toolbox mel script icon_size = 36 From d3eca27140e7068dc9a05f1336992da8b9060f56 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 5 Jan 2022 02:07:49 +0100 Subject: [PATCH 11/16] Avoid python version check and use `from six.moves import zip` --- openpype/hosts/maya/api/lib.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 6dc27b459d0..b5bbf122ea0 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -9,7 +9,6 @@ import json import logging -import itertools import contextlib from collections import OrderedDict, defaultdict from math import ceil @@ -130,14 +129,10 @@ def float_round(num, places=0, direction=ceil): def pairwise(iterable): """s -> (s0,s1), (s2,s3), (s4, s5), ...""" - a = iter(iterable) - - if sys.version_info[0] == 2: - izip = itertools.izip - else: - izip = zip + from six.moves import zip - return izip(a, a) + a = iter(iterable) + return zip(a, a) def unique(name): From eca18fa5bbff712ba379c2946fb500f99da72b47 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 5 Jan 2022 02:09:56 +0100 Subject: [PATCH 12/16] Fix Py3 compatibility, refactor itertools.izip_longest --- .../hosts/maya/plugins/publish/extract_camera_mayaScene.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_camera_mayaScene.py b/openpype/hosts/maya/plugins/publish/extract_camera_mayaScene.py index 888dc636b25..fdd36cf0b4d 100644 --- a/openpype/hosts/maya/plugins/publish/extract_camera_mayaScene.py +++ b/openpype/hosts/maya/plugins/publish/extract_camera_mayaScene.py @@ -44,7 +44,8 @@ def grouper(iterable, n, fillvalue=None): """ args = [iter(iterable)] * n - return itertools.izip_longest(fillvalue=fillvalue, *args) + from six.moves import zip_longest + return zip_longest(fillvalue=fillvalue, *args) def unlock(plug): From cb5d3e29eaa4b1280ebdd9a5f19e8dcbef739411 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 5 Jan 2022 02:11:24 +0100 Subject: [PATCH 13/16] Remove unused import sys --- openpype/hosts/maya/api/lib.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index b5bbf122ea0..21d5e581a5b 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -5,7 +5,6 @@ import platform import uuid import math -import sys import json import logging From 3b63abfa6a2b8b54e061834b3d42b5ee013a9627 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 5 Jan 2022 02:17:25 +0100 Subject: [PATCH 14/16] Remove "(Testing Only)" from defaults for Maya 2022 --- openpype/settings/defaults/system_settings/applications.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/defaults/system_settings/applications.json b/openpype/settings/defaults/system_settings/applications.json index 1cbe09f5768..f855117c075 100644 --- a/openpype/settings/defaults/system_settings/applications.json +++ b/openpype/settings/defaults/system_settings/applications.json @@ -93,7 +93,7 @@ } }, "__dynamic_keys_labels__": { - "2022": "2022 (Testing Only)" + "2022": "2022" } } }, From 40978d7ed488e3a1aab2f2ae9344804cd897eb22 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Sun, 23 Jan 2022 14:30:00 +0100 Subject: [PATCH 15/16] Clarify logic of falling back to first server url --- openpype/hosts/maya/plugins/create/create_render.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/maya/plugins/create/create_render.py b/openpype/hosts/maya/plugins/create/create_render.py index 9e94996734c..f1a8acadf4c 100644 --- a/openpype/hosts/maya/plugins/create/create_render.py +++ b/openpype/hosts/maya/plugins/create/create_render.py @@ -287,15 +287,12 @@ def _create_render_settings(self): raise RuntimeError("Both Deadline and Muster are enabled") if deadline_enabled: - # if default server is not between selected, use first one for - # initial list of pools. try: deadline_url = self.deadline_servers["default"] except KeyError: - deadline_url = [ - self.deadline_servers[k] - for k in self.deadline_servers.keys() - ][0] + # if 'default' server is not between selected, + # use first one for initial list of pools. + deadline_url = next(iter(self.deadline_servers.values())) pool_names = self._get_deadline_pools(deadline_url) From c7559b602fbbf3b1fcfe94509859020cbbaedba0 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 25 Jan 2022 17:39:36 +0100 Subject: [PATCH 16/16] Draft to support Color Management v2 preferences in Maya 2022+ --- openpype/hosts/maya/api/lib.py | 75 ++++++++++++++++--- .../defaults/project_anatomy/imageio.json | 11 +++ .../schemas/schema_anatomy_imageio.json | 42 ++++++++++- 3 files changed, 115 insertions(+), 13 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 21d5e581a5b..6578d423e6d 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -2780,7 +2780,27 @@ def set_colorspace(): """ project_name = os.getenv("AVALON_PROJECT") imageio = get_anatomy_settings(project_name)["imageio"]["maya"] - root_dict = imageio["colorManagementPreference"] + + # Maya 2022+ introduces new OCIO v2 color management settings that + # can override the old color managenement preferences. OpenPype has + # separate settings for both so we fall back when necessary. + use_ocio_v2 = imageio["colorManagementPreference_v2"]["enabled"] + required_maya_version = 2022 + maya_version = int(cmds.about(version=True)) + maya_supports_ocio_v2 = maya_version >= required_maya_version + if use_ocio_v2 and not maya_supports_ocio_v2: + # Fallback to legacy behavior with a warning + log.warning("Color Management Preference v2 is enabled but not " + "supported by current Maya version: {} (< {}). Falling " + "back to legacy settings.".format( + maya_version, required_maya_version) + ) + use_ocio_v2 = False + + if use_ocio_v2: + root_dict = imageio["colorManagementPreference_v2"] + else: + root_dict = imageio["colorManagementPreference"] if not isinstance(root_dict, dict): msg = "set_colorspace(): argument should be dictionary" @@ -2788,11 +2808,12 @@ def set_colorspace(): log.debug(">> root_dict: {}".format(root_dict)) - # first enable color management + # enable color management cmds.colorManagementPrefs(e=True, cmEnabled=True) cmds.colorManagementPrefs(e=True, ocioRulesEnabled=True) - # second set config path + # set config path + custom_ocio_config = False if root_dict.get("configFilePath"): unresolved_path = root_dict["configFilePath"] ocio_paths = unresolved_path[platform.system().lower()] @@ -2809,13 +2830,47 @@ def set_colorspace(): cmds.colorManagementPrefs(e=True, cmConfigFileEnabled=True) log.debug("maya '{}' changed to: {}".format( "configFilePath", resolved_path)) - root_dict.pop("configFilePath") + custom_ocio_config = True else: cmds.colorManagementPrefs(e=True, cmConfigFileEnabled=False) - cmds.colorManagementPrefs(e=True, configFilePath="" ) + cmds.colorManagementPrefs(e=True, configFilePath="") + + # If no custom OCIO config file was set we make sure that Maya 2022+ + # either chooses between Maya's newer default v2 or legacy config based + # on OpenPype setting to use ocio v2 or not. + if maya_supports_ocio_v2 and not custom_ocio_config: + if use_ocio_v2: + # Use Maya 2022+ default OCIO v2 config + log.info("Setting default Maya OCIO v2 config") + cmds.colorManagementPrefs(edit=True, configFilePath="") + else: + # Set the Maya default config file path + log.info("Setting default Maya OCIO v1 legacy config") + cmds.colorManagementPrefs(edit=True, configFilePath="legacy") + + # set color spaces for rendering space and view transforms + def _colormanage(**kwargs): + """Wrapper around `cmds.colorManagementPrefs`. - # third set rendering space and view transform - renderSpace = root_dict["renderSpace"] - cmds.colorManagementPrefs(e=True, renderingSpaceName=renderSpace) - viewTransform = root_dict["viewTransform"] - cmds.colorManagementPrefs(e=True, viewTransformName=viewTransform) + This logs errors instead of raising an error so color management + settings get applied as much as possible. + + """ + assert len(kwargs) == 1, "Must receive one keyword argument" + try: + cmds.colorManagementPrefs(edit=True, **kwargs) + log.debug("Setting Color Management Preference: {}".format(kwargs)) + except RuntimeError as exc: + log.error(exc) + + if use_ocio_v2: + _colormanage(renderingSpaceName=root_dict["renderSpace"]) + _colormanage(displayName=root_dict["displayName"]) + _colormanage(viewName=root_dict["viewName"]) + else: + _colormanage(renderingSpaceName=root_dict["renderSpace"]) + if maya_supports_ocio_v2: + _colormanage(viewName=root_dict["viewTransform"]) + _colormanage(displayName="legacy") + else: + _colormanage(viewTransformName=root_dict["viewTransform"]) diff --git a/openpype/settings/defaults/project_anatomy/imageio.json b/openpype/settings/defaults/project_anatomy/imageio.json index 09ab398c371..1065ac58b25 100644 --- a/openpype/settings/defaults/project_anatomy/imageio.json +++ b/openpype/settings/defaults/project_anatomy/imageio.json @@ -177,6 +177,17 @@ } }, "maya": { + "colorManagementPreference_v2": { + "enabled": true, + "configFilePath": { + "windows": [], + "darwin": [], + "linux": [] + }, + "renderSpace": "ACEScg", + "viewName": "ACES 1.0 SDR-video", + "displayName": "sRGB" + }, "colorManagementPreference": { "configFilePath": { "windows": [], diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_anatomy_imageio.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_anatomy_imageio.json index 380ea4a83df..fe37a450f31 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_anatomy_imageio.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_anatomy_imageio.json @@ -377,11 +377,47 @@ "type": "dict", "label": "Maya", "children": [ + { + "key": "colorManagementPreference_v2", + "type": "dict", + "label": "Color Management Preference v2 (Maya 2022+)", + "collapsible": true, + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Use Color Management Preference v2" + }, + { + "type": "path", + "key": "configFilePath", + "label": "OCIO Config File Path", + "multiplatform": true, + "multipath": true + }, + { + "type": "text", + "key": "renderSpace", + "label": "Rendering Space" + }, + { + "type": "text", + "key": "displayName", + "label": "Display" + }, + { + "type": "text", + "key": "viewName", + "label": "View" + } + ] + }, { "key": "colorManagementPreference", "type": "dict", - "label": "Color Managment Preference", - "collapsible": false, + "label": "Color Management Preference (legacy)", + "collapsible": true, "children": [ { "type": "path", @@ -401,7 +437,7 @@ "label": "Viewer Transform" } ] - } + } ] } ]