From 6074876adf2ff180108cc24ec94c0a59bb5ea248 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 22 Nov 2023 17:29:12 +0800 Subject: [PATCH 01/51] 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 2ecaf87fce9..27c61d0af37 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 cfab239da31..8835f288eae 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -43,7 +43,6 @@ def _capture(self, preset): 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 @@ def process(self, instance): 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 @@ def process(self, instance): "wireframeOnShaded", "xray", "jointXray", - "backfaceCulling" + "backfaceCulling", + "textures" ] viewport_defaults = {} for key in keys: @@ -180,6 +181,7 @@ def process(self, instance): 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 c0be3d77dbc..550243f2742 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -101,6 +101,8 @@ def process(self, instance): 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/51] 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 27c61d0af37..a2a014caef9 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 8835f288eae..5b98fb5fc93 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -43,6 +43,8 @@ def _capture(self, preset): 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 @@ def process(self, instance): 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 550243f2742..e2dd89836f9 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -101,8 +101,6 @@ def process(self, instance): 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 @@ def process(self, instance): 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/51] 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 a2a014caef9..271b90d8784 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 5b98fb5fc93..66ebe2ba0da 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -44,7 +44,7 @@ def _capture(self, preset): ) ) 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 e2dd89836f9..2b5360efe6b 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -153,7 +153,7 @@ def process(self, instance): ) ) 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/51] 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 271b90d8784..293889ddcc4 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/51] 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 293889ddcc4..4066ee640bd 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 66ebe2ba0da..872702e66e7 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -44,7 +44,7 @@ def _capture(self, preset): ) ) 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 @@ def process(self, instance): 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 2b5360efe6b..27f008652b2 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -152,10 +152,10 @@ def process(self, instance): 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 7719a5e2558..fa2f6947478 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 d90527ac8cc..1aa5b3d2e43 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 acfcaf59889..205f0eb847f 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 @@ class ExtractPlayblastSetting(BaseSettingsModel): "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 805897cda31..b87834cc35b 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/51] 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 4066ee640bd..078ed5192ba 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 872702e66e7..a3a2f8a5a59 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -43,8 +43,11 @@ def _capture(self, preset): 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 27f008652b2..ef843c9df8b 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -152,8 +152,11 @@ def process(self, instance): 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 ce62dde43f8..d62e50d3c74 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 224699f916b..b6d15ae47a8 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/51] 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 a3a2f8a5a59..26b2ac70864 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -45,7 +45,7 @@ def _capture(self, preset): ) 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 ef843c9df8b..a64d31f6d9a 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -154,7 +154,7 @@ def process(self, instance): ) 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/51] 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 26b2ac70864..e59309c0fd2 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -48,6 +48,8 @@ def _capture(self, preset): 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 b6d15ae47a8..224699f916b 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/51] 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 a64d31f6d9a..380810d8c02 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -157,6 +157,7 @@ def process(self, instance): 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/51] 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 e59309c0fd2..56113d6a53d 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -48,8 +48,7 @@ def _capture(self, preset): 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 380810d8c02..aa0a68e4f50 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -157,7 +157,7 @@ def process(self, instance): 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/51] 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 02fa75e0322..114575cd0e4 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 56113d6a53d..0e001497bdb 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -48,7 +48,7 @@ def _capture(self, preset): 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/51] 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 aa0a68e4f50..67455f60f09 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -157,7 +157,7 @@ def process(self, instance): 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/51] 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 114575cd0e4..1b912ac0ec4 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 0e001497bdb..b8853086130 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -43,11 +43,12 @@ def _capture(self, preset): 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 67455f60f09..77a538b95db 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -152,12 +152,13 @@ def process(self, instance): 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/51] 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 1b912ac0ec4..02fa75e0322 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/51] 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 b8853086130..4ce7e19ee2a 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -49,7 +49,8 @@ def _capture(self, preset): 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 77a538b95db..bc5f9bc4eda 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -158,7 +158,8 @@ def process(self, instance): 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/51] 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 2a9defbf2d2..817688258bc 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 4ce7e19ee2a..b540a2c56df 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -43,15 +43,17 @@ def _capture(self, preset): 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 bc5f9bc4eda..10082436d65 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -154,12 +154,16 @@ def process(self, instance): ) 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/51] 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 817688258bc..41290b805e1 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 b540a2c56df..7bcddf97f19 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -43,17 +43,13 @@ def _capture(self, preset): 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 @@ def process(self, instance): # 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 @@ def process(self, instance): 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 10082436d65..b24cda8f07d 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -152,19 +152,18 @@ def process(self, instance): 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/51] 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 b24cda8f07d..3f25a9b17b5 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -161,7 +161,8 @@ def process(self, instance): 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/51] 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 00000000000..dcf7131bd35 --- /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 7bcddf97f19..2e11a5f26e6 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -7,6 +7,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 @@ -199,37 +200,15 @@ def process(self, instance): 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) - - 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()) + 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 3f25a9b17b5..b8e7b19bc67 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -153,11 +153,11 @@ def process(self, instance): ) ) - 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/51] 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 dcf7131bd35..ee32fad56bc 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 @@ def pop_all(self): 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 @@ def push(self, exit): 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 @@ def _exit_wrapper(exc_type, exc, tb): # 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 @@ def enter_context(self, cm): 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 @@ 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__ @@ -110,7 +113,7 @@ def _fix_exception_context(new_exc, old_exc): 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/51] 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 ee32fad56bc..9b049f19146 100644 --- a/openpype/hosts/maya/api/exitstack.py +++ b/openpype/hosts/maya/api/exitstack.py @@ -5,8 +5,7 @@ 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/51] 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 9b049f19146..cacaa396f0d 100644 --- a/openpype/hosts/maya/api/exitstack.py +++ b/openpype/hosts/maya/api/exitstack.py @@ -5,7 +5,9 @@ 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 @@ def __init__(self): 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/51] 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 2e11a5f26e6..78d771c2505 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -45,13 +45,20 @@ def _capture(self, 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)) + 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 @@ def process(self, instance): 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 b8e7b19bc67..96c7226db3a 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -153,16 +153,16 @@ def process(self, instance): ) ) - 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/51] 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 41290b805e1..d2a2ab253b0 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -9,6 +9,8 @@ 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 78d771c2505..0f1423d63db 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.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 @@ def process(self, instance): 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 96c7226db3a..897383d0cbf 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 @@ def process(self, instance): 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/51] 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 d2a2ab253b0..0dd18bb978f 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 0f1423d63db..192eb2639dc 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 @@ def process(self, instance): 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 @@ def process(self, instance): 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 897383d0cbf..09665a1a580 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -5,8 +5,6 @@ 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 @@ def process(self, instance): 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 @@ def process(self, instance): 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/51] hound --- openpype/hosts/maya/api/lib.py | 248 +++++++++++++++++---------------- 1 file changed, 125 insertions(+), 123 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 0dd18bb978f..6d30a58506f 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) - - # "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"] + 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} ) - - # 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: + if preset["viewport_options"][key]: cmds.modelEditor( - instance.data["panel"], edit=True, **viewport_defaults + instance.data["panel"], edit=True, **{key: True} ) - try: - cmds.setAttr( - "{}.panZoomEnabled".format(preset["camera"]), pan_zoom) - except RuntimeError: - self.log.warning("Cannot restore Pan/Zoom settings.") + 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 + 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/51] 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 6d30a58506f..8749ac0d6aa 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/51] refactor the capture and capture preset function --- openpype/hosts/maya/api/lib.py | 104 +++++++++--------- .../maya/plugins/publish/extract_playblast.py | 4 +- .../maya/plugins/publish/extract_thumbnail.py | 20 +++- 3 files changed, 71 insertions(+), 57 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 8749ac0d6aa..c1d1a43d1ec 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,27 +322,56 @@ 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) + return preset + - # Restoring viewport options. - if viewport_defaults: - cmds.modelEditor( - instance.data["panel"], edit=True, **viewport_defaults - ) +@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: - cmds.setAttr( - "{}.panZoomEnabled".format(preset["camera"]), pan_zoom) - except RuntimeError: - self.log.warning("Cannot restore Pan/Zoom settings.") - - return preset + 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 diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 192eb2639dc..5a2beaca12a 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -53,11 +53,11 @@ def process(self, instance): 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 09665a1a580..b4931b637f3 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -4,6 +4,7 @@ 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 @@ def process(self, instance): 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/51] 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 c1d1a43d1ec..bc66ec350f4 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 b4931b637f3..05fad0025d5 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -51,16 +51,17 @@ def process(self, instance): 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/51] 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 05fad0025d5..6f61515019d 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -60,8 +60,7 @@ def process(self, instance): "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/51] 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 bc66ec350f4..4db7269d9bf 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/51] 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 4db7269d9bf..9892fd02552 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/51] Code cleanup --- openpype/hosts/maya/api/lib.py | 139 +++++++++++++++++---------------- 1 file changed, 73 insertions(+), 66 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 9892fd02552..5c15bfba260 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,50 +304,34 @@ 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 + # 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"] + + # Override camera options # 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) + "{0}.depthOfField".format(camera) + ) - refreshFrameInt = int(cmds.playbackOptions(q=True, minTime=True)) - cmds.currentTime(refreshFrameInt - 1, edit=True) - cmds.currentTime(refreshFrameInt, edit=True) + # Use Pan/Zoom from instance data instead of from preset + preset.pop("pan_zoom", None) + preset["camera_options"]["panZoomEnabled"] = instance.data["panZoom"] - # Use displayLights setting from instance - key = "displayLights" - preset["viewport_options"][key] = instance.data[key] + # 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 - # 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} - - # 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 override_viewport_options = ( @@ -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 _get_attrs(node): 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/51] 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 5a2beaca12a..4ec4f733fde 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -57,7 +57,7 @@ def process(self, instance): 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 6f61515019d..d85c00a7da9 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -63,7 +63,7 @@ def process(self, instance): "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/51] 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 5c15bfba260..cf4a6b6b6aa 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/51] 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 4ec4f733fde..377b6096038 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 d85c00a7da9..d15877d6036 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/51] 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 d15877d6036..9bece030a47 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -60,7 +60,6 @@ def process(self, instance): "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/51] 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 9bece030a47..0d332d73eaa 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -4,7 +4,6 @@ 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 @@ def process(self, instance): "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/51] 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 377b6096038..c41cf67fb4a 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -57,28 +57,25 @@ def process(self, instance): 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 @@ def process(self, instance): 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/51] 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 cf4a6b6b6aa..0a835ebeed9 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/51] 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 0a835ebeed9..8acf8507820 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/51] 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 8acf8507820..711b36e7462 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/51] 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 cacaa396f0d..2460f25f59b 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 711b36e7462..e763ea67027 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 4ea2f932f14..87ca3323cbd 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/51] 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 2460f25f59b..d151ee16d71 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/51] 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 e763ea67027..57deb24a949 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/51] 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 87ca3323cbd..4ea2f932f14 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/51] 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 57deb24a949..1a8a80f224b 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/51] 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 c41cf67fb4a..507229a7b31 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -48,7 +48,7 @@ def process(self, instance): 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 0d332d73eaa..08f061985e0 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -39,7 +39,7 @@ def process(self, instance): "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 cf29a532d2ace421651d39e2104c03014b9a8aff Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 2 Jan 2024 22:51:51 +0800 Subject: [PATCH 49/51] 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 1a8a80f224b..6a0ccbdbfa5 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 1778530311c..8136af8c735 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 1aa5b3d2e43..76ad9a3ba29 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 205f0eb847f..db92c80db7b 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 @@ class ExtractPlayblastSetting(BaseSettingsModel): "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 50/51] 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 db92c80db7b..0abc9f71106 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 379674d7931d4e479b157443757465850c582976 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 3 Jan 2024 15:27:09 +0800 Subject: [PATCH 51/51] 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 6a0ccbdbfa5..394f92ed42a 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 08f061985e0..28362b355c4 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -34,7 +34,7 @@ def process(self, instance): # 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) )