From 6074876adf2ff180108cc24ec94c0a59bb5ea248 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 22 Nov 2023 17:29:12 +0800 Subject: [PATCH 01/62] regenerate UV Tile Preview and reload textures during playblasting --- openpype/hosts/maya/api/lib.py | 9 +++++++++ openpype/hosts/maya/plugins/publish/extract_playblast.py | 6 ++++-- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 2 ++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 2ecaf87fce..27c61d0af3 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -174,6 +174,15 @@ def maintained_selection(): cmds.select(clear=True) +def regenerate_uv_tile_preview(): + texture_files = cmds.ls(type="file") + if not texture_files: + return + for texture_file in texture_files: + cmds.ogs(regenerateUVTilePreview=texture_file) + cmds.ogs(reloadTextures=True) + + def get_namespace(node): """Return namespace of given node""" node_name = node.rsplit("|", 1)[-1] diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index cfab239da3..8835f288ea 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -43,7 +43,6 @@ class ExtractPlayblast(publish.Extractor): json.dumps(preset, indent=4, sort_keys=True) ) ) - path = capture.capture(log=self.log, **preset) self.log.debug("playblast path {}".format(path)) @@ -125,6 +124,7 @@ class ExtractPlayblast(publish.Extractor): preset["overwrite"] = True cmds.refresh(force=True) + lib.regenerate_uv_tile_preview() refreshFrameInt = int(cmds.playbackOptions(q=True, minTime=True)) cmds.currentTime(refreshFrameInt - 1, edit=True) @@ -164,7 +164,8 @@ class ExtractPlayblast(publish.Extractor): "wireframeOnShaded", "xray", "jointXray", - "backfaceCulling" + "backfaceCulling", + "textures" ] viewport_defaults = {} for key in keys: @@ -180,6 +181,7 @@ class ExtractPlayblast(publish.Extractor): capture_preset["Viewport Options"]["override_viewport_options"] ) + self.log.debug("{}".format(instance.data["panel"])) # Force viewer to False in call to capture because we have our own # viewer opening call to allow a signal to trigger between # playblast and viewer diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index c0be3d77db..550243f274 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -101,6 +101,8 @@ class ExtractThumbnail(publish.Extractor): preset["overwrite"] = True cmds.refresh(force=True) + lib.regenerate_uv_tile_preview() + refreshFrameInt = int(cmds.playbackOptions(q=True, minTime=True)) cmds.currentTime(refreshFrameInt - 1, edit=True) From 15923ddf9c70a296366241c9cefdae0921e59ee9 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 22 Nov 2023 19:02:38 +0800 Subject: [PATCH 02/62] move the regenerate uv_tile_preview code right before the capture --- openpype/hosts/maya/api/lib.py | 6 +++++- openpype/hosts/maya/plugins/publish/extract_playblast.py | 3 ++- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 9 ++++----- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 27c61d0af3..a2a014caef 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -175,11 +175,15 @@ def maintained_selection(): def regenerate_uv_tile_preview(): + """Regenerate UV Tile Preview during playblast + """ + original_texture_loading = cmds.ogs(query=True, reloadTextures=True) texture_files = cmds.ls(type="file") if not texture_files: return for texture_file in texture_files: - cmds.ogs(regenerateUVTilePreview=texture_file) + if cmds.getAttr("{}.uvTilingMode".format(texture_file)) > 0: + cmds.ogs(regenerateUVTilePreview=texture_file) cmds.ogs(reloadTextures=True) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 8835f288ea..5b98fb5fc9 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -43,6 +43,8 @@ class ExtractPlayblast(publish.Extractor): json.dumps(preset, indent=4, sort_keys=True) ) ) + if "textures" in preset["viewport_options"]: + lib.regenerate_uv_tile_preview() path = capture.capture(log=self.log, **preset) self.log.debug("playblast path {}".format(path)) @@ -124,7 +126,6 @@ class ExtractPlayblast(publish.Extractor): preset["overwrite"] = True cmds.refresh(force=True) - lib.regenerate_uv_tile_preview() refreshFrameInt = int(cmds.playbackOptions(q=True, minTime=True)) cmds.currentTime(refreshFrameInt - 1, edit=True) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 550243f274..e2dd89836f 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -101,8 +101,6 @@ class ExtractThumbnail(publish.Extractor): preset["overwrite"] = True cmds.refresh(force=True) - lib.regenerate_uv_tile_preview() - refreshFrameInt = int(cmds.playbackOptions(q=True, minTime=True)) cmds.currentTime(refreshFrameInt - 1, edit=True) @@ -154,9 +152,10 @@ class ExtractThumbnail(publish.Extractor): json.dumps(preset, indent=4, sort_keys=True) ) ) - - path = capture.capture(**preset) - playblast = self._fix_playblast_output_path(path) + if "textures" in preset["viewport_options"]: + lib.regenerate_uv_tile_preview() + path = capture.capture(**preset) + playblast = self._fix_playblast_output_path(path) _, thumbnail = os.path.split(playblast) From 2b98ac1ef2445280e8d0cc0d4131119f9afc8fb9 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 22 Nov 2023 19:04:20 +0800 Subject: [PATCH 03/62] rename regenerateUVTilePreview as reload_textures --- openpype/hosts/maya/api/lib.py | 4 ++-- openpype/hosts/maya/plugins/publish/extract_playblast.py | 2 +- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index a2a014caef..271b90d878 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -174,8 +174,8 @@ def maintained_selection(): cmds.select(clear=True) -def regenerate_uv_tile_preview(): - """Regenerate UV Tile Preview during playblast +def reload_textures(): + """Reload textures during playblast """ original_texture_loading = cmds.ogs(query=True, reloadTextures=True) texture_files = cmds.ls(type="file") diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 5b98fb5fc9..66ebe2ba0d 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -44,7 +44,7 @@ class ExtractPlayblast(publish.Extractor): ) ) if "textures" in preset["viewport_options"]: - lib.regenerate_uv_tile_preview() + lib.reload_textures() path = capture.capture(log=self.log, **preset) self.log.debug("playblast path {}".format(path)) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index e2dd89836f..2b5360efe6 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -153,7 +153,7 @@ class ExtractThumbnail(publish.Extractor): ) ) if "textures" in preset["viewport_options"]: - lib.regenerate_uv_tile_preview() + lib.reload_textures() path = capture.capture(**preset) playblast = self._fix_playblast_output_path(path) From ba83d4cc2f828c8f6c1600f90627d5e86a9c4ec7 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 22 Nov 2023 19:05:36 +0800 Subject: [PATCH 04/62] remove unused variables --- 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 271b90d878..293889ddcc 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -177,7 +177,6 @@ def maintained_selection(): def reload_textures(): """Reload textures during playblast """ - original_texture_loading = cmds.ogs(query=True, reloadTextures=True) texture_files = cmds.ls(type="file") if not texture_files: return From 51f4d8f06f1ff97a86ea20bdcccad16b57210e8f Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 23 Nov 2023 17:28:08 +0800 Subject: [PATCH 05/62] make the reload texture being optional and only enabled when the reloadTextures being enabled --- openpype/hosts/maya/api/lib.py | 6 +++++- .../hosts/maya/plugins/publish/extract_playblast.py | 3 +-- .../hosts/maya/plugins/publish/extract_thumbnail.py | 8 ++++---- openpype/settings/defaults/project_settings/maya.json | 1 + .../projects_schema/schemas/schema_maya_capture.json | 11 +++++++++++ .../maya/server/settings/publish_playblast.py | 2 ++ server_addon/maya/server/version.py | 2 +- 7 files changed, 25 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 293889ddcc..4066ee640b 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -174,9 +174,13 @@ def maintained_selection(): cmds.select(clear=True) -def reload_textures(): +def reload_textures(preset): """Reload textures during playblast """ + if not preset["viewport_options"]["reloadTextures"]: + self.log.debug("Reload Textures during playblasting is disabled.") + return + texture_files = cmds.ls(type="file") if not texture_files: return diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 66ebe2ba0d..872702e66e 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -44,7 +44,7 @@ class ExtractPlayblast(publish.Extractor): ) ) if "textures" in preset["viewport_options"]: - lib.reload_textures() + lib.reload_textures(preset) path = capture.capture(log=self.log, **preset) self.log.debug("playblast path {}".format(path)) @@ -182,7 +182,6 @@ class ExtractPlayblast(publish.Extractor): capture_preset["Viewport Options"]["override_viewport_options"] ) - self.log.debug("{}".format(instance.data["panel"])) # Force viewer to False in call to capture because we have our own # viewer opening call to allow a signal to trigger between # playblast and viewer diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 2b5360efe6..27f008652b 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -152,10 +152,10 @@ class ExtractThumbnail(publish.Extractor): json.dumps(preset, indent=4, sort_keys=True) ) ) - if "textures" in preset["viewport_options"]: - lib.reload_textures() - path = capture.capture(**preset) - playblast = self._fix_playblast_output_path(path) + if "textures" in preset["viewport_options"]: + lib.reload_textures(preset) + path = capture.capture(**preset) + playblast = self._fix_playblast_output_path(path) _, thumbnail = os.path.split(playblast) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index 7719a5e255..fa2f694747 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -1289,6 +1289,7 @@ "twoSidedLighting": true, "lineAAEnable": true, "multiSample": 8, + "reloadTextures": false, "useDefaultMaterial": false, "wireframeOnShaded": false, "xray": false, diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json index d90527ac8c..1aa5b3d2e4 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json @@ -236,6 +236,11 @@ { "type": "splitter" }, + { + "type": "boolean", + "key": "reloadTextures", + "label": "Reload Textures" + }, { "type": "boolean", "key": "useDefaultMaterial", @@ -908,6 +913,12 @@ { "type": "splitter" }, + { + "type": "boolean", + "key": "reloadTextures", + "label": "Reload Textures", + "default": false + }, { "type": "boolean", "key": "useDefaultMaterial", diff --git a/server_addon/maya/server/settings/publish_playblast.py b/server_addon/maya/server/settings/publish_playblast.py index acfcaf5988..205f0eb847 100644 --- a/server_addon/maya/server/settings/publish_playblast.py +++ b/server_addon/maya/server/settings/publish_playblast.py @@ -108,6 +108,7 @@ class ViewportOptionsSetting(BaseSettingsModel): True, title="Enable Anti-Aliasing", section="Anti-Aliasing" ) multiSample: int = Field(8, title="Anti Aliasing Samples") + reloadTextures: bool = Field(False, title="Reload Textures") useDefaultMaterial: bool = Field(False, title="Use Default Material") wireframeOnShaded: bool = Field(False, title="Wireframe On Shaded") xray: bool = Field(False, title="X-Ray") @@ -302,6 +303,7 @@ DEFAULT_PLAYBLAST_SETTING = { "twoSidedLighting": True, "lineAAEnable": True, "multiSample": 8, + "reloadTextures": False, "useDefaultMaterial": False, "wireframeOnShaded": False, "xray": False, diff --git a/server_addon/maya/server/version.py b/server_addon/maya/server/version.py index 805897cda3..b87834cc35 100644 --- a/server_addon/maya/server/version.py +++ b/server_addon/maya/server/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring addon version.""" -__version__ = "0.1.6" +__version__ = "0.1.7" From 2d85b5f106d04e2147e73dfb2bb8c4425ba31ba5 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 24 Nov 2023 12:32:15 +0800 Subject: [PATCH 06/62] code tweaks on capturing playblast and reloadtexture function --- openpype/hosts/maya/api/lib.py | 15 +++++---------- .../maya/plugins/publish/extract_playblast.py | 7 +++++-- .../maya/plugins/publish/extract_thumbnail.py | 7 +++++-- openpype/settings/lib.py | 2 +- openpype/vendor/python/common/capture.py | 2 ++ 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 4066ee640b..078ed5192b 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -174,19 +174,14 @@ def maintained_selection(): cmds.select(clear=True) -def reload_textures(preset): +def reload_textures(): """Reload textures during playblast """ - if not preset["viewport_options"]["reloadTextures"]: - self.log.debug("Reload Textures during playblasting is disabled.") - return - texture_files = cmds.ls(type="file") - if not texture_files: - return - for texture_file in texture_files: - if cmds.getAttr("{}.uvTilingMode".format(texture_file)) > 0: - cmds.ogs(regenerateUVTilePreview=texture_file) + if texture_files: + for texture_file in texture_files: + if cmds.getAttr("{}.uvTilingMode".format(texture_file)) > 0: + cmds.ogs(regenerateUVTilePreview=texture_file) cmds.ogs(reloadTextures=True) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 872702e66e..a3a2f8a5a5 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -43,8 +43,11 @@ class ExtractPlayblast(publish.Extractor): json.dumps(preset, indent=4, sort_keys=True) ) ) - if "textures" in preset["viewport_options"]: - lib.reload_textures(preset) + if ( + preset["viewport_options"].get("reloadTextures") + and "textures" in preset["viewport_options"] + ): + lib.reload_textures() path = capture.capture(log=self.log, **preset) self.log.debug("playblast path {}".format(path)) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 27f008652b..ef843c9df8 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -152,8 +152,11 @@ class ExtractThumbnail(publish.Extractor): json.dumps(preset, indent=4, sort_keys=True) ) ) - if "textures" in preset["viewport_options"]: - lib.reload_textures(preset) + if ( + preset["viewport_options"].get("reloadTextures") + and "textures" in preset["viewport_options"] + ): + lib.reload_textures() path = capture.capture(**preset) playblast = self._fix_playblast_output_path(path) diff --git a/openpype/settings/lib.py b/openpype/settings/lib.py index ce62dde43f..d62e50d3c7 100644 --- a/openpype/settings/lib.py +++ b/openpype/settings/lib.py @@ -172,7 +172,7 @@ def save_studio_settings(data): clear_metadata_from_settings(new_data) changes = calculate_changes(old_data, new_data) - modules_manager = ModulesManager(_system_settings=new_data) + modules_manager = ModulesManager(new_data) warnings = [] for module in modules_manager.get_enabled_modules(): diff --git a/openpype/vendor/python/common/capture.py b/openpype/vendor/python/common/capture.py index 224699f916..b6d15ae47a 100644 --- a/openpype/vendor/python/common/capture.py +++ b/openpype/vendor/python/common/capture.py @@ -760,6 +760,8 @@ def _applied_viewport_options(options, panel): # Try to set as much as possible of the state by setting them one by # one. This way we can also report the failing key values explicitly. for key, value in options.items(): + if key == "reloadTextures": + continue try: cmds.modelEditor(panel, edit=True, **{key: value}) except TypeError: From 950581fcd865c43482995bed876ce10977648f70 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 24 Nov 2023 18:14:01 +0800 Subject: [PATCH 07/62] code tweaks on getting texture from the viewport_options dict --- openpype/hosts/maya/plugins/publish/extract_playblast.py | 2 +- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index a3a2f8a5a5..26b2ac7086 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -45,7 +45,7 @@ class ExtractPlayblast(publish.Extractor): ) if ( preset["viewport_options"].get("reloadTextures") - and "textures" in preset["viewport_options"] + and preset["viewport_options"].get("textures") ): lib.reload_textures() path = capture.capture(log=self.log, **preset) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index ef843c9df8..a64d31f6d9 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -154,7 +154,7 @@ class ExtractThumbnail(publish.Extractor): ) if ( preset["viewport_options"].get("reloadTextures") - and "textures" in preset["viewport_options"] + and preset["viewport_options"].get("textures") ): lib.reload_textures() path = capture.capture(**preset) From 39faa7001e53f5f3dd76064b9ae9d6ddb3daf3be Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 27 Nov 2023 18:09:06 +0800 Subject: [PATCH 08/62] pop the value of reloadTextures before capture --- openpype/hosts/maya/plugins/publish/extract_playblast.py | 2 ++ openpype/vendor/python/common/capture.py | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 26b2ac7086..e59309c0fd 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -48,6 +48,8 @@ class ExtractPlayblast(publish.Extractor): and preset["viewport_options"].get("textures") ): lib.reload_textures() + + preset.pop("reloadTextures") # not supported by `capture` path = capture.capture(log=self.log, **preset) self.log.debug("playblast path {}".format(path)) diff --git a/openpype/vendor/python/common/capture.py b/openpype/vendor/python/common/capture.py index b6d15ae47a..224699f916 100644 --- a/openpype/vendor/python/common/capture.py +++ b/openpype/vendor/python/common/capture.py @@ -760,8 +760,6 @@ def _applied_viewport_options(options, panel): # Try to set as much as possible of the state by setting them one by # one. This way we can also report the failing key values explicitly. for key, value in options.items(): - if key == "reloadTextures": - continue try: cmds.modelEditor(panel, edit=True, **{key: value}) except TypeError: From 84f58241a6f1347d12fb9b7e1868765a0eeef428 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 27 Nov 2023 18:49:12 +0800 Subject: [PATCH 09/62] pop the reloadvalues from the preset in thumbnail extractor --- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index a64d31f6d9..380810d8c0 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -157,6 +157,7 @@ class ExtractThumbnail(publish.Extractor): and preset["viewport_options"].get("textures") ): lib.reload_textures() + preset.pop("reloadTextures") # not supported by `capture` path = capture.capture(**preset) playblast = self._fix_playblast_output_path(path) From 69c45c517f3dd594c379f1172ce739ceeba9cb39 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 27 Nov 2023 23:32:47 +0800 Subject: [PATCH 10/62] make sure reloadtextures is popped when it exists in the preset dict --- openpype/hosts/maya/plugins/publish/extract_playblast.py | 3 +-- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index e59309c0fd..56113d6a53 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -48,8 +48,7 @@ class ExtractPlayblast(publish.Extractor): and preset["viewport_options"].get("textures") ): lib.reload_textures() - - preset.pop("reloadTextures") # not supported by `capture` + preset.pop("reloadTextures") # not supported by `capture` path = capture.capture(log=self.log, **preset) self.log.debug("playblast path {}".format(path)) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 380810d8c0..aa0a68e4f5 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -157,7 +157,7 @@ class ExtractThumbnail(publish.Extractor): and preset["viewport_options"].get("textures") ): lib.reload_textures() - preset.pop("reloadTextures") # not supported by `capture` + preset.pop("reloadTextures") # not supported by `capture` path = capture.capture(**preset) playblast = self._fix_playblast_output_path(path) From 899bf8604661efee620a7dd65a44c41e9bd191ab Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 28 Nov 2023 12:13:32 +0800 Subject: [PATCH 11/62] tweak on the preset.pop --- openpype/hosts/max/plugins/publish/extract_thumbnail.py | 7 +++++-- openpype/hosts/maya/plugins/publish/extract_playblast.py | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/extract_thumbnail.py b/openpype/hosts/max/plugins/publish/extract_thumbnail.py index 02fa75e032..114575cd0e 100644 --- a/openpype/hosts/max/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/max/plugins/publish/extract_thumbnail.py @@ -1,10 +1,10 @@ import os import pyblish.api -from openpype.pipeline import publish +from openpype.pipeline import publish, OptionalPyblishPluginMixin from openpype.hosts.max.api.preview_animation import render_preview_animation -class ExtractThumbnail(publish.Extractor): +class ExtractThumbnail(publish.Extractor, OptionalPyblishPluginMixin): """Extract Thumbnail for Review """ @@ -12,8 +12,11 @@ class ExtractThumbnail(publish.Extractor): label = "Extract Thumbnail" hosts = ["max"] families = ["review"] + optional = True def process(self, instance): + if not self.is_active(instance.data): + return ext = instance.data.get("imageFormat") frame = int(instance.data["frameStart"]) staging_dir = self.staging_dir(instance) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 56113d6a53..0e001497bd 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -48,7 +48,7 @@ class ExtractPlayblast(publish.Extractor): and preset["viewport_options"].get("textures") ): lib.reload_textures() - preset.pop("reloadTextures") # not supported by `capture` + preset.pop("reloadTextures", None) # not supported by `capture` path = capture.capture(log=self.log, **preset) self.log.debug("playblast path {}".format(path)) From cafd02a8512b6cd24137febcc393443240949f69 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 28 Nov 2023 12:15:26 +0800 Subject: [PATCH 12/62] preset.pop tweaks in thumbnail extractor --- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index aa0a68e4f5..67455f60f0 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -157,7 +157,7 @@ class ExtractThumbnail(publish.Extractor): and preset["viewport_options"].get("textures") ): lib.reload_textures() - preset.pop("reloadTextures") # not supported by `capture` + preset.pop("reloadTextures", None) # not supported by `capture` path = capture.capture(**preset) playblast = self._fix_playblast_output_path(path) From cbc4c679223a6a3230105b8fe9cae356a4cf3a59 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 7 Dec 2023 21:45:29 +0800 Subject: [PATCH 13/62] make sure the texture can be reloaded --- .../hosts/max/plugins/publish/extract_thumbnail.py | 6 ++---- .../hosts/maya/plugins/publish/extract_playblast.py | 11 ++++++----- .../hosts/maya/plugins/publish/extract_thumbnail.py | 13 +++++++------ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/extract_thumbnail.py b/openpype/hosts/max/plugins/publish/extract_thumbnail.py index 114575cd0e..1b912ac0ec 100644 --- a/openpype/hosts/max/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/max/plugins/publish/extract_thumbnail.py @@ -1,10 +1,10 @@ import os import pyblish.api -from openpype.pipeline import publish, OptionalPyblishPluginMixin +from openpype.pipeline import publish from openpype.hosts.max.api.preview_animation import render_preview_animation -class ExtractThumbnail(publish.Extractor, OptionalPyblishPluginMixin): +class ExtractThumbnail(publish.Extractor): """Extract Thumbnail for Review """ @@ -15,8 +15,6 @@ class ExtractThumbnail(publish.Extractor, OptionalPyblishPluginMixin): optional = True def process(self, instance): - if not self.is_active(instance.data): - return ext = instance.data.get("imageFormat") frame = int(instance.data["frameStart"]) staging_dir = self.staging_dir(instance) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 0e001497bd..b885308613 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -43,11 +43,12 @@ class ExtractPlayblast(publish.Extractor): json.dumps(preset, indent=4, sort_keys=True) ) ) - if ( - preset["viewport_options"].get("reloadTextures") - and preset["viewport_options"].get("textures") - ): - lib.reload_textures() + if "textures" in preset["viewport_options"]: + if "reloadTextures" in preset["viewport_options"]: + lib.reload_textures() + else: + self.log.debug( + "Reload Textures during playblasting is disabled.") preset.pop("reloadTextures", None) # not supported by `capture` path = capture.capture(log=self.log, **preset) self.log.debug("playblast path {}".format(path)) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 67455f60f0..77a538b95d 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -152,12 +152,13 @@ class ExtractThumbnail(publish.Extractor): json.dumps(preset, indent=4, sort_keys=True) ) ) - if ( - preset["viewport_options"].get("reloadTextures") - and preset["viewport_options"].get("textures") - ): - lib.reload_textures() - preset.pop("reloadTextures", None) # not supported by `capture` + if "textures" in preset["viewport_options"]: + if "reloadTextures" in preset["viewport_options"]: + lib.reload_textures() + else: + self.log.debug( + "Reload Textures during playblasting is disabled.") + preset.pop("reloadTextures", None) path = capture.capture(**preset) playblast = self._fix_playblast_output_path(path) From 7061eabdb52f06abcb12bccc1ff5ef79bced75bb Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 7 Dec 2023 21:47:03 +0800 Subject: [PATCH 14/62] restore unnecessary tweaks --- openpype/hosts/max/plugins/publish/extract_thumbnail.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/max/plugins/publish/extract_thumbnail.py b/openpype/hosts/max/plugins/publish/extract_thumbnail.py index 1b912ac0ec..02fa75e032 100644 --- a/openpype/hosts/max/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/max/plugins/publish/extract_thumbnail.py @@ -12,7 +12,6 @@ class ExtractThumbnail(publish.Extractor): label = "Extract Thumbnail" hosts = ["max"] families = ["review"] - optional = True def process(self, instance): ext = instance.data.get("imageFormat") From b73146a538a13c8e5f94a5cb1d3ca5e0c3d4eefe Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 11 Dec 2023 23:47:10 +0800 Subject: [PATCH 15/62] preset pop value should be correct --- openpype/hosts/maya/plugins/publish/extract_playblast.py | 3 ++- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index b885308613..4ce7e19ee2 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -49,7 +49,8 @@ class ExtractPlayblast(publish.Extractor): else: self.log.debug( "Reload Textures during playblasting is disabled.") - preset.pop("reloadTextures", None) # not supported by `capture` + # not supported by `capture` + preset["viewport_options"].pop("reloadTextures", None) path = capture.capture(log=self.log, **preset) self.log.debug("playblast path {}".format(path)) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 77a538b95d..bc5f9bc4ed 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -158,7 +158,8 @@ class ExtractThumbnail(publish.Extractor): else: self.log.debug( "Reload Textures during playblasting is disabled.") - preset.pop("reloadTextures", None) + # not supported by `capture` + preset["viewport_options"].pop("reloadTextures", None) path = capture.capture(**preset) playblast = self._fix_playblast_output_path(path) From 28a62bff59fc12c857c38090b923280a0c2d9ffc Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 12 Dec 2023 00:15:25 +0800 Subject: [PATCH 16/62] make sure the material loading mode is parallel --- openpype/hosts/maya/api/lib.py | 12 +++++++++++- .../maya/plugins/publish/extract_playblast.py | 18 ++++++++++-------- .../maya/plugins/publish/extract_thumbnail.py | 8 ++++++-- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 2a9defbf2d..817688258b 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -180,7 +180,17 @@ def reload_textures(): for texture_file in texture_files: if cmds.getAttr("{}.uvTilingMode".format(texture_file)) > 0: cmds.ogs(regenerateUVTilePreview=texture_file) - cmds.ogs(reloadTextures=True) + + +@contextlib.contextmanager +def material_loading_mode(mode="immediate"): + """Set material loading mode during context""" + original = cmds.displayPref(query=True, materialLoadingMode=True) + cmds.displayPref(materialLoadingMode=mode) + try: + yield + finally: + cmds.displayPref(materialLoadingMode=original) def get_namespace(node): diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 4ce7e19ee2..b540a2c56d 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -43,15 +43,17 @@ class ExtractPlayblast(publish.Extractor): json.dumps(preset, indent=4, sort_keys=True) ) ) - if "textures" in preset["viewport_options"]: - if "reloadTextures" in preset["viewport_options"]: + if "textures" in preset["viewport_options"] and ( + "reloadTextures" in preset["viewport_options"] + ): + with lib.material_loading_mode(): lib.reload_textures() - else: - self.log.debug( - "Reload Textures during playblasting is disabled.") - # not supported by `capture` - preset["viewport_options"].pop("reloadTextures", None) - path = capture.capture(log=self.log, **preset) + # not supported by `capture` + preset["viewport_options"].pop("reloadTextures", None) + path = capture.capture(log=self.log, **preset) + else: + preset["viewport_options"].pop("reloadTextures", None) + path = capture.capture(log=self.log, **preset) self.log.debug("playblast path {}".format(path)) def process(self, instance): diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index bc5f9bc4ed..10082436d6 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -154,12 +154,16 @@ class ExtractThumbnail(publish.Extractor): ) if "textures" in preset["viewport_options"]: if "reloadTextures" in preset["viewport_options"]: - lib.reload_textures() + with lib.material_loading_mode(): + lib.reload_textures() + preset["viewport_options"].pop("reloadTextures", None) + path = capture.capture(**preset) else: self.log.debug( "Reload Textures during playblasting is disabled.") + preset["viewport_options"].pop("reloadTextures", None) + path = capture.capture(**preset) # not supported by `capture` - preset["viewport_options"].pop("reloadTextures", None) path = capture.capture(**preset) playblast = self._fix_playblast_output_path(path) From 464889529132d2a6921dfb8fe80abe7db2f02d38 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 15 Dec 2023 23:09:11 +0800 Subject: [PATCH 17/62] make sure the contextlib.nested used before material loading while it is compatible for both python2 and 3 --- openpype/hosts/maya/api/lib.py | 5 ++- .../maya/plugins/publish/extract_playblast.py | 42 ++++++++++++------- .../maya/plugins/publish/extract_thumbnail.py | 21 +++++----- 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 817688258b..41290b805e 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -172,8 +172,9 @@ def maintained_selection(): cmds.select(clear=True) -def reload_textures(): - """Reload textures during playblast +def reload_all_udim_tile_previews(): + """Regenerate all UDIM tile preview in texture file + nodes during context """ texture_files = cmds.ls(type="file") if texture_files: diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index b540a2c56d..7bcddf97f1 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -43,17 +43,13 @@ class ExtractPlayblast(publish.Extractor): json.dumps(preset, indent=4, sort_keys=True) ) ) - if "textures" in preset["viewport_options"] and ( - "reloadTextures" in preset["viewport_options"] - ): - with lib.material_loading_mode(): - lib.reload_textures() - # not supported by `capture` - preset["viewport_options"].pop("reloadTextures", None) - path = capture.capture(log=self.log, **preset) - else: - preset["viewport_options"].pop("reloadTextures", None) - path = capture.capture(log=self.log, **preset) + + if preset["viewport_options"].get("reloadTextures"): + # Regenerate all UDIM tiles previews + lib.reload_all_udim_tile_previews() + # not supported by `capture` + preset["viewport_options"].pop("reloadTextures", None) + path = capture.capture(log=self.log, **preset) self.log.debug("playblast path {}".format(path)) def process(self, instance): @@ -206,11 +202,23 @@ class ExtractPlayblast(publish.Extractor): # TODO: Remove once dropping Python 2. if getattr(contextlib, "nested", None): # Python 3 compatibility. - with contextlib.nested( - lib.maintained_time(), - panel_camera(instance.data["panel"], preset["camera"]) - ): - self._capture(preset) + if preset["viewport_options"].get("textures"): + # If capture includes textures then ensure material + # load mode is set to `immediate` to ensure all + # textures have loaded when playblast starts + with contextlib.nested( + lib.maintained_time(), + panel_camera(instance.data["panel"], preset["camera"]), + lib.material_loading_mode() + ): + self._capture(preset) + + else: + with contextlib.nested( + lib.maintained_time(), + panel_camera(instance.data["panel"], preset["camera"]) + ): + self._capture(preset) else: # Python 2 compatibility. with contextlib.ExitStack() as stack: @@ -218,6 +226,8 @@ class ExtractPlayblast(publish.Extractor): stack.enter_context( panel_camera(instance.data["panel"], preset["camera"]) ) + if preset["viewport_options"].get("textures"): + stack.enter_context(lib.material_loading_mode()) self._capture(preset) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 10082436d6..b24cda8f07 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -152,19 +152,18 @@ class ExtractThumbnail(publish.Extractor): json.dumps(preset, indent=4, sort_keys=True) ) ) + + if "reloadTextures" in preset["viewport_options"]: + lib.reload_all_udim_tile_previews() + + preset["viewport_options"].pop("reloadTextures", None) if "textures" in preset["viewport_options"]: - if "reloadTextures" in preset["viewport_options"]: - with lib.material_loading_mode(): - lib.reload_textures() - preset["viewport_options"].pop("reloadTextures", None) - path = capture.capture(**preset) - else: - self.log.debug( - "Reload Textures during playblasting is disabled.") - preset["viewport_options"].pop("reloadTextures", None) + with lib.material_loading_mode(): path = capture.capture(**preset) - # not supported by `capture` - path = capture.capture(**preset) + else: + self.log.debug("Reload Textures during playblasting is disabled.") + path = capture.capture(**preset) + playblast = self._fix_playblast_output_path(path) _, thumbnail = os.path.split(playblast) From c62862a773ebc819d1385771a10287c8ae04f9df Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 15 Dec 2023 23:10:21 +0800 Subject: [PATCH 18/62] hound --- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index b24cda8f07..3f25a9b17b 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -161,7 +161,8 @@ class ExtractThumbnail(publish.Extractor): with lib.material_loading_mode(): path = capture.capture(**preset) else: - self.log.debug("Reload Textures during playblasting is disabled.") + self.log.debug( + "Reload Textures during playblasting is disabled.") path = capture.capture(**preset) playblast = self._fix_playblast_output_path(path) From 9f1ab7519fac8f7715ea42c21578fff3ef4225e2 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 15 Dec 2023 23:48:05 +0800 Subject: [PATCH 19/62] add exitstack.py into maya api folder & code tweaks --- openpype/hosts/maya/api/exitstack.py | 120 ++++++++++++++++++ .../maya/plugins/publish/extract_playblast.py | 37 ++---- .../maya/plugins/publish/extract_thumbnail.py | 4 +- 3 files changed, 130 insertions(+), 31 deletions(-) create mode 100644 openpype/hosts/maya/api/exitstack.py diff --git a/openpype/hosts/maya/api/exitstack.py b/openpype/hosts/maya/api/exitstack.py new file mode 100644 index 0000000000..dcf7131bd3 --- /dev/null +++ b/openpype/hosts/maya/api/exitstack.py @@ -0,0 +1,120 @@ +import contextlib + # TODO: Remove the entire script once dropping Python 2. +if getattr(contextlib, "nested", None): + from contextlib import ExitStack # noqa +else: + import sys + from collections import deque + + + class ExitStack(object): + """Context manager for dynamic management of a stack of exit callbacks + + For example: + + with ExitStack() as stack: + files = [stack.enter_context(open(fname)) for fname in filenames] + # All opened files will automatically be closed at the end of + # the with statement, even if attempts to open files later + # in the list raise an exception + + """ + def __init__(self): + self._exit_callbacks = deque() + + def pop_all(self): + """Preserve the context stack by transferring it to a new instance""" + new_stack = type(self)() + new_stack._exit_callbacks = self._exit_callbacks + self._exit_callbacks = deque() + return new_stack + + def _push_cm_exit(self, cm, cm_exit): + """Helper to correctly register callbacks to __exit__ methods""" + def _exit_wrapper(*exc_details): + return cm_exit(cm, *exc_details) + _exit_wrapper.__self__ = cm + self.push(_exit_wrapper) + + def push(self, exit): + """Registers a callback with the standard __exit__ method signature + + Can suppress exceptions the same way __exit__ methods can. + + Also accepts any object with an __exit__ method (registering a call + to the method instead of the object itself) + """ + # We use an unbound method rather than a bound method to follow + # the standard lookup behaviour for special methods + _cb_type = type(exit) + try: + exit_method = _cb_type.__exit__ + except AttributeError: + # Not a context manager, so assume its a callable + self._exit_callbacks.append(exit) + else: + self._push_cm_exit(exit, exit_method) + return exit # Allow use as a decorator + + def callback(self, callback, *args, **kwds): + """Registers an arbitrary callback and arguments. + + Cannot suppress exceptions. + """ + def _exit_wrapper(exc_type, exc, tb): + callback(*args, **kwds) + # We changed the signature, so using @wraps is not appropriate, but + # setting __wrapped__ may still help with introspection + _exit_wrapper.__wrapped__ = callback + self.push(_exit_wrapper) + return callback # Allow use as a decorator + + def enter_context(self, cm): + """Enters the supplied context manager + + If successful, also pushes its __exit__ method as a callback and + returns the result of the __enter__ method. + """ + # We look up the special methods on the type to match the with statement + _cm_type = type(cm) + _exit = _cm_type.__exit__ + result = _cm_type.__enter__(cm) + self._push_cm_exit(cm, _exit) + return result + + def close(self): + """Immediately unwind the context stack""" + self.__exit__(None, None, None) + + def __enter__(self): + return self + + def __exit__(self, *exc_details): + # We manipulate the exception state so it behaves as though + # we were actually nesting multiple with statements + frame_exc = sys.exc_info()[1] + def _fix_exception_context(new_exc, old_exc): + while 1: + exc_context = new_exc.__context__ + if exc_context in (None, frame_exc): + break + new_exc = exc_context + new_exc.__context__ = old_exc + + # Callbacks are invoked in LIFO order to match the behaviour of + # nested context managers + suppressed_exc = False + while self._exit_callbacks: + cb = self._exit_callbacks.pop() + try: + if cb(*exc_details): + suppressed_exc = True + exc_details = (None, None, None) + except: + new_exc_details = sys.exc_info() + # simulate the stack of exceptions by setting the context + _fix_exception_context(new_exc_details[1], exc_details[1]) + if not self._exit_callbacks: + raise + exc_details = new_exc_details + return suppressed_exc diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 7bcddf97f1..2e11a5f26e 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -7,6 +7,7 @@ import capture from openpype.pipeline import publish from openpype.hosts.maya.api import lib +from openpype.hosts.maya.api.exitstack import ExitStack from maya import cmds @@ -199,37 +200,15 @@ class ExtractPlayblast(publish.Extractor): preset.update(panel_preset) # Need to ensure Python 2 compatibility. - # TODO: Remove once dropping Python 2. - if getattr(contextlib, "nested", None): - # Python 3 compatibility. + with ExitStack() as stack: + stack.enter_context(lib.maintained_time()) + stack.enter_context( + panel_camera(instance.data["panel"], preset["camera"]) + ) if preset["viewport_options"].get("textures"): - # If capture includes textures then ensure material - # load mode is set to `immediate` to ensure all - # textures have loaded when playblast starts - with contextlib.nested( - lib.maintained_time(), - panel_camera(instance.data["panel"], preset["camera"]), - lib.material_loading_mode() - ): - self._capture(preset) + stack.enter_context(lib.material_loading_mode()) - else: - with contextlib.nested( - lib.maintained_time(), - panel_camera(instance.data["panel"], preset["camera"]) - ): - self._capture(preset) - else: - # Python 2 compatibility. - with contextlib.ExitStack() as stack: - stack.enter_context(lib.maintained_time()) - stack.enter_context( - panel_camera(instance.data["panel"], preset["camera"]) - ) - if preset["viewport_options"].get("textures"): - stack.enter_context(lib.material_loading_mode()) - - self._capture(preset) + self._capture(preset) # Restoring viewport options. if viewport_defaults: diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 3f25a9b17b..b8e7b19bc6 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -153,11 +153,11 @@ class ExtractThumbnail(publish.Extractor): ) ) - if "reloadTextures" in preset["viewport_options"]: + if preset["viewport_options"].get("reloadTextures"): lib.reload_all_udim_tile_previews() preset["viewport_options"].pop("reloadTextures", None) - if "textures" in preset["viewport_options"]: + if preset["viewport_options"].get("textures"): with lib.material_loading_mode(): path = capture.capture(**preset) else: From b7da5708786130ebbfddaaa75d3ff40aea6453c9 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 15 Dec 2023 23:53:40 +0800 Subject: [PATCH 20/62] hound --- openpype/hosts/maya/api/exitstack.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/maya/api/exitstack.py b/openpype/hosts/maya/api/exitstack.py index dcf7131bd3..ee32fad56b 100644 --- a/openpype/hosts/maya/api/exitstack.py +++ b/openpype/hosts/maya/api/exitstack.py @@ -1,19 +1,19 @@ import contextlib - # TODO: Remove the entire script once dropping Python 2. +# TODO: Remove the entire script once dropping Python 2. if getattr(contextlib, "nested", None): from contextlib import ExitStack # noqa else: import sys from collections import deque - class ExitStack(object): """Context manager for dynamic management of a stack of exit callbacks For example: with ExitStack() as stack: - files = [stack.enter_context(open(fname)) for fname in filenames] + files = [stack.enter_context(open(fname)) + for fname in filenames] # All opened files will automatically be closed at the end of # the with statement, even if attempts to open files later # in the list raise an exception @@ -30,7 +30,8 @@ else: return new_stack def _push_cm_exit(self, cm, cm_exit): - """Helper to correctly register callbacks to __exit__ methods""" + """Helper to correctly register callbacks + to __exit__ methods""" def _exit_wrapper(*exc_details): return cm_exit(cm, *exc_details) _exit_wrapper.__self__ = cm @@ -54,7 +55,7 @@ else: self._exit_callbacks.append(exit) else: self._push_cm_exit(exit, exit_method) - return exit # Allow use as a decorator + return exit # Allow use as a decorator def callback(self, callback, *args, **kwds): """Registers an arbitrary callback and arguments. @@ -67,7 +68,7 @@ else: # setting __wrapped__ may still help with introspection _exit_wrapper.__wrapped__ = callback self.push(_exit_wrapper) - return callback # Allow use as a decorator + return callback # Allow use as a decorator def enter_context(self, cm): """Enters the supplied context manager @@ -75,7 +76,8 @@ else: If successful, also pushes its __exit__ method as a callback and returns the result of the __enter__ method. """ - # We look up the special methods on the type to match the with statement + # We look up the special methods on the type to + # match the with statement _cm_type = type(cm) _exit = _cm_type.__exit__ result = _cm_type.__enter__(cm) @@ -93,6 +95,7 @@ else: # We manipulate the exception state so it behaves as though # we were actually nesting multiple with statements frame_exc = sys.exc_info()[1] + def _fix_exception_context(new_exc, old_exc): while 1: exc_context = new_exc.__context__ @@ -110,7 +113,7 @@ else: if cb(*exc_details): suppressed_exc = True exc_details = (None, None, None) - except: + except Exception: new_exc_details = sys.exc_info() # simulate the stack of exceptions by setting the context _fix_exception_context(new_exc_details[1], exc_details[1]) From 4e005bfd5780c17ea128ac25c480f339b048f96a Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 15 Dec 2023 23:55:46 +0800 Subject: [PATCH 21/62] hound --- openpype/hosts/maya/api/exitstack.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openpype/hosts/maya/api/exitstack.py b/openpype/hosts/maya/api/exitstack.py index ee32fad56b..9b049f1914 100644 --- a/openpype/hosts/maya/api/exitstack.py +++ b/openpype/hosts/maya/api/exitstack.py @@ -5,8 +5,7 @@ if getattr(contextlib, "nested", None): else: import sys from collections import deque - - class ExitStack(object): + class ExitStack(object) """Context manager for dynamic management of a stack of exit callbacks For example: From 7dc19ec7594ce20669b2d4727cf0a2267f119e58 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 15 Dec 2023 23:56:55 +0800 Subject: [PATCH 22/62] hound --- openpype/hosts/maya/api/exitstack.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/api/exitstack.py b/openpype/hosts/maya/api/exitstack.py index 9b049f1914..cacaa396f0 100644 --- a/openpype/hosts/maya/api/exitstack.py +++ b/openpype/hosts/maya/api/exitstack.py @@ -5,7 +5,9 @@ if getattr(contextlib, "nested", None): else: import sys from collections import deque - class ExitStack(object) + + class ExitStack(object): + """Context manager for dynamic management of a stack of exit callbacks For example: @@ -22,7 +24,8 @@ else: self._exit_callbacks = deque() def pop_all(self): - """Preserve the context stack by transferring it to a new instance""" + """Preserve the context stack by transferring + it to a new instance""" new_stack = type(self)() new_stack._exit_callbacks = self._exit_callbacks self._exit_callbacks = deque() From 008f78e6a095f9c3c4af3b3f9fac7150705f1670 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 19 Dec 2023 22:04:30 +0800 Subject: [PATCH 23/62] implement the exitstack inside the capture --- .../maya/plugins/publish/extract_playblast.py | 24 +++++++++++-------- .../maya/plugins/publish/extract_thumbnail.py | 8 +++---- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 2e11a5f26e..78d771c250 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -45,13 +45,20 @@ class ExtractPlayblast(publish.Extractor): ) ) - if preset["viewport_options"].get("reloadTextures"): - # Regenerate all UDIM tiles previews - lib.reload_all_udim_tile_previews() - # not supported by `capture` - preset["viewport_options"].pop("reloadTextures", None) - path = capture.capture(log=self.log, **preset) - self.log.debug("playblast path {}".format(path)) + if preset["viewport_options"].get("textures"): + with ExitStack() as stack: + stack.enter_context(lib.material_loading_mode()) + if preset["viewport_options"].get("reloadTextures"): + # Regenerate all UDIM tiles previews + lib.reload_all_udim_tile_previews() + # not supported by `capture` + preset["viewport_options"].pop("reloadTextures", None) + path = capture.capture(log=self.log, **preset) + self.log.debug("playblast path {}".format(path)) + else: + preset["viewport_options"].pop("reloadTextures", None) + path = capture.capture(log=self.log, **preset) + self.log.debug("playblast path {}".format(path)) def process(self, instance): self.log.debug("Extracting capture..") @@ -205,9 +212,6 @@ class ExtractPlayblast(publish.Extractor): stack.enter_context( panel_camera(instance.data["panel"], preset["camera"]) ) - if preset["viewport_options"].get("textures"): - stack.enter_context(lib.material_loading_mode()) - self._capture(preset) # Restoring viewport options. diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index b8e7b19bc6..96c7226db3 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -153,16 +153,16 @@ class ExtractThumbnail(publish.Extractor): ) ) - if preset["viewport_options"].get("reloadTextures"): - lib.reload_all_udim_tile_previews() - - preset["viewport_options"].pop("reloadTextures", None) if preset["viewport_options"].get("textures"): with lib.material_loading_mode(): + if preset["viewport_options"].get("reloadTextures"): + lib.reload_all_udim_tile_previews() + preset["viewport_options"].pop("reloadTextures", None) path = capture.capture(**preset) else: self.log.debug( "Reload Textures during playblasting is disabled.") + preset["viewport_options"].pop("reloadTextures", None) path = capture.capture(**preset) playblast = self._fix_playblast_output_path(path) From f9603bb0a5514e5fb28c60d56a50c26a1409e8ec Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 19 Dec 2023 22:44:18 +0800 Subject: [PATCH 24/62] refactor the capture function and move it to lib --- openpype/hosts/maya/api/lib.py | 28 +++++++++++++++++++ .../maya/plugins/publish/extract_playblast.py | 27 ++---------------- .../maya/plugins/publish/extract_thumbnail.py | 22 +-------------- 3 files changed, 31 insertions(+), 46 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 41290b805e..d2a2ab253b 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -9,6 +9,8 @@ import re import json import logging import contextlib +import capture +from .exitstack import ExitStack from collections import OrderedDict, defaultdict from math import ceil from six import string_types @@ -183,6 +185,32 @@ def reload_all_udim_tile_previews(): cmds.ogs(regenerateUVTilePreview=texture_file) +def capture_with_preset(preset): + if os.environ.get("OPENPYPE_DEBUG") == "1": + log.debug( + "Using preset: {}".format( + json.dumps(preset, indent=4, sort_keys=True) + ) + ) + + if preset["viewport_options"].get("textures"): + with ExitStack() as stack: + stack.enter_context(material_loading_mode()) + if preset["viewport_options"].get("reloadTextures"): + # Regenerate all UDIM tiles previews + reload_all_udim_tile_previews() + # not supported by `capture` + preset["viewport_options"].pop("reloadTextures", None) + path = capture.capture(log=self.log, **preset) + self.log.debug("playblast path {}".format(path)) + else: + preset["viewport_options"].pop("reloadTextures", None) + path = capture.capture(log=self.log, **preset) + self.log.debug("playblast path {}".format(path)) + + return path + + @contextlib.contextmanager def material_loading_mode(mode="immediate"): """Set material loading mode during context""" diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 78d771c250..0f1423d63d 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -1,5 +1,4 @@ import os -import json import contextlib import clique @@ -9,6 +8,7 @@ from openpype.pipeline import publish from openpype.hosts.maya.api import lib from openpype.hosts.maya.api.exitstack import ExitStack + from maya import cmds @@ -37,29 +37,6 @@ class ExtractPlayblast(publish.Extractor): capture_preset = {} profiles = None - def _capture(self, preset): - if os.environ.get("OPENPYPE_DEBUG") == "1": - self.log.debug( - "Using preset: {}".format( - json.dumps(preset, indent=4, sort_keys=True) - ) - ) - - if preset["viewport_options"].get("textures"): - with ExitStack() as stack: - stack.enter_context(lib.material_loading_mode()) - if preset["viewport_options"].get("reloadTextures"): - # Regenerate all UDIM tiles previews - lib.reload_all_udim_tile_previews() - # not supported by `capture` - preset["viewport_options"].pop("reloadTextures", None) - path = capture.capture(log=self.log, **preset) - self.log.debug("playblast path {}".format(path)) - else: - preset["viewport_options"].pop("reloadTextures", None) - path = capture.capture(log=self.log, **preset) - self.log.debug("playblast path {}".format(path)) - def process(self, instance): self.log.debug("Extracting capture..") @@ -212,7 +189,7 @@ class ExtractPlayblast(publish.Extractor): stack.enter_context( panel_camera(instance.data["panel"], preset["camera"]) ) - self._capture(preset) + path = lib.capture_with_preset(preset) # Restoring viewport options. if viewport_defaults: diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 96c7226db3..897383d0cb 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -1,9 +1,6 @@ import os import glob import tempfile -import json - -import capture from openpype.pipeline import publish from openpype.hosts.maya.api import lib @@ -146,24 +143,7 @@ class ExtractThumbnail(publish.Extractor): preset.update(panel_preset) cmds.setFocus(panel) - if os.environ.get("OPENPYPE_DEBUG") == "1": - self.log.debug( - "Using preset: {}".format( - json.dumps(preset, indent=4, sort_keys=True) - ) - ) - - if preset["viewport_options"].get("textures"): - with lib.material_loading_mode(): - if preset["viewport_options"].get("reloadTextures"): - lib.reload_all_udim_tile_previews() - preset["viewport_options"].pop("reloadTextures", None) - path = capture.capture(**preset) - else: - self.log.debug( - "Reload Textures during playblasting is disabled.") - preset["viewport_options"].pop("reloadTextures", None) - path = capture.capture(**preset) + path = lib.capture_with_preset(preset) playblast = self._fix_playblast_output_path(path) From 2f03b61c11a6d39dd2e1e3082830d9893ffb6e75 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 20 Dec 2023 17:28:58 +0800 Subject: [PATCH 25/62] refactor the capture and playblast functions and put them into lib.py --- openpype/hosts/maya/api/lib.py | 189 +++++++++++++++++- .../maya/plugins/publish/extract_playblast.py | 158 +-------------- .../maya/plugins/publish/extract_thumbnail.py | 108 +--------- 3 files changed, 194 insertions(+), 261 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index d2a2ab253b..0dd18bb978 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -185,16 +185,46 @@ def reload_all_udim_tile_previews(): cmds.ogs(regenerateUVTilePreview=texture_file) -def capture_with_preset(preset): +@contextlib.contextmanager +def panel_camera(panel, camera): + original_camera = cmds.modelPanel(panel, query=True, camera=True) + try: + cmds.modelPanel(panel, edit=True, camera=camera) + yield + finally: + cmds.modelPanel(panel, edit=True, camera=original_camera) + + +@contextlib.contextmanager +def panel_camera(panel, camera): + original_camera = cmds.modelPanel(panel, query=True, camera=True) + try: + cmds.modelPanel(panel, edit=True, camera=camera) + yield + finally: + cmds.modelPanel(panel, edit=True, camera=original_camera) + + +def capture_with_preset(preset, instance): + """Function for playblast capturing with the preset options + + Args: + preset (dict): preset options + instance (str): instance + + Returns: + _type_: _description_ + """ if os.environ.get("OPENPYPE_DEBUG") == "1": log.debug( "Using preset: {}".format( json.dumps(preset, indent=4, sort_keys=True) ) ) - - if preset["viewport_options"].get("textures"): - with ExitStack() as stack: + with ExitStack() as stack: + stack.enter_context(maintained_time()) + stack.enter_context(panel_camera(instance.data["panel"], preset["camera"])) + if preset["viewport_options"].get("textures"): stack.enter_context(material_loading_mode()) if preset["viewport_options"].get("reloadTextures"): # Regenerate all UDIM tiles previews @@ -203,13 +233,156 @@ def capture_with_preset(preset): preset["viewport_options"].pop("reloadTextures", None) path = capture.capture(log=self.log, **preset) self.log.debug("playblast path {}".format(path)) - else: - preset["viewport_options"].pop("reloadTextures", None) - path = capture.capture(log=self.log, **preset) - self.log.debug("playblast path {}".format(path)) + else: + preset["viewport_options"].pop("reloadTextures", None) + path = capture.capture(log=self.log, **preset) + self.log.debug("playblast path {}".format(path)) return path +def get_presets(instance, camera, path, start, end, capture_preset): + """Function for getting all the data of preset options for + playblast capturing + + Args: + instance (str): instance + camera (str): review camera + path (str): filepath + start (int): frameStart + end (int): frameEnd + capture_preset (dict): capture preset + + Returns: + _type_: _description_ + """ + preset = load_capture_preset(data=capture_preset) + + # "isolate_view" will already have been applied at creation, so we'll + # ignore it here. + preset.pop("isolate_view") + + # Set resolution variables from capture presets + width_preset = capture_preset["Resolution"]["width"] + height_preset = capture_preset["Resolution"]["height"] + + # Set resolution variables from asset values + asset_data = instance.data["assetEntity"]["data"] + asset_width = asset_data.get("resolutionWidth") + asset_height = asset_data.get("resolutionHeight") + review_instance_width = instance.data.get("review_width") + review_instance_height = instance.data.get("review_height") + preset["camera"] = camera + + # Tests if project resolution is set, + # if it is a value other than zero, that value is + # used, if not then the asset resolution is + # used + if review_instance_width and review_instance_height: + preset["width"] = review_instance_width + preset["height"] = review_instance_height + elif width_preset and height_preset: + preset["width"] = width_preset + preset["height"] = height_preset + elif asset_width and asset_height: + preset["width"] = asset_width + preset["height"] = asset_height + preset["start_frame"] = start + preset["end_frame"] = end + + # Enforce persisting camera depth of field + camera_options = preset.setdefault("camera_options", {}) + camera_options["depthOfField"] = cmds.getAttr( + "{0}.depthOfField".format(camera)) + + preset["filename"] = path + preset["overwrite"] = True + + cmds.refresh(force=True) + + refreshFrameInt = int(cmds.playbackOptions(q=True, minTime=True)) + cmds.currentTime(refreshFrameInt - 1, edit=True) + cmds.currentTime(refreshFrameInt, edit=True) + + # Use displayLights setting from instance + key = "displayLights" + preset["viewport_options"][key] = instance.data[key] + + # Override transparency if requested. + transparency = instance.data.get("transparency", 0) + if transparency != 0: + preset["viewport2_options"]["transparencyAlgorithm"] = transparency + + # Isolate view is requested by having objects in the set besides a + # camera. If there is only 1 member it'll be the camera because we + # validate to have 1 camera only. + if instance.data["isolate"] and len(instance.data["setMembers"]) > 1: + preset["isolate"] = instance.data["setMembers"] + + # Show/Hide image planes on request. + image_plane = instance.data.get("imagePlane", True) + if "viewport_options" in preset: + preset["viewport_options"]["imagePlane"] = image_plane + else: + preset["viewport_options"] = {"imagePlane": image_plane} + + # Disable Pan/Zoom. + pan_zoom = cmds.getAttr("{}.panZoomEnabled".format(preset["camera"])) + preset.pop("pan_zoom", None) + preset["camera_options"]["panZoomEnabled"] = instance.data["panZoom"] + + # Need to explicitly enable some viewport changes so the viewport is + # refreshed ahead of playblasting. + keys = [ + "useDefaultMaterial", + "wireframeOnShaded", + "xray", + "jointXray", + "backfaceCulling", + "textures" + ] + viewport_defaults = {} + for key in keys: + viewport_defaults[key] = cmds.modelEditor( + instance.data["panel"], query=True, **{key: True} + ) + if preset["viewport_options"][key]: + cmds.modelEditor( + instance.data["panel"], edit=True, **{key: True} + ) + + override_viewport_options = ( + capture_preset["Viewport Options"]["override_viewport_options"] + ) + + # Force viewer to False in call to capture because we have our own + # viewer opening call to allow a signal to trigger between + # playblast and viewer + preset["viewer"] = False + + # Update preset with current panel setting + # if override_viewport_options is turned off + if not override_viewport_options: + panel_preset = capture.parse_view(instance.data["panel"]) + panel_preset.pop("camera") + preset.update(panel_preset) + + path = capture_with_preset( + preset, instance) + + # Restoring viewport options. + if viewport_defaults: + cmds.modelEditor( + instance.data["panel"], edit=True, **viewport_defaults + ) + + try: + cmds.setAttr( + "{}.panZoomEnabled".format(preset["camera"]), pan_zoom) + except RuntimeError: + self.log.warning("Cannot restore Pan/Zoom settings.") + + return preset + @contextlib.contextmanager def material_loading_mode(mode="immediate"): diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 0f1423d63d..192eb2639d 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -1,27 +1,13 @@ import os -import contextlib import clique -import capture from openpype.pipeline import publish from openpype.hosts.maya.api import lib -from openpype.hosts.maya.api.exitstack import ExitStack - from maya import cmds -@contextlib.contextmanager -def panel_camera(panel, camera): - original_camera = cmds.modelPanel(panel, query=True, camera=True) - try: - cmds.modelPanel(panel, edit=True, camera=camera) - yield - finally: - cmds.modelPanel(panel, edit=True, camera=original_camera) - - class ExtractPlayblast(publish.Extractor): """Extract viewport playblast. @@ -53,10 +39,6 @@ class ExtractPlayblast(publish.Extractor): end = cmds.playbackOptions(query=True, animationEndTime=True) self.log.debug("start: {}, end: {}".format(start, end)) - - # get cameras - camera = instance.data["review_camera"] - task_data = instance.data["anatomyData"].get("task", {}) capture_preset = lib.get_capture_preset( task_data.get("name"), @@ -65,143 +47,17 @@ class ExtractPlayblast(publish.Extractor): instance.context.data["project_settings"], self.log ) - - preset = lib.load_capture_preset(data=capture_preset) - - # "isolate_view" will already have been applied at creation, so we'll - # ignore it here. - preset.pop("isolate_view") - - # Set resolution variables from capture presets - width_preset = capture_preset["Resolution"]["width"] - height_preset = capture_preset["Resolution"]["height"] - - # Set resolution variables from asset values - asset_data = instance.data["assetEntity"]["data"] - asset_width = asset_data.get("resolutionWidth") - asset_height = asset_data.get("resolutionHeight") - review_instance_width = instance.data.get("review_width") - review_instance_height = instance.data.get("review_height") - preset["camera"] = camera - - # Tests if project resolution is set, - # if it is a value other than zero, that value is - # used, if not then the asset resolution is - # used - if review_instance_width and review_instance_height: - preset["width"] = review_instance_width - preset["height"] = review_instance_height - elif width_preset and height_preset: - preset["width"] = width_preset - preset["height"] = height_preset - elif asset_width and asset_height: - preset["width"] = asset_width - preset["height"] = asset_height - preset["start_frame"] = start - preset["end_frame"] = end - - # Enforce persisting camera depth of field - camera_options = preset.setdefault("camera_options", {}) - camera_options["depthOfField"] = cmds.getAttr( - "{0}.depthOfField".format(camera)) - stagingdir = self.staging_dir(instance) filename = "{0}".format(instance.name) path = os.path.join(stagingdir, filename) - self.log.debug("Outputting images to %s" % path) - - preset["filename"] = path - preset["overwrite"] = True - - cmds.refresh(force=True) - - refreshFrameInt = int(cmds.playbackOptions(q=True, minTime=True)) - cmds.currentTime(refreshFrameInt - 1, edit=True) - cmds.currentTime(refreshFrameInt, edit=True) - - # Use displayLights setting from instance - key = "displayLights" - preset["viewport_options"][key] = instance.data[key] - - # Override transparency if requested. - transparency = instance.data.get("transparency", 0) - if transparency != 0: - preset["viewport2_options"]["transparencyAlgorithm"] = transparency - - # Isolate view is requested by having objects in the set besides a - # camera. If there is only 1 member it'll be the camera because we - # validate to have 1 camera only. - if instance.data["isolate"] and len(instance.data["setMembers"]) > 1: - preset["isolate"] = instance.data["setMembers"] - - # Show/Hide image planes on request. - image_plane = instance.data.get("imagePlane", True) - if "viewport_options" in preset: - preset["viewport_options"]["imagePlane"] = image_plane - else: - preset["viewport_options"] = {"imagePlane": image_plane} - - # Disable Pan/Zoom. - pan_zoom = cmds.getAttr("{}.panZoomEnabled".format(preset["camera"])) - preset.pop("pan_zoom", None) - preset["camera_options"]["panZoomEnabled"] = instance.data["panZoom"] - - # Need to explicitly enable some viewport changes so the viewport is - # refreshed ahead of playblasting. - keys = [ - "useDefaultMaterial", - "wireframeOnShaded", - "xray", - "jointXray", - "backfaceCulling", - "textures" - ] - viewport_defaults = {} - for key in keys: - viewport_defaults[key] = cmds.modelEditor( - instance.data["panel"], query=True, **{key: True} - ) - if preset["viewport_options"][key]: - cmds.modelEditor( - instance.data["panel"], edit=True, **{key: True} - ) - - override_viewport_options = ( - capture_preset["Viewport Options"]["override_viewport_options"] - ) - - # Force viewer to False in call to capture because we have our own - # viewer opening call to allow a signal to trigger between - # playblast and viewer - preset["viewer"] = False - - # Update preset with current panel setting - # if override_viewport_options is turned off - if not override_viewport_options: - panel_preset = capture.parse_view(instance.data["panel"]) - panel_preset.pop("camera") - preset.update(panel_preset) - - # Need to ensure Python 2 compatibility. - with ExitStack() as stack: - stack.enter_context(lib.maintained_time()) - stack.enter_context( - panel_camera(instance.data["panel"], preset["camera"]) - ) - path = lib.capture_with_preset(preset) - - # Restoring viewport options. - if viewport_defaults: - cmds.modelEditor( - instance.data["panel"], edit=True, **viewport_defaults - ) - - try: - cmds.setAttr( - "{}.panZoomEnabled".format(preset["camera"]), pan_zoom) - except RuntimeError: - self.log.warning("Cannot restore Pan/Zoom settings.") + # get cameras + camera = instance.data["review_camera"] + preset = lib.get_presets( + instance, camera, path, + start=start, end=end, + capture_preset=capture_preset) + path = lib.capture_with_preset(preset, instance) collected_files = os.listdir(stagingdir) patterns = [clique.PATTERNS["frames"]] diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 897383d0cb..09665a1a58 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -5,8 +5,6 @@ import tempfile from openpype.pipeline import publish from openpype.hosts.maya.api import lib -from maya import cmds - class ExtractThumbnail(publish.Extractor): """Extract viewport thumbnail. @@ -34,54 +32,6 @@ class ExtractThumbnail(publish.Extractor): self.log ) - preset = lib.load_capture_preset(data=capture_preset) - - # "isolate_view" will already have been applied at creation, so we'll - # ignore it here. - preset.pop("isolate_view") - - override_viewport_options = ( - capture_preset["Viewport Options"]["override_viewport_options"] - ) - - preset["camera"] = camera - preset["start_frame"] = instance.data["frameStart"] - preset["end_frame"] = instance.data["frameStart"] - preset["camera_options"] = { - "displayGateMask": False, - "displayResolution": False, - "displayFilmGate": False, - "displayFieldChart": False, - "displaySafeAction": False, - "displaySafeTitle": False, - "displayFilmPivot": False, - "displayFilmOrigin": False, - "overscan": 1.0, - "depthOfField": cmds.getAttr("{0}.depthOfField".format(camera)), - } - # Set resolution variables from capture presets - width_preset = capture_preset["Resolution"]["width"] - height_preset = capture_preset["Resolution"]["height"] - # Set resolution variables from asset values - asset_data = instance.data["assetEntity"]["data"] - asset_width = asset_data.get("resolutionWidth") - asset_height = asset_data.get("resolutionHeight") - review_instance_width = instance.data.get("review_width") - review_instance_height = instance.data.get("review_height") - # Tests if project resolution is set, - # if it is a value other than zero, that value is - # used, if not then the asset resolution is - # used - if review_instance_width and review_instance_height: - preset["width"] = review_instance_width - preset["height"] = review_instance_height - elif width_preset and height_preset: - preset["width"] = width_preset - preset["height"] = height_preset - elif asset_width and asset_height: - preset["width"] = asset_width - preset["height"] = asset_height - # Create temp directory for thumbnail # - this is to avoid "override" of source file dst_staging = tempfile.mkdtemp(prefix="pyblish_tmp_") @@ -93,59 +43,13 @@ class ExtractThumbnail(publish.Extractor): path = os.path.join(dst_staging, filename) self.log.debug("Outputting images to %s" % path) + preset = lib.get_presets( + instance, camera, path, + start=1, end=1, + capture_preset=capture_preset) + path = lib.capture_with_preset(preset, instance) - preset["filename"] = path - preset["overwrite"] = True - - cmds.refresh(force=True) - - refreshFrameInt = int(cmds.playbackOptions(q=True, minTime=True)) - cmds.currentTime(refreshFrameInt - 1, edit=True) - cmds.currentTime(refreshFrameInt, edit=True) - - # Use displayLights setting from instance - key = "displayLights" - preset["viewport_options"][key] = instance.data[key] - - # Override transparency if requested. - transparency = instance.data.get("transparency", 0) - if transparency != 0: - preset["viewport2_options"]["transparencyAlgorithm"] = transparency - - # Isolate view is requested by having objects in the set besides a - # camera. If there is only 1 member it'll be the camera because we - # validate to have 1 camera only. - if instance.data["isolate"] and len(instance.data["setMembers"]) > 1: - preset["isolate"] = instance.data["setMembers"] - - # Show or Hide Image Plane - image_plane = instance.data.get("imagePlane", True) - if "viewport_options" in preset: - preset["viewport_options"]["imagePlane"] = image_plane - else: - preset["viewport_options"] = {"imagePlane": image_plane} - - # Disable Pan/Zoom. - preset.pop("pan_zoom", None) - preset["camera_options"]["panZoomEnabled"] = instance.data["panZoom"] - - with lib.maintained_time(): - # Force viewer to False in call to capture because we have our own - # viewer opening call to allow a signal to trigger between - # playblast and viewer - preset["viewer"] = False - - # Update preset with current panel setting - # if override_viewport_options is turned off - panel = cmds.getPanel(withFocus=True) or "" - if not override_viewport_options and "modelPanel" in panel: - panel_preset = capture.parse_active_view() - preset.update(panel_preset) - cmds.setFocus(panel) - - path = lib.capture_with_preset(preset) - - playblast = self._fix_playblast_output_path(path) + playblast = self._fix_playblast_output_path(path) _, thumbnail = os.path.split(playblast) From 25e216b0c419c05067a3eec1cbf8473c9d8d2297 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 20 Dec 2023 17:31:31 +0800 Subject: [PATCH 26/62] hound --- openpype/hosts/maya/api/lib.py | 220 +++++++++++++++++---------------- 1 file changed, 111 insertions(+), 109 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 0dd18bb978..6d30a58506 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -223,7 +223,8 @@ def capture_with_preset(preset, instance): ) with ExitStack() as stack: stack.enter_context(maintained_time()) - stack.enter_context(panel_camera(instance.data["panel"], preset["camera"])) + stack.enter_context(panel_camera( + instance.data["panel"], preset["camera"])) if preset["viewport_options"].get("textures"): stack.enter_context(material_loading_mode()) if preset["viewport_options"].get("reloadTextures"): @@ -240,6 +241,7 @@ def capture_with_preset(preset, instance): return path + def get_presets(instance, camera, path, start, end, capture_preset): """Function for getting all the data of preset options for playblast capturing @@ -255,133 +257,133 @@ def get_presets(instance, camera, path, start, end, capture_preset): Returns: _type_: _description_ """ - preset = load_capture_preset(data=capture_preset) + preset = load_capture_preset(data=capture_preset) - # "isolate_view" will already have been applied at creation, so we'll - # ignore it here. - preset.pop("isolate_view") + # "isolate_view" will already have been applied at creation, so we'll + # ignore it here. + preset.pop("isolate_view") - # Set resolution variables from capture presets - width_preset = capture_preset["Resolution"]["width"] - height_preset = capture_preset["Resolution"]["height"] + # Set resolution variables from capture presets + width_preset = capture_preset["Resolution"]["width"] + height_preset = capture_preset["Resolution"]["height"] - # Set resolution variables from asset values - asset_data = instance.data["assetEntity"]["data"] - asset_width = asset_data.get("resolutionWidth") - asset_height = asset_data.get("resolutionHeight") - review_instance_width = instance.data.get("review_width") - review_instance_height = instance.data.get("review_height") - preset["camera"] = camera + # Set resolution variables from asset values + asset_data = instance.data["assetEntity"]["data"] + asset_width = asset_data.get("resolutionWidth") + asset_height = asset_data.get("resolutionHeight") + review_instance_width = instance.data.get("review_width") + review_instance_height = instance.data.get("review_height") + preset["camera"] = camera - # Tests if project resolution is set, - # if it is a value other than zero, that value is - # used, if not then the asset resolution is - # used - if review_instance_width and review_instance_height: - preset["width"] = review_instance_width - preset["height"] = review_instance_height - elif width_preset and height_preset: - preset["width"] = width_preset - preset["height"] = height_preset - elif asset_width and asset_height: - preset["width"] = asset_width - preset["height"] = asset_height - preset["start_frame"] = start - preset["end_frame"] = end + # Tests if project resolution is set, + # if it is a value other than zero, that value is + # used, if not then the asset resolution is + # used + if review_instance_width and review_instance_height: + preset["width"] = review_instance_width + preset["height"] = review_instance_height + elif width_preset and height_preset: + preset["width"] = width_preset + preset["height"] = height_preset + elif asset_width and asset_height: + preset["width"] = asset_width + preset["height"] = asset_height + preset["start_frame"] = start + preset["end_frame"] = end - # Enforce persisting camera depth of field - camera_options = preset.setdefault("camera_options", {}) - camera_options["depthOfField"] = cmds.getAttr( - "{0}.depthOfField".format(camera)) + # Enforce persisting camera depth of field + camera_options = preset.setdefault("camera_options", {}) + camera_options["depthOfField"] = cmds.getAttr( + "{0}.depthOfField".format(camera)) - preset["filename"] = path - preset["overwrite"] = True + preset["filename"] = path + preset["overwrite"] = True - cmds.refresh(force=True) + cmds.refresh(force=True) - refreshFrameInt = int(cmds.playbackOptions(q=True, minTime=True)) - cmds.currentTime(refreshFrameInt - 1, edit=True) - cmds.currentTime(refreshFrameInt, edit=True) + refreshFrameInt = int(cmds.playbackOptions(q=True, minTime=True)) + cmds.currentTime(refreshFrameInt - 1, edit=True) + cmds.currentTime(refreshFrameInt, edit=True) - # Use displayLights setting from instance - key = "displayLights" - preset["viewport_options"][key] = instance.data[key] + # Use displayLights setting from instance + key = "displayLights" + preset["viewport_options"][key] = instance.data[key] - # Override transparency if requested. - transparency = instance.data.get("transparency", 0) - if transparency != 0: - preset["viewport2_options"]["transparencyAlgorithm"] = transparency + # Override transparency if requested. + transparency = instance.data.get("transparency", 0) + if transparency != 0: + preset["viewport2_options"]["transparencyAlgorithm"] = transparency - # Isolate view is requested by having objects in the set besides a - # camera. If there is only 1 member it'll be the camera because we - # validate to have 1 camera only. - if instance.data["isolate"] and len(instance.data["setMembers"]) > 1: - preset["isolate"] = instance.data["setMembers"] + # Isolate view is requested by having objects in the set besides a + # camera. If there is only 1 member it'll be the camera because we + # validate to have 1 camera only. + if instance.data["isolate"] and len(instance.data["setMembers"]) > 1: + preset["isolate"] = instance.data["setMembers"] - # Show/Hide image planes on request. - image_plane = instance.data.get("imagePlane", True) - if "viewport_options" in preset: - preset["viewport_options"]["imagePlane"] = image_plane - else: - preset["viewport_options"] = {"imagePlane": image_plane} + # Show/Hide image planes on request. + image_plane = instance.data.get("imagePlane", True) + if "viewport_options" in preset: + preset["viewport_options"]["imagePlane"] = image_plane + else: + preset["viewport_options"] = {"imagePlane": image_plane} - # Disable Pan/Zoom. - pan_zoom = cmds.getAttr("{}.panZoomEnabled".format(preset["camera"])) - preset.pop("pan_zoom", None) - preset["camera_options"]["panZoomEnabled"] = instance.data["panZoom"] + # Disable Pan/Zoom. + pan_zoom = cmds.getAttr("{}.panZoomEnabled".format(preset["camera"])) + preset.pop("pan_zoom", None) + preset["camera_options"]["panZoomEnabled"] = instance.data["panZoom"] - # Need to explicitly enable some viewport changes so the viewport is - # refreshed ahead of playblasting. - keys = [ - "useDefaultMaterial", - "wireframeOnShaded", - "xray", - "jointXray", - "backfaceCulling", - "textures" - ] - viewport_defaults = {} - for key in keys: - viewport_defaults[key] = cmds.modelEditor( - instance.data["panel"], query=True, **{key: True} + # Need to explicitly enable some viewport changes so the viewport is + # refreshed ahead of playblasting. + keys = [ + "useDefaultMaterial", + "wireframeOnShaded", + "xray", + "jointXray", + "backfaceCulling", + "textures" + ] + viewport_defaults = {} + for key in keys: + viewport_defaults[key] = cmds.modelEditor( + instance.data["panel"], query=True, **{key: True} + ) + if preset["viewport_options"][key]: + cmds.modelEditor( + instance.data["panel"], edit=True, **{key: True} ) - if preset["viewport_options"][key]: - cmds.modelEditor( - instance.data["panel"], edit=True, **{key: True} - ) - override_viewport_options = ( - capture_preset["Viewport Options"]["override_viewport_options"] + override_viewport_options = ( + capture_preset["Viewport Options"]["override_viewport_options"] + ) + + # Force viewer to False in call to capture because we have our own + # viewer opening call to allow a signal to trigger between + # playblast and viewer + preset["viewer"] = False + + # Update preset with current panel setting + # if override_viewport_options is turned off + if not override_viewport_options: + panel_preset = capture.parse_view(instance.data["panel"]) + panel_preset.pop("camera") + preset.update(panel_preset) + + path = capture_with_preset( + preset, instance) + + # Restoring viewport options. + if viewport_defaults: + cmds.modelEditor( + instance.data["panel"], edit=True, **viewport_defaults ) - # Force viewer to False in call to capture because we have our own - # viewer opening call to allow a signal to trigger between - # playblast and viewer - preset["viewer"] = False + try: + cmds.setAttr( + "{}.panZoomEnabled".format(preset["camera"]), pan_zoom) + except RuntimeError: + self.log.warning("Cannot restore Pan/Zoom settings.") - # Update preset with current panel setting - # if override_viewport_options is turned off - if not override_viewport_options: - panel_preset = capture.parse_view(instance.data["panel"]) - panel_preset.pop("camera") - preset.update(panel_preset) - - path = capture_with_preset( - preset, instance) - - # Restoring viewport options. - if viewport_defaults: - cmds.modelEditor( - instance.data["panel"], edit=True, **viewport_defaults - ) - - try: - cmds.setAttr( - "{}.panZoomEnabled".format(preset["camera"]), pan_zoom) - except RuntimeError: - self.log.warning("Cannot restore Pan/Zoom settings.") - - return preset + return preset @contextlib.contextmanager From 29876a496edce570cccf8e0a5e7c4d36cf210de5 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 20 Dec 2023 17:32:27 +0800 Subject: [PATCH 27/62] hound --- openpype/hosts/maya/api/lib.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 6d30a58506..8749ac0d6a 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -195,16 +195,6 @@ def panel_camera(panel, camera): cmds.modelPanel(panel, edit=True, camera=original_camera) -@contextlib.contextmanager -def panel_camera(panel, camera): - original_camera = cmds.modelPanel(panel, query=True, camera=True) - try: - cmds.modelPanel(panel, edit=True, camera=camera) - yield - finally: - cmds.modelPanel(panel, edit=True, camera=original_camera) - - def capture_with_preset(preset, instance): """Function for playblast capturing with the preset options From 0ae3ef03d22fbf13ae1dd7f4eee8d5c7cedac11f Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 20 Dec 2023 23:41:39 +0800 Subject: [PATCH 28/62] refactor the capture and capture preset function --- openpype/hosts/maya/api/lib.py | 108 +++++++++--------- .../maya/plugins/publish/extract_playblast.py | 4 +- .../maya/plugins/publish/extract_thumbnail.py | 20 +++- 3 files changed, 73 insertions(+), 59 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 8749ac0d6a..c1d1a43d1e 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -195,7 +195,7 @@ def panel_camera(panel, camera): cmds.modelPanel(panel, edit=True, camera=original_camera) -def capture_with_preset(preset, instance): +def playblast_capture(preset, instance): """Function for playblast capturing with the preset options Args: @@ -215,24 +215,22 @@ def capture_with_preset(preset, instance): stack.enter_context(maintained_time()) stack.enter_context(panel_camera( instance.data["panel"], preset["camera"])) + stack.enter_context(viewport_default_options(preset, instance)) if preset["viewport_options"].get("textures"): - stack.enter_context(material_loading_mode()) + material_loading_mode() if preset["viewport_options"].get("reloadTextures"): # Regenerate all UDIM tiles previews reload_all_udim_tile_previews() - # not supported by `capture` - preset["viewport_options"].pop("reloadTextures", None) - path = capture.capture(log=self.log, **preset) - self.log.debug("playblast path {}".format(path)) - else: - preset["viewport_options"].pop("reloadTextures", None) - path = capture.capture(log=self.log, **preset) - self.log.debug("playblast path {}".format(path)) + # not supported by `capture` + preset["viewport_options"].pop("reloadTextures", None) + path = capture.capture(log=self.log, **preset) + self.log.debug("playblast path {}".format(path)) return path -def get_presets(instance, camera, path, start, end, capture_preset): +def generate_capture_preset(instance, camera, path, + start=None, end=None, capture_preset={}): """Function for getting all the data of preset options for playblast capturing @@ -317,35 +315,6 @@ def get_presets(instance, camera, path, start, end, capture_preset): else: preset["viewport_options"] = {"imagePlane": image_plane} - # Disable Pan/Zoom. - pan_zoom = cmds.getAttr("{}.panZoomEnabled".format(preset["camera"])) - preset.pop("pan_zoom", None) - preset["camera_options"]["panZoomEnabled"] = instance.data["panZoom"] - - # Need to explicitly enable some viewport changes so the viewport is - # refreshed ahead of playblasting. - keys = [ - "useDefaultMaterial", - "wireframeOnShaded", - "xray", - "jointXray", - "backfaceCulling", - "textures" - ] - viewport_defaults = {} - for key in keys: - viewport_defaults[key] = cmds.modelEditor( - instance.data["panel"], query=True, **{key: True} - ) - if preset["viewport_options"][key]: - cmds.modelEditor( - instance.data["panel"], edit=True, **{key: True} - ) - - override_viewport_options = ( - capture_preset["Viewport Options"]["override_viewport_options"] - ) - # Force viewer to False in call to capture because we have our own # viewer opening call to allow a signal to trigger between # playblast and viewer @@ -353,29 +322,58 @@ def get_presets(instance, camera, path, start, end, capture_preset): # Update preset with current panel setting # if override_viewport_options is turned off + override_viewport_options = ( + capture_preset["Viewport Options"]["override_viewport_options"] + ) if not override_viewport_options: panel_preset = capture.parse_view(instance.data["panel"]) panel_preset.pop("camera") preset.update(panel_preset) - path = capture_with_preset( - preset, instance) - - # Restoring viewport options. - if viewport_defaults: - cmds.modelEditor( - instance.data["panel"], edit=True, **viewport_defaults - ) - - try: - cmds.setAttr( - "{}.panZoomEnabled".format(preset["camera"]), pan_zoom) - except RuntimeError: - self.log.warning("Cannot restore Pan/Zoom settings.") - return preset +@contextlib.contextmanager +def viewport_default_options(preset, instance): + # Disable Pan/Zoom. + pan_zoom = cmds.getAttr("{}.panZoomEnabled".format(preset["camera"])) + preset.pop("pan_zoom", None) + preset["camera_options"]["panZoomEnabled"] = instance.data["panZoom"] + + viewport_defaults = {} + # Need to explicitly enable some viewport changes so the viewport is + # refreshed ahead of playblasting. + try: + keys = [ + "useDefaultMaterial", + "wireframeOnShaded", + "xray", + "jointXray", + "backfaceCulling", + "textures" + ] + for key in keys: + viewport_defaults[key] = cmds.modelEditor( + instance.data["panel"], query=True, **{key: True} + ) + if preset["viewport_options"][key]: + cmds.modelEditor( + instance.data["panel"], edit=True, **{key: True} + ) + yield + finally: + # Restoring viewport options. + if viewport_defaults: + cmds.modelEditor( + instance.data["panel"], edit=True, **viewport_defaults + ) + try: + cmds.setAttr( + "{}.panZoomEnabled".format(preset["camera"]), pan_zoom) + except RuntimeError: + self.log.warning("Cannot restore Pan/Zoom settings.") + + @contextlib.contextmanager def material_loading_mode(mode="immediate"): """Set material loading mode during context""" diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 192eb2639d..5a2beaca12 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -53,11 +53,11 @@ class ExtractPlayblast(publish.Extractor): self.log.debug("Outputting images to %s" % path) # get cameras camera = instance.data["review_camera"] - preset = lib.get_presets( + preset = lib.generate_capture_preset( instance, camera, path, start=start, end=end, capture_preset=capture_preset) - path = lib.capture_with_preset(preset, instance) + path = lib.playblast_capture(preset, instance) collected_files = os.listdir(stagingdir) patterns = [clique.PATTERNS["frames"]] diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 09665a1a58..b4931b637f 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -4,6 +4,7 @@ import tempfile from openpype.pipeline import publish from openpype.hosts.maya.api import lib +from maya.cmds import cmds class ExtractThumbnail(publish.Extractor): @@ -43,11 +44,26 @@ class ExtractThumbnail(publish.Extractor): path = os.path.join(dst_staging, filename) self.log.debug("Outputting images to %s" % path) - preset = lib.get_presets( + + preset = lib.generate_capture_preset( instance, camera, path, start=1, end=1, capture_preset=capture_preset) - path = lib.capture_with_preset(preset, instance) + + preset["camera_options"].update({ + "displayGateMask": False, + "displayResolution": False, + "displayFilmGate": False, + "displayFieldChart": False, + "displaySafeAction": False, + "displaySafeTitle": False, + "displayFilmPivot": False, + "displayFilmOrigin": False, + "overscan": 1.0, + "depthOfField": cmds.getAttr("{0}.depthOfField".format(camera)), + } + ) + path = lib.playblast_capture(preset, instance) playblast = self._fix_playblast_output_path(path) From 04f9d4caaa40410995c84ef89821d9a7b525a70f Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 20 Dec 2023 23:44:40 +0800 Subject: [PATCH 29/62] hound --- openpype/hosts/maya/api/lib.py | 2 +- .../maya/plugins/publish/extract_thumbnail.py | 21 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index c1d1a43d1e..bc66ec350f 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -230,7 +230,7 @@ def playblast_capture(preset, instance): def generate_capture_preset(instance, camera, path, - start=None, end=None, capture_preset={}): + start=None, end=None, capture_preset=None): """Function for getting all the data of preset options for playblast capturing diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index b4931b637f..05fad0025d 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -51,16 +51,17 @@ class ExtractThumbnail(publish.Extractor): capture_preset=capture_preset) preset["camera_options"].update({ - "displayGateMask": False, - "displayResolution": False, - "displayFilmGate": False, - "displayFieldChart": False, - "displaySafeAction": False, - "displaySafeTitle": False, - "displayFilmPivot": False, - "displayFilmOrigin": False, - "overscan": 1.0, - "depthOfField": cmds.getAttr("{0}.depthOfField".format(camera)), + "displayGateMask": False, + "displayResolution": False, + "displayFilmGate": False, + "displayFieldChart": False, + "displaySafeAction": False, + "displaySafeTitle": False, + "displayFilmPivot": False, + "displayFilmOrigin": False, + "overscan": 1.0, + "depthOfField": cmds.getAttr( + "{0}.depthOfField".format(camera)) } ) path = lib.playblast_capture(preset, instance) From 746e34aa559126b7eea2901839366fe6fea06b3d Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 20 Dec 2023 23:46:10 +0800 Subject: [PATCH 30/62] hound --- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 05fad0025d..6f61515019 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -60,8 +60,7 @@ class ExtractThumbnail(publish.Extractor): "displayFilmPivot": False, "displayFilmOrigin": False, "overscan": 1.0, - "depthOfField": cmds.getAttr( - "{0}.depthOfField".format(camera)) + "depthOfField": cmds.getAttr("{0}.depthOfField".format(camera)), # noqa } ) path = lib.playblast_capture(preset, instance) From 8ce8d72c0341d1003b6632395fe760fe7098a72e Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 20 Dec 2023 23:56:40 +0800 Subject: [PATCH 31/62] add reloadTextures argument back to cmds.ogs --- openpype/hosts/maya/api/lib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index bc66ec350f..4db7269d9b 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -183,6 +183,7 @@ def reload_all_udim_tile_previews(): for texture_file in texture_files: if cmds.getAttr("{}.uvTilingMode".format(texture_file)) > 0: cmds.ogs(regenerateUVTilePreview=texture_file) + cmds.ogs(reloadTextures=True) @contextlib.contextmanager From 4b6e5e29dcb2a3ec21ed5437690e5b11a3bfcb31 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 20 Dec 2023 23:59:00 +0800 Subject: [PATCH 32/62] add material_loading_mode into enter_context --- openpype/hosts/maya/api/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 4db7269d9b..9892fd0255 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -218,7 +218,7 @@ def playblast_capture(preset, instance): instance.data["panel"], preset["camera"])) stack.enter_context(viewport_default_options(preset, instance)) if preset["viewport_options"].get("textures"): - material_loading_mode() + stack.enter_context(material_loading_mode()) if preset["viewport_options"].get("reloadTextures"): # Regenerate all UDIM tiles previews reload_all_udim_tile_previews() From 0dd4d7b5059d8e1103a6d9a5edda8c04a578e5bb Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 20 Dec 2023 21:46:23 +0100 Subject: [PATCH 33/62] Code cleanup --- openpype/hosts/maya/api/lib.py | 145 +++++++++++++++++---------------- 1 file changed, 76 insertions(+), 69 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 9892fd0255..5c15bfba26 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -175,9 +175,7 @@ def maintained_selection(): def reload_all_udim_tile_previews(): - """Regenerate all UDIM tile preview in texture file - nodes during context - """ + """Regenerate all UDIM tile preview in texture file""" texture_files = cmds.ls(type="file") if texture_files: for texture_file in texture_files: @@ -188,6 +186,13 @@ def reload_all_udim_tile_previews(): @contextlib.contextmanager def panel_camera(panel, camera): + """Set modelPanel's camera during the context. + + Arguments: + panel (str): modelPanel name. + camera (str): camera name. + + """ original_camera = cmds.modelPanel(panel, query=True, camera=True) try: cmds.modelPanel(panel, edit=True, camera=camera) @@ -196,36 +201,48 @@ def panel_camera(panel, camera): cmds.modelPanel(panel, edit=True, camera=original_camera) -def playblast_capture(preset, instance): - """Function for playblast capturing with the preset options +def render_capture_preset(preset): + """Capture playblast with a preset. + + To generate the preset use `generate_capture_preset`. Args: preset (dict): preset options - instance (str): instance Returns: - _type_: _description_ + str: Output path of `capture.capture` """ + + # Force a refresh at the start of the timeline + # TODO (Question): Why do we need to do this? What bug does it solve? + # Is this for simulations? + cmds.refresh(force=True) + refresh_frame_int = int(cmds.playbackOptions(query=True, minTime=True)) + cmds.currentTime(refresh_frame_int - 1, edit=True) + cmds.currentTime(refresh_frame_int, edit=True) + if os.environ.get("OPENPYPE_DEBUG") == "1": log.debug( "Using preset: {}".format( json.dumps(preset, indent=4, sort_keys=True) ) ) + + # not supported by `capture` so we pop it off of the preset + reload_textures = preset["viewport_options"].pop("reloadTextures", True) + with ExitStack() as stack: stack.enter_context(maintained_time()) - stack.enter_context(panel_camera( - instance.data["panel"], preset["camera"])) - stack.enter_context(viewport_default_options(preset, instance)) + stack.enter_context(panel_camera(preset["panel"], preset["camera"])) + stack.enter_context(viewport_default_options(preset)) if preset["viewport_options"].get("textures"): - stack.enter_context(material_loading_mode()) - if preset["viewport_options"].get("reloadTextures"): + # Force immediate texture loading when to ensure + # all textures have loaded before the playblast starts + stack.enter_context(material_loading_mode("immediate")) + if reload_textures: # Regenerate all UDIM tiles previews reload_all_udim_tile_previews() - # not supported by `capture` - preset["viewport_options"].pop("reloadTextures", None) path = capture.capture(log=self.log, **preset) - self.log.debug("playblast path {}".format(path)) return path @@ -236,7 +253,7 @@ def generate_capture_preset(instance, camera, path, playblast capturing Args: - instance (str): instance + instance (pyblish.api.Instance): instance camera (str): review camera path (str): filepath start (int): frameStart @@ -244,10 +261,21 @@ def generate_capture_preset(instance, camera, path, capture_preset (dict): capture preset Returns: - _type_: _description_ + dict: Resulting preset """ preset = load_capture_preset(data=capture_preset) + preset["camera"] = camera + preset["start_frame"] = start + preset["end_frame"] = end + preset["filename"] = path + preset["overwrite"] = True + preset["panel"] = instance.data["panel"] + + # Disable viewer since we use the rendering logic for publishing + # We don't want to open the generated playblast in a viewer directly. + preset["viewer"] = False + # "isolate_view" will already have been applied at creation, so we'll # ignore it here. preset.pop("isolate_view") @@ -262,7 +290,6 @@ def generate_capture_preset(instance, camera, path, asset_height = asset_data.get("resolutionHeight") review_instance_width = instance.data.get("review_width") review_instance_height = instance.data.get("review_height") - preset["camera"] = camera # Tests if project resolution is set, # if it is a value other than zero, that value is @@ -277,31 +304,6 @@ def generate_capture_preset(instance, camera, path, elif asset_width and asset_height: preset["width"] = asset_width preset["height"] = asset_height - preset["start_frame"] = start - preset["end_frame"] = end - - # Enforce persisting camera depth of field - camera_options = preset.setdefault("camera_options", {}) - camera_options["depthOfField"] = cmds.getAttr( - "{0}.depthOfField".format(camera)) - - preset["filename"] = path - preset["overwrite"] = True - - cmds.refresh(force=True) - - refreshFrameInt = int(cmds.playbackOptions(q=True, minTime=True)) - cmds.currentTime(refreshFrameInt - 1, edit=True) - cmds.currentTime(refreshFrameInt, edit=True) - - # Use displayLights setting from instance - key = "displayLights" - preset["viewport_options"][key] = instance.data[key] - - # Override transparency if requested. - transparency = instance.data.get("transparency", 0) - if transparency != 0: - preset["viewport2_options"]["transparencyAlgorithm"] = transparency # Isolate view is requested by having objects in the set besides a # camera. If there is only 1 member it'll be the camera because we @@ -309,17 +311,26 @@ def generate_capture_preset(instance, camera, path, if instance.data["isolate"] and len(instance.data["setMembers"]) > 1: preset["isolate"] = instance.data["setMembers"] - # Show/Hide image planes on request. - image_plane = instance.data.get("imagePlane", True) - if "viewport_options" in preset: - preset["viewport_options"]["imagePlane"] = image_plane - else: - preset["viewport_options"] = {"imagePlane": image_plane} + # Override camera options + # Enforce persisting camera depth of field + camera_options = preset.setdefault("camera_options", {}) + camera_options["depthOfField"] = cmds.getAttr( + "{0}.depthOfField".format(camera) + ) - # Force viewer to False in call to capture because we have our own - # viewer opening call to allow a signal to trigger between - # playblast and viewer - preset["viewer"] = False + # Use Pan/Zoom from instance data instead of from preset + preset.pop("pan_zoom", None) + preset["camera_options"]["panZoomEnabled"] = instance.data["panZoom"] + + # Override viewport options by instance data + viewport_options = preset.setdefault("viewport_options", {}) + viewport_options["displayLights"] = instance.data["displayLights"] + viewport_options["imagePlane"] = instance.data.get("imagePlane", True) + + # Override transparency if requested. + transparency = instance.data.get("transparency", 0) + if transparency != 0: + preset["viewport2_options"]["transparencyAlgorithm"] = transparency # Update preset with current panel setting # if override_viewport_options is turned off @@ -335,15 +346,16 @@ def generate_capture_preset(instance, camera, path, @contextlib.contextmanager -def viewport_default_options(preset, instance): - # Disable Pan/Zoom. - pan_zoom = cmds.getAttr("{}.panZoomEnabled".format(preset["camera"])) - preset.pop("pan_zoom", None) - preset["camera_options"]["panZoomEnabled"] = instance.data["panZoom"] +def viewport_default_options(preset): + """Context manager used by `render_capture_preset`. + We need to explicitly enable some viewport changes so the viewport is + refreshed ahead of playblasting. + + """ + # TODO: Clarify in the docstring WHY we need to set it ahead of + # playblasting. What issues does it solve? viewport_defaults = {} - # Need to explicitly enable some viewport changes so the viewport is - # refreshed ahead of playblasting. try: keys = [ "useDefaultMaterial", @@ -355,24 +367,19 @@ def viewport_default_options(preset, instance): ] for key in keys: viewport_defaults[key] = cmds.modelEditor( - instance.data["panel"], query=True, **{key: True} + preset["panel"], query=True, **{key: True} ) if preset["viewport_options"][key]: cmds.modelEditor( - instance.data["panel"], edit=True, **{key: True} + preset["panel"], edit=True, **{key: True} ) yield finally: # Restoring viewport options. if viewport_defaults: cmds.modelEditor( - instance.data["panel"], edit=True, **viewport_defaults + preset["panel"], edit=True, **viewport_defaults ) - try: - cmds.setAttr( - "{}.panZoomEnabled".format(preset["camera"]), pan_zoom) - except RuntimeError: - self.log.warning("Cannot restore Pan/Zoom settings.") @contextlib.contextmanager @@ -2891,7 +2898,7 @@ def bake_to_world_space(nodes, return world_space_nodes -def load_capture_preset(data=None): +def load_capture_preset(data): """Convert OpenPype Extract Playblast settings to `capture` arguments Input data is the settings from: From 5a7079c2e4936a393237d3baed592546d09ce6ff Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 20 Dec 2023 21:49:48 +0100 Subject: [PATCH 34/62] Fix calls to refactored function name --- openpype/hosts/maya/plugins/publish/extract_playblast.py | 2 +- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 5a2beaca12..4ec4f733fd 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -57,7 +57,7 @@ class ExtractPlayblast(publish.Extractor): instance, camera, path, start=start, end=end, capture_preset=capture_preset) - path = lib.playblast_capture(preset, instance) + path = lib.render_capture_preset(preset) collected_files = os.listdir(stagingdir) patterns = [clique.PATTERNS["frames"]] diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 6f61515019..d85c00a7da 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -63,7 +63,7 @@ class ExtractThumbnail(publish.Extractor): "depthOfField": cmds.getAttr("{0}.depthOfField".format(camera)), # noqa } ) - path = lib.playblast_capture(preset, instance) + path = lib.render_capture_preset(preset) playblast = self._fix_playblast_output_path(path) From 9f543f89292d9c30bc05dd20f44f6d076c364835 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 20 Dec 2023 21:51:08 +0100 Subject: [PATCH 35/62] Remove `capture` import that's already imported at top --- openpype/hosts/maya/api/lib.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 5c15bfba26..cf4a6b6b6a 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -2912,8 +2912,6 @@ def load_capture_preset(data): """ - import capture - options = dict() viewport_options = dict() viewport2_options = dict() From 82e5e6bcdea325315ff7efcc85314c122b588339 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 20 Dec 2023 23:16:00 +0100 Subject: [PATCH 36/62] Clarify log messages --- openpype/hosts/maya/plugins/publish/extract_playblast.py | 2 +- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 4ec4f733fd..377b609603 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -24,7 +24,7 @@ class ExtractPlayblast(publish.Extractor): profiles = None def process(self, instance): - self.log.debug("Extracting capture..") + self.log.debug("Extracting playblast..") # get scene fps fps = instance.data.get("fps") or instance.context.data.get("fps") diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index d85c00a7da..d15877d603 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -20,7 +20,7 @@ class ExtractThumbnail(publish.Extractor): families = ["review"] def process(self, instance): - self.log.debug("Extracting capture..") + self.log.debug("Extracting thumbnail..") camera = instance.data["review_camera"] From 208e3f16540e5834b9549b82d858eae49acb5c77 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 20 Dec 2023 23:18:19 +0100 Subject: [PATCH 37/62] Depth of field is already preserved from camera by `generate_capture_preset` --- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index d15877d603..9bece030a4 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -60,7 +60,6 @@ class ExtractThumbnail(publish.Extractor): "displayFilmPivot": False, "displayFilmOrigin": False, "overscan": 1.0, - "depthOfField": cmds.getAttr("{0}.depthOfField".format(camera)), # noqa } ) path = lib.render_capture_preset(preset) From 4796bca514e03e0152534648ed10958f00f5c09d Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 20 Dec 2023 23:19:58 +0100 Subject: [PATCH 38/62] Cosmetics, + remove unused import --- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 9bece030a4..0d332d73ea 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -4,7 +4,6 @@ import tempfile from openpype.pipeline import publish from openpype.hosts.maya.api import lib -from maya.cmds import cmds class ExtractThumbnail(publish.Extractor): @@ -60,8 +59,7 @@ class ExtractThumbnail(publish.Extractor): "displayFilmPivot": False, "displayFilmOrigin": False, "overscan": 1.0, - } - ) + }) path = lib.render_capture_preset(preset) playblast = self._fix_playblast_output_path(path) From d880cdd1bb43213fb0c73991ec29eaaa6d433a39 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 20 Dec 2023 23:22:42 +0100 Subject: [PATCH 39/62] Cosmetics - avoid confusion about what `preset.get("filename")` actually is, it's the path passed to the generated preset. Remove unused `path` return value from `lib.render_capture_preset` Match representations logic with other extractors defining the list closer to creation of the representation, match more with ExtractThumbnail --- .../maya/plugins/publish/extract_playblast.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 377b609603..c41cf67fb4 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -57,28 +57,25 @@ class ExtractPlayblast(publish.Extractor): instance, camera, path, start=start, end=end, capture_preset=capture_preset) - path = lib.render_capture_preset(preset) + lib.render_capture_preset(preset) + # Find playblast sequence collected_files = os.listdir(stagingdir) patterns = [clique.PATTERNS["frames"]] collections, remainder = clique.assemble(collected_files, minimum_items=1, patterns=patterns) - filename = preset.get("filename", "%TEMP%") - self.log.debug("filename {}".format(filename)) + self.log.debug("Searching playblast collection for: %s", path) frame_collection = None for collection in collections: filebase = collection.format("{head}").rstrip(".") - self.log.debug("collection head {}".format(filebase)) - if filebase in filename: + self.log.debug("Checking collection head: %s", filebase) + if filebase in path: frame_collection = collection self.log.debug( - "we found collection of interest {}".format( - str(frame_collection))) - - if "representations" not in instance.data: - instance.data["representations"] = [] + "Found playblast collection: %s", frame_collection + ) tags = ["review"] if not instance.data.get("keepImages"): @@ -92,6 +89,9 @@ class ExtractPlayblast(publish.Extractor): if len(collected_files) == 1: collected_files = collected_files[0] + if "representations" not in instance.data: + instance.data["representations"] = [] + representation = { "name": capture_preset["Codec"]["compression"], "ext": capture_preset["Codec"]["compression"], From fa032d5f5519c8ffd6ca7a111447c6fc0f953ffa Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 20 Dec 2023 23:27:20 +0100 Subject: [PATCH 40/62] Cosmetis + improve comment --- openpype/hosts/maya/api/lib.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index cf4a6b6b6a..0a835ebeed 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -291,10 +291,10 @@ def generate_capture_preset(instance, camera, path, review_instance_width = instance.data.get("review_width") review_instance_height = instance.data.get("review_height") - # Tests if project resolution is set, - # if it is a value other than zero, that value is - # used, if not then the asset resolution is - # used + # Use resolution from instance if review width/height is set + # Otherwise use the resolution from preset if it has non-zero values + # Otherwise fall back to asset width x height + # Else define no width, then `capture.capture` will use render resolution if review_instance_width and review_instance_height: preset["width"] = review_instance_width preset["height"] = review_instance_height @@ -320,7 +320,7 @@ def generate_capture_preset(instance, camera, path, # Use Pan/Zoom from instance data instead of from preset preset.pop("pan_zoom", None) - preset["camera_options"]["panZoomEnabled"] = instance.data["panZoom"] + camera_options["panZoomEnabled"] = instance.data["panZoom"] # Override viewport options by instance data viewport_options = preset.setdefault("viewport_options", {}) @@ -334,10 +334,7 @@ def generate_capture_preset(instance, camera, path, # Update preset with current panel setting # if override_viewport_options is turned off - override_viewport_options = ( - capture_preset["Viewport Options"]["override_viewport_options"] - ) - if not override_viewport_options: + if not capture_preset["Viewport Options"]["override_viewport_options"]: panel_preset = capture.parse_view(instance.data["panel"]) panel_preset.pop("camera") preset.update(panel_preset) From f922d3c8f78be9596f58829960b6889f2d4aacdf Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 21 Dec 2023 07:41:39 +0100 Subject: [PATCH 41/62] Update openpype/hosts/maya/api/lib.py Co-authored-by: Kayla Man <64118225+moonyuet@users.noreply.github.com> --- openpype/hosts/maya/api/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 0a835ebeed..8acf850782 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -335,7 +335,7 @@ def generate_capture_preset(instance, camera, path, # Update preset with current panel setting # if override_viewport_options is turned off if not capture_preset["Viewport Options"]["override_viewport_options"]: - panel_preset = capture.parse_view(instance.data["panel"]) + panel_preset = capture.parse_view(preset["panel"]) panel_preset.pop("camera") preset.update(panel_preset) From 67a6a1169ebb297d792d7f24f7dadb636ac439b5 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 21 Dec 2023 07:41:47 +0100 Subject: [PATCH 42/62] Update openpype/hosts/maya/api/lib.py Co-authored-by: Kayla Man <64118225+moonyuet@users.noreply.github.com> --- openpype/hosts/maya/api/lib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 8acf850782..711b36e746 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -242,6 +242,7 @@ def render_capture_preset(preset): if reload_textures: # Regenerate all UDIM tiles previews reload_all_udim_tile_previews() + preset.pop("panel") path = capture.capture(log=self.log, **preset) return path From 5f309994c39ae8600f414da8ce1da15fec729408 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 21 Dec 2023 18:30:44 +0800 Subject: [PATCH 43/62] cosmetic tweaks and code clean up --- openpype/hosts/maya/api/exitstack.py | 16 +++++++++++++++- openpype/hosts/maya/api/lib.py | 14 ++++++-------- openpype/pipeline/publish/lib.py | 2 +- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/maya/api/exitstack.py b/openpype/hosts/maya/api/exitstack.py index cacaa396f0..2460f25f59 100644 --- a/openpype/hosts/maya/api/exitstack.py +++ b/openpype/hosts/maya/api/exitstack.py @@ -1,5 +1,19 @@ +"""Backwards compatible implementation of ExitStack for Python 2. + +ExitStack contextmanager was implemented with Python 3.3. As long as we support +Python 2 hosts we can use this backwards compatible implementation to support both +Python 2 and Python 3. + +Instead of using ExitStack from contextlib, use it from this module: + +>>> from openpype.hosts.maya.api.exitstack import ExitStack + +It will provide the appropriate ExitStack implementation for the current +running Python version. + +""" +# TODO: Remove the entire script once dropping Python 2 support. import contextlib -# TODO: Remove the entire script once dropping Python 2. if getattr(contextlib, "nested", None): from contextlib import ExitStack # noqa else: diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 711b36e746..e763ea6702 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -1,6 +1,7 @@ """Standalone helper functions""" import os +import copy from pprint import pformat import sys import uuid @@ -176,12 +177,9 @@ def maintained_selection(): def reload_all_udim_tile_previews(): """Regenerate all UDIM tile preview in texture file""" - texture_files = cmds.ls(type="file") - if texture_files: - for texture_file in texture_files: - if cmds.getAttr("{}.uvTilingMode".format(texture_file)) > 0: - cmds.ogs(regenerateUVTilePreview=texture_file) - cmds.ogs(reloadTextures=True) + for texture_file in cmds.ls(type="file"): + if cmds.getAttr("{}.uvTilingMode".format(texture_file)) > 0: + cmds.ogs(regenerateUVTilePreview=texture_file) @contextlib.contextmanager @@ -227,7 +225,7 @@ def render_capture_preset(preset): json.dumps(preset, indent=4, sort_keys=True) ) ) - + preset = copy.deepcopy(preset) # not supported by `capture` so we pop it off of the preset reload_textures = preset["viewport_options"].pop("reloadTextures", True) @@ -235,6 +233,7 @@ def render_capture_preset(preset): stack.enter_context(maintained_time()) stack.enter_context(panel_camera(preset["panel"], preset["camera"])) stack.enter_context(viewport_default_options(preset)) + preset.pop("panel") if preset["viewport_options"].get("textures"): # Force immediate texture loading when to ensure # all textures have loaded before the playblast starts @@ -242,7 +241,6 @@ def render_capture_preset(preset): if reload_textures: # Regenerate all UDIM tiles previews reload_all_udim_tile_previews() - preset.pop("panel") path = capture.capture(log=self.log, **preset) return path diff --git a/openpype/pipeline/publish/lib.py b/openpype/pipeline/publish/lib.py index 4ea2f932f1..87ca3323cb 100644 --- a/openpype/pipeline/publish/lib.py +++ b/openpype/pipeline/publish/lib.py @@ -74,7 +74,7 @@ def get_template_name_profiles( project_settings ["global"] ["publish"] - ["IntegrateAssetNew"] + ["IntegrateHeroVersion"] ["template_name_profiles"] ) if legacy_profiles: From 1d4acb78538364cd5ba5d16c82d8d561341eaa06 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 21 Dec 2023 18:33:25 +0800 Subject: [PATCH 44/62] hound --- openpype/hosts/maya/api/exitstack.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/api/exitstack.py b/openpype/hosts/maya/api/exitstack.py index 2460f25f59..d151ee16d7 100644 --- a/openpype/hosts/maya/api/exitstack.py +++ b/openpype/hosts/maya/api/exitstack.py @@ -1,8 +1,8 @@ """Backwards compatible implementation of ExitStack for Python 2. -ExitStack contextmanager was implemented with Python 3.3. As long as we support -Python 2 hosts we can use this backwards compatible implementation to support both -Python 2 and Python 3. +ExitStack contextmanager was implemented with Python 3.3. +As long as we supportPython 2 hosts we can use this backwards +compatible implementation to support bothPython 2 and Python 3. Instead of using ExitStack from contextlib, use it from this module: From a3f93790f1fcae59b2b7db18a5c1fd7a88b8b6ba Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 22 Dec 2023 00:07:16 +0800 Subject: [PATCH 45/62] repharse the preset pop for panel --- openpype/hosts/maya/api/lib.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index e763ea6702..57deb24a94 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -228,12 +228,11 @@ def render_capture_preset(preset): preset = copy.deepcopy(preset) # not supported by `capture` so we pop it off of the preset reload_textures = preset["viewport_options"].pop("reloadTextures", True) - + panel = preset.pop("panel") with ExitStack() as stack: stack.enter_context(maintained_time()) - stack.enter_context(panel_camera(preset["panel"], preset["camera"])) - stack.enter_context(viewport_default_options(preset)) - preset.pop("panel") + stack.enter_context(panel_camera(panel, preset["camera"])) + stack.enter_context(viewport_default_options(preset, panel)) if preset["viewport_options"].get("textures"): # Force immediate texture loading when to ensure # all textures have loaded before the playblast starts @@ -342,7 +341,7 @@ def generate_capture_preset(instance, camera, path, @contextlib.contextmanager -def viewport_default_options(preset): +def viewport_default_options(preset, panel): """Context manager used by `render_capture_preset`. We need to explicitly enable some viewport changes so the viewport is @@ -363,18 +362,18 @@ def viewport_default_options(preset): ] for key in keys: viewport_defaults[key] = cmds.modelEditor( - preset["panel"], query=True, **{key: True} + panel, query=True, **{key: True} ) if preset["viewport_options"][key]: cmds.modelEditor( - preset["panel"], edit=True, **{key: True} + panel, edit=True, **{key: True} ) yield finally: # Restoring viewport options. if viewport_defaults: cmds.modelEditor( - preset["panel"], edit=True, **viewport_defaults + panel, edit=True, **viewport_defaults ) From 6f5432611fb7020d76a69886a0798e157ede629e Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 22 Dec 2023 00:07:56 +0800 Subject: [PATCH 46/62] restore unnecessary tweaks --- openpype/pipeline/publish/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/pipeline/publish/lib.py b/openpype/pipeline/publish/lib.py index 87ca3323cb..4ea2f932f1 100644 --- a/openpype/pipeline/publish/lib.py +++ b/openpype/pipeline/publish/lib.py @@ -74,7 +74,7 @@ def get_template_name_profiles( project_settings ["global"] ["publish"] - ["IntegrateHeroVersion"] + ["IntegrateAssetNew"] ["template_name_profiles"] ) if legacy_profiles: From 7acbef93288da4f1925ba4ef29bf43b8cec23d9d Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 22 Dec 2023 00:35:21 +0800 Subject: [PATCH 47/62] change the args oder in viewport_default_options --- openpype/hosts/maya/api/lib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 57deb24a94..1a8a80f224 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -232,7 +232,7 @@ def render_capture_preset(preset): with ExitStack() as stack: stack.enter_context(maintained_time()) stack.enter_context(panel_camera(panel, preset["camera"])) - stack.enter_context(viewport_default_options(preset, panel)) + stack.enter_context(viewport_default_options(panel, preset)) if preset["viewport_options"].get("textures"): # Force immediate texture loading when to ensure # all textures have loaded before the playblast starts @@ -341,7 +341,7 @@ def generate_capture_preset(instance, camera, path, @contextlib.contextmanager -def viewport_default_options(preset, panel): +def viewport_default_options(panel, preset): """Context manager used by `render_capture_preset`. We need to explicitly enable some viewport changes so the viewport is From 3fd9d47a387d9bc428ca809d473ce038ebac2a6f Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 22 Dec 2023 00:45:09 +0800 Subject: [PATCH 48/62] use filename = instance.name --- openpype/hosts/maya/plugins/publish/extract_playblast.py | 2 +- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index c41cf67fb4..507229a7b3 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -48,7 +48,7 @@ class ExtractPlayblast(publish.Extractor): self.log ) stagingdir = self.staging_dir(instance) - filename = "{0}".format(instance.name) + filename = instance.name path = os.path.join(stagingdir, filename) self.log.debug("Outputting images to %s" % path) # get cameras diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 0d332d73ea..08f061985e 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -39,7 +39,7 @@ class ExtractThumbnail(publish.Extractor): "Create temp directory {} for thumbnail".format(dst_staging) ) # Store new staging to cleanup paths - filename = "{0}".format(instance.name) + filename = instance.name path = os.path.join(dst_staging, filename) self.log.debug("Outputting images to %s" % path) From 4b6e7beb87f57d34931801c9993fa61f8a135a74 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Sat, 23 Dec 2023 21:23:34 +0800 Subject: [PATCH 49/62] make sure extract review intermediate disabled when both deprecrated and current setting diabled --- .../nuke/plugins/publish/extract_review_intermediates.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openpype/hosts/nuke/plugins/publish/extract_review_intermediates.py b/openpype/hosts/nuke/plugins/publish/extract_review_intermediates.py index 3ee166eb56..a02a807206 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_review_intermediates.py +++ b/openpype/hosts/nuke/plugins/publish/extract_review_intermediates.py @@ -34,6 +34,11 @@ class ExtractReviewIntermediates(publish.Extractor): nuke_publish = project_settings["nuke"]["publish"] deprecated_setting = nuke_publish["ExtractReviewDataMov"] current_setting = nuke_publish.get("ExtractReviewIntermediates") + if not deprecated_setting["enabled"] and ( + not current_setting["enabled"] + ): + cls.enabled = False + if deprecated_setting["enabled"]: # Use deprecated settings if they are still enabled cls.viewer_lut_raw = deprecated_setting["viewer_lut_raw"] From e107526bbd8e3daf9cfed36de3d06c5db3cb078b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 2 Jan 2024 11:59:18 +0100 Subject: [PATCH 50/62] fix action to be able to run --- .../ftrack/event_handlers_user/action_djvview.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openpype/modules/ftrack/event_handlers_user/action_djvview.py b/openpype/modules/ftrack/event_handlers_user/action_djvview.py index 334519b4bb..bd9cd62e49 100644 --- a/openpype/modules/ftrack/event_handlers_user/action_djvview.py +++ b/openpype/modules/ftrack/event_handlers_user/action_djvview.py @@ -190,12 +190,12 @@ class DJVViewAction(BaseAction): """Callback method for DJVView action.""" # Launching application - event_data = event["data"] - if "values" not in event_data: + event_values = event["data"].get("value") + if not event_values: return - djv_app_name = event_data["djv_app_name"] - app = self.applicaion_manager.applications.get(djv_app_name) + djv_app_name = event_values["djv_app_name"] + app = self.application_manager.applications.get(djv_app_name) executable = None if app is not None: executable = app.find_executable() @@ -206,11 +206,11 @@ class DJVViewAction(BaseAction): "message": "Couldn't find DJV executable." } - filpath = os.path.normpath(event_data["values"]["path"]) + filpath = os.path.normpath(event_values["path"]) cmd = [ # DJV path - executable, + str(executable), # PATH TO COMPONENT filpath ] From 1e485614bdd01169627b2a05f2005b4d1ef0ade6 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 2 Jan 2024 11:59:45 +0100 Subject: [PATCH 51/62] keep process in momery for some time --- .../modules/ftrack/event_handlers_user/action_djvview.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openpype/modules/ftrack/event_handlers_user/action_djvview.py b/openpype/modules/ftrack/event_handlers_user/action_djvview.py index bd9cd62e49..5cc056cd91 100644 --- a/openpype/modules/ftrack/event_handlers_user/action_djvview.py +++ b/openpype/modules/ftrack/event_handlers_user/action_djvview.py @@ -217,7 +217,10 @@ class DJVViewAction(BaseAction): try: # Run DJV with these commands - subprocess.Popen(cmd) + _process = subprocess.Popen(cmd) + # Keep process in memory for some time + time.sleep(0.1) + except FileNotFoundError: return { "success": False, From 58a36c541462eda406f90e5d8d0174a689d3ec3b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 2 Jan 2024 12:00:03 +0100 Subject: [PATCH 52/62] formatting changes --- .../event_handlers_user/action_djvview.py | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/openpype/modules/ftrack/event_handlers_user/action_djvview.py b/openpype/modules/ftrack/event_handlers_user/action_djvview.py index 5cc056cd91..5778f0d26e 100644 --- a/openpype/modules/ftrack/event_handlers_user/action_djvview.py +++ b/openpype/modules/ftrack/event_handlers_user/action_djvview.py @@ -60,7 +60,7 @@ class DJVViewAction(BaseAction): return False def interface(self, session, entities, event): - if event['data'].get('values', {}): + if event["data"].get("values", {}): return entity = entities[0] @@ -70,32 +70,32 @@ class DJVViewAction(BaseAction): if entity_type == "assetversion": if ( entity[ - 'components' - ][0]['file_type'][1:] in self.allowed_types + "components" + ][0]["file_type"][1:] in self.allowed_types ): versions.append(entity) else: master_entity = entity if entity_type == "task": - master_entity = entity['parent'] + master_entity = entity["parent"] - for asset in master_entity['assets']: - for version in asset['versions']: + for asset in master_entity["assets"]: + for version in asset["versions"]: # Get only AssetVersion of selected task if ( entity_type == "task" and - version['task']['id'] != entity['id'] + version["task"]["id"] != entity["id"] ): continue # Get only components with allowed type - filetype = version['components'][0]['file_type'] + filetype = version["components"][0]["file_type"] if filetype[1:] in self.allowed_types: versions.append(version) if len(versions) < 1: return { - 'success': False, - 'message': 'There are no Asset Versions to open.' + "success": False, + "message": "There are no Asset Versions to open." } # TODO sort them (somehow?) @@ -134,57 +134,57 @@ class DJVViewAction(BaseAction): last_available = None select_value = None for version in versions: - for component in version['components']: + for component in version["components"]: label = base_label.format( - str(version['version']).zfill(3), - version['asset']['type']['name'], - component['name'] + str(version["version"]).zfill(3), + version["asset"]["type"]["name"], + component["name"] ) try: location = component[ - 'component_locations' - ][0]['location'] + "component_locations" + ][0]["location"] file_path = location.get_filesystem_path(component) except Exception: file_path = component[ - 'component_locations' - ][0]['resource_identifier'] + "component_locations" + ][0]["resource_identifier"] if os.path.isdir(os.path.dirname(file_path)): last_available = file_path - if component['name'] == default_component: + if component["name"] == default_component: select_value = file_path version_items.append( - {'label': label, 'value': file_path} + {"label": label, "value": file_path} ) if len(version_items) == 0: return { - 'success': False, - 'message': ( - 'There are no Asset Versions with accessible path.' + "success": False, + "message": ( + "There are no Asset Versions with accessible path." ) } item = { - 'label': 'Items to view', - 'type': 'enumerator', - 'name': 'path', - 'data': sorted( + "label": "Items to view", + "type": "enumerator", + "name": "path", + "data": sorted( version_items, - key=itemgetter('label'), + key=itemgetter("label"), reverse=True ) } if select_value is not None: - item['value'] = select_value + item["value"] = select_value else: - item['value'] = last_available + item["value"] = last_available items.append(item) - return {'items': items} + return {"items": items} def launch(self, session, entities, event): """Callback method for DJVView action.""" From 480c509f8ea4ac4baa835dcb5ae52cb428ad3cbf Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 2 Jan 2024 15:36:51 +0100 Subject: [PATCH 53/62] fix used key --- openpype/modules/ftrack/event_handlers_user/action_djvview.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/modules/ftrack/event_handlers_user/action_djvview.py b/openpype/modules/ftrack/event_handlers_user/action_djvview.py index 5778f0d26e..cc37faacf2 100644 --- a/openpype/modules/ftrack/event_handlers_user/action_djvview.py +++ b/openpype/modules/ftrack/event_handlers_user/action_djvview.py @@ -13,7 +13,7 @@ class DJVViewAction(BaseAction): description = "DJV View Launcher" icon = statics_icon("app_icons", "djvView.png") - type = 'Application' + type = "Application" allowed_types = [ "cin", "dpx", "avi", "dv", "gif", "flv", "mkv", "mov", "mpg", "mpeg", @@ -190,7 +190,7 @@ class DJVViewAction(BaseAction): """Callback method for DJVView action.""" # Launching application - event_values = event["data"].get("value") + event_values = event["data"].get("values") if not event_values: return From cf29a532d2ace421651d39e2104c03014b9a8aff Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 2 Jan 2024 22:51:51 +0800 Subject: [PATCH 54/62] make sure the texture only loaded when the texture is being enabled --- openpype/hosts/maya/api/lib.py | 12 ++++++------ .../settings/defaults/project_settings/maya.json | 2 +- .../projects_schema/schemas/schema_maya_capture.json | 8 ++++---- .../maya/server/settings/publish_playblast.py | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 1a8a80f224..6a0ccbdbfa 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -227,19 +227,19 @@ def render_capture_preset(preset): ) preset = copy.deepcopy(preset) # not supported by `capture` so we pop it off of the preset - reload_textures = preset["viewport_options"].pop("reloadTextures", True) + reload_textures = preset["viewport_options"].get("loadTextures") panel = preset.pop("panel") with ExitStack() as stack: stack.enter_context(maintained_time()) stack.enter_context(panel_camera(panel, preset["camera"])) stack.enter_context(viewport_default_options(panel, preset)) - if preset["viewport_options"].get("textures"): + if reload_textures: # Force immediate texture loading when to ensure # all textures have loaded before the playblast starts - stack.enter_context(material_loading_mode("immediate")) - if reload_textures: - # Regenerate all UDIM tiles previews - reload_all_udim_tile_previews() + stack.enter_context(material_loading_mode(mode="immediate")) + # Regenerate all UDIM tiles previews + reload_all_udim_tile_previews() + preset["viewport_options"].pop("loadTextures") path = capture.capture(log=self.log, **preset) return path diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index 1778530311..8136af8c73 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -1289,7 +1289,7 @@ "twoSidedLighting": true, "lineAAEnable": true, "multiSample": 8, - "reloadTextures": false, + "loadTextures": false, "useDefaultMaterial": false, "wireframeOnShaded": false, "xray": false, diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json index 1aa5b3d2e4..76ad9a3ba2 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json @@ -238,8 +238,8 @@ }, { "type": "boolean", - "key": "reloadTextures", - "label": "Reload Textures" + "key": "loadTextures", + "label": "Load Textures" }, { "type": "boolean", @@ -915,8 +915,8 @@ }, { "type": "boolean", - "key": "reloadTextures", - "label": "Reload Textures", + "key": "loadTextures", + "label": "Load Textures", "default": false }, { diff --git a/server_addon/maya/server/settings/publish_playblast.py b/server_addon/maya/server/settings/publish_playblast.py index 205f0eb847..db92c80db7 100644 --- a/server_addon/maya/server/settings/publish_playblast.py +++ b/server_addon/maya/server/settings/publish_playblast.py @@ -108,7 +108,7 @@ class ViewportOptionsSetting(BaseSettingsModel): True, title="Enable Anti-Aliasing", section="Anti-Aliasing" ) multiSample: int = Field(8, title="Anti Aliasing Samples") - reloadTextures: bool = Field(False, title="Reload Textures") + loadTextures: bool = Field(False, title="Reload Textures") useDefaultMaterial: bool = Field(False, title="Use Default Material") wireframeOnShaded: bool = Field(False, title="Wireframe On Shaded") xray: bool = Field(False, title="X-Ray") @@ -303,7 +303,7 @@ DEFAULT_PLAYBLAST_SETTING = { "twoSidedLighting": True, "lineAAEnable": True, "multiSample": 8, - "reloadTextures": False, + "loadTextures": False, "useDefaultMaterial": False, "wireframeOnShaded": False, "xray": False, From d351e5f1745f9875b496cbf873eec8b3c0e61ab1 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 2 Jan 2024 22:54:22 +0800 Subject: [PATCH 55/62] renamed reload Textures to Load Textures --- server_addon/maya/server/settings/publish_playblast.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_addon/maya/server/settings/publish_playblast.py b/server_addon/maya/server/settings/publish_playblast.py index db92c80db7..0abc9f7110 100644 --- a/server_addon/maya/server/settings/publish_playblast.py +++ b/server_addon/maya/server/settings/publish_playblast.py @@ -108,7 +108,7 @@ class ViewportOptionsSetting(BaseSettingsModel): True, title="Enable Anti-Aliasing", section="Anti-Aliasing" ) multiSample: int = Field(8, title="Anti Aliasing Samples") - loadTextures: bool = Field(False, title="Reload Textures") + loadTextures: bool = Field(False, title="Load Textures") useDefaultMaterial: bool = Field(False, title="Use Default Material") wireframeOnShaded: bool = Field(False, title="Wireframe On Shaded") xray: bool = Field(False, title="X-Ray") From bea3c78079e2caa27876873beabc83efea9b6d07 Mon Sep 17 00:00:00 2001 From: erictsaivfx Date: Tue, 2 Jan 2024 09:31:10 -0800 Subject: [PATCH 56/62] fix arrow to timezone typo --- openpype/tools/ayon_workfiles/models/workfiles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/tools/ayon_workfiles/models/workfiles.py b/openpype/tools/ayon_workfiles/models/workfiles.py index d74a8e164d..f9f910ac8a 100644 --- a/openpype/tools/ayon_workfiles/models/workfiles.py +++ b/openpype/tools/ayon_workfiles/models/workfiles.py @@ -606,7 +606,7 @@ class PublishWorkfilesModel: print("Failed to format workfile path: {}".format(exc)) dirpath, filename = os.path.split(workfile_path) - created_at = arrow.get(repre_entity["createdAt"].to("local")) + created_at = arrow.get(repre_entity["createdAt"]).to("local") return FileItem( dirpath, filename, From c4ee2f785849db86db967c54d4f256946fbb093a Mon Sep 17 00:00:00 2001 From: Ynbot Date: Wed, 3 Jan 2024 03:26:06 +0000 Subject: [PATCH 57/62] [Automated] Bump version --- openpype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/version.py b/openpype/version.py index 550bdb70c7..6a8e6f0d95 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.18.2-nightly.5" +__version__ = "3.18.2-nightly.6" From 58909f2b4d90fc6165142014ad59825bad550eda Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 3 Jan 2024 03:26:39 +0000 Subject: [PATCH 58/62] chore(): update bug report / version --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index f345829356..3471c32430 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -35,6 +35,7 @@ body: label: Version description: What version are you running? Look to OpenPype Tray options: + - 3.18.2-nightly.6 - 3.18.2-nightly.5 - 3.18.2-nightly.4 - 3.18.2-nightly.3 @@ -134,7 +135,6 @@ body: - 3.15.6-nightly.1 - 3.15.5 - 3.15.5-nightly.2 - - 3.15.5-nightly.1 validations: required: true - type: dropdown From 379674d7931d4e479b157443757465850c582976 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 3 Jan 2024 15:27:09 +0800 Subject: [PATCH 59/62] remove the condition with the deprecated environment variable in AYON --- openpype/hosts/maya/api/lib.py | 15 ++++++--------- .../maya/plugins/publish/extract_thumbnail.py | 2 +- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 6a0ccbdbfa..394f92ed42 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -218,16 +218,14 @@ def render_capture_preset(preset): refresh_frame_int = int(cmds.playbackOptions(query=True, minTime=True)) cmds.currentTime(refresh_frame_int - 1, edit=True) cmds.currentTime(refresh_frame_int, edit=True) - - if os.environ.get("OPENPYPE_DEBUG") == "1": - log.debug( - "Using preset: {}".format( - json.dumps(preset, indent=4, sort_keys=True) - ) + log.debug( + "Using preset: {}".format( + json.dumps(preset, indent=4, sort_keys=True) ) + ) preset = copy.deepcopy(preset) # not supported by `capture` so we pop it off of the preset - reload_textures = preset["viewport_options"].get("loadTextures") + reload_textures = preset["viewport_options"].pop("loadTextures", False) panel = preset.pop("panel") with ExitStack() as stack: stack.enter_context(maintained_time()) @@ -239,7 +237,6 @@ def render_capture_preset(preset): stack.enter_context(material_loading_mode(mode="immediate")) # Regenerate all UDIM tiles previews reload_all_udim_tile_previews() - preset["viewport_options"].pop("loadTextures") path = capture.capture(log=self.log, **preset) return path @@ -364,7 +361,7 @@ def viewport_default_options(panel, preset): viewport_defaults[key] = cmds.modelEditor( panel, query=True, **{key: True} ) - if preset["viewport_options"][key]: + if preset["viewport_options"].get(key): cmds.modelEditor( panel, edit=True, **{key: True} ) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 08f061985e..28362b355c 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -34,7 +34,7 @@ class ExtractThumbnail(publish.Extractor): # Create temp directory for thumbnail # - this is to avoid "override" of source file - dst_staging = tempfile.mkdtemp(prefix="pyblish_tmp_") + dst_staging = tempfile.mkdtemp(prefix="pyblish_tmp_thumbnail") self.log.debug( "Create temp directory {} for thumbnail".format(dst_staging) ) From e4e6503017c4b1333129df4c16208fd239a7f779 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 3 Jan 2024 12:07:32 +0100 Subject: [PATCH 60/62] Testing: Release Maya/Deadline job from pending when testing. (#5988) * Release job from pending when testing. * Removed render instance This test was created as simple model and workfile publish, without Deadline rendering. Cleaned up render elements. * Revert changes in submit publish plugin --------- Co-authored-by: kalisp --- .../modules/deadline/plugins/publish/submit_maya_deadline.py | 4 ++-- .../modules/deadline/plugins/publish/submit_publish_job.py | 4 +++- .../work/test_task/test_project_test_asset_test_task_v001.ma | 4 ++-- .../work/test_task/test_project_test_asset_test_task_v002.ma | 4 ++-- .../input/workfile/test_project_test_asset_test_task_v001.ma | 4 ++-- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py index 26a605a744..5591db151a 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -231,7 +231,7 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, job_info.EnvironmentKeyValue["OPENPYPE_LOG_NO_COLORS"] = "1" # Adding file dependencies. - if self.asset_dependencies: + if not bool(os.environ.get("IS_TEST")) and self.asset_dependencies: dependencies = instance.context.data["fileDependencies"] for dependency in dependencies: job_info.AssetDependency += dependency @@ -570,7 +570,7 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, job_info = copy.deepcopy(self.job_info) - if self.asset_dependencies: + if not bool(os.environ.get("IS_TEST")) and self.asset_dependencies: # Asset dependency to wait for at least the scene file to sync. job_info.AssetDependency += self.scene_path diff --git a/openpype/modules/deadline/plugins/publish/submit_publish_job.py b/openpype/modules/deadline/plugins/publish/submit_publish_job.py index 228aa3ec81..04ce2b3433 100644 --- a/openpype/modules/deadline/plugins/publish/submit_publish_job.py +++ b/openpype/modules/deadline/plugins/publish/submit_publish_job.py @@ -297,7 +297,9 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin, job_index)] = assembly_id # noqa: E501 job_index += 1 elif instance.data.get("bakingSubmissionJobs"): - self.log.info("Adding baking submission jobs as dependencies...") + self.log.info( + "Adding baking submission jobs as dependencies..." + ) job_index = 0 for assembly_id in instance.data["bakingSubmissionJobs"]: payload["JobInfo"]["JobDependency{}".format( diff --git a/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v001.ma b/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v001.ma index 2cc87c2f48..8b90e987de 100644 --- a/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v001.ma +++ b/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v001.ma @@ -185,7 +185,7 @@ createNode objectSet -n "modelMain"; addAttr -ci true -sn "attrPrefix" -ln "attrPrefix" -dt "string"; addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; addAttr -ci true -sn "creator_attributes" -ln "creator_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" + addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" -dt "string"; setAttr ".ihi" 0; setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:7364ea6776c9"; @@ -296,7 +296,7 @@ createNode objectSet -n "workfileMain"; addAttr -ci true -sn "task" -ln "task" -dt "string"; addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; addAttr -ci true -sn "creator_attributes" -ln "creator_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" + addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" -dt "string"; setAttr ".ihi" 0; setAttr ".hio" yes; diff --git a/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v002.ma b/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v002.ma index 6bd334466a..f2906058cf 100644 --- a/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v002.ma +++ b/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v002.ma @@ -185,7 +185,7 @@ createNode objectSet -n "modelMain"; addAttr -ci true -sn "attrPrefix" -ln "attrPrefix" -dt "string"; addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; addAttr -ci true -sn "creator_attributes" -ln "creator_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" + addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" -dt "string"; setAttr ".ihi" 0; setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:7364ea6776c9"; @@ -296,7 +296,7 @@ createNode objectSet -n "workfileMain"; addAttr -ci true -sn "task" -ln "task" -dt "string"; addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; addAttr -ci true -sn "creator_attributes" -ln "creator_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" + addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" -dt "string"; setAttr ".ihi" 0; setAttr ".hio" yes; diff --git a/tests/integration/hosts/maya/test_publish_in_maya/input/workfile/test_project_test_asset_test_task_v001.ma b/tests/integration/hosts/maya/test_publish_in_maya/input/workfile/test_project_test_asset_test_task_v001.ma index 2cc87c2f48..8b90e987de 100644 --- a/tests/integration/hosts/maya/test_publish_in_maya/input/workfile/test_project_test_asset_test_task_v001.ma +++ b/tests/integration/hosts/maya/test_publish_in_maya/input/workfile/test_project_test_asset_test_task_v001.ma @@ -185,7 +185,7 @@ createNode objectSet -n "modelMain"; addAttr -ci true -sn "attrPrefix" -ln "attrPrefix" -dt "string"; addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; addAttr -ci true -sn "creator_attributes" -ln "creator_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" + addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" -dt "string"; setAttr ".ihi" 0; setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:7364ea6776c9"; @@ -296,7 +296,7 @@ createNode objectSet -n "workfileMain"; addAttr -ci true -sn "task" -ln "task" -dt "string"; addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; addAttr -ci true -sn "creator_attributes" -ln "creator_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" + addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" -dt "string"; setAttr ".ihi" 0; setAttr ".hio" yes; From 70062011f7f052f8f918c2a22897a8765cbb1e9e Mon Sep 17 00:00:00 2001 From: Ynbot Date: Wed, 3 Jan 2024 15:14:06 +0000 Subject: [PATCH 61/62] [Automated] Release --- CHANGELOG.md | 317 ++++++++++++++++++++++++++++++++++++++++++++ openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 319 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f309d904eb..4a21882008 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,323 @@ # Changelog +## [3.18.2](https://github.com/ynput/OpenPype/tree/3.18.2) + + +[Full Changelog](https://github.com/ynput/OpenPype/compare/3.18.1...3.18.2) + +### **🚀 Enhancements** + + +
+Testing: Release Maya/Deadline job from pending when testing. #5988 + +When testing we wont put the Deadline jobs into pending with dependencies, so the worker can start as soon as possible. + + +___ + +
+ + +
+Max: Tweaks on Extractions for the exporters #5814 + +With this PR +- Suspend Refresh would be introduced in abc & obj extractors for optimization. +- Allow users to choose the custom attributes to be included in abc exports + + +___ + +
+ + +
+Maya: Optional preserve references. #5994 + +Optional preserve references when publishing Maya scenes. + + +___ + +
+ + +
+AYON ftrack: Expect 'ayon' group in custom attributes #6066 + +Expect `ayon` group as one of options to get custom attributes. + + +___ + +
+ + +
+AYON Chore: Remove dependencies related to separated addons #6074 + +Removed dependencies from openpype client pyproject.toml that are already defined by addons which require them. + + +___ + +
+ + +
+Editorial & chore: Stop using pathlib2 #6075 + +Do not use `pathlib2` which is Python 2 backport for `pathlib` module in python 3. + + +___ + +
+ + +
+Traypublisher: Correct validator label #6084 + +Use correct label for Validate filepaths. + + +___ + +
+ + +
+Nuke: Extract Review Intermediate disabled when both Extract Review Mov and Extract Review Intermediate disabled in setting #6089 + +Report in Discord https://discord.com/channels/517362899170230292/563751989075378201/1187874498234556477 + + +___ + +
+ +### **🐛 Bug fixes** + + +
+Maya: Bug fix the file from texture node not being collected correctly in Yeti Rig #5990 + +Fix the bug of collect Yeti Rig not being able to get the file parameter(s) from the texture node(s), resulting to the failure of publishing the textures to the resource directory. + + +___ + +
+ + +
+Bug: fix AYON settings for Maya workspace #6069 + +This is changing bug in default AYON setting for Maya workspace, where missing semicolumn caused workspace not being set. This is also syncing default workspace settings to OpenPype + + +___ + +
+ + +
+Refactor colorspace handling in CollectColorspace plugin #6033 + +Traypublisher is now capable set available colorspaces or roles to publishing images sequence or video. This is fix of new implementation where we allowed to use roles in the enumerator selector. + + +___ + +
+ + +
+Bugfix: Houdini render split bugs #6037 + +This PR is a follow up PR to https://github.com/ynput/OpenPype/pull/5420This PR does: +- refactor `get_output_parameter` to what is used to be. +- fix a bug with split render +- rename `exportJob` flag to `split_render` + + +___ + +
+ + +
+Fusion: fix for single frame rendering #6056 + +Fixes publishes of single frame of `render` product type. + + +___ + +
+ + +
+Photoshop: fix layer publish thumbnail missing in loader #6061 + +Thumbnails from any products (either `review` nor separate layer instances) weren't stored in Ayon.This resulted in not showing them in Loader and Server UI. After this PR thumbnails should be shown in the Loader and on the Server (`http://YOUR_AYON_HOSTNAME:5000/projects/YOUR_PROJECT/browser`). + + +___ + +
+ + +
+AYON Chore: Do not use thumbnailSource for thumbnail integration #6063 + +Do not use `thumbnailSource` for thumbnail integration. + + +___ + +
+ + +
+Photoshop: fix creation of .mov #6064 + +Generation of .mov file with 1 frame per published layer was failing. + + +___ + +
+ + +
+Photoshop: fix Collect Color Coded settings #6065 + +Fix for wrong default value for `Collect Color Coded Instances` Settings + + +___ + +
+ + +
+Bug: Fix Publisher parent window in Nuke #6067 + +Fixing issue where publisher parent window wasn't set because wrong use of version constant. + + +___ + +
+ + +
+Python console widget: Save registry fix #6076 + +Do not save registry until there is something to save. + + +___ + +
+ + +
+Ftrack: update asset names for multiple reviewable items #6077 + +Multiple reviewable assetVersion components with better grouping to asset version name. + + +___ + +
+ + +
+Ftrack: DJV action fixes #6098 + +Fix bugs in DJV ftrack action. + + +___ + +
+ + +
+AYON Workfiles tool: Fix arrow to timezone typo #6099 + +Fix parenthesis typo with arrow local timezone function. + + +___ + +
+ +### **🔀 Refactored code** + + +
+Chore: Update folder-favorite icon to ayon icon #5718 + +Updates old "Pype-2.0-era" (from ancient greece times) to AYON logo equivalent.I believe it's only used in Nuke. + + +___ + +
+ +### **Merged pull requests** + + +
+Chore: Maya / Nuke remove publish gui filters from settings #5570 + +- Remove Publish GUI Filters from Nuke settings +- Remove Publish GUI Filters from Maya settings + + +___ + +
+ + +
+Fusion: Project/User option for output format (create_saver) #6045 + +Adds "Output Image Format" option which can be set via project settings and overwritten by users in "Create" menu. This replaces the current behaviour of being hardcoded to "exr". Replacing the need for people to manually edit the saver path if they require a different extension. + + +___ + +
+ + +
+Fusion: Output Image Format Updating Instances (create_saver) #6060 + +Adds the ability to update Saver image output format if changed in the Publish UI.~~Adds an optional validator that compares "Output Image Format" in the Publish menu against the one currently found on the saver. It then offers a repair action to update the output extension on the saver.~~ + + +___ + +
+ + +
+Tests: Fix representation count for AE legacy test #6072 + + +___ + +
+ + + + ## [3.18.1](https://github.com/ynput/OpenPype/tree/3.18.1) diff --git a/openpype/version.py b/openpype/version.py index 6a8e6f0d95..4d7b8f372f 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.18.2-nightly.6" +__version__ = "3.18.2" diff --git a/pyproject.toml b/pyproject.toml index e64018498f..38236f88bc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.18.1" # OpenPype +version = "3.18.2" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From c4dea2c74a2ce25963a796d29a130c8355778718 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 3 Jan 2024 15:15:06 +0000 Subject: [PATCH 62/62] chore(): update bug report / version --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 3471c32430..132e960885 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -35,6 +35,7 @@ body: label: Version description: What version are you running? Look to OpenPype Tray options: + - 3.18.2 - 3.18.2-nightly.6 - 3.18.2-nightly.5 - 3.18.2-nightly.4 @@ -134,7 +135,6 @@ body: - 3.15.6-nightly.2 - 3.15.6-nightly.1 - 3.15.5 - - 3.15.5-nightly.2 validations: required: true - type: dropdown