From 2fdd13738066f320359a2cf7d84407bcd93e8fbd Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 28 Nov 2022 09:40:42 +0000 Subject: [PATCH 001/106] Optional control of display lights on playblast. --- openpype/hosts/maya/plugins/create/create_review.py | 2 ++ openpype/hosts/maya/plugins/publish/extract_playblast.py | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/openpype/hosts/maya/plugins/create/create_review.py b/openpype/hosts/maya/plugins/create/create_review.py index ba51ffa009..65aeb2d76a 100644 --- a/openpype/hosts/maya/plugins/create/create_review.py +++ b/openpype/hosts/maya/plugins/create/create_review.py @@ -25,6 +25,7 @@ class CreateReview(plugin.Creator): "depth peeling", "alpha cut" ] + displayLights = ["default", "all", "selected", "active", "none"] def __init__(self, *args, **kwargs): super(CreateReview, self).__init__(*args, **kwargs) @@ -41,5 +42,6 @@ class CreateReview(plugin.Creator): data["keepImages"] = self.keepImages data["imagePlane"] = self.imagePlane data["transparency"] = self.transparency + data["displayLights"] = self.displayLights self.data = data diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index b19d24fad7..cbf99eccaa 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -97,6 +97,10 @@ class ExtractPlayblast(publish.Extractor): refreshFrameInt = int(pm.playbackOptions(q=True, minTime=True)) pm.currentTime(refreshFrameInt - 1, edit=True) pm.currentTime(refreshFrameInt, edit=True) + + # Show lighting mode. + index = instance.data.get("displayLights", 0) + preset["viewport_options"]["displayLights"] = self.displayLights[index] # Override transparency if requested. transparency = instance.data.get("transparency", 0) From e214062047f09e6b0879cb015e6445b889b0d33a Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 2 Dec 2022 12:19:57 +0000 Subject: [PATCH 002/106] Missing class data. --- openpype/hosts/maya/plugins/publish/extract_playblast.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index cbf99eccaa..c6bbe44efc 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -23,6 +23,7 @@ class ExtractPlayblast(publish.Extractor): families = ["review"] optional = True capture_preset = {} + displayLights = ["default", "all", "selected", "active", "none"] def process(self, instance): self.log.info("Extracting capture..") @@ -97,7 +98,7 @@ class ExtractPlayblast(publish.Extractor): refreshFrameInt = int(pm.playbackOptions(q=True, minTime=True)) pm.currentTime(refreshFrameInt - 1, edit=True) pm.currentTime(refreshFrameInt, edit=True) - + # Show lighting mode. index = instance.data.get("displayLights", 0) preset["viewport_options"]["displayLights"] = self.displayLights[index] From 6bc8748b99e58894479071e14b04780a3da9cd15 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 14 Dec 2022 09:18:45 +0000 Subject: [PATCH 003/106] Collect display lights list in lib. --- openpype/hosts/maya/api/lib.py | 2 ++ openpype/hosts/maya/plugins/create/create_review.py | 3 +-- openpype/hosts/maya/plugins/publish/extract_playblast.py | 3 +-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 2530021eba..617e4e3d3a 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -113,6 +113,8 @@ FLOAT_FPS = {23.98, 23.976, 29.97, 47.952, 59.94} RENDERLIKE_INSTANCE_FAMILIES = ["rendering", "vrayscene"] +DISPLAY_LIGHTS = ["default", "all", "selected", "active", "none"] + def get_main_window(): """Acquire Maya's main window""" diff --git a/openpype/hosts/maya/plugins/create/create_review.py b/openpype/hosts/maya/plugins/create/create_review.py index 65aeb2d76a..1935d18deb 100644 --- a/openpype/hosts/maya/plugins/create/create_review.py +++ b/openpype/hosts/maya/plugins/create/create_review.py @@ -25,7 +25,6 @@ class CreateReview(plugin.Creator): "depth peeling", "alpha cut" ] - displayLights = ["default", "all", "selected", "active", "none"] def __init__(self, *args, **kwargs): super(CreateReview, self).__init__(*args, **kwargs) @@ -42,6 +41,6 @@ class CreateReview(plugin.Creator): data["keepImages"] = self.keepImages data["imagePlane"] = self.imagePlane data["transparency"] = self.transparency - data["displayLights"] = self.displayLights + data["displayLights"] = lib.DISPLAY_LIGHTS self.data = data diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index c6bbe44efc..d8e1184335 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -23,7 +23,6 @@ class ExtractPlayblast(publish.Extractor): families = ["review"] optional = True capture_preset = {} - displayLights = ["default", "all", "selected", "active", "none"] def process(self, instance): self.log.info("Extracting capture..") @@ -101,7 +100,7 @@ class ExtractPlayblast(publish.Extractor): # Show lighting mode. index = instance.data.get("displayLights", 0) - preset["viewport_options"]["displayLights"] = self.displayLights[index] + preset["viewport_options"]["displayLights"] = lib.DISPLAY_LIGHTS[index] # Override transparency if requested. transparency = instance.data.get("transparency", 0) From c921bc14c56ec3780981e6a432a26bc32fd84235 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 15 Dec 2022 08:57:22 +0000 Subject: [PATCH 004/106] Convert enum to string in collector --- openpype/hosts/maya/plugins/publish/collect_review.py | 5 +++++ openpype/hosts/maya/plugins/publish/extract_playblast.py | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_review.py b/openpype/hosts/maya/plugins/publish/collect_review.py index eb872c2935..995bd23687 100644 --- a/openpype/hosts/maya/plugins/publish/collect_review.py +++ b/openpype/hosts/maya/plugins/publish/collect_review.py @@ -5,6 +5,7 @@ import pyblish.api from openpype.client import get_subset_by_name from openpype.pipeline import legacy_io +from openpype.hosts.maya.api import lib class CollectReview(pyblish.api.InstancePlugin): @@ -139,3 +140,7 @@ class CollectReview(pyblish.api.InstancePlugin): "filename": node.filename.get() } ) + + # Convert enum attribute to string. + index = instance.data.get("displayLights", 0) + instance.data["displayLights"] = lib.DISPLAY_LIGHTS[index] diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index d8e1184335..08eb754c6d 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -99,8 +99,8 @@ class ExtractPlayblast(publish.Extractor): pm.currentTime(refreshFrameInt, edit=True) # Show lighting mode. - index = instance.data.get("displayLights", 0) - preset["viewport_options"]["displayLights"] = lib.DISPLAY_LIGHTS[index] + display_lights = instance.data["displayLights"] + preset["viewport_options"]["displayLights"] = display_lights # Override transparency if requested. transparency = instance.data.get("transparency", 0) From 9284e986d1f3d3131bb4b4cce1a2808cad141bb0 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 15 Dec 2022 08:57:36 +0000 Subject: [PATCH 005/106] Use display lights in thumbnail --- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 712159c2be..bb9cef2c5c 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -105,6 +105,10 @@ class ExtractThumbnail(publish.Extractor): pm.currentTime(refreshFrameInt - 1, edit=True) pm.currentTime(refreshFrameInt, edit=True) + # Show lighting mode. + display_lights = instance.data["displayLights"] + preset["viewport_options"]["displayLights"] = display_lights + # Isolate view is requested by having objects in the set besides a # camera. if preset.pop("isolate_view", False) and instance.data.get("isolate"): From 67b95c218b51e5c87132e5270d0a7c47760ed7e5 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Thu, 15 Dec 2022 13:13:48 +0000 Subject: [PATCH 006/106] Update openpype/hosts/maya/plugins/publish/collect_review.py Co-authored-by: Roy Nieterau --- openpype/hosts/maya/plugins/publish/collect_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_review.py b/openpype/hosts/maya/plugins/publish/collect_review.py index 995bd23687..d15eb7a12b 100644 --- a/openpype/hosts/maya/plugins/publish/collect_review.py +++ b/openpype/hosts/maya/plugins/publish/collect_review.py @@ -141,6 +141,6 @@ class CollectReview(pyblish.api.InstancePlugin): } ) - # Convert enum attribute to string. + # Convert enum attribute index to string. index = instance.data.get("displayLights", 0) instance.data["displayLights"] = lib.DISPLAY_LIGHTS[index] From ae496b9712bafc77a0d8350b92b0e84505eee512 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 9 Jan 2023 07:30:29 +0000 Subject: [PATCH 007/106] Use project settings by default. --- openpype/hosts/maya/api/lib.py | 4 +++- openpype/hosts/maya/plugins/publish/extract_playblast.py | 3 ++- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 4b8b6b1949..9aa2325e25 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -113,7 +113,9 @@ FLOAT_FPS = {23.98, 23.976, 29.97, 47.952, 59.94} RENDERLIKE_INSTANCE_FAMILIES = ["rendering", "vrayscene"] -DISPLAY_LIGHTS = ["default", "all", "selected", "active", "none"] +DISPLAY_LIGHTS = [ + "project_settings", "default", "all", "selected", "active", "none" +] def get_main_window(): diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index a1e6b2d503..7542785152 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -100,7 +100,8 @@ class ExtractPlayblast(publish.Extractor): # Show lighting mode. display_lights = instance.data["displayLights"] - preset["viewport_options"]["displayLights"] = display_lights + if display_lights != "project_settings": + preset["viewport_options"]["displayLights"] = display_lights # Override transparency if requested. transparency = instance.data.get("transparency", 0) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 80e94303a6..de6bc3895e 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -107,7 +107,8 @@ class ExtractThumbnail(publish.Extractor): # Show lighting mode. display_lights = instance.data["displayLights"] - preset["viewport_options"]["displayLights"] = display_lights + if display_lights != "project_settings": + preset["viewport_options"]["displayLights"] = display_lights # Override transparency if requested. transparency = instance.data.get("transparency", 0) From 3860fe36926aad704cf6d0ef66c89542e2acf922 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 23 Mar 2023 18:09:11 +0100 Subject: [PATCH 008/106] OP-3951 - updated validator to use special pattern Handles numbers (version, instance number) in file names. --- .../publish/validate_sequence_frames.py | 45 ++++++++++++++----- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/openpype/plugins/publish/validate_sequence_frames.py b/openpype/plugins/publish/validate_sequence_frames.py index f03229da22..c932c0e779 100644 --- a/openpype/plugins/publish/validate_sequence_frames.py +++ b/openpype/plugins/publish/validate_sequence_frames.py @@ -1,3 +1,8 @@ +import os.path + +import clique +import re + import pyblish.api @@ -7,6 +12,11 @@ class ValidateSequenceFrames(pyblish.api.InstancePlugin): The files found in the folder are checked against the startFrame and endFrame of the instance. If the first or last file is not corresponding with the first or last frame it is flagged as invalid. + + Used regular expression pattern handles numbers in the file names + (eg "Main_beauty.v001.1001.exr", "Main_beauty_v001.1001.exr", + "Main_beauty.1001.1001.exr") but not numbers behind frames (eg. + "Main_beauty.1001.v001.exr") """ order = pyblish.api.ValidatorOrder @@ -15,20 +25,31 @@ class ValidateSequenceFrames(pyblish.api.InstancePlugin): hosts = ["shell"] def process(self, instance): + representations = instance.data.get("representations") + for repr in representations: + if isinstance(repr["files"], str): + repr["files"] = [repr["files"]] - collection = instance[0] - self.log.info(collection) + _, ext = os.path.splitext(repr["files"][0]) + pattern = r"\D?(?P(?P0*)\d+){}$".format( + re.escape(ext)) + patterns = [pattern] - frames = list(collection.indexes) + collections, remainder = clique.assemble( + repr["files"], minimum_items=1, patterns=patterns) - current_range = (frames[0], frames[-1]) - required_range = (instance.data["frameStart"], - instance.data["frameEnd"]) + assert not remainder, "Must not have remainder" + assert len(collections) == 1, "Must detect single collection" + collection = collections[0] + frames = list(collection.indexes) - if current_range != required_range: - raise ValueError("Invalid frame range: {0} - " - "expected: {1}".format(current_range, - required_range)) + current_range = (frames[0], frames[-1]) + required_range = (instance.data["frameStart"], + instance.data["frameEnd"]) - missing = collection.holes().indexes - assert not missing, "Missing frames: %s" % (missing,) + if current_range != required_range: + raise ValueError(f"Invalid frame range: {current_range} - " + f"expected: {required_range}") + + missing = collection.holes().indexes + assert not missing, "Missing frames: %s" % (missing,) From e8f9c130bbb7b805f6ea68a3bbc37d81168d5893 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 23 Mar 2023 18:11:28 +0100 Subject: [PATCH 009/106] OP-3951 - merged global validator and unreal one Both should do same thing. Combination of host and family should be safe. --- .../publish/validate_sequence_frames.py | 41 ------------------- .../publish/validate_sequence_frames.py | 4 +- 2 files changed, 2 insertions(+), 43 deletions(-) delete mode 100644 openpype/hosts/unreal/plugins/publish/validate_sequence_frames.py diff --git a/openpype/hosts/unreal/plugins/publish/validate_sequence_frames.py b/openpype/hosts/unreal/plugins/publish/validate_sequence_frames.py deleted file mode 100644 index 87f1338ee8..0000000000 --- a/openpype/hosts/unreal/plugins/publish/validate_sequence_frames.py +++ /dev/null @@ -1,41 +0,0 @@ -import clique - -import pyblish.api - - -class ValidateSequenceFrames(pyblish.api.InstancePlugin): - """Ensure the sequence of frames is complete - - The files found in the folder are checked against the frameStart and - frameEnd of the instance. If the first or last file is not - corresponding with the first or last frame it is flagged as invalid. - """ - - order = pyblish.api.ValidatorOrder - label = "Validate Sequence Frames" - families = ["render"] - hosts = ["unreal"] - optional = True - - def process(self, instance): - representations = instance.data.get("representations") - for repr in representations: - patterns = [clique.PATTERNS["frames"]] - collections, remainder = clique.assemble( - repr["files"], minimum_items=1, patterns=patterns) - - assert not remainder, "Must not have remainder" - assert len(collections) == 1, "Must detect single collection" - collection = collections[0] - frames = list(collection.indexes) - - current_range = (frames[0], frames[-1]) - required_range = (instance.data["frameStart"], - instance.data["frameEnd"]) - - if current_range != required_range: - raise ValueError(f"Invalid frame range: {current_range} - " - f"expected: {required_range}") - - missing = collection.holes().indexes - assert not missing, "Missing frames: %s" % (missing,) diff --git a/openpype/plugins/publish/validate_sequence_frames.py b/openpype/plugins/publish/validate_sequence_frames.py index c932c0e779..56641fbf57 100644 --- a/openpype/plugins/publish/validate_sequence_frames.py +++ b/openpype/plugins/publish/validate_sequence_frames.py @@ -21,8 +21,8 @@ class ValidateSequenceFrames(pyblish.api.InstancePlugin): order = pyblish.api.ValidatorOrder label = "Validate Sequence Frames" - families = ["imagesequence"] - hosts = ["shell"] + families = ["imagesequence", "render"] + hosts = ["shell", "unreal"] def process(self, instance): representations = instance.data.get("representations") From 0648271ec784824fef1c7ffe373d0ae1034b9ec6 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 23 Mar 2023 18:15:11 +0100 Subject: [PATCH 010/106] OP-3951 - added tests for validate_sequence_frames Introduced conftest with dummy environment for basic tests --- tests/unit/openpype/conftest.py | 38 +++++ .../publish/test_validate_sequence_frames.py | 143 ++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 tests/unit/openpype/conftest.py create mode 100644 tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py diff --git a/tests/unit/openpype/conftest.py b/tests/unit/openpype/conftest.py new file mode 100644 index 0000000000..e5355a3120 --- /dev/null +++ b/tests/unit/openpype/conftest.py @@ -0,0 +1,38 @@ +"""Dummy environment that allows importing Openpype modules and run +tests in parent folder and all subfolders manually from IDE. + +This should not get triggered if the tests are running from `runtests` as it +is expected there that environment is handled by OP itself. + +This environment should be enough to run simple `BaseTest` where no +external preparation is necessary (eg. no prepared DB, no source files). +These tests might be enough to import and run simple pyblish plugins to +validate logic. + +Please be aware that these tests might use values in real databases, so use +`BaseTest` only for logic without side effects or special configuration. For +these there is `tests.lib.testing_classes.ModuleUnitTest` which would setup +proper test DB (but it requires `mongorestore` on the sys.path) + +If pyblish plugins require any host dependent communication, it would need + to be mocked. + +This setting of env vars is necessary to run before any imports of OP code! +(This is why it is in `conftest.py` file.) +If your test requires any additional env var, copy this file to folder of your +test, it should only that folder. +""" + +import os + + +if not os.environ.get("IS_TEST"): # running tests from cmd or CI + os.environ["AVALON_MONGO"] = "mongodb://localhost:27017" + os.environ["OPENPYPE_MONGO"] = "mongodb://localhost:27017" + os.environ["AVALON_DB"] = "avalon" + os.environ["OPENPYPE_DATABASE_NAME"] = "avalon" + os.environ["AVALON_TIMEOUT"] = '3000' + os.environ["OPENPYPE_DEBUG"] = "3" + os.environ["AVALON_CONFIG"] = "pype" + os.environ["AVALON_ASSET"] = "test_asset" + os.environ["AVALON_PROJECT"] = "test_project" diff --git a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py new file mode 100644 index 0000000000..5580621cfb --- /dev/null +++ b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py @@ -0,0 +1,143 @@ + + +"""Test Publish_plugins pipeline publish modul, tests API methods + + File: + creates temporary directory and downloads .zip file from GDrive + unzips .zip file + uses content of .zip file (MongoDB's dumps) to import to new databases + with use of 'monkeypatch_session' modifies required env vars + temporarily + runs battery of tests checking that site operation for Sync Server + module are working + removes temporary folder + removes temporary databases (?) +""" +import pytest +import logging + +from pyblish.api import Instance as PyblishInstance + +from tests.lib.testing_classes import BaseTest +from openpype.plugins.publish.validate_sequence_frames import ( + ValidateSequenceFrames +) + +log = logging.getLogger(__name__) + + +class TestValidateSequenceFrames(BaseTest): + """ Testing ValidateSequenceFrames plugin + + """ + + @pytest.fixture + def instance(self): + + class Instance(PyblishInstance): + data = { + "frameStart": 1001, + "frameEnd": 1001, + "representations": [] + } + yield Instance + + @pytest.fixture(scope="module") + def plugin(self): + plugin = ValidateSequenceFrames() + plugin.log = log + + yield plugin + + def test_validate_sequence_frames_single_frame(self, instance, plugin): + representations = [ + { + "ext": "exr", + "files": "Main_beauty.1001.exr", + } + ] + instance.data["representations"] = representations + + plugin.process(instance) + + @pytest.mark.parametrize("files", + ["Main_beauty.v001.1001.exr", + "Main_beauty_v001.1001.exr", + "Main_beauty.1001.1001.exr"]) + def test_validate_sequence_frames_single_frame_name(self, instance, + plugin, + files): + # tests for names with number inside, caused clique failure before + representations = [ + { + "ext": "exr", + "files": files, + } + ] + instance.data["representations"] = representations + + plugin.process(instance) + + @pytest.mark.parametrize("files", + ["Main_beauty.1001.v001.exr"]) + def test_validate_sequence_frames_single_frame_wrong_name(self, instance, + plugin, + files): + # tests for names with number inside, caused clique failure before + representations = [ + { + "ext": "exr", + "files": files, + } + ] + instance.data["representations"] = representations + + with pytest.raises(ValueError) as excinfo: + plugin.process(instance) + assert ("Invalid frame range: (1, 1) - expected: (1001, 1001)" in + str(excinfo.value)) + + def test_validate_sequence_frames_multi_frame(self, instance, plugin): + representations = [ + { + "ext": "exr", + "files": ["Main_beauty.1001.exr", "Main_beauty.1002.exr", + "Main_beauty.1003.exr"] + } + ] + instance.data["representations"] = representations + instance.data["frameEnd"] = 1003 + + plugin.process(instance) + + def test_validate_sequence_frames_multi_frame_missing(self, instance, + plugin): + representations = [ + { + "ext": "exr", + "files": ["Main_beauty.1001.exr", "Main_beauty.1002.exr"] + } + ] + instance.data["representations"] = representations + instance.data["frameEnd"] = 1003 + + with pytest.raises(ValueError) as excinfo: + plugin.process(instance) + assert ("Invalid frame range: (1001, 1002) - expected: (1001, 1003)" in + str(excinfo.value)) + + def test_validate_sequence_frames_multi_frame_hole(self, instance, plugin): + representations = [ + { + "ext": "exr", + "files": ["Main_beauty.1001.exr", "Main_beauty.1003.exr"] + } + ] + instance.data["representations"] = representations + instance.data["frameEnd"] = 1003 + + with pytest.raises(AssertionError) as excinfo: + plugin.process(instance) + assert ("Missing frames: [1002]" in str(excinfo.value)) + +test_case = TestValidateSequenceFrames() From 87fe237aa718d5e387b288bb7ad430d586712ec6 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Mar 2023 11:14:51 +0100 Subject: [PATCH 011/106] OP-3951 - fix - do not change files in place Integrator depends that single files is not in list. --- openpype/plugins/publish/validate_sequence_frames.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openpype/plugins/publish/validate_sequence_frames.py b/openpype/plugins/publish/validate_sequence_frames.py index 56641fbf57..98df259cc8 100644 --- a/openpype/plugins/publish/validate_sequence_frames.py +++ b/openpype/plugins/publish/validate_sequence_frames.py @@ -27,16 +27,17 @@ class ValidateSequenceFrames(pyblish.api.InstancePlugin): def process(self, instance): representations = instance.data.get("representations") for repr in representations: - if isinstance(repr["files"], str): - repr["files"] = [repr["files"]] + repr_files = repr["files"] + if isinstance(repr_files, str): + repr_files = [repr_files] - _, ext = os.path.splitext(repr["files"][0]) + _, ext = os.path.splitext(repr_files[0]) pattern = r"\D?(?P(?P0*)\d+){}$".format( re.escape(ext)) patterns = [pattern] collections, remainder = clique.assemble( - repr["files"], minimum_items=1, patterns=patterns) + repr_files, minimum_items=1, patterns=patterns) assert not remainder, "Must not have remainder" assert len(collections) == 1, "Must detect single collection" From f95007b660c9d573d9c41b4ec6169e022434daed Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Mar 2023 11:15:27 +0100 Subject: [PATCH 012/106] OP-3951 - Hound --- .../openpype/plugins/publish/test_validate_sequence_frames.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py index 5580621cfb..8e690f4f65 100644 --- a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py +++ b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py @@ -124,7 +124,7 @@ class TestValidateSequenceFrames(BaseTest): with pytest.raises(ValueError) as excinfo: plugin.process(instance) assert ("Invalid frame range: (1001, 1002) - expected: (1001, 1003)" in - str(excinfo.value)) + str(excinfo.value)) def test_validate_sequence_frames_multi_frame_hole(self, instance, plugin): representations = [ @@ -140,4 +140,5 @@ class TestValidateSequenceFrames(BaseTest): plugin.process(instance) assert ("Missing frames: [1002]" in str(excinfo.value)) + test_case = TestValidateSequenceFrames() From 30916962c8bc0f6fbfb557c286014efe62065bd2 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Mar 2023 12:34:23 +0100 Subject: [PATCH 013/106] OP-3951 - refactor Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/plugins/publish/validate_sequence_frames.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/plugins/publish/validate_sequence_frames.py b/openpype/plugins/publish/validate_sequence_frames.py index 98df259cc8..409d9ac17e 100644 --- a/openpype/plugins/publish/validate_sequence_frames.py +++ b/openpype/plugins/publish/validate_sequence_frames.py @@ -26,6 +26,8 @@ class ValidateSequenceFrames(pyblish.api.InstancePlugin): def process(self, instance): representations = instance.data.get("representations") + if not representations: + return for repr in representations: repr_files = repr["files"] if isinstance(repr_files, str): From bc50139ec8ef7d93636f7ccfc861bd98dbdc2ba0 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 24 Mar 2023 15:20:01 +0000 Subject: [PATCH 014/106] Only parent to world on extraction if nested. --- openpype/hosts/maya/plugins/publish/extract_xgen.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_xgen.py b/openpype/hosts/maya/plugins/publish/extract_xgen.py index 0cc842b4ec..fb097ca84a 100644 --- a/openpype/hosts/maya/plugins/publish/extract_xgen.py +++ b/openpype/hosts/maya/plugins/publish/extract_xgen.py @@ -65,9 +65,10 @@ class ExtractXgen(publish.Extractor): ) cmds.delete(set(children) - set(shapes)) - duplicate_transform = cmds.parent( - duplicate_transform, world=True - )[0] + if cmds.listRelatives(duplicate_transform, parent=True): + duplicate_transform = cmds.parent( + duplicate_transform, world=True + )[0] duplicate_nodes.append(duplicate_transform) From 399541602898ce342f3f8639a1969a144c9824c7 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 24 Mar 2023 15:27:33 +0000 Subject: [PATCH 015/106] Validation for required namespace. --- .../hosts/maya/plugins/publish/validate_xgen.py | 13 +++++++++++++ website/docs/artist_hosts_maya_xgen.md | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/openpype/hosts/maya/plugins/publish/validate_xgen.py b/openpype/hosts/maya/plugins/publish/validate_xgen.py index 2870909974..47b24e218c 100644 --- a/openpype/hosts/maya/plugins/publish/validate_xgen.py +++ b/openpype/hosts/maya/plugins/publish/validate_xgen.py @@ -57,3 +57,16 @@ class ValidateXgen(pyblish.api.InstancePlugin): json.dumps(inactive_modifiers, indent=4, sort_keys=True) ) ) + + # We need a namespace else there will be a naming conflict when + # extracting because of stripping namespaces and parenting to world. + node_names = [instance.data["xgmPalette"]] + for _, connections in instance.data["xgenConnections"].items(): + node_names.append(connections["transform"].split(".")[0]) + + non_namespaced_nodes = [n for n in node_names if ":" not in n] + if non_namespaced_nodes: + raise PublishValidationError( + "Could not find namespace on {}. Namespace is required for" + " xgen publishing.".format(non_namespaced_nodes) + ) diff --git a/website/docs/artist_hosts_maya_xgen.md b/website/docs/artist_hosts_maya_xgen.md index ec5f2ed921..db7bbd0557 100644 --- a/website/docs/artist_hosts_maya_xgen.md +++ b/website/docs/artist_hosts_maya_xgen.md @@ -43,6 +43,10 @@ Create an Xgen instance to publish. This needs to contain only **one Xgen collec You can create multiple Xgen instances if you have multiple collections to publish. +:::note +The Xgen publishing requires a namespace on the Xgen collection (palette) and the geometry used. +::: + ### Publish The publishing process will grab geometry used for Xgen along with any external files used in the collection's descriptions. This creates an isolated Maya file with just the Xgen collection's dependencies, so you can use any nested geometry when creating the Xgen description. An Xgen version will consist of: From 94ceba790edf1cb4c8d04f9ed67ab518f6722455 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Mar 2023 16:49:43 +0100 Subject: [PATCH 016/106] OP-3951 - updated tests --- .../publish/test_validate_sequence_frames.py | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py index 8e690f4f65..232557b76d 100644 --- a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py +++ b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py @@ -63,7 +63,8 @@ class TestValidateSequenceFrames(BaseTest): @pytest.mark.parametrize("files", ["Main_beauty.v001.1001.exr", "Main_beauty_v001.1001.exr", - "Main_beauty.1001.1001.exr"]) + "Main_beauty.1001.1001.exr", + "Main_beauty_v001_1001.exr"]) def test_validate_sequence_frames_single_frame_name(self, instance, plugin, files): @@ -97,6 +98,24 @@ class TestValidateSequenceFrames(BaseTest): assert ("Invalid frame range: (1, 1) - expected: (1001, 1001)" in str(excinfo.value)) + @pytest.mark.parametrize("files", + ["Main_beauty.1001.v001.ass.gz"]) + def test_validate_sequence_frames_single_frame_possible_wrong_name(self, + instance, plugin, files): + # currently pattern fails on extensions with dots + representations = [ + { + "ext": "exr", + "files": files, + } + ] + instance.data["representations"] = representations + + with pytest.raises(AssertionError) as excinfo: + plugin.process(instance) + assert ("Must not have remainder" in + str(excinfo.value)) + def test_validate_sequence_frames_multi_frame(self, instance, plugin): representations = [ { From 7dc59ece7b245e3bf47daf5bb7cbbd76cf49cf33 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Mar 2023 09:46:35 +0100 Subject: [PATCH 017/106] Define settings --- .../projects_schema/schema_project_maya.json | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json index 47dfb37024..80e2d43411 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json @@ -10,6 +10,41 @@ "key": "open_workfile_post_initialization", "label": "Open Workfile Post Initialization" }, + { + "type": "dict", + "key": "explicit_plugins_loading", + "label": "Explicit Plugins Loading", + "collapsible": true, + "is_group": true, + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "list", + "key": "plugins_to_load", + "label": "Plugins To Load", + "object_type": { + "type": "dict", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "text", + "key": "name", + "label": "Name" + } + ] + } + } + ] + }, { "key": "imageio", "type": "dict", From 5349579f748bc1522d0ade1ef24da3c07337ad7c Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Mar 2023 09:46:46 +0100 Subject: [PATCH 018/106] Define setting defaults --- .../defaults/project_settings/maya.json | 409 ++++++++++++++++++ 1 file changed, 409 insertions(+) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index 2aa95fd1be..cc3a76c599 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -1,5 +1,414 @@ { "open_workfile_post_initialization": false, + "explicit_plugins_loading": { + "enabled": false, + "plugins_to_load": [ + { + "enabled": false, + "name": "AbcBullet" + }, + { + "enabled": true, + "name": "AbcExport" + }, + { + "enabled": true, + "name": "AbcImport" + }, + { + "enabled": false, + "name": "animImportExport" + }, + { + "enabled": false, + "name": "ArubaTessellator" + }, + { + "enabled": false, + "name": "ATFPlugin" + }, + { + "enabled": false, + "name": "atomImportExport" + }, + { + "enabled": false, + "name": "AutodeskPacketFile" + }, + { + "enabled": false, + "name": "autoLoader" + }, + { + "enabled": false, + "name": "bifmeshio" + }, + { + "enabled": false, + "name": "bifrostGraph" + }, + { + "enabled": false, + "name": "bifrostshellnode" + }, + { + "enabled": false, + "name": "bifrostvisplugin" + }, + { + "enabled": false, + "name": "blast2Cmd" + }, + { + "enabled": false, + "name": "bluePencil" + }, + { + "enabled": false, + "name": "Boss" + }, + { + "enabled": false, + "name": "bullet" + }, + { + "enabled": true, + "name": "cacheEvaluator" + }, + { + "enabled": false, + "name": "cgfxShader" + }, + { + "enabled": false, + "name": "cleanPerFaceAssignment" + }, + { + "enabled": false, + "name": "clearcoat" + }, + { + "enabled": false, + "name": "convertToComponentTags" + }, + { + "enabled": false, + "name": "curveWarp" + }, + { + "enabled": false, + "name": "ddsFloatReader" + }, + { + "enabled": true, + "name": "deformerEvaluator" + }, + { + "enabled": false, + "name": "dgProfiler" + }, + { + "enabled": false, + "name": "drawUfe" + }, + { + "enabled": false, + "name": "dx11Shader" + }, + { + "enabled": false, + "name": "fbxmaya" + }, + { + "enabled": false, + "name": "fltTranslator" + }, + { + "enabled": false, + "name": "freeze" + }, + { + "enabled": false, + "name": "Fur" + }, + { + "enabled": false, + "name": "gameFbxExporter" + }, + { + "enabled": false, + "name": "gameInputDevice" + }, + { + "enabled": false, + "name": "GamePipeline" + }, + { + "enabled": false, + "name": "gameVertexCount" + }, + { + "enabled": false, + "name": "geometryReport" + }, + { + "enabled": false, + "name": "geometryTools" + }, + { + "enabled": false, + "name": "glslShader" + }, + { + "enabled": true, + "name": "GPUBuiltInDeformer" + }, + { + "enabled": false, + "name": "gpuCache" + }, + { + "enabled": false, + "name": "hairPhysicalShader" + }, + { + "enabled": false, + "name": "ik2Bsolver" + }, + { + "enabled": false, + "name": "ikSpringSolver" + }, + { + "enabled": false, + "name": "invertShape" + }, + { + "enabled": false, + "name": "lges" + }, + { + "enabled": false, + "name": "lookdevKit" + }, + { + "enabled": false, + "name": "MASH" + }, + { + "enabled": false, + "name": "matrixNodes" + }, + { + "enabled": false, + "name": "mayaCharacterization" + }, + { + "enabled": false, + "name": "mayaHIK" + }, + { + "enabled": false, + "name": "MayaMuscle" + }, + { + "enabled": false, + "name": "mayaUsdPlugin" + }, + { + "enabled": false, + "name": "mayaVnnPlugin" + }, + { + "enabled": false, + "name": "melProfiler" + }, + { + "enabled": false, + "name": "meshReorder" + }, + { + "enabled": false, + "name": "modelingToolkit" + }, + { + "enabled": false, + "name": "mtoa" + }, + { + "enabled": false, + "name": "mtoh" + }, + { + "enabled": false, + "name": "nearestPointOnMesh" + }, + { + "enabled": true, + "name": "objExport" + }, + { + "enabled": false, + "name": "OneClick" + }, + { + "enabled": false, + "name": "OpenEXRLoader" + }, + { + "enabled": false, + "name": "pgYetiMaya" + }, + { + "enabled": false, + "name": "pgyetiVrayMaya" + }, + { + "enabled": false, + "name": "polyBoolean" + }, + { + "enabled": false, + "name": "poseInterpolator" + }, + { + "enabled": false, + "name": "quatNodes" + }, + { + "enabled": false, + "name": "randomizerDevice" + }, + { + "enabled": false, + "name": "redshift4maya" + }, + { + "enabled": true, + "name": "renderSetup" + }, + { + "enabled": false, + "name": "retargeterNodes" + }, + { + "enabled": false, + "name": "RokokoMotionLibrary" + }, + { + "enabled": false, + "name": "rotateHelper" + }, + { + "enabled": false, + "name": "sceneAssembly" + }, + { + "enabled": false, + "name": "shaderFXPlugin" + }, + { + "enabled": false, + "name": "shotCamera" + }, + { + "enabled": false, + "name": "snapTransform" + }, + { + "enabled": false, + "name": "stage" + }, + { + "enabled": true, + "name": "stereoCamera" + }, + { + "enabled": false, + "name": "stlTranslator" + }, + { + "enabled": false, + "name": "studioImport" + }, + { + "enabled": false, + "name": "Substance" + }, + { + "enabled": false, + "name": "substancelink" + }, + { + "enabled": false, + "name": "substancemaya" + }, + { + "enabled": false, + "name": "substanceworkflow" + }, + { + "enabled": false, + "name": "svgFileTranslator" + }, + { + "enabled": false, + "name": "sweep" + }, + { + "enabled": false, + "name": "testify" + }, + { + "enabled": false, + "name": "tiffFloatReader" + }, + { + "enabled": false, + "name": "timeSliderBookmark" + }, + { + "enabled": false, + "name": "Turtle" + }, + { + "enabled": false, + "name": "Type" + }, + { + "enabled": false, + "name": "udpDevice" + }, + { + "enabled": false, + "name": "ufeSupport" + }, + { + "enabled": false, + "name": "Unfold3D" + }, + { + "enabled": false, + "name": "VectorRender" + }, + { + "enabled": false, + "name": "vrayformaya" + }, + { + "enabled": false, + "name": "vrayvolumegrid" + }, + { + "enabled": false, + "name": "xgenToolkit" + }, + { + "enabled": false, + "name": "xgenVray" + } + ] + }, "imageio": { "ocio_config": { "enabled": false, From f99c968df3dca4949e2e12a24ee908d5bf1ca997 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Mar 2023 09:48:13 +0100 Subject: [PATCH 019/106] Add launch arguments and env --- openpype/hooks/pre_add_last_workfile_arg.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/openpype/hooks/pre_add_last_workfile_arg.py b/openpype/hooks/pre_add_last_workfile_arg.py index 2558daef30..3d5f59cc67 100644 --- a/openpype/hooks/pre_add_last_workfile_arg.py +++ b/openpype/hooks/pre_add_last_workfile_arg.py @@ -44,10 +44,20 @@ class AddLastWorkfileToLaunchArgs(PreLaunchHook): # Determine whether to open workfile post initialization. if self.host_name == "maya": - key = "open_workfile_post_initialization" - if self.data["project_settings"]["maya"][key]: + maya_settings = self.data["project_settings"]["maya"] + + if maya_settings["explicit_plugins_loading"]["enabled"]: + self.log.debug("Explicit plugins loading.") + self.launch_context.launch_args.append("-noAutoloadPlugins") + + keys = [ + "open_workfile_post_initialization", "explicit_plugins_loading" + ] + values = [maya_settings[k] for k in keys] + if any(values): self.log.debug("Opening workfile post initialization.") - self.data["env"]["OPENPYPE_" + key.upper()] = "1" + key = "OPENPYPE_OPEN_WORKFILE_POST_INITIALIZATION" + self.data["env"][key] = "1" return # Add path to workfile to arguments From ae4468bd209144fa406ba17b15a5c4d54c147516 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Mar 2023 09:48:25 +0100 Subject: [PATCH 020/106] Load plugins explicitly --- openpype/hosts/maya/startup/userSetup.py | 34 +++++++++++++++++------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/maya/startup/userSetup.py b/openpype/hosts/maya/startup/userSetup.py index c77ecb829e..4932bf14c0 100644 --- a/openpype/hosts/maya/startup/userSetup.py +++ b/openpype/hosts/maya/startup/userSetup.py @@ -1,5 +1,4 @@ import os -from functools import partial from openpype.settings import get_project_settings from openpype.pipeline import install_host @@ -13,23 +12,40 @@ install_host(host) print("Starting OpenPype usersetup...") +settings = get_project_settings(os.environ['AVALON_PROJECT']) + +# Loading plugins explicitly. +if settings["maya"]["explicit_plugins_loading"]["enabled"]: + def _explicit_load_plugins(): + project_settings = get_project_settings(os.environ["AVALON_PROJECT"]) + maya_settings = project_settings["maya"] + explicit_plugins_loading = maya_settings["explicit_plugins_loading"] + if explicit_plugins_loading["enabled"]: + for plugin in explicit_plugins_loading["plugins_to_load"]: + if plugin["enabled"]: + print("Loading " + plugin["name"]) + try: + cmds.loadPlugin(plugin["name"], quiet=True) + except RuntimeError as e: + print(e) + + cmds.evalDeferred( + _explicit_load_plugins, + lowestPriority=True + ) # Open Workfile Post Initialization. key = "OPENPYPE_OPEN_WORKFILE_POST_INITIALIZATION" if bool(int(os.environ.get(key, "0"))): + def _log_and_open(): + print("Opening \"{}\"".format(os.environ["AVALON_LAST_WORKFILE"])) + cmds.file(os.environ["AVALON_LAST_WORKFILE"], open=True, force=True) cmds.evalDeferred( - partial( - cmds.file, - os.environ["AVALON_LAST_WORKFILE"], - open=True, - force=True - ), + _log_and_open, lowestPriority=True ) - # Build a shelf. -settings = get_project_settings(os.environ['AVALON_PROJECT']) shelf_preset = settings['maya'].get('project_shelf') if shelf_preset: From 53361fe9dfae15bd4a1f318561dd4ea8393ce353 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Mar 2023 09:53:41 +0100 Subject: [PATCH 021/106] Modeling Toolkit is default loaded. --- openpype/settings/defaults/project_settings/maya.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index cc3a76c599..9b71b97d75 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -228,7 +228,7 @@ "name": "meshReorder" }, { - "enabled": false, + "enabled": true, "name": "modelingToolkit" }, { From 4bfb4aa75779cdd75d380cb0a976b5cb1757cbbd Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Mar 2023 10:03:53 +0100 Subject: [PATCH 022/106] Docs --- website/docs/admin_hosts_maya.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/website/docs/admin_hosts_maya.md b/website/docs/admin_hosts_maya.md index 23cacb4193..edbfa8da36 100644 --- a/website/docs/admin_hosts_maya.md +++ b/website/docs/admin_hosts_maya.md @@ -172,3 +172,12 @@ Fill in the necessary fields (the optional fields are regex filters) - Build your workfile ![maya build template](assets/maya-build_workfile_from_template.png) + +## Explicit Plugins Loading +You can define which plugins to load on launch of Maya here; `project_settings/maya/explicit_plugins_loading`. This can help improve Maya's launch speed, if you know which plugins are needed. + +By default only the required plugins are enabled. You can also add any plugin to the list to enable on launch. + +:::note technical +When enabling this feature, the workfile will be launched post initialization no matter the setting on `project_settings/maya/open_workfile_post_initialization`. This is to avoid any issues with references needing plugins. +::: From 93d98c3f9c48da9477cd6ac7ffda186b57a202b8 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 27 Mar 2023 16:55:19 +0200 Subject: [PATCH 023/106] OP-3951 - use ext on representation Without it ass.gz files won't work --- .../publish/validate_sequence_frames.py | 6 ++++- .../publish/test_validate_sequence_frames.py | 22 +++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/openpype/plugins/publish/validate_sequence_frames.py b/openpype/plugins/publish/validate_sequence_frames.py index 409d9ac17e..a804a6d9dd 100644 --- a/openpype/plugins/publish/validate_sequence_frames.py +++ b/openpype/plugins/publish/validate_sequence_frames.py @@ -33,7 +33,11 @@ class ValidateSequenceFrames(pyblish.api.InstancePlugin): if isinstance(repr_files, str): repr_files = [repr_files] - _, ext = os.path.splitext(repr_files[0]) + ext = repr.get("ext") + if not ext: + _, ext = os.path.splitext(repr_files[0]) + elif not ext.startswith("."): + ext = ".{}".format(ext) pattern = r"\D?(?P(?P0*)\d+){}$".format( re.escape(ext)) patterns = [pattern] diff --git a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py index 232557b76d..e1facdc37b 100644 --- a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py +++ b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py @@ -99,13 +99,12 @@ class TestValidateSequenceFrames(BaseTest): str(excinfo.value)) @pytest.mark.parametrize("files", - ["Main_beauty.1001.v001.ass.gz"]) - def test_validate_sequence_frames_single_frame_possible_wrong_name(self, - instance, plugin, files): + ["Main_beauty.v001.1001.ass.gz"]) + def test_validate_sequence_frames_single_frame_possible_wrong_name( + self, instance, plugin, files): # currently pattern fails on extensions with dots representations = [ { - "ext": "exr", "files": files, } ] @@ -116,6 +115,21 @@ class TestValidateSequenceFrames(BaseTest): assert ("Must not have remainder" in str(excinfo.value)) + @pytest.mark.parametrize("files", + ["Main_beauty.v001.1001.ass.gz"]) + def test_validate_sequence_frames_single_frame_correct_ext( + self, instance, plugin, files): + # currently pattern fails on extensions with dots + representations = [ + { + "ext": "ass.gz", + "files": files, + } + ] + instance.data["representations"] = representations + + plugin.process(instance) + def test_validate_sequence_frames_multi_frame(self, instance, plugin): representations = [ { From 6d2a45e9516ef55b84a181d0b30a8abe5405afbd Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Mar 2023 16:42:35 +0100 Subject: [PATCH 024/106] Move -noAutoLoadPlugins flag to separate hook. --- openpype/hooks/pre_add_last_workfile_arg.py | 7 +------ .../hosts/maya/hooks/pre_auto_load_plugins.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 openpype/hosts/maya/hooks/pre_auto_load_plugins.py diff --git a/openpype/hooks/pre_add_last_workfile_arg.py b/openpype/hooks/pre_add_last_workfile_arg.py index 3d5f59cc67..df4aa5cc5d 100644 --- a/openpype/hooks/pre_add_last_workfile_arg.py +++ b/openpype/hooks/pre_add_last_workfile_arg.py @@ -44,15 +44,10 @@ class AddLastWorkfileToLaunchArgs(PreLaunchHook): # Determine whether to open workfile post initialization. if self.host_name == "maya": - maya_settings = self.data["project_settings"]["maya"] - - if maya_settings["explicit_plugins_loading"]["enabled"]: - self.log.debug("Explicit plugins loading.") - self.launch_context.launch_args.append("-noAutoloadPlugins") - keys = [ "open_workfile_post_initialization", "explicit_plugins_loading" ] + maya_settings = self.data["project_settings"]["maya"] values = [maya_settings[k] for k in keys] if any(values): self.log.debug("Opening workfile post initialization.") diff --git a/openpype/hosts/maya/hooks/pre_auto_load_plugins.py b/openpype/hosts/maya/hooks/pre_auto_load_plugins.py new file mode 100644 index 0000000000..3c3ddbe4dc --- /dev/null +++ b/openpype/hosts/maya/hooks/pre_auto_load_plugins.py @@ -0,0 +1,15 @@ +from openpype.lib import PreLaunchHook + + +class PreAutoLoadPlugins(PreLaunchHook): + """Define -noAutoloadPlugins command flag.""" + + # Execute before workfile argument. + order = 0 + app_groups = ["maya"] + + def execute(self): + maya_settings = self.data["project_settings"]["maya"] + if maya_settings["explicit_plugins_loading"]["enabled"]: + self.log.debug("Explicit plugins loading.") + self.launch_context.launch_args.append("-noAutoloadPlugins") From 72af67fc657fd7e52eca302d86f887c9af041212 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Mar 2023 16:42:45 +0100 Subject: [PATCH 025/106] Warn about render farm support. --- website/docs/admin_hosts_maya.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/admin_hosts_maya.md b/website/docs/admin_hosts_maya.md index edbfa8da36..5211760632 100644 --- a/website/docs/admin_hosts_maya.md +++ b/website/docs/admin_hosts_maya.md @@ -180,4 +180,6 @@ By default only the required plugins are enabled. You can also add any plugin to :::note technical When enabling this feature, the workfile will be launched post initialization no matter the setting on `project_settings/maya/open_workfile_post_initialization`. This is to avoid any issues with references needing plugins. + +Renderfarm integration is not supported for this feature. ::: From c5172b74101dda2be4a797c0bc61056dfa134569 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 29 Mar 2023 13:17:24 +0200 Subject: [PATCH 026/106] OP-3951 - update imports Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/plugins/publish/validate_sequence_frames.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openpype/plugins/publish/validate_sequence_frames.py b/openpype/plugins/publish/validate_sequence_frames.py index a804a6d9dd..db71f2e23c 100644 --- a/openpype/plugins/publish/validate_sequence_frames.py +++ b/openpype/plugins/publish/validate_sequence_frames.py @@ -1,8 +1,7 @@ -import os.path - -import clique +import os import re +import clique import pyblish.api From 36328f8b1abbb03051795646bec8ceed5d78a874 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 29 Mar 2023 13:18:07 +0200 Subject: [PATCH 027/106] OP-3951 - removed unnecessary key Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- tests/unit/openpype/conftest.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/openpype/conftest.py b/tests/unit/openpype/conftest.py index e5355a3120..220ec3ba86 100644 --- a/tests/unit/openpype/conftest.py +++ b/tests/unit/openpype/conftest.py @@ -33,6 +33,5 @@ if not os.environ.get("IS_TEST"): # running tests from cmd or CI os.environ["OPENPYPE_DATABASE_NAME"] = "avalon" os.environ["AVALON_TIMEOUT"] = '3000' os.environ["OPENPYPE_DEBUG"] = "3" - os.environ["AVALON_CONFIG"] = "pype" os.environ["AVALON_ASSET"] = "test_asset" os.environ["AVALON_PROJECT"] = "test_project" From e2546e5547b10d085ff6b57375355361e8bda5f7 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 29 Mar 2023 13:18:37 +0200 Subject: [PATCH 028/106] OP-3951 - removed unnecessary key Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- tests/unit/openpype/conftest.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/openpype/conftest.py b/tests/unit/openpype/conftest.py index 220ec3ba86..0bc3f0dcfe 100644 --- a/tests/unit/openpype/conftest.py +++ b/tests/unit/openpype/conftest.py @@ -27,7 +27,6 @@ import os if not os.environ.get("IS_TEST"): # running tests from cmd or CI - os.environ["AVALON_MONGO"] = "mongodb://localhost:27017" os.environ["OPENPYPE_MONGO"] = "mongodb://localhost:27017" os.environ["AVALON_DB"] = "avalon" os.environ["OPENPYPE_DATABASE_NAME"] = "avalon" From 0a642d475cda961e033f2b4aa58e5dd09e7ec781 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 29 Mar 2023 13:19:02 +0200 Subject: [PATCH 029/106] OP-3951 - changed debug value Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- tests/unit/openpype/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/openpype/conftest.py b/tests/unit/openpype/conftest.py index 0bc3f0dcfe..9b5be54a0d 100644 --- a/tests/unit/openpype/conftest.py +++ b/tests/unit/openpype/conftest.py @@ -31,6 +31,6 @@ if not os.environ.get("IS_TEST"): # running tests from cmd or CI os.environ["AVALON_DB"] = "avalon" os.environ["OPENPYPE_DATABASE_NAME"] = "avalon" os.environ["AVALON_TIMEOUT"] = '3000' - os.environ["OPENPYPE_DEBUG"] = "3" + os.environ["OPENPYPE_DEBUG"] = "1" os.environ["AVALON_ASSET"] = "test_asset" os.environ["AVALON_PROJECT"] = "test_project" From 53d395e7087c2b4bd65c33706be25b3fb2dafb4d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 29 Mar 2023 13:19:21 +0200 Subject: [PATCH 030/106] OP-3951 - updated value Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- tests/unit/openpype/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/openpype/conftest.py b/tests/unit/openpype/conftest.py index 9b5be54a0d..0aec25becb 100644 --- a/tests/unit/openpype/conftest.py +++ b/tests/unit/openpype/conftest.py @@ -29,7 +29,7 @@ import os if not os.environ.get("IS_TEST"): # running tests from cmd or CI os.environ["OPENPYPE_MONGO"] = "mongodb://localhost:27017" os.environ["AVALON_DB"] = "avalon" - os.environ["OPENPYPE_DATABASE_NAME"] = "avalon" + os.environ["OPENPYPE_DATABASE_NAME"] = "openpype" os.environ["AVALON_TIMEOUT"] = '3000' os.environ["OPENPYPE_DEBUG"] = "1" os.environ["AVALON_ASSET"] = "test_asset" From 97d5b187e81601864d70a84ec54f13baf885a509 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 30 Mar 2023 13:42:30 +0200 Subject: [PATCH 031/106] OP-3951 - updated logic Doesn't make sense to validate sequence for single frame. Updated tests accordingly. No sense in testing single frames so widely. --- .../publish/validate_sequence_frames.py | 2 +- .../publish/test_validate_sequence_frames.py | 36 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/openpype/plugins/publish/validate_sequence_frames.py b/openpype/plugins/publish/validate_sequence_frames.py index a804a6d9dd..6c14d0cbbf 100644 --- a/openpype/plugins/publish/validate_sequence_frames.py +++ b/openpype/plugins/publish/validate_sequence_frames.py @@ -31,7 +31,7 @@ class ValidateSequenceFrames(pyblish.api.InstancePlugin): for repr in representations: repr_files = repr["files"] if isinstance(repr_files, str): - repr_files = [repr_files] + continue ext = repr.get("ext") if not ext: diff --git a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py index e1facdc37b..f9d1e59096 100644 --- a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py +++ b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py @@ -37,7 +37,7 @@ class TestValidateSequenceFrames(BaseTest): class Instance(PyblishInstance): data = { "frameStart": 1001, - "frameEnd": 1001, + "frameEnd": 1002, "representations": [] } yield Instance @@ -57,17 +57,18 @@ class TestValidateSequenceFrames(BaseTest): } ] instance.data["representations"] = representations + instance.data["frameEnd"] = 1001 plugin.process(instance) @pytest.mark.parametrize("files", - ["Main_beauty.v001.1001.exr", - "Main_beauty_v001.1001.exr", - "Main_beauty.1001.1001.exr", - "Main_beauty_v001_1001.exr"]) - def test_validate_sequence_frames_single_frame_name(self, instance, - plugin, - files): + [ + ["Main_beauty.v001.1001.exr", "Main_beauty.v001.1002.exr"], + ["Main_beauty_v001.1001.exr", "Main_beauty_v001.1002.exr"], + ["Main_beauty.1001.1001.exr", "Main_beauty.1001.1002.exr"], + ["Main_beauty_v001_1001.exr", "Main_beauty_v001_1002.exr"]]) + def test_validate_sequence_frames_name(self, instance, + plugin, files): # tests for names with number inside, caused clique failure before representations = [ { @@ -80,10 +81,9 @@ class TestValidateSequenceFrames(BaseTest): plugin.process(instance) @pytest.mark.parametrize("files", - ["Main_beauty.1001.v001.exr"]) - def test_validate_sequence_frames_single_frame_wrong_name(self, instance, - plugin, - files): + [["Main_beauty.1001.v001.exr", "Main_beauty.1002.v001.exr"]]) + def test_validate_sequence_frames_wrong_name(self, instance, + plugin, files): # tests for names with number inside, caused clique failure before representations = [ { @@ -93,14 +93,14 @@ class TestValidateSequenceFrames(BaseTest): ] instance.data["representations"] = representations - with pytest.raises(ValueError) as excinfo: + with pytest.raises(AssertionError) as excinfo: plugin.process(instance) - assert ("Invalid frame range: (1, 1) - expected: (1001, 1001)" in + assert ("Must detect single collection" in str(excinfo.value)) @pytest.mark.parametrize("files", - ["Main_beauty.v001.1001.ass.gz"]) - def test_validate_sequence_frames_single_frame_possible_wrong_name( + [["Main_beauty.v001.1001.ass.gz", "Main_beauty.v001.1002.ass.gz"]]) + def test_validate_sequence_frames_possible_wrong_name( self, instance, plugin, files): # currently pattern fails on extensions with dots representations = [ @@ -116,8 +116,8 @@ class TestValidateSequenceFrames(BaseTest): str(excinfo.value)) @pytest.mark.parametrize("files", - ["Main_beauty.v001.1001.ass.gz"]) - def test_validate_sequence_frames_single_frame_correct_ext( + [["Main_beauty.v001.1001.ass.gz", "Main_beauty.v001.1002.ass.gz"]]) + def test_validate_sequence_frames__correct_ext( self, instance, plugin, files): # currently pattern fails on extensions with dots representations = [ From 80c50af2b903737c3d4635063423876cc3b9d210 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 30 Mar 2023 13:45:37 +0200 Subject: [PATCH 032/106] OP-3951 - Hound --- .../publish/test_validate_sequence_frames.py | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py index f9d1e59096..58d9de011d 100644 --- a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py +++ b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py @@ -63,10 +63,14 @@ class TestValidateSequenceFrames(BaseTest): @pytest.mark.parametrize("files", [ - ["Main_beauty.v001.1001.exr", "Main_beauty.v001.1002.exr"], - ["Main_beauty_v001.1001.exr", "Main_beauty_v001.1002.exr"], - ["Main_beauty.1001.1001.exr", "Main_beauty.1001.1002.exr"], - ["Main_beauty_v001_1001.exr", "Main_beauty_v001_1002.exr"]]) + ["Main_beauty.v001.1001.exr", + "Main_beauty.v001.1002.exr"], + ["Main_beauty_v001.1001.exr", + "Main_beauty_v001.1002.exr"], + ["Main_beauty.1001.1001.exr", + "Main_beauty.1001.1002.exr"], + ["Main_beauty_v001_1001.exr", + "Main_beauty_v001_1002.exr"]]) def test_validate_sequence_frames_name(self, instance, plugin, files): # tests for names with number inside, caused clique failure before @@ -81,7 +85,8 @@ class TestValidateSequenceFrames(BaseTest): plugin.process(instance) @pytest.mark.parametrize("files", - [["Main_beauty.1001.v001.exr", "Main_beauty.1002.v001.exr"]]) + [["Main_beauty.1001.v001.exr", + "Main_beauty.1002.v001.exr"]]) def test_validate_sequence_frames_wrong_name(self, instance, plugin, files): # tests for names with number inside, caused clique failure before @@ -99,7 +104,8 @@ class TestValidateSequenceFrames(BaseTest): str(excinfo.value)) @pytest.mark.parametrize("files", - [["Main_beauty.v001.1001.ass.gz", "Main_beauty.v001.1002.ass.gz"]]) + [["Main_beauty.v001.1001.ass.gz", + "Main_beauty.v001.1002.ass.gz"]]) def test_validate_sequence_frames_possible_wrong_name( self, instance, plugin, files): # currently pattern fails on extensions with dots @@ -116,7 +122,8 @@ class TestValidateSequenceFrames(BaseTest): str(excinfo.value)) @pytest.mark.parametrize("files", - [["Main_beauty.v001.1001.ass.gz", "Main_beauty.v001.1002.ass.gz"]]) + [["Main_beauty.v001.1001.ass.gz", + "Main_beauty.v001.1002.ass.gz"]]) def test_validate_sequence_frames__correct_ext( self, instance, plugin, files): # currently pattern fails on extensions with dots From 32743b7a855e1a9df980f923f35da0620adbb237 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 30 Mar 2023 12:48:00 +0100 Subject: [PATCH 033/106] Setup settings. --- .../defaults/project_settings/maya.json | 245 ++-- .../schemas/schema_maya_capture.json | 1258 +++++++++-------- 2 files changed, 770 insertions(+), 733 deletions(-) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index e914eb29f9..4044bdf5df 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -788,126 +788,133 @@ "validate_shapes": true }, "ExtractPlayblast": { - "capture_preset": { - "Codec": { - "compression": "png", - "format": "image", - "quality": 95 - }, - "Display Options": { - "background": [ - 125, - 125, - 125, - 255 - ], - "backgroundBottom": [ - 125, - 125, - 125, - 255 - ], - "backgroundTop": [ - 125, - 125, - 125, - 255 - ], - "override_display": true - }, - "Generic": { - "isolate_view": true, - "off_screen": true, - "pan_zoom": false - }, - "Renderer": { - "rendererName": "vp2Renderer" - }, - "Resolution": { - "width": 1920, - "height": 1080 - }, - "Viewport Options": { - "override_viewport_options": true, - "displayLights": "default", - "displayTextures": true, - "textureMaxResolution": 1024, - "renderDepthOfField": true, - "shadows": true, - "twoSidedLighting": true, - "lineAAEnable": true, - "multiSample": 8, - "useDefaultMaterial": false, - "wireframeOnShaded": false, - "xray": false, - "jointXray": false, - "backfaceCulling": false, - "ssaoEnable": false, - "ssaoAmount": 1, - "ssaoRadius": 16, - "ssaoFilterRadius": 16, - "ssaoSamples": 16, - "fogging": false, - "hwFogFalloff": "0", - "hwFogDensity": 0.0, - "hwFogStart": 0, - "hwFogEnd": 100, - "hwFogAlpha": 0, - "hwFogColorR": 1.0, - "hwFogColorG": 1.0, - "hwFogColorB": 1.0, - "motionBlurEnable": false, - "motionBlurSampleCount": 8, - "motionBlurShutterOpenFraction": 0.2, - "cameras": false, - "clipGhosts": false, - "deformers": false, - "dimensions": false, - "dynamicConstraints": false, - "dynamics": false, - "fluids": false, - "follicles": false, - "gpuCacheDisplayFilter": false, - "greasePencils": false, - "grid": false, - "hairSystems": true, - "handles": false, - "headsUpDisplay": false, - "ikHandles": false, - "imagePlane": true, - "joints": false, - "lights": false, - "locators": false, - "manipulators": false, - "motionTrails": false, - "nCloths": false, - "nParticles": false, - "nRigids": false, - "controlVertices": false, - "nurbsCurves": false, - "hulls": false, - "nurbsSurfaces": false, - "particleInstancers": false, - "pivots": false, - "planes": false, - "pluginShapes": false, - "polymeshes": true, - "strokes": false, - "subdivSurfaces": false, - "textures": false - }, - "Camera Options": { - "displayGateMask": false, - "displayResolution": false, - "displayFilmGate": false, - "displayFieldChart": false, - "displaySafeAction": false, - "displaySafeTitle": false, - "displayFilmPivot": false, - "displayFilmOrigin": false, - "overscan": 1.0 + "profiles": [ + { + "task_types": [], + "task_names": [], + "subsets": [], + "capture_preset": { + "Codec": { + "compression": "png", + "format": "image", + "quality": 95 + }, + "Display Options": { + "background": [ + 125, + 125, + 125, + 255 + ], + "backgroundBottom": [ + 125, + 125, + 125, + 255 + ], + "backgroundTop": [ + 125, + 125, + 125, + 255 + ], + "override_display": true + }, + "Generic": { + "isolate_view": true, + "off_screen": true, + "pan_zoom": false + }, + "Renderer": { + "rendererName": "vp2Renderer" + }, + "Resolution": { + "width": 1920, + "height": 1080 + }, + "Viewport Options": { + "override_viewport_options": true, + "displayLights": "default", + "displayTextures": true, + "textureMaxResolution": 1024, + "renderDepthOfField": true, + "shadows": true, + "twoSidedLighting": true, + "lineAAEnable": true, + "multiSample": 8, + "useDefaultMaterial": false, + "wireframeOnShaded": false, + "xray": false, + "jointXray": false, + "backfaceCulling": false, + "ssaoEnable": false, + "ssaoAmount": 1, + "ssaoRadius": 16, + "ssaoFilterRadius": 16, + "ssaoSamples": 16, + "fogging": false, + "hwFogFalloff": "0", + "hwFogDensity": 0.0, + "hwFogStart": 0, + "hwFogEnd": 100, + "hwFogAlpha": 0, + "hwFogColorR": 1.0, + "hwFogColorG": 1.0, + "hwFogColorB": 1.0, + "motionBlurEnable": false, + "motionBlurSampleCount": 0, + "motionBlurShutterOpenFraction": 0.2, + "cameras": false, + "clipGhosts": false, + "deformers": false, + "dimensions": false, + "dynamicConstraints": false, + "dynamics": false, + "fluids": false, + "follicles": false, + "gpuCacheDisplayFilter": false, + "greasePencils": false, + "grid": false, + "hairSystems": true, + "handles": false, + "headsUpDisplay": false, + "ikHandles": false, + "imagePlane": true, + "joints": false, + "lights": false, + "locators": false, + "manipulators": false, + "motionTrails": false, + "nCloths": false, + "nParticles": false, + "nRigids": false, + "controlVertices": false, + "nurbsCurves": false, + "hulls": false, + "nurbsSurfaces": false, + "particleInstancers": false, + "pivots": false, + "planes": false, + "pluginShapes": false, + "polymeshes": false, + "strokes": false, + "subdivSurfaces": false, + "textures": false + }, + "Camera Options": { + "displayGateMask": false, + "displayResolution": false, + "displayFilmGate": false, + "displayFieldChart": false, + "displaySafeAction": false, + "displaySafeTitle": false, + "displayFilmPivot": false, + "displayFilmOrigin": false, + "overscan": 1.0 + } + } } - } + ] }, "ExtractMayaSceneRaw": { "enabled": true, 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 416e530db2..1d0f94e5b8 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 @@ -5,622 +5,652 @@ "label": "Extract Playblast settings", "children": [ { - "type": "dict", - "key": "capture_preset", - "children": [ - { - "type": "dict", - "key": "Codec", - "children": [ - { - "type": "label", - "label": "Codec" - }, - { - "type": "text", - "key": "compression", - "label": "Encoding" - }, - { - "type": "text", - "key": "format", - "label": "Format" - }, - { - "type": "number", - "key": "quality", - "label": "Quality", - "decimal": 0, - "minimum": 0, - "maximum": 100 - }, + "type": "list", + "key": "profiles", + "label": "Profiles", + "object_type": { + "type": "dict", + "children": [ + { + "key": "task_types", + "label": "Task types", + "type": "task-types-enum" + }, + { + "key": "task_names", + "label": "Task names", + "type": "list", + "object_type": "text" + }, + { + "key": "subsets", + "label": "Subset names", + "type": "list", + "object_type": "text" + }, + { + "type": "splitter" + }, + { + "type": "dict", + "key": "capture_preset", + "children": [ + { + "type": "dict", + "key": "Codec", + "children": [ + { + "type": "label", + "label": "Codec" + }, + { + "type": "text", + "key": "compression", + "label": "Encoding" + }, + { + "type": "text", + "key": "format", + "label": "Format" + }, + { + "type": "number", + "key": "quality", + "label": "Quality", + "decimal": 0, + "minimum": 0, + "maximum": 100 + }, - { - "type": "splitter" - } - ] - }, - { - "type": "dict", - "key": "Display Options", - "children": [ - { - "type": "label", - "label": "Display Options" - }, + { + "type": "splitter" + } + ] + }, + { + "type": "dict", + "key": "Display Options", + "children": [ + { + "type": "label", + "label": "Display Options" + }, - { - "type": "color", - "key": "background", - "label": "Background Color: " - }, - { - "type": "color", - "key": "backgroundBottom", - "label": "Background Bottom: " - }, - { - "type": "color", - "key": "backgroundTop", - "label": "Background Top: " - }, - { - "type": "boolean", - "key": "override_display", - "label": "Override display options" - } - ] - }, - { - "type": "splitter" - }, - { - "type": "dict", - "key": "Generic", - "children": [ - { - "type": "label", - "label": "Generic" - }, - { - "type": "boolean", - "key": "isolate_view", - "label": " Isolate view" - }, - { - "type": "boolean", - "key": "off_screen", - "label": " Off Screen" - }, - { - "type": "boolean", - "key": "pan_zoom", - "label": " 2D Pan/Zoom" - } - ] - }, - { - "type": "splitter" - }, - { - "type": "dict", - "key": "Renderer", - "children": [ - { - "type": "label", - "label": "Renderer" - }, - { - "type": "enum", - "key": "rendererName", - "label": "Renderer name", - "enum_items": [ - { "vp2Renderer": "Viewport 2.0" } - ] - } - ] - }, - { - "type": "dict", - "key": "Resolution", - "children": [ - { - "type": "splitter" - }, - { - "type": "label", - "label": "Resolution" - }, - { - "type": "number", - "key": "width", - "label": " Width", - "decimal": 0, - "minimum": 0, - "maximum": 99999 - }, - { - "type": "number", - "key": "height", - "label": "Height", - "decimal": 0, - "minimum": 0, - "maximum": 99999 - } - ] - }, - { - "type": "splitter" - }, - { - "type": "dict", - "collapsible": true, - "key": "Viewport Options", - "label": "Viewport Options", - "children": [ - { - "type": "boolean", - "key": "override_viewport_options", - "label": "Override Viewport Options" - }, - { - "type": "enum", - "key": "displayLights", - "label": "Display Lights", - "enum_items": [ - { "default": "Default Lighting"}, - { "all": "All Lights"}, - { "selected": "Selected Lights"}, - { "flat": "Flat Lighting"}, - { "nolights": "No Lights"} - ] - }, - { - "type": "boolean", - "key": "displayTextures", - "label": "Display Textures" - }, - { - "type": "number", - "key": "textureMaxResolution", - "label": "Texture Clamp Resolution", - "decimal": 0 - }, - { - "type": "splitter" - }, - { - "type": "label", - "label": "Display" - }, - { - "type":"boolean", - "key": "renderDepthOfField", - "label": "Depth of Field" - }, - { - "type": "splitter" - }, - { - "type": "boolean", - "key": "shadows", - "label": "Display Shadows" - }, - { - "type": "boolean", - "key": "twoSidedLighting", - "label": "Two Sided Lighting" - }, - { - "type": "splitter" - }, - { - "type": "boolean", - "key": "lineAAEnable", - "label": "Enable Anti-Aliasing" - }, - { - "type": "number", - "key": "multiSample", - "label": "Anti Aliasing Samples", - "decimal": 0, - "minimum": 0, - "maximum": 32 - }, - { - "type": "splitter" - }, - { - "type": "boolean", - "key": "useDefaultMaterial", - "label": "Use Default Material" - }, - { - "type": "boolean", - "key": "wireframeOnShaded", - "label": "Wireframe On Shaded" - }, - { - "type": "boolean", - "key": "xray", - "label": "X-Ray" - }, - { - "type": "boolean", - "key": "jointXray", - "label": "X-Ray Joints" - }, - { - "type": "boolean", - "key": "backfaceCulling", - "label": "Backface Culling" - }, - { - "type": "boolean", - "key": "ssaoEnable", - "label": "Screen Space Ambient Occlusion" - }, - { - "type": "number", - "key": "ssaoAmount", - "label": "SSAO Amount" - }, - { - "type": "number", - "key": "ssaoRadius", - "label": "SSAO Radius" - }, - { - "type": "number", - "key": "ssaoFilterRadius", - "label": "SSAO Filter Radius", - "decimal": 0, - "minimum": 1, - "maximum": 32 - }, - { - "type": "number", - "key": "ssaoSamples", - "label": "SSAO Samples", - "decimal": 0, - "minimum": 8, - "maximum": 32 - }, - { - "type": "splitter" - }, - { - "type": "boolean", - "key": "fogging", - "label": "Enable Hardware Fog" - }, - { - "type": "enum", - "key": "hwFogFalloff", - "label": "Hardware Falloff", - "enum_items": [ - { "0": "Linear"}, - { "1": "Exponential"}, - { "2": "Exponential Squared"} - ] - }, - { - "type": "number", - "key": "hwFogDensity", - "label": "Fog Density", - "decimal": 2, - "minimum": 0, - "maximum": 1 - }, - { - "type": "number", - "key": "hwFogStart", - "label": "Fog Start" - }, - { - "type": "number", - "key": "hwFogEnd", - "label": "Fog End" - }, - { - "type": "number", - "key": "hwFogAlpha", - "label": "Fog Alpha" - }, - { - "type": "number", - "key": "hwFogColorR", - "label": "Fog Color R", - "decimal": 2, - "minimum": 0, - "maximum": 1 - }, - { - "type": "number", - "key": "hwFogColorG", - "label": "Fog Color G", - "decimal": 2, - "minimum": 0, - "maximum": 1 - }, - { - "type": "number", - "key": "hwFogColorB", - "label": "Fog Color B", - "decimal": 2, - "minimum": 0, - "maximum": 1 - }, - { - "type": "splitter" - }, - { - "type": "boolean", - "key": "motionBlurEnable", - "label": "Enable Motion Blur" - }, - { - "type": "number", - "key": "motionBlurSampleCount", - "label": "Motion Blur Sample Count", - "decimal": 0, - "minimum": 8, - "maximum": 32 - }, - { - "type": "number", - "key": "motionBlurShutterOpenFraction", - "label": "Shutter Open Fraction", - "decimal": 3, - "minimum": 0.01, - "maximum": 32 - }, - { - "type": "splitter" - }, - { - "type": "label", - "label": "Show" - }, - { - "type": "boolean", - "key": "cameras", - "label": "Cameras" - }, - { - "type": "boolean", - "key": "clipGhosts", - "label": "Clip Ghosts" - }, - { - "type": "boolean", - "key": "deformers", - "label": "Deformers" - }, - { - "type": "boolean", - "key": "dimensions", - "label": "Dimensions" - }, - { - "type": "boolean", - "key": "dynamicConstraints", - "label": "Dynamic Constraints" - }, - { - "type": "boolean", - "key": "dynamics", - "label": "Dynamics" - }, - { - "type": "boolean", - "key": "fluids", - "label": "Fluids" - }, - { - "type": "boolean", - "key": "follicles", - "label": "Follicles" - }, - { - "type": "boolean", - "key": "gpuCacheDisplayFilter", - "label": "GPU Cache" - }, - { - "type": "boolean", - "key": "greasePencils", - "label": "Grease Pencil" - }, - { - "type": "boolean", - "key": "grid", - "label": "Grid" - }, - { - "type": "boolean", - "key": "hairSystems", - "label": "Hair Systems" - }, - { - "type": "boolean", - "key": "handles", - "label": "Handles" - }, - { - "type": "boolean", - "key": "headsUpDisplay", - "label": "HUD" - }, - { - "type": "boolean", - "key": "ikHandles", - "label": "IK Handles" - }, - { - "type": "boolean", - "key": "imagePlane", - "label": "Image Planes" - }, - { - "type": "boolean", - "key": "joints", - "label": "Joints" - }, - { - "type": "boolean", - "key": "lights", - "label": "Lights" - }, - { - "type": "boolean", - "key": "locators", - "label": "Locators" - }, - { - "type": "boolean", - "key": "manipulators", - "label": "Manipulators" - }, - { - "type": "boolean", - "key": "motionTrails", - "label": "Motion Trails" - }, - { - "type": "boolean", - "key": "nCloths", - "label": "nCloths" - }, - { - "type": "boolean", - "key": "nParticles", - "label": "nParticles" - }, - { - "type": "boolean", - "key": "nRigids", - "label": "nRigids" - }, - { - "type": "boolean", - "key": "controlVertices", - "label": "NURBS CVs" - }, - { - "type": "boolean", - "key": "nurbsCurves", - "label": "NURBS Curves" - }, - { - "type": "boolean", - "key": "hulls", - "label": "NURBS Hulls" - }, - { - "type": "boolean", - "key": "nurbsSurfaces", - "label": "NURBS Surfaces" - }, - { - "type": "boolean", - "key": "particleInstancers", - "label": "Particle Instancers" - }, - { - "type": "boolean", - "key": "pivots", - "label": "Pivots" - }, - { - "type": "boolean", - "key": "planes", - "label": "Planes" - }, - { - "type": "boolean", - "key": "pluginShapes", - "label": "Plugin Shapes" - }, - { - "type": "boolean", - "key": "polymeshes", - "label": "Polygons" - }, - { - "type": "boolean", - "key": "strokes", - "label": "Strokes" - }, - { - "type": "boolean", - "key": "subdivSurfaces", - "label": "Subdiv Surfaces" - }, - { - "type": "boolean", - "key": "textures", - "label": "Texture Placements" - } - ] - }, - { - "type": "dict", - "collapsible": true, - "key": "Camera Options", - "label": "Camera Options", - "children": [ - { - "type": "boolean", - "key": "displayGateMask", - "label": "Display Gate Mask" - }, - { - "type": "boolean", - "key": "displayResolution", - "label": "Display Resolution" - }, - { - "type": "boolean", - "key": "displayFilmGate", - "label": "Display Film Gate" - }, - { - "type": "boolean", - "key": "displayFieldChart", - "label": "Display Field Chart" - }, - { - "type": "boolean", - "key": "displaySafeAction", - "label": "Display Safe Action" - }, - { - "type": "boolean", - "key": "displaySafeTitle", - "label": "Display Safe Title" - }, - { - "type": "boolean", - "key": "displayFilmPivot", - "label": "Display Film Pivot" - }, - { - "type": "boolean", - "key": "displayFilmOrigin", - "label": "Display Film Origin" - }, - { - "type": "number", - "key": "overscan", - "label": "Overscan", - "decimal": 1, - "minimum": 0, - "maximum": 10 - } - ] - } - ] + { + "type": "color", + "key": "background", + "label": "Background Color: " + }, + { + "type": "color", + "key": "backgroundBottom", + "label": "Background Bottom: " + }, + { + "type": "color", + "key": "backgroundTop", + "label": "Background Top: " + }, + { + "type": "boolean", + "key": "override_display", + "label": "Override display options" + } + ] + }, + { + "type": "splitter" + }, + { + "type": "dict", + "key": "Generic", + "children": [ + { + "type": "label", + "label": "Generic" + }, + { + "type": "boolean", + "key": "isolate_view", + "label": " Isolate view" + }, + { + "type": "boolean", + "key": "off_screen", + "label": " Off Screen" + }, + { + "type": "boolean", + "key": "pan_zoom", + "label": " 2D Pan/Zoom" + } + ] + }, + { + "type": "splitter" + }, + { + "type": "dict", + "key": "Renderer", + "children": [ + { + "type": "label", + "label": "Renderer" + }, + { + "type": "enum", + "key": "rendererName", + "label": "Renderer name", + "enum_items": [ + { "vp2Renderer": "Viewport 2.0" } + ] + } + ] + }, + { + "type": "dict", + "key": "Resolution", + "children": [ + { + "type": "splitter" + }, + { + "type": "label", + "label": "Resolution" + }, + { + "type": "number", + "key": "width", + "label": " Width", + "decimal": 0, + "minimum": 0, + "maximum": 99999 + }, + { + "type": "number", + "key": "height", + "label": "Height", + "decimal": 0, + "minimum": 0, + "maximum": 99999 + } + ] + }, + { + "type": "splitter" + }, + { + "type": "dict", + "collapsible": true, + "key": "Viewport Options", + "label": "Viewport Options", + "children": [ + { + "type": "boolean", + "key": "override_viewport_options", + "label": "Override Viewport Options" + }, + { + "type": "enum", + "key": "displayLights", + "label": "Display Lights", + "enum_items": [ + { "default": "Default Lighting"}, + { "all": "All Lights"}, + { "selected": "Selected Lights"}, + { "flat": "Flat Lighting"}, + { "nolights": "No Lights"} + ] + }, + { + "type": "boolean", + "key": "displayTextures", + "label": "Display Textures" + }, + { + "type": "number", + "key": "textureMaxResolution", + "label": "Texture Clamp Resolution", + "decimal": 0 + }, + { + "type": "splitter" + }, + { + "type": "label", + "label": "Display" + }, + { + "type":"boolean", + "key": "renderDepthOfField", + "label": "Depth of Field" + }, + { + "type": "splitter" + }, + { + "type": "boolean", + "key": "shadows", + "label": "Display Shadows" + }, + { + "type": "boolean", + "key": "twoSidedLighting", + "label": "Two Sided Lighting" + }, + { + "type": "splitter" + }, + { + "type": "boolean", + "key": "lineAAEnable", + "label": "Enable Anti-Aliasing" + }, + { + "type": "number", + "key": "multiSample", + "label": "Anti Aliasing Samples", + "decimal": 0, + "minimum": 0, + "maximum": 32 + }, + { + "type": "splitter" + }, + { + "type": "boolean", + "key": "useDefaultMaterial", + "label": "Use Default Material" + }, + { + "type": "boolean", + "key": "wireframeOnShaded", + "label": "Wireframe On Shaded" + }, + { + "type": "boolean", + "key": "xray", + "label": "X-Ray" + }, + { + "type": "boolean", + "key": "jointXray", + "label": "X-Ray Joints" + }, + { + "type": "boolean", + "key": "backfaceCulling", + "label": "Backface Culling" + }, + { + "type": "boolean", + "key": "ssaoEnable", + "label": "Screen Space Ambient Occlusion" + }, + { + "type": "number", + "key": "ssaoAmount", + "label": "SSAO Amount" + }, + { + "type": "number", + "key": "ssaoRadius", + "label": "SSAO Radius" + }, + { + "type": "number", + "key": "ssaoFilterRadius", + "label": "SSAO Filter Radius", + "decimal": 0, + "minimum": 1, + "maximum": 32 + }, + { + "type": "number", + "key": "ssaoSamples", + "label": "SSAO Samples", + "decimal": 0, + "minimum": 8, + "maximum": 32 + }, + { + "type": "splitter" + }, + { + "type": "boolean", + "key": "fogging", + "label": "Enable Hardware Fog" + }, + { + "type": "enum", + "key": "hwFogFalloff", + "label": "Hardware Falloff", + "enum_items": [ + { "0": "Linear"}, + { "1": "Exponential"}, + { "2": "Exponential Squared"} + ] + }, + { + "type": "number", + "key": "hwFogDensity", + "label": "Fog Density", + "decimal": 2, + "minimum": 0, + "maximum": 1 + }, + { + "type": "number", + "key": "hwFogStart", + "label": "Fog Start" + }, + { + "type": "number", + "key": "hwFogEnd", + "label": "Fog End" + }, + { + "type": "number", + "key": "hwFogAlpha", + "label": "Fog Alpha" + }, + { + "type": "number", + "key": "hwFogColorR", + "label": "Fog Color R", + "decimal": 2, + "minimum": 0, + "maximum": 1 + }, + { + "type": "number", + "key": "hwFogColorG", + "label": "Fog Color G", + "decimal": 2, + "minimum": 0, + "maximum": 1 + }, + { + "type": "number", + "key": "hwFogColorB", + "label": "Fog Color B", + "decimal": 2, + "minimum": 0, + "maximum": 1 + }, + { + "type": "splitter" + }, + { + "type": "boolean", + "key": "motionBlurEnable", + "label": "Enable Motion Blur" + }, + { + "type": "number", + "key": "motionBlurSampleCount", + "label": "Motion Blur Sample Count", + "decimal": 0, + "minimum": 8, + "maximum": 32 + }, + { + "type": "number", + "key": "motionBlurShutterOpenFraction", + "label": "Shutter Open Fraction", + "decimal": 3, + "minimum": 0.01, + "maximum": 32 + }, + { + "type": "splitter" + }, + { + "type": "label", + "label": "Show" + }, + { + "type": "boolean", + "key": "cameras", + "label": "Cameras" + }, + { + "type": "boolean", + "key": "clipGhosts", + "label": "Clip Ghosts" + }, + { + "type": "boolean", + "key": "deformers", + "label": "Deformers" + }, + { + "type": "boolean", + "key": "dimensions", + "label": "Dimensions" + }, + { + "type": "boolean", + "key": "dynamicConstraints", + "label": "Dynamic Constraints" + }, + { + "type": "boolean", + "key": "dynamics", + "label": "Dynamics" + }, + { + "type": "boolean", + "key": "fluids", + "label": "Fluids" + }, + { + "type": "boolean", + "key": "follicles", + "label": "Follicles" + }, + { + "type": "boolean", + "key": "gpuCacheDisplayFilter", + "label": "GPU Cache" + }, + { + "type": "boolean", + "key": "greasePencils", + "label": "Grease Pencil" + }, + { + "type": "boolean", + "key": "grid", + "label": "Grid" + }, + { + "type": "boolean", + "key": "hairSystems", + "label": "Hair Systems" + }, + { + "type": "boolean", + "key": "handles", + "label": "Handles" + }, + { + "type": "boolean", + "key": "headsUpDisplay", + "label": "HUD" + }, + { + "type": "boolean", + "key": "ikHandles", + "label": "IK Handles" + }, + { + "type": "boolean", + "key": "imagePlane", + "label": "Image Planes" + }, + { + "type": "boolean", + "key": "joints", + "label": "Joints" + }, + { + "type": "boolean", + "key": "lights", + "label": "Lights" + }, + { + "type": "boolean", + "key": "locators", + "label": "Locators" + }, + { + "type": "boolean", + "key": "manipulators", + "label": "Manipulators" + }, + { + "type": "boolean", + "key": "motionTrails", + "label": "Motion Trails" + }, + { + "type": "boolean", + "key": "nCloths", + "label": "nCloths" + }, + { + "type": "boolean", + "key": "nParticles", + "label": "nParticles" + }, + { + "type": "boolean", + "key": "nRigids", + "label": "nRigids" + }, + { + "type": "boolean", + "key": "controlVertices", + "label": "NURBS CVs" + }, + { + "type": "boolean", + "key": "nurbsCurves", + "label": "NURBS Curves" + }, + { + "type": "boolean", + "key": "hulls", + "label": "NURBS Hulls" + }, + { + "type": "boolean", + "key": "nurbsSurfaces", + "label": "NURBS Surfaces" + }, + { + "type": "boolean", + "key": "particleInstancers", + "label": "Particle Instancers" + }, + { + "type": "boolean", + "key": "pivots", + "label": "Pivots" + }, + { + "type": "boolean", + "key": "planes", + "label": "Planes" + }, + { + "type": "boolean", + "key": "pluginShapes", + "label": "Plugin Shapes" + }, + { + "type": "boolean", + "key": "polymeshes", + "label": "Polygons" + }, + { + "type": "boolean", + "key": "strokes", + "label": "Strokes" + }, + { + "type": "boolean", + "key": "subdivSurfaces", + "label": "Subdiv Surfaces" + }, + { + "type": "boolean", + "key": "textures", + "label": "Texture Placements" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "Camera Options", + "label": "Camera Options", + "children": [ + { + "type": "boolean", + "key": "displayGateMask", + "label": "Display Gate Mask" + }, + { + "type": "boolean", + "key": "displayResolution", + "label": "Display Resolution" + }, + { + "type": "boolean", + "key": "displayFilmGate", + "label": "Display Film Gate" + }, + { + "type": "boolean", + "key": "displayFieldChart", + "label": "Display Field Chart" + }, + { + "type": "boolean", + "key": "displaySafeAction", + "label": "Display Safe Action" + }, + { + "type": "boolean", + "key": "displaySafeTitle", + "label": "Display Safe Title" + }, + { + "type": "boolean", + "key": "displayFilmPivot", + "label": "Display Film Pivot" + }, + { + "type": "boolean", + "key": "displayFilmOrigin", + "label": "Display Film Origin" + }, + { + "type": "number", + "key": "overscan", + "label": "Overscan", + "decimal": 1, + "minimum": 0, + "maximum": 10 + } + ] + } + ] + } + ] + } } ] } From 2278478598dbda1b465f2d9108ce27106d807e21 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Sun, 2 Apr 2023 08:25:06 +0100 Subject: [PATCH 034/106] Update openpype/hosts/maya/plugins/publish/collect_review.py Co-authored-by: Roy Nieterau --- openpype/hosts/maya/plugins/publish/collect_review.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_review.py b/openpype/hosts/maya/plugins/publish/collect_review.py index d15eb7a12b..a184865602 100644 --- a/openpype/hosts/maya/plugins/publish/collect_review.py +++ b/openpype/hosts/maya/plugins/publish/collect_review.py @@ -143,4 +143,8 @@ class CollectReview(pyblish.api.InstancePlugin): # Convert enum attribute index to string. index = instance.data.get("displayLights", 0) - instance.data["displayLights"] = lib.DISPLAY_LIGHTS[index] + display_lights = lib.DISPLAY_LIGHTS[index] + if display_lights == "project_settings": + # project_settings/maya/publish/ExtractPlayblast/capture_preset/Viewport Options/displayLights + display_lights = instance.context.data["project_settings"]["maya"]["publish"]["ExtractPlayblast"]["capture_preset"]["Viewport Options"]["displayLights"] # noqa + instance.data["displayLights"] = display_lights From b9e9750377d44836c94013f2222422bca736c644 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Sun, 2 Apr 2023 08:25:25 +0100 Subject: [PATCH 035/106] Update openpype/hosts/maya/plugins/publish/extract_playblast.py Co-authored-by: Roy Nieterau --- openpype/hosts/maya/plugins/publish/extract_playblast.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 801f05a770..2167f2c5b3 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -95,10 +95,8 @@ class ExtractPlayblast(publish.Extractor): pm.currentTime(refreshFrameInt - 1, edit=True) pm.currentTime(refreshFrameInt, edit=True) - # Show lighting mode. - display_lights = instance.data["displayLights"] - if display_lights != "project_settings": - preset["viewport_options"]["displayLights"] = display_lights + # Use displayLights setting from instance + preset["viewport_options"]["displayLights"] = instance.data["displayLights"] # Override transparency if requested. transparency = instance.data.get("transparency", 0) From 3ebac0b326e4f06aaa5a396554e4fff16df5efeb Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Sun, 2 Apr 2023 08:25:34 +0100 Subject: [PATCH 036/106] Update openpype/hosts/maya/plugins/publish/extract_thumbnail.py Co-authored-by: Roy Nieterau --- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 79c768228f..92d0141f01 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -105,11 +105,8 @@ class ExtractThumbnail(publish.Extractor): pm.currentTime(refreshFrameInt - 1, edit=True) pm.currentTime(refreshFrameInt, edit=True) - # Show lighting mode. - display_lights = instance.data["displayLights"] - if display_lights != "project_settings": - preset["viewport_options"]["displayLights"] = display_lights - + # Use displayLights setting from instance + preset["viewport_options"]["displayLights"] = instance.data["displayLights"] # Override transparency if requested. transparency = instance.data.get("transparency", 0) if transparency != 0: From 2e234a84dc791bf3452fb9e0610a23bda3cec233 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Sun, 2 Apr 2023 08:34:26 +0100 Subject: [PATCH 037/106] Hound --- openpype/hosts/maya/plugins/publish/extract_playblast.py | 3 ++- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 0381a8adc1..f790d08ae3 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -117,7 +117,8 @@ class ExtractPlayblast(publish.Extractor): pm.currentTime(refreshFrameInt, edit=True) # Use displayLights setting from instance - preset["viewport_options"]["displayLights"] = instance.data["displayLights"] + key = "displayLights" + preset["viewport_options"][key] = instance.data[key] # Override transparency if requested. transparency = instance.data.get("transparency", 0) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 430322c911..d66f65ce88 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -106,7 +106,9 @@ class ExtractThumbnail(publish.Extractor): pm.currentTime(refreshFrameInt, edit=True) # Use displayLights setting from instance - preset["viewport_options"]["displayLights"] = instance.data["displayLights"] + key = "displayLights" + preset["viewport_options"][key] = instance.data[key] + # Override transparency if requested. transparency = instance.data.get("transparency", 0) if transparency != 0: From 87dc14fe9e91c202d4eefa82f85093a4a2814c76 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 3 Apr 2023 11:59:16 +0100 Subject: [PATCH 038/106] Default values for profiles. --- .../defaults/project_settings/maya.json | 6 +- openpype/settings/entities/color_entity.py | 6 +- openpype/settings/entities/input_entities.py | 4 +- .../schemas/schema_maya_capture.json | 267 ++++++++++++------ 4 files changed, 188 insertions(+), 95 deletions(-) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index 4044bdf5df..f6162182e8 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -829,8 +829,8 @@ "rendererName": "vp2Renderer" }, "Resolution": { - "width": 1920, - "height": 1080 + "width": 0, + "height": 0 }, "Viewport Options": { "override_viewport_options": true, @@ -896,7 +896,7 @@ "pivots": false, "planes": false, "pluginShapes": false, - "polymeshes": false, + "polymeshes": true, "strokes": false, "subdivSurfaces": false, "textures": false diff --git a/openpype/settings/entities/color_entity.py b/openpype/settings/entities/color_entity.py index bdaab6f583..a542f2fa38 100644 --- a/openpype/settings/entities/color_entity.py +++ b/openpype/settings/entities/color_entity.py @@ -11,7 +11,9 @@ class ColorEntity(InputEntity): def _item_initialization(self): self.valid_value_types = (list, ) - self.value_on_not_set = [0, 0, 0, 255] + self.value_on_not_set = self.convert_to_valid_type( + self.schema_data.get("default", [0, 0, 0, 255]) + ) self.use_alpha = self.schema_data.get("use_alpha", True) def set_override_state(self, *args, **kwargs): @@ -64,6 +66,6 @@ class ColorEntity(InputEntity): new_value.append(item) # Make sure - if not self.use_alpha: + if hasattr(self, "use_alpha") and not self.use_alpha: new_value[3] = 255 return new_value diff --git a/openpype/settings/entities/input_entities.py b/openpype/settings/entities/input_entities.py index 89f12afd9b..842117ad48 100644 --- a/openpype/settings/entities/input_entities.py +++ b/openpype/settings/entities/input_entities.py @@ -442,7 +442,9 @@ class TextEntity(InputEntity): def _item_initialization(self): self.valid_value_types = (STRING_TYPE, ) - self.value_on_not_set = "" + self.value_on_not_set = self.convert_to_valid_type( + self.schema_data.get("default", "") + ) # GUI attributes self.multiline = self.schema_data.get("multiline", 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 1d0f94e5b8..beaa7c442d 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 @@ -46,12 +46,14 @@ { "type": "text", "key": "compression", - "label": "Encoding" + "label": "Encoding", + "default": "png" }, { "type": "text", "key": "format", - "label": "Format" + "label": "Format", + "default": "image" }, { "type": "number", @@ -59,7 +61,8 @@ "label": "Quality", "decimal": 0, "minimum": 0, - "maximum": 100 + "maximum": 100, + "default": 95 }, { @@ -79,22 +82,26 @@ { "type": "color", "key": "background", - "label": "Background Color: " + "label": "Background Color: ", + "default": [125, 125, 125, 255] }, { "type": "color", "key": "backgroundBottom", - "label": "Background Bottom: " + "label": "Background Bottom: ", + "default": [125, 125, 125, 255] }, { "type": "color", "key": "backgroundTop", - "label": "Background Top: " + "label": "Background Top: ", + "default": [125, 125, 125, 255] }, { "type": "boolean", "key": "override_display", - "label": "Override display options" + "label": "Override display options", + "default": true } ] }, @@ -112,17 +119,20 @@ { "type": "boolean", "key": "isolate_view", - "label": " Isolate view" + "label": " Isolate view", + "default": true }, { "type": "boolean", "key": "off_screen", - "label": " Off Screen" + "label": " Off Screen", + "default": true }, { "type": "boolean", "key": "pan_zoom", - "label": " 2D Pan/Zoom" + "label": " 2D Pan/Zoom", + "default": false } ] }, @@ -143,7 +153,8 @@ "label": "Renderer name", "enum_items": [ { "vp2Renderer": "Viewport 2.0" } - ] + ], + "default": "vp2Renderer" } ] }, @@ -164,7 +175,8 @@ "label": " Width", "decimal": 0, "minimum": 0, - "maximum": 99999 + "maximum": 99999, + "default": 0 }, { "type": "number", @@ -172,7 +184,8 @@ "label": "Height", "decimal": 0, "minimum": 0, - "maximum": 99999 + "maximum": 99999, + "default": 0 } ] }, @@ -188,7 +201,8 @@ { "type": "boolean", "key": "override_viewport_options", - "label": "Override Viewport Options" + "label": "Override Viewport Options", + "default": true }, { "type": "enum", @@ -200,18 +214,21 @@ { "selected": "Selected Lights"}, { "flat": "Flat Lighting"}, { "nolights": "No Lights"} - ] + ], + "default": "default" }, { "type": "boolean", "key": "displayTextures", - "label": "Display Textures" + "label": "Display Textures", + "default": true }, { "type": "number", "key": "textureMaxResolution", "label": "Texture Clamp Resolution", - "decimal": 0 + "decimal": 0, + "default": 1024 }, { "type": "splitter" @@ -223,7 +240,8 @@ { "type":"boolean", "key": "renderDepthOfField", - "label": "Depth of Field" + "label": "Depth of Field", + "default": true }, { "type": "splitter" @@ -231,12 +249,14 @@ { "type": "boolean", "key": "shadows", - "label": "Display Shadows" + "label": "Display Shadows", + "default": true }, { "type": "boolean", "key": "twoSidedLighting", - "label": "Two Sided Lighting" + "label": "Two Sided Lighting", + "default": true }, { "type": "splitter" @@ -244,7 +264,8 @@ { "type": "boolean", "key": "lineAAEnable", - "label": "Enable Anti-Aliasing" + "label": "Enable Anti-Aliasing", + "default": true }, { "type": "number", @@ -252,7 +273,8 @@ "label": "Anti Aliasing Samples", "decimal": 0, "minimum": 0, - "maximum": 32 + "maximum": 32, + "default": 8 }, { "type": "splitter" @@ -260,42 +282,50 @@ { "type": "boolean", "key": "useDefaultMaterial", - "label": "Use Default Material" + "label": "Use Default Material", + "default": false }, { "type": "boolean", "key": "wireframeOnShaded", - "label": "Wireframe On Shaded" + "label": "Wireframe On Shaded", + "default": false }, { "type": "boolean", "key": "xray", - "label": "X-Ray" + "label": "X-Ray", + "default": false }, { "type": "boolean", "key": "jointXray", - "label": "X-Ray Joints" + "label": "X-Ray Joints", + "default": false }, { "type": "boolean", "key": "backfaceCulling", - "label": "Backface Culling" + "label": "Backface Culling", + "default": false }, { "type": "boolean", "key": "ssaoEnable", - "label": "Screen Space Ambient Occlusion" + "label": "Screen Space Ambient Occlusion", + "default": false }, { "type": "number", "key": "ssaoAmount", - "label": "SSAO Amount" + "label": "SSAO Amount", + "default": 1 }, { "type": "number", "key": "ssaoRadius", - "label": "SSAO Radius" + "label": "SSAO Radius", + "default": 16 }, { "type": "number", @@ -303,7 +333,8 @@ "label": "SSAO Filter Radius", "decimal": 0, "minimum": 1, - "maximum": 32 + "maximum": 32, + "default": 16 }, { "type": "number", @@ -311,7 +342,8 @@ "label": "SSAO Samples", "decimal": 0, "minimum": 8, - "maximum": 32 + "maximum": 32, + "default": 16 }, { "type": "splitter" @@ -319,7 +351,8 @@ { "type": "boolean", "key": "fogging", - "label": "Enable Hardware Fog" + "label": "Enable Hardware Fog", + "default": false }, { "type": "enum", @@ -329,7 +362,8 @@ { "0": "Linear"}, { "1": "Exponential"}, { "2": "Exponential Squared"} - ] + ], + "default": "0" }, { "type": "number", @@ -337,22 +371,26 @@ "label": "Fog Density", "decimal": 2, "minimum": 0, - "maximum": 1 + "maximum": 1, + "default": 0 }, { "type": "number", "key": "hwFogStart", - "label": "Fog Start" + "label": "Fog Start", + "default": 0 }, { "type": "number", "key": "hwFogEnd", - "label": "Fog End" + "label": "Fog End", + "default": 100 }, { "type": "number", "key": "hwFogAlpha", - "label": "Fog Alpha" + "label": "Fog Alpha", + "default": 0 }, { "type": "number", @@ -360,7 +398,8 @@ "label": "Fog Color R", "decimal": 2, "minimum": 0, - "maximum": 1 + "maximum": 1, + "default": 1 }, { "type": "number", @@ -368,7 +407,8 @@ "label": "Fog Color G", "decimal": 2, "minimum": 0, - "maximum": 1 + "maximum": 1, + "default": 1 }, { "type": "number", @@ -376,7 +416,8 @@ "label": "Fog Color B", "decimal": 2, "minimum": 0, - "maximum": 1 + "maximum": 1, + "default": 1 }, { "type": "splitter" @@ -384,7 +425,8 @@ { "type": "boolean", "key": "motionBlurEnable", - "label": "Enable Motion Blur" + "label": "Enable Motion Blur", + "default": false }, { "type": "number", @@ -392,7 +434,8 @@ "label": "Motion Blur Sample Count", "decimal": 0, "minimum": 8, - "maximum": 32 + "maximum": 32, + "default": 8 }, { "type": "number", @@ -400,7 +443,8 @@ "label": "Shutter Open Fraction", "decimal": 3, "minimum": 0.01, - "maximum": 32 + "maximum": 32, + "default": 0.2 }, { "type": "splitter" @@ -412,182 +456,218 @@ { "type": "boolean", "key": "cameras", - "label": "Cameras" + "label": "Cameras", + "default": false }, { "type": "boolean", "key": "clipGhosts", - "label": "Clip Ghosts" + "label": "Clip Ghosts", + "default": false }, { "type": "boolean", "key": "deformers", - "label": "Deformers" + "label": "Deformers", + "default": false }, { "type": "boolean", "key": "dimensions", - "label": "Dimensions" + "label": "Dimensions", + "default": false }, { "type": "boolean", "key": "dynamicConstraints", - "label": "Dynamic Constraints" + "label": "Dynamic Constraints", + "default": false }, { "type": "boolean", "key": "dynamics", - "label": "Dynamics" + "label": "Dynamics", + "default": false }, { "type": "boolean", "key": "fluids", - "label": "Fluids" + "label": "Fluids", + "default": false }, { "type": "boolean", "key": "follicles", - "label": "Follicles" + "label": "Follicles", + "default": false }, { "type": "boolean", "key": "gpuCacheDisplayFilter", - "label": "GPU Cache" + "label": "GPU Cache", + "default": false }, { "type": "boolean", "key": "greasePencils", - "label": "Grease Pencil" + "label": "Grease Pencil", + "default": false }, { "type": "boolean", "key": "grid", - "label": "Grid" + "label": "Grid", + "default": false }, { "type": "boolean", "key": "hairSystems", - "label": "Hair Systems" + "label": "Hair Systems", + "default": true }, { "type": "boolean", "key": "handles", - "label": "Handles" + "label": "Handles", + "default": false }, { "type": "boolean", "key": "headsUpDisplay", - "label": "HUD" + "label": "HUD", + "default": false }, { "type": "boolean", "key": "ikHandles", - "label": "IK Handles" + "label": "IK Handles", + "default": false }, { "type": "boolean", "key": "imagePlane", - "label": "Image Planes" + "label": "Image Planes", + "default": true }, { "type": "boolean", "key": "joints", - "label": "Joints" + "label": "Joints", + "default": false }, { "type": "boolean", "key": "lights", - "label": "Lights" + "label": "Lights", + "default": false }, { "type": "boolean", "key": "locators", - "label": "Locators" + "label": "Locators", + "default": false }, { "type": "boolean", "key": "manipulators", - "label": "Manipulators" + "label": "Manipulators", + "default": false }, { "type": "boolean", "key": "motionTrails", - "label": "Motion Trails" + "label": "Motion Trails", + "default": false }, { "type": "boolean", "key": "nCloths", - "label": "nCloths" + "label": "nCloths", + "default": false }, { "type": "boolean", "key": "nParticles", - "label": "nParticles" + "label": "nParticles", + "default": false }, { "type": "boolean", "key": "nRigids", - "label": "nRigids" + "label": "nRigids", + "default": false }, { "type": "boolean", "key": "controlVertices", - "label": "NURBS CVs" + "label": "NURBS CVs", + "default": false }, { "type": "boolean", "key": "nurbsCurves", - "label": "NURBS Curves" + "label": "NURBS Curves", + "default": false }, { "type": "boolean", "key": "hulls", - "label": "NURBS Hulls" + "label": "NURBS Hulls", + "default": false }, { "type": "boolean", "key": "nurbsSurfaces", - "label": "NURBS Surfaces" + "label": "NURBS Surfaces", + "default": false }, { "type": "boolean", "key": "particleInstancers", - "label": "Particle Instancers" + "label": "Particle Instancers", + "default": false }, { "type": "boolean", "key": "pivots", - "label": "Pivots" + "label": "Pivots", + "default": false }, { "type": "boolean", "key": "planes", - "label": "Planes" + "label": "Planes", + "default": false }, { "type": "boolean", "key": "pluginShapes", - "label": "Plugin Shapes" + "label": "Plugin Shapes", + "default": false }, { "type": "boolean", "key": "polymeshes", - "label": "Polygons" + "label": "Polygons", + "default": true }, { "type": "boolean", "key": "strokes", - "label": "Strokes" + "label": "Strokes", + "default": false }, { "type": "boolean", "key": "subdivSurfaces", - "label": "Subdiv Surfaces" + "label": "Subdiv Surfaces", + "default": false }, { "type": "boolean", "key": "textures", - "label": "Texture Placements" + "label": "Texture Placements", + "default": false } ] }, @@ -600,42 +680,50 @@ { "type": "boolean", "key": "displayGateMask", - "label": "Display Gate Mask" + "label": "Display Gate Mask", + "default": false }, { "type": "boolean", "key": "displayResolution", - "label": "Display Resolution" + "label": "Display Resolution", + "default": false }, { "type": "boolean", "key": "displayFilmGate", - "label": "Display Film Gate" + "label": "Display Film Gate", + "default": false }, { "type": "boolean", "key": "displayFieldChart", - "label": "Display Field Chart" + "label": "Display Field Chart", + "default": false }, { "type": "boolean", "key": "displaySafeAction", - "label": "Display Safe Action" + "label": "Display Safe Action", + "default": false }, { "type": "boolean", "key": "displaySafeTitle", - "label": "Display Safe Title" + "label": "Display Safe Title", + "default": false }, { "type": "boolean", "key": "displayFilmPivot", - "label": "Display Film Pivot" + "label": "Display Film Pivot", + "default": false }, { "type": "boolean", "key": "displayFilmOrigin", - "label": "Display Film Origin" + "label": "Display Film Origin", + "default": false }, { "type": "number", @@ -643,7 +731,8 @@ "label": "Overscan", "decimal": 1, "minimum": 0, - "maximum": 10 + "maximum": 10, + "default": 1 } ] } From 655ae7e7f879cac7127fc754bd472426d09ce9b1 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 3 Apr 2023 12:09:26 +0100 Subject: [PATCH 039/106] create review for profiles --- .../maya/plugins/create/create_review.py | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/openpype/hosts/maya/plugins/create/create_review.py b/openpype/hosts/maya/plugins/create/create_review.py index e709239ae7..5a1afe9790 100644 --- a/openpype/hosts/maya/plugins/create/create_review.py +++ b/openpype/hosts/maya/plugins/create/create_review.py @@ -1,8 +1,14 @@ from collections import OrderedDict +import json + from openpype.hosts.maya.api import ( lib, plugin ) +from openpype.settings import get_project_settings +from openpype.pipeline import legacy_io +from openpype.lib.profiles_filtering import filter_profiles +from openpype.client import get_asset_by_name class CreateReview(plugin.Creator): @@ -32,6 +38,30 @@ class CreateReview(plugin.Creator): super(CreateReview, self).__init__(*args, **kwargs) data = OrderedDict(**self.data) + project_name = legacy_io.Session["AVALON_PROJECT"] + profiles = get_project_settings( + project_name + )["maya"]["publish"]["ExtractPlayblast"]["profiles"] + + preset = None + if not profiles: + self.log.warning("No profiles present for extract playblast.") + else: + asset_doc = get_asset_by_name(project_name, data["asset"]) + task_name = legacy_io.Session["AVALON_TASK"] + task_type = asset_doc["data"]["tasks"][task_name]["type"] + + filtering_criteria = { + "hosts": "maya", + "families": "review", + "task_names": task_name, + "task_types": task_type, + "subset": data["subset"] + } + preset = filter_profiles( + profiles, filtering_criteria, logger=self.log + )["capture_preset"] + # Option for using Maya or asset frame range in settings. frame_range = lib.get_frame_range() if self.useMayaTimeline: @@ -40,6 +70,7 @@ class CreateReview(plugin.Creator): data[key] = value data["fps"] = lib.collect_animation_data(fps=True)["fps"] + data["review_width"] = self.Width data["review_height"] = self.Height data["isolate"] = self.isolate @@ -48,4 +79,16 @@ class CreateReview(plugin.Creator): data["transparency"] = self.transparency data["panZoom"] = self.panZoom + if preset: + self.log.info( + "Using preset: {}".format( + json.dumps(preset, indent=4, sort_keys=True) + ) + ) + data["review_width"] = preset["Resolution"]["width"] + data["review_height"] = preset["Resolution"]["height"] + data["isolate"] = preset["Generic"]["isolate_view"] + data["imagePlane"] = preset["Viewport Options"]["imagePlane"] + data["panZoom"] = preset["Generic"]["pan_zoom"] + self.data = data From 0ff0b6b645e1f7293347a24a638bb2afb80556e9 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 07:39:53 +0100 Subject: [PATCH 040/106] Move launch logic to host module. --- openpype/hooks/pre_add_last_workfile_arg.py | 13 ---------- .../hosts/maya/hooks/pre_auto_load_plugins.py | 22 +++++++++++++--- .../pre_open_workfile_post_initialization.py | 25 +++++++++++++++++++ 3 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 openpype/hosts/maya/hooks/pre_open_workfile_post_initialization.py diff --git a/openpype/hooks/pre_add_last_workfile_arg.py b/openpype/hooks/pre_add_last_workfile_arg.py index df4aa5cc5d..2a35db869a 100644 --- a/openpype/hooks/pre_add_last_workfile_arg.py +++ b/openpype/hooks/pre_add_last_workfile_arg.py @@ -42,18 +42,5 @@ class AddLastWorkfileToLaunchArgs(PreLaunchHook): self.log.info("Current context does not have any workfile yet.") return - # Determine whether to open workfile post initialization. - if self.host_name == "maya": - keys = [ - "open_workfile_post_initialization", "explicit_plugins_loading" - ] - maya_settings = self.data["project_settings"]["maya"] - values = [maya_settings[k] for k in keys] - if any(values): - self.log.debug("Opening workfile post initialization.") - key = "OPENPYPE_OPEN_WORKFILE_POST_INITIALIZATION" - self.data["env"][key] = "1" - return - # Add path to workfile to arguments self.launch_context.launch_args.append(last_workfile) diff --git a/openpype/hosts/maya/hooks/pre_auto_load_plugins.py b/openpype/hosts/maya/hooks/pre_auto_load_plugins.py index 3c3ddbe4dc..689d7adb4f 100644 --- a/openpype/hosts/maya/hooks/pre_auto_load_plugins.py +++ b/openpype/hosts/maya/hooks/pre_auto_load_plugins.py @@ -1,15 +1,29 @@ from openpype.lib import PreLaunchHook -class PreAutoLoadPlugins(PreLaunchHook): +class MayaPreAutoLoadPlugins(PreLaunchHook): """Define -noAutoloadPlugins command flag.""" - # Execute before workfile argument. - order = 0 + # Before AddLastWorkfileToLaunchArgs + order = 9 app_groups = ["maya"] def execute(self): + + # Ignore if there's no last workfile to start. + if not self.data.get("start_last_workfile"): + return + maya_settings = self.data["project_settings"]["maya"] - if maya_settings["explicit_plugins_loading"]["enabled"]: + enabled = maya_settings["explicit_plugins_loading"]["enabled"] + if enabled: + # Force disable the `AddLastWorkfileToLaunchArgs`. + self.data.pop("start_last_workfile") + + # Force post initialization so our dedicated plug-in load can run + # prior to Maya opening a scene file. + key = "OPENPYPE_OPEN_WORKFILE_POST_INITIALIZATION" + self.launch_context.env[key] = "1" + self.log.debug("Explicit plugins loading.") self.launch_context.launch_args.append("-noAutoloadPlugins") diff --git a/openpype/hosts/maya/hooks/pre_open_workfile_post_initialization.py b/openpype/hosts/maya/hooks/pre_open_workfile_post_initialization.py new file mode 100644 index 0000000000..7582ce0591 --- /dev/null +++ b/openpype/hosts/maya/hooks/pre_open_workfile_post_initialization.py @@ -0,0 +1,25 @@ +from openpype.lib import PreLaunchHook + + +class MayaPreOpenWorkfilePostInitialization(PreLaunchHook): + """Define whether open last workfile should run post initialize.""" + + # Before AddLastWorkfileToLaunchArgs. + order = 9 + app_groups = ["maya"] + + def execute(self): + + # Ignore if there's no last workfile to start. + if not self.data.get("start_last_workfile"): + return + + maya_settings = self.data["project_settings"]["maya"] + enabled = maya_settings["open_workfile_post_initialization"] + if enabled: + # Force disable the `AddLastWorkfileToLaunchArgs`. + self.data.pop("start_last_workfile") + + self.log.debug("Opening workfile post initialization.") + key = "OPENPYPE_OPEN_WORKFILE_POST_INITIALIZATION" + self.launch_context.env[key] = "1" From 7444e33a941498bf040bacd6b3710a34f9f59e92 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 07:53:50 +0100 Subject: [PATCH 041/106] Move review camera validation to validator. --- .../maya/plugins/publish/collect_review.py | 11 +++----- .../maya/plugins/publish/validate_review.py | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 openpype/hosts/maya/plugins/publish/validate_review.py diff --git a/openpype/hosts/maya/plugins/publish/collect_review.py b/openpype/hosts/maya/plugins/publish/collect_review.py index 00565c5819..ab730db66e 100644 --- a/openpype/hosts/maya/plugins/publish/collect_review.py +++ b/openpype/hosts/maya/plugins/publish/collect_review.py @@ -31,14 +31,11 @@ class CollectReview(pyblish.api.InstancePlugin): # get cameras members = instance.data['setMembers'] - cameras = cmds.ls(members, long=True, - dag=True, cameras=True) self.log.debug('members: {}'.format(members)) - - # validate required settings - assert len(cameras) == 1, "Not a single camera found in extraction" - camera = cameras[0] - self.log.debug('camera: {}'.format(camera)) + cameras = cmds.ls(members, long=True, dag=True, cameras=True) + camera = None + if cameras: + camera = cameras[0] objectset = instance.context.data['objectsets'] diff --git a/openpype/hosts/maya/plugins/publish/validate_review.py b/openpype/hosts/maya/plugins/publish/validate_review.py new file mode 100644 index 0000000000..fd11b2147b --- /dev/null +++ b/openpype/hosts/maya/plugins/publish/validate_review.py @@ -0,0 +1,25 @@ +from maya import cmds + +import pyblish.api + +from openpype.pipeline.publish import ( + ValidateContentsOrder, PublishValidationError +) + + +class ValidateReview(pyblish.api.InstancePlugin): + """Validate review.""" + + order = ValidateContentsOrder + label = "Validate Review" + families = ["review"] + + def process(self, instance): + cameras = cmds.ls( + instance.data["setMembers"], long=True, dag=True, cameras=True + ) + + if len(cameras) != 1: + raise PublishValidationError( + "Not a single camera found in instance." + ) From c4b887597a3ad9318367553f0151675063ab9560 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 07:54:31 +0100 Subject: [PATCH 042/106] Support review profiles in extraction --- .../maya/plugins/publish/extract_playblast.py | 51 +++++++++++--- .../maya/plugins/publish/extract_thumbnail.py | 67 ++++++++++++++----- 2 files changed, 89 insertions(+), 29 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 72b1489522..0556fd9eea 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -7,6 +7,7 @@ import capture from openpype.pipeline import publish from openpype.hosts.maya.api import lib +from openpype.lib.profiles_filtering import filter_profiles from maya import cmds import pymel.core as pm @@ -34,7 +35,7 @@ class ExtractPlayblast(publish.Extractor): hosts = ["maya"] families = ["review"] optional = True - capture_preset = {} + profiles = None def _capture(self, preset): self.log.info( @@ -47,6 +48,10 @@ class ExtractPlayblast(publish.Extractor): self.log.debug("playblast path {}".format(path)) def process(self, instance): + if not self.profiles: + self.log.warning("No profiles present for Extract Playblast") + return + self.log.info("Extracting capture..") # get scene fps @@ -66,12 +71,35 @@ class ExtractPlayblast(publish.Extractor): # get cameras camera = instance.data["review_camera"] - preset = lib.load_capture_preset(data=self.capture_preset) - # Grab capture presets from the project settings - capture_presets = self.capture_preset + host_name = instance.context.data["hostName"] + family = instance.data["family"] + task_data = instance.data["anatomyData"].get("task", {}) + task_name = task_data.get("name") + task_type = task_data.get("type") + subset = instance.data["subset"] + + filtering_criteria = { + "hosts": host_name, + "families": family, + "task_names": task_name, + "task_types": task_type, + "subset": subset + } + capture_preset = filter_profiles( + self.profiles, filtering_criteria, logger=self.log + )["capture_preset"] + 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_presets["Resolution"]["width"] - height_preset = capture_presets["Resolution"]["height"] + 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") @@ -122,8 +150,9 @@ class ExtractPlayblast(publish.Extractor): preset["viewport2_options"]["transparencyAlgorithm"] = transparency # Isolate view is requested by having objects in the set besides a - # camera. - if preset.pop("isolate_view", False) and instance.data.get("isolate"): + # 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. @@ -158,7 +187,7 @@ class ExtractPlayblast(publish.Extractor): ) override_viewport_options = ( - capture_presets["Viewport Options"]["override_viewport_options"] + capture_preset["Viewport Options"]["override_viewport_options"] ) # Force viewer to False in call to capture because we have our own @@ -234,8 +263,8 @@ class ExtractPlayblast(publish.Extractor): collected_files = collected_files[0] representation = { - "name": self.capture_preset["Codec"]["compression"], - "ext": self.capture_preset["Codec"]["compression"], + "name": capture_preset["Codec"]["compression"], + "ext": capture_preset["Codec"]["compression"], "files": collected_files, "stagingDir": stagingdir, "frameStart": start, diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index f2d084b828..4672940254 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -1,11 +1,14 @@ import os import glob import tempfile +import json import capture -from openpype.pipeline import publish +from openpype.pipeline import publish, legacy_io from openpype.hosts.maya.api import lib +from openpype.lib.profiles_filtering import filter_profiles +from openpype.settings import get_project_settings from maya import cmds import pymel.core as pm @@ -24,26 +27,48 @@ class ExtractThumbnail(publish.Extractor): families = ["review"] def process(self, instance): + project_name = legacy_io.Session["AVALON_PROJECT"] + profiles = get_project_settings( + project_name + )["maya"]["publish"]["ExtractPlayblast"]["profiles"] + + if not profiles: + self.log.warning("No profiles present for Extract Playblast") + return + self.log.info("Extracting capture..") camera = instance.data["review_camera"] - maya_setting = instance.context.data["project_settings"]["maya"] - plugin_setting = maya_setting["publish"]["ExtractPlayblast"] - capture_preset = plugin_setting["capture_preset"] + host_name = instance.context.data["hostName"] + family = instance.data["family"] + task_data = instance.data["anatomyData"].get("task", {}) + task_name = task_data.get("name") + task_type = task_data.get("type") + subset = instance.data["subset"] + + filtering_criteria = { + "hosts": host_name, + "families": family, + "task_names": task_name, + "task_types": task_type, + "subset": subset + } + capture_preset = filter_profiles( + profiles, filtering_criteria, logger=self.log + )["capture_preset"] + 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"] ) - try: - preset = lib.load_capture_preset(data=capture_preset) - except KeyError as ke: - self.log.error("Error loading capture presets: {}".format(str(ke))) - preset = {} - self.log.info("Using viewport preset: {}".format(preset)) - - # preset["off_screen"] = False - preset["camera"] = camera preset["start_frame"] = instance.data["frameStart"] preset["end_frame"] = instance.data["frameStart"] @@ -59,10 +84,9 @@ class ExtractThumbnail(publish.Extractor): "overscan": 1.0, "depthOfField": cmds.getAttr("{0}.depthOfField".format(camera)), } - capture_presets = capture_preset # Set resolution variables from capture presets - width_preset = capture_presets["Resolution"]["width"] - height_preset = capture_presets["Resolution"]["height"] + 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") @@ -111,8 +135,9 @@ class ExtractThumbnail(publish.Extractor): preset["viewport2_options"]["transparencyAlgorithm"] = transparency # Isolate view is requested by having objects in the set besides a - # camera. - if preset.pop("isolate_view", False) and instance.data.get("isolate"): + # 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 @@ -140,6 +165,12 @@ class ExtractThumbnail(publish.Extractor): preset.update(panel_preset) cmds.setFocus(panel) + self.log.info( + "Using preset: {}".format( + json.dumps(preset, indent=4, sort_keys=True) + ) + ) + path = capture.capture(**preset) playblast = self._fix_playblast_output_path(path) From b960b653300bff616918f14cb1b6f3a65d519056 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 08:13:35 +0100 Subject: [PATCH 043/106] Order display options better. --- .../schemas/schema_maya_capture.json | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) 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 a8961b48dd..3fc92a1b05 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 @@ -77,13 +77,24 @@ "type": "label", "label": "Display Options" }, - + { + "type": "boolean", + "key": "override_display", + "label": "Override display options", + "default": true + }, { "type": "color", "key": "background", "label": "Background Color: ", "default": [125, 125, 125, 255] }, + { + "type": "boolean", + "key": "displayGradient", + "label": "Display background gradient", + "default": true + }, { "type": "color", "key": "backgroundBottom", @@ -95,18 +106,6 @@ "key": "backgroundTop", "label": "Background Top: ", "default": [125, 125, 125, 255] - }, - { - "type": "boolean", - "key": "override_display", - "label": "Override display options", - "default": true - }, - { - "type": "boolean", - "key": "displayGradient", - "label": "Display background gradient", - "default": true } ] }, From bc004453edd0cc42648ce228e1249c9eb05a2700 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 5 Apr 2023 08:33:18 +0100 Subject: [PATCH 044/106] Update openpype/hosts/maya/startup/userSetup.py Co-authored-by: Roy Nieterau --- openpype/hosts/maya/startup/userSetup.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/startup/userSetup.py b/openpype/hosts/maya/startup/userSetup.py index 4932bf14c0..b28d89e7bd 100644 --- a/openpype/hosts/maya/startup/userSetup.py +++ b/openpype/hosts/maya/startup/userSetup.py @@ -38,8 +38,9 @@ if settings["maya"]["explicit_plugins_loading"]["enabled"]: key = "OPENPYPE_OPEN_WORKFILE_POST_INITIALIZATION" if bool(int(os.environ.get(key, "0"))): def _log_and_open(): - print("Opening \"{}\"".format(os.environ["AVALON_LAST_WORKFILE"])) - cmds.file(os.environ["AVALON_LAST_WORKFILE"], open=True, force=True) + path = os.environ["AVALON_LAST_WORKFILE"] + print("Opening \"{}\"".format(path)) + cmds.file(path, open=True, force=True) cmds.evalDeferred( _log_and_open, lowestPriority=True From b5e80e565b5de71625531beb7818d34d9b7da1df Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 5 Apr 2023 08:34:42 +0100 Subject: [PATCH 045/106] Update openpype/hosts/maya/startup/userSetup.py Co-authored-by: Roy Nieterau --- openpype/hosts/maya/startup/userSetup.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/maya/startup/userSetup.py b/openpype/hosts/maya/startup/userSetup.py index b28d89e7bd..4a00c3dce7 100644 --- a/openpype/hosts/maya/startup/userSetup.py +++ b/openpype/hosts/maya/startup/userSetup.py @@ -20,14 +20,13 @@ if settings["maya"]["explicit_plugins_loading"]["enabled"]: project_settings = get_project_settings(os.environ["AVALON_PROJECT"]) maya_settings = project_settings["maya"] explicit_plugins_loading = maya_settings["explicit_plugins_loading"] - if explicit_plugins_loading["enabled"]: - for plugin in explicit_plugins_loading["plugins_to_load"]: - if plugin["enabled"]: - print("Loading " + plugin["name"]) - try: - cmds.loadPlugin(plugin["name"], quiet=True) - except RuntimeError as e: - print(e) + for plugin in explicit_plugins_loading["plugins_to_load"]: + if plugin["enabled"]: + print("Loading plug-in: " + plugin["name"]) + try: + cmds.loadPlugin(plugin["name"], quiet=True) + except RuntimeError as e: + print(e) cmds.evalDeferred( _explicit_load_plugins, From 0c626f54c5aa69730692f50a6de3123a555d3419 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 08:52:53 +0100 Subject: [PATCH 046/106] Refactor settings variables. --- openpype/hosts/maya/startup/userSetup.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/maya/startup/userSetup.py b/openpype/hosts/maya/startup/userSetup.py index 4a00c3dce7..b58ebb0f7f 100644 --- a/openpype/hosts/maya/startup/userSetup.py +++ b/openpype/hosts/maya/startup/userSetup.py @@ -12,14 +12,12 @@ install_host(host) print("Starting OpenPype usersetup...") -settings = get_project_settings(os.environ['AVALON_PROJECT']) +project_settings = get_project_settings(os.environ['AVALON_PROJECT']) # Loading plugins explicitly. -if settings["maya"]["explicit_plugins_loading"]["enabled"]: +explicit_plugins_loading = project_settings["maya"]["explicit_plugins_loading"] +if explicit_plugins_loading["enabled"]: def _explicit_load_plugins(): - project_settings = get_project_settings(os.environ["AVALON_PROJECT"]) - maya_settings = project_settings["maya"] - explicit_plugins_loading = maya_settings["explicit_plugins_loading"] for plugin in explicit_plugins_loading["plugins_to_load"]: if plugin["enabled"]: print("Loading plug-in: " + plugin["name"]) @@ -46,7 +44,7 @@ if bool(int(os.environ.get(key, "0"))): ) # Build a shelf. -shelf_preset = settings['maya'].get('project_shelf') +shelf_preset = project_settings['maya'].get('project_shelf') if shelf_preset: project = os.environ["AVALON_PROJECT"] From 4b3f96af5e41ccc29461fd5e0fec9306a062edd1 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 08:53:08 +0100 Subject: [PATCH 047/106] Comment deferred evaluation --- openpype/hosts/maya/startup/userSetup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/maya/startup/userSetup.py b/openpype/hosts/maya/startup/userSetup.py index b58ebb0f7f..ae6a999d98 100644 --- a/openpype/hosts/maya/startup/userSetup.py +++ b/openpype/hosts/maya/startup/userSetup.py @@ -26,6 +26,8 @@ if explicit_plugins_loading["enabled"]: except RuntimeError as e: print(e) + # We need to load plugins deferred as loading them directly does not work + # correctly due to Maya's initialization. cmds.evalDeferred( _explicit_load_plugins, lowestPriority=True From 2d6d1ba88200fbf0cd9813dbe8b56553a86c6c55 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 5 Apr 2023 10:11:20 +0100 Subject: [PATCH 048/106] Fix OP-5542 # Traceback (most recent call last): # File "C:\Users\florianbehr\AppData\Local\pypeclub\openpype\3.15\openpype-v3.15.4-thescope230404\openpype\hosts\maya\tools\mayalookassigner\app.py", line 272, in on_process_selected # nodes = list(set(item["nodes"]).difference(arnold_standins)) # UnboundLocalError: local variable 'arnold_standins' referenced before assignment --- openpype/hosts/maya/tools/mayalookassigner/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/tools/mayalookassigner/app.py b/openpype/hosts/maya/tools/mayalookassigner/app.py index 2a8775fff6..4619c80913 100644 --- a/openpype/hosts/maya/tools/mayalookassigner/app.py +++ b/openpype/hosts/maya/tools/mayalookassigner/app.py @@ -263,14 +263,14 @@ class MayaLookAssignerWindow(QtWidgets.QWidget): for standin in arnold_standins: if standin in nodes: arnold_standin.assign_look(standin, subset_name) + + nodes = list(set(item["nodes"]).difference(arnold_standins)) else: self.echo( "Could not assign to aiStandIn because mtoa plugin is not " "loaded." ) - nodes = list(set(item["nodes"]).difference(arnold_standins)) - # Assign look if nodes: assign_look_by_version(nodes, version_id=version["_id"]) From 94cd27fbc27d1c11a1b2fd0edb193257fc2717e9 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 5 Apr 2023 10:25:35 +0100 Subject: [PATCH 049/106] Update openpype/hosts/maya/tools/mayalookassigner/app.py --- openpype/hosts/maya/tools/mayalookassigner/app.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/maya/tools/mayalookassigner/app.py b/openpype/hosts/maya/tools/mayalookassigner/app.py index 4619c80913..a8d0f243e9 100644 --- a/openpype/hosts/maya/tools/mayalookassigner/app.py +++ b/openpype/hosts/maya/tools/mayalookassigner/app.py @@ -263,7 +263,6 @@ class MayaLookAssignerWindow(QtWidgets.QWidget): for standin in arnold_standins: if standin in nodes: arnold_standin.assign_look(standin, subset_name) - nodes = list(set(item["nodes"]).difference(arnold_standins)) else: self.echo( From 912f757390a93df678bb964c6beb3665bc5fb08d Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 5 Apr 2023 11:31:27 +0100 Subject: [PATCH 050/106] Update openpype/hosts/maya/plugins/create/create_review.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/hosts/maya/plugins/create/create_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/create/create_review.py b/openpype/hosts/maya/plugins/create/create_review.py index 5a1afe9790..eeccc5b21e 100644 --- a/openpype/hosts/maya/plugins/create/create_review.py +++ b/openpype/hosts/maya/plugins/create/create_review.py @@ -38,7 +38,7 @@ class CreateReview(plugin.Creator): super(CreateReview, self).__init__(*args, **kwargs) data = OrderedDict(**self.data) - project_name = legacy_io.Session["AVALON_PROJECT"] + project_name = get_current_project_name() profiles = get_project_settings( project_name )["maya"]["publish"]["ExtractPlayblast"]["profiles"] From 462d3247e82725c9bfaf083b63c240441de5ef40 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 5 Apr 2023 11:42:40 +0100 Subject: [PATCH 051/106] Update openpype/hosts/maya/plugins/create/create_review.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/hosts/maya/plugins/create/create_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/create/create_review.py b/openpype/hosts/maya/plugins/create/create_review.py index eeccc5b21e..1eb8e421a1 100644 --- a/openpype/hosts/maya/plugins/create/create_review.py +++ b/openpype/hosts/maya/plugins/create/create_review.py @@ -48,7 +48,7 @@ class CreateReview(plugin.Creator): self.log.warning("No profiles present for extract playblast.") else: asset_doc = get_asset_by_name(project_name, data["asset"]) - task_name = legacy_io.Session["AVALON_TASK"] + task_name = get_current_task_name() task_type = asset_doc["data"]["tasks"][task_name]["type"] filtering_criteria = { From 54a135a1284e72330dcf57e7c70d45fef3de5ce8 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 5 Apr 2023 11:43:01 +0100 Subject: [PATCH 052/106] Update openpype/hosts/maya/plugins/publish/extract_thumbnail.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- 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 2daea7f3eb..ca08016fab 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -26,7 +26,7 @@ class ExtractThumbnail(publish.Extractor): families = ["review"] def process(self, instance): - project_name = legacy_io.Session["AVALON_PROJECT"] + project_name = instance.context.data["projectName"] profiles = get_project_settings( project_name )["maya"]["publish"]["ExtractPlayblast"]["profiles"] From c969120d15a9dab03548f538c2ba662ced596166 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 5 Apr 2023 11:44:11 +0100 Subject: [PATCH 053/106] Update openpype/hosts/maya/plugins/publish/extract_thumbnail.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- 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 ca08016fab..038a3c0c7f 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -27,7 +27,8 @@ class ExtractThumbnail(publish.Extractor): def process(self, instance): project_name = instance.context.data["projectName"] - profiles = get_project_settings( + project_settings = instance.context.data["project_settings"] + profiles = project_settings["maya"]["publish"]["ExtractPlayblast"]["profiles"] project_name )["maya"]["publish"]["ExtractPlayblast"]["profiles"] From a3d358a661b9c32dea6cce3c4b6b0e4dcd010bbb Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 5 Apr 2023 11:44:35 +0100 Subject: [PATCH 054/106] Update openpype/settings/entities/color_entity.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/settings/entities/color_entity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/entities/color_entity.py b/openpype/settings/entities/color_entity.py index a542f2fa38..e9a2136754 100644 --- a/openpype/settings/entities/color_entity.py +++ b/openpype/settings/entities/color_entity.py @@ -11,10 +11,10 @@ class ColorEntity(InputEntity): def _item_initialization(self): self.valid_value_types = (list, ) + self.use_alpha = self.schema_data.get("use_alpha", True) self.value_on_not_set = self.convert_to_valid_type( self.schema_data.get("default", [0, 0, 0, 255]) ) - self.use_alpha = self.schema_data.get("use_alpha", True) def set_override_state(self, *args, **kwargs): super(ColorEntity, self).set_override_state(*args, **kwargs) From c290422fcde6077f744e7d14593076412c79f991 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 5 Apr 2023 11:44:48 +0100 Subject: [PATCH 055/106] Update openpype/settings/entities/color_entity.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/settings/entities/color_entity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/entities/color_entity.py b/openpype/settings/entities/color_entity.py index e9a2136754..f838a6b0ad 100644 --- a/openpype/settings/entities/color_entity.py +++ b/openpype/settings/entities/color_entity.py @@ -66,6 +66,6 @@ class ColorEntity(InputEntity): new_value.append(item) # Make sure - if hasattr(self, "use_alpha") and not self.use_alpha: + if not self.use_alpha: new_value[3] = 255 return new_value From d8d2a317ac24c3618d0a99ee5235b3b71e1718d7 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 5 Apr 2023 11:45:20 +0100 Subject: [PATCH 056/106] Update openpype/settings/entities/color_entity.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> From 890d88908c20e97b384e02bb88d605c22804934f Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 11:46:45 +0100 Subject: [PATCH 057/106] BigRoy feedback --- .../hosts/maya/plugins/publish/collect_review.py | 9 ++++----- .../hosts/maya/plugins/publish/validate_review.py | 7 ++----- .../settings/defaults/project_settings/maya.json | 6 ++++-- .../projects_schema/schemas/schema_maya_capture.json | 12 ++++++------ 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_review.py b/openpype/hosts/maya/plugins/publish/collect_review.py index 858ee24026..0b3799ac13 100644 --- a/openpype/hosts/maya/plugins/publish/collect_review.py +++ b/openpype/hosts/maya/plugins/publish/collect_review.py @@ -31,9 +31,6 @@ class CollectReview(pyblish.api.InstancePlugin): members = instance.data['setMembers'] self.log.debug('members: {}'.format(members)) cameras = cmds.ls(members, long=True, dag=True, cameras=True) - camera = None - if cameras: - camera = cameras[0] context = instance.context objectset = context.data['objectsets'] @@ -64,7 +61,8 @@ class CollectReview(pyblish.api.InstancePlugin): else: data['families'] = ['review'] - data['review_camera'] = camera + data["cameras"] = cameras + data['review_camera'] = cameras[0] if cameras else None data['frameStartFtrack'] = instance.data["frameStartHandle"] data['frameEndFtrack'] = instance.data["frameEndHandle"] data['frameStartHandle'] = instance.data["frameStartHandle"] @@ -98,7 +96,8 @@ class CollectReview(pyblish.api.InstancePlugin): self.log.debug("Existing subsets found, keep legacy name.") instance.data['subset'] = legacy_subset_name - instance.data['review_camera'] = camera + instance.data["cameras"] = cameras + instance.data['review_camera'] = cameras[0] if cameras else None instance.data['frameStartFtrack'] = \ instance.data["frameStartHandle"] instance.data['frameEndFtrack'] = \ diff --git a/openpype/hosts/maya/plugins/publish/validate_review.py b/openpype/hosts/maya/plugins/publish/validate_review.py index 7e9b86c64f..68e8c4a74a 100644 --- a/openpype/hosts/maya/plugins/publish/validate_review.py +++ b/openpype/hosts/maya/plugins/publish/validate_review.py @@ -15,9 +15,7 @@ class ValidateReview(pyblish.api.InstancePlugin): families = ["review"] def process(self, instance): - cameras = cmds.ls( - instance.data["setMembers"], long=True, dag=True, cameras=True - ) + cameras = instance.data["cameras"] # validate required settings if len(cameras) == 0: @@ -31,5 +29,4 @@ class ValidateReview(pyblish.api.InstancePlugin): "Cameras found: {}".format(instance, ", ".join(cameras)) ) - camera = cameras[0] - self.log.debug('camera: {}'.format(camera)) + self.log.debug('camera: {}'.format(instance.data["review_camera"])) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index a54c869939..24d55de1fd 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -874,7 +874,6 @@ "dynamics": false, "fluids": false, "follicles": false, - "gpuCacheDisplayFilter": false, "greasePencils": false, "grid": false, "hairSystems": true, @@ -901,7 +900,10 @@ "polymeshes": true, "strokes": false, "subdivSurfaces": false, - "textures": false + "textures": false, + "pluginObjects": { + "gpuCacheDisplayFilter": false + } }, "Camera Options": { "displayGateMask": 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 3fc92a1b05..1909a20cf5 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 @@ -505,12 +505,6 @@ "label": "Follicles", "default": false }, - { - "type": "boolean", - "key": "gpuCacheDisplayFilter", - "label": "GPU Cache", - "default": false - }, { "type": "boolean", "key": "greasePencils", @@ -672,6 +666,12 @@ "key": "textures", "label": "Texture Placements", "default": false + }, + { + "type": "dict-modifiable", + "key": "pluginObjects", + "label": "Plugin Objects", + "object_type": "boolean" } ] }, From a5918bc3f8116309c2a5bd2d790686eacb2e63bb Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 11:50:05 +0100 Subject: [PATCH 058/106] Move preset debug log behind OPENPYPE_DEBUG --- openpype/hosts/maya/plugins/create/create_review.py | 10 ++++++---- .../hosts/maya/plugins/publish/extract_playblast.py | 9 +++++---- .../hosts/maya/plugins/publish/extract_thumbnail.py | 9 +++++---- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/openpype/hosts/maya/plugins/create/create_review.py b/openpype/hosts/maya/plugins/create/create_review.py index 5a1afe9790..786c795a1a 100644 --- a/openpype/hosts/maya/plugins/create/create_review.py +++ b/openpype/hosts/maya/plugins/create/create_review.py @@ -1,3 +1,4 @@ +import os from collections import OrderedDict import json @@ -80,11 +81,12 @@ class CreateReview(plugin.Creator): data["panZoom"] = self.panZoom if preset: - self.log.info( - "Using preset: {}".format( - json.dumps(preset, indent=4, sort_keys=True) + if os.environ.get("OPENPYPE_DEBUG") == "1": + self.log.debug( + "Using preset: {}".format( + json.dumps(preset, indent=4, sort_keys=True) + ) ) - ) data["review_width"] = preset["Resolution"]["width"] data["review_height"] = preset["Resolution"]["height"] data["isolate"] = preset["Generic"]["isolate_view"] diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 7787c1df7f..81007520a8 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -37,11 +37,12 @@ class ExtractPlayblast(publish.Extractor): profiles = None def _capture(self, preset): - self.log.info( - "Using preset:\n{}".format( - json.dumps(preset, sort_keys=True, indent=4) + if os.environ.get("OPENPYPE_DEBUG") == "1": + self.log.debug( + "Using preset: {}".format( + json.dumps(preset, indent=4, sort_keys=True) + ) ) - ) 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 2daea7f3eb..ee64c11ca4 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -164,11 +164,12 @@ class ExtractThumbnail(publish.Extractor): preset.update(panel_preset) cmds.setFocus(panel) - self.log.info( - "Using preset: {}".format( - json.dumps(preset, indent=4, sort_keys=True) + if os.environ.get("OPENPYPE_DEBUG") == "1": + self.log.debug( + "Using preset: {}".format( + json.dumps(preset, indent=4, sort_keys=True) + ) ) - ) path = capture.capture(**preset) playblast = self._fix_playblast_output_path(path) From 70c9c534f017fe3281547f9248a9bb41c1bcb765 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 11:57:06 +0100 Subject: [PATCH 059/106] Hound --- openpype/hosts/maya/plugins/create/create_review.py | 2 +- .../hosts/maya/plugins/publish/extract_thumbnail.py | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/maya/plugins/create/create_review.py b/openpype/hosts/maya/plugins/create/create_review.py index 75a1a5bf08..594faa7978 100644 --- a/openpype/hosts/maya/plugins/create/create_review.py +++ b/openpype/hosts/maya/plugins/create/create_review.py @@ -7,7 +7,7 @@ from openpype.hosts.maya.api import ( plugin ) from openpype.settings import get_project_settings -from openpype.pipeline import legacy_io +from openpype.pipeline import get_current_project_name, get_current_task_name from openpype.lib.profiles_filtering import filter_profiles from openpype.client import get_asset_by_name diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 67d085e2f5..cf0f80fa15 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -5,10 +5,9 @@ import json import capture -from openpype.pipeline import publish, legacy_io +from openpype.pipeline import publish from openpype.hosts.maya.api import lib from openpype.lib.profiles_filtering import filter_profiles -from openpype.settings import get_project_settings from maya import cmds @@ -26,11 +25,8 @@ class ExtractThumbnail(publish.Extractor): families = ["review"] def process(self, instance): - project_name = instance.context.data["projectName"] - project_settings = instance.context.data["project_settings"] - profiles = project_settings["maya"]["publish"]["ExtractPlayblast"]["profiles"] - project_name - )["maya"]["publish"]["ExtractPlayblast"]["profiles"] + maya_settings = instance.context.data["project_settings"]["maya"] + profiles = maya_settings["publish"]["ExtractPlayblast"]["profiles"] if not profiles: self.log.warning("No profiles present for Extract Playblast") From 56fc69a9c98639be06a18c2a6a6e74ee05386744 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 11:58:40 +0100 Subject: [PATCH 060/106] Hound --- openpype/hosts/maya/plugins/publish/validate_review.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_review.py b/openpype/hosts/maya/plugins/publish/validate_review.py index 68e8c4a74a..346fb54ac4 100644 --- a/openpype/hosts/maya/plugins/publish/validate_review.py +++ b/openpype/hosts/maya/plugins/publish/validate_review.py @@ -1,5 +1,3 @@ -from maya import cmds - import pyblish.api from openpype.pipeline.publish import ( From 09f5e3ecc1eb067b60524c66618cbce0e6514e86 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Fri, 31 Mar 2023 14:43:10 +0200 Subject: [PATCH 061/106] remove placeholder parent to root at cleanup --- .../maya/api/workfile_template_builder.py | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index 4bee0664ef..d65e4c74d2 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -234,26 +234,10 @@ class MayaPlaceholderLoadPlugin(PlaceholderPlugin, PlaceholderLoadMixin): return self.get_load_plugin_options(options) def cleanup_placeholder(self, placeholder, failed): - """Hide placeholder, parent them to root - add them to placeholder set and register placeholder's parent - to keep placeholder info available for future use + """Hide placeholder, add them to placeholder set """ - node = placeholder._scene_identifier - node_parent = placeholder.data["parent"] - if node_parent: - cmds.setAttr(node + ".parent", node_parent, type="string") - if cmds.getAttr(node + ".index") < 0: - cmds.setAttr(node + ".index", placeholder.data["index"]) - - holding_sets = cmds.listSets(object=node) - if holding_sets: - for set in holding_sets: - cmds.sets(node, remove=set) - - if cmds.listRelatives(node, p=True): - node = cmds.parent(node, world=True)[0] cmds.sets(node, addElement=PLACEHOLDER_SET) cmds.hide(node) cmds.setAttr(node + ".hiddenInOutliner", True) @@ -286,8 +270,6 @@ class MayaPlaceholderLoadPlugin(PlaceholderPlugin, PlaceholderLoadMixin): elif not cmds.sets(root, q=True): return - if placeholder.data["parent"]: - cmds.parent(nodes_to_parent, placeholder.data["parent"]) # Move loaded nodes to correct index in outliner hierarchy placeholder_form = cmds.xform( placeholder.scene_identifier, From 9aa8aa469fc3a81e714207809af786b520043bf6 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Fri, 31 Mar 2023 14:44:18 +0200 Subject: [PATCH 062/106] fix missing var standard --- openpype/client/entities.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/client/entities.py b/openpype/client/entities.py index 7054658c64..376157d210 100644 --- a/openpype/client/entities.py +++ b/openpype/client/entities.py @@ -1216,7 +1216,7 @@ def get_representations( version_ids=version_ids, context_filters=context_filters, names_by_version_ids=names_by_version_ids, - standard=True, + standard=standard, archived=archived, fields=fields ) From 9be576c2147e712db4d257f95c187e951eca40ec Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Fri, 31 Mar 2023 14:45:49 +0200 Subject: [PATCH 063/106] fix linked asset import --- .../workfile/workfile_template_builder.py | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index 0ce59de8ad..a3d7340367 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -158,7 +158,7 @@ class AbstractTemplateBuilder(object): def linked_asset_docs(self): if self._linked_asset_docs is None: self._linked_asset_docs = get_linked_assets( - self.current_asset_doc + self.project_name, self.current_asset_doc ) return self._linked_asset_docs @@ -1151,13 +1151,10 @@ class PlaceholderItem(object): return self._log def __repr__(self): - name = None - if hasattr("name", self): - name = self.name - if hasattr("_scene_identifier ", self): - name = self._scene_identifier - - return "< {} {} >".format(self.__class__.__name__, name) + return "< {} {} >".format( + self.__class__.__name__, + self._scene_identifier + ) @property def order(self): @@ -1419,16 +1416,7 @@ class PlaceholderLoadMixin(object): "family": [placeholder.data["family"]] } - elif builder_type != "linked_asset": - context_filters = { - "asset": [re.compile(placeholder.data["asset"])], - "subset": [re.compile(placeholder.data["subset"])], - "hierarchy": [re.compile(placeholder.data["hierarchy"])], - "representation": [placeholder.data["representation"]], - "family": [placeholder.data["family"]] - } - - else: + elif builder_type == "linked_asset": asset_regex = re.compile(placeholder.data["asset"]) linked_asset_names = [] for asset_doc in linked_asset_docs: @@ -1444,6 +1432,15 @@ class PlaceholderLoadMixin(object): "family": [placeholder.data["family"]], } + else: + context_filters = { + "asset": [re.compile(placeholder.data["asset"])], + "subset": [re.compile(placeholder.data["subset"])], + "hierarchy": [re.compile(placeholder.data["hierarchy"])], + "representation": [placeholder.data["representation"]], + "family": [placeholder.data["family"]] + } + return list(get_representations( project_name, context_filters=context_filters From 6f8f61fb4a47e26c67180bf84a169baff45df4f2 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 15:10:34 +0100 Subject: [PATCH 064/106] Reinstate settings backwards compatibility. --- .../defaults/project_settings/maya.json | 123 ++++ .../schemas/schema_maya_capture.json | 625 ++++++++++++++++++ 2 files changed, 748 insertions(+) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index 24d55de1fd..234a02c6d4 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -789,6 +789,129 @@ "validate_shapes": true }, "ExtractPlayblast": { + "capture_preset": { + "Codec": { + "compression": "png", + "format": "image", + "quality": 95 + }, + "Display Options": { + "override_display": true, + "background": [ + 125, + 125, + 125, + 255 + ], + "backgroundBottom": [ + 125, + 125, + 125, + 255 + ], + "backgroundTop": [ + 125, + 125, + 125, + 255 + ], + "displayGradient": true + }, + "Generic": { + "isolate_view": true, + "off_screen": true, + "pan_zoom": false + }, + "Renderer": { + "rendererName": "vp2Renderer" + }, + "Resolution": { + "width": 1920, + "height": 1080 + }, + "Viewport Options": { + "override_viewport_options": true, + "displayLights": "default", + "displayTextures": true, + "textureMaxResolution": 1024, + "renderDepthOfField": true, + "shadows": true, + "twoSidedLighting": true, + "lineAAEnable": true, + "multiSample": 8, + "useDefaultMaterial": false, + "wireframeOnShaded": false, + "xray": false, + "jointXray": false, + "backfaceCulling": false, + "ssaoEnable": false, + "ssaoAmount": 1, + "ssaoRadius": 16, + "ssaoFilterRadius": 16, + "ssaoSamples": 16, + "fogging": false, + "hwFogFalloff": "0", + "hwFogDensity": 0.0, + "hwFogStart": 0, + "hwFogEnd": 100, + "hwFogAlpha": 0, + "hwFogColorR": 1.0, + "hwFogColorG": 1.0, + "hwFogColorB": 1.0, + "motionBlurEnable": false, + "motionBlurSampleCount": 8, + "motionBlurShutterOpenFraction": 0.2, + "cameras": false, + "clipGhosts": false, + "deformers": false, + "dimensions": false, + "dynamicConstraints": false, + "dynamics": false, + "fluids": false, + "follicles": false, + "greasePencils": false, + "grid": false, + "hairSystems": true, + "handles": false, + "headsUpDisplay": false, + "ikHandles": false, + "imagePlane": true, + "joints": false, + "lights": false, + "locators": false, + "manipulators": false, + "motionTrails": false, + "nCloths": false, + "nParticles": false, + "nRigids": false, + "controlVertices": false, + "nurbsCurves": false, + "hulls": false, + "nurbsSurfaces": false, + "particleInstancers": false, + "pivots": false, + "planes": false, + "pluginShapes": false, + "polymeshes": true, + "strokes": false, + "subdivSurfaces": false, + "textures": false, + "pluginObjects": { + "gpuCacheDisplayFilter": false + } + }, + "Camera Options": { + "displayGateMask": false, + "displayResolution": false, + "displayFilmGate": false, + "displayFieldChart": false, + "displaySafeAction": false, + "displaySafeTitle": false, + "displayFilmPivot": false, + "displayFilmOrigin": false, + "overscan": 1.0 + } + }, "profiles": [ { "task_types": [], 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 1909a20cf5..19c169df9c 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 @@ -4,6 +4,631 @@ "key": "ExtractPlayblast", "label": "Extract Playblast settings", "children": [ + { + "type": "dict", + "key": "capture_preset", + "label": "DEPRECATED! Please use \"Profiles\" below.", + "collapsed": false, + "children": [ + { + "type": "dict", + "key": "Codec", + "children": [ + { + "type": "label", + "label": "Codec" + }, + { + "type": "text", + "key": "compression", + "label": "Encoding" + }, + { + "type": "text", + "key": "format", + "label": "Format" + }, + { + "type": "number", + "key": "quality", + "label": "Quality", + "decimal": 0, + "minimum": 0, + "maximum": 100 + }, + + { + "type": "splitter" + } + ] + }, + { + "type": "dict", + "key": "Display Options", + "children": [ + { + "type": "label", + "label": "Display Options" + }, + { + "type": "boolean", + "key": "override_display", + "label": "Override display options" + }, + { + "type": "color", + "key": "background", + "label": "Background Color: " + }, + { + "type": "color", + "key": "backgroundBottom", + "label": "Background Bottom: " + }, + { + "type": "color", + "key": "backgroundTop", + "label": "Background Top: " + }, + { + "type": "boolean", + "key": "displayGradient", + "label": "Display background gradient" + } + ] + }, + { + "type": "splitter" + }, + { + "type": "dict", + "key": "Generic", + "children": [ + { + "type": "label", + "label": "Generic" + }, + { + "type": "boolean", + "key": "isolate_view", + "label": " Isolate view" + }, + { + "type": "boolean", + "key": "off_screen", + "label": " Off Screen" + }, + { + "type": "boolean", + "key": "pan_zoom", + "label": " 2D Pan/Zoom" + } + ] + }, + { + "type": "splitter" + }, + { + "type": "dict", + "key": "Renderer", + "children": [ + { + "type": "label", + "label": "Renderer" + }, + { + "type": "enum", + "key": "rendererName", + "label": "Renderer name", + "enum_items": [ + { "vp2Renderer": "Viewport 2.0" } + ] + } + ] + }, + { + "type": "dict", + "key": "Resolution", + "children": [ + { + "type": "splitter" + }, + { + "type": "label", + "label": "Resolution" + }, + { + "type": "number", + "key": "width", + "label": " Width", + "decimal": 0, + "minimum": 0, + "maximum": 99999 + }, + { + "type": "number", + "key": "height", + "label": "Height", + "decimal": 0, + "minimum": 0, + "maximum": 99999 + } + ] + }, + { + "type": "splitter" + }, + { + "type": "dict", + "collapsible": true, + "key": "Viewport Options", + "label": "Viewport Options", + "children": [ + { + "type": "boolean", + "key": "override_viewport_options", + "label": "Override Viewport Options" + }, + { + "type": "enum", + "key": "displayLights", + "label": "Display Lights", + "enum_items": [ + { "default": "Default Lighting"}, + { "all": "All Lights"}, + { "selected": "Selected Lights"}, + { "flat": "Flat Lighting"}, + { "nolights": "No Lights"} + ] + }, + { + "type": "boolean", + "key": "displayTextures", + "label": "Display Textures" + }, + { + "type": "number", + "key": "textureMaxResolution", + "label": "Texture Clamp Resolution", + "decimal": 0 + }, + { + "type": "splitter" + }, + { + "type": "label", + "label": "Display" + }, + { + "type":"boolean", + "key": "renderDepthOfField", + "label": "Depth of Field" + }, + { + "type": "splitter" + }, + { + "type": "boolean", + "key": "shadows", + "label": "Display Shadows" + }, + { + "type": "boolean", + "key": "twoSidedLighting", + "label": "Two Sided Lighting" + }, + { + "type": "splitter" + }, + { + "type": "boolean", + "key": "lineAAEnable", + "label": "Enable Anti-Aliasing" + }, + { + "type": "number", + "key": "multiSample", + "label": "Anti Aliasing Samples", + "decimal": 0, + "minimum": 0, + "maximum": 32 + }, + { + "type": "splitter" + }, + { + "type": "boolean", + "key": "useDefaultMaterial", + "label": "Use Default Material" + }, + { + "type": "boolean", + "key": "wireframeOnShaded", + "label": "Wireframe On Shaded" + }, + { + "type": "boolean", + "key": "xray", + "label": "X-Ray" + }, + { + "type": "boolean", + "key": "jointXray", + "label": "X-Ray Joints" + }, + { + "type": "boolean", + "key": "backfaceCulling", + "label": "Backface Culling" + }, + { + "type": "boolean", + "key": "ssaoEnable", + "label": "Screen Space Ambient Occlusion" + }, + { + "type": "number", + "key": "ssaoAmount", + "label": "SSAO Amount" + }, + { + "type": "number", + "key": "ssaoRadius", + "label": "SSAO Radius" + }, + { + "type": "number", + "key": "ssaoFilterRadius", + "label": "SSAO Filter Radius", + "decimal": 0, + "minimum": 1, + "maximum": 32 + }, + { + "type": "number", + "key": "ssaoSamples", + "label": "SSAO Samples", + "decimal": 0, + "minimum": 8, + "maximum": 32 + }, + { + "type": "splitter" + }, + { + "type": "boolean", + "key": "fogging", + "label": "Enable Hardware Fog" + }, + { + "type": "enum", + "key": "hwFogFalloff", + "label": "Hardware Falloff", + "enum_items": [ + { "0": "Linear"}, + { "1": "Exponential"}, + { "2": "Exponential Squared"} + ] + }, + { + "type": "number", + "key": "hwFogDensity", + "label": "Fog Density", + "decimal": 2, + "minimum": 0, + "maximum": 1 + }, + { + "type": "number", + "key": "hwFogStart", + "label": "Fog Start" + }, + { + "type": "number", + "key": "hwFogEnd", + "label": "Fog End" + }, + { + "type": "number", + "key": "hwFogAlpha", + "label": "Fog Alpha" + }, + { + "type": "number", + "key": "hwFogColorR", + "label": "Fog Color R", + "decimal": 2, + "minimum": 0, + "maximum": 1 + }, + { + "type": "number", + "key": "hwFogColorG", + "label": "Fog Color G", + "decimal": 2, + "minimum": 0, + "maximum": 1 + }, + { + "type": "number", + "key": "hwFogColorB", + "label": "Fog Color B", + "decimal": 2, + "minimum": 0, + "maximum": 1 + }, + { + "type": "splitter" + }, + { + "type": "boolean", + "key": "motionBlurEnable", + "label": "Enable Motion Blur" + }, + { + "type": "number", + "key": "motionBlurSampleCount", + "label": "Motion Blur Sample Count", + "decimal": 0, + "minimum": 8, + "maximum": 32 + }, + { + "type": "number", + "key": "motionBlurShutterOpenFraction", + "label": "Shutter Open Fraction", + "decimal": 3, + "minimum": 0.01, + "maximum": 32 + }, + { + "type": "splitter" + }, + { + "type": "label", + "label": "Show" + }, + { + "type": "boolean", + "key": "cameras", + "label": "Cameras" + }, + { + "type": "boolean", + "key": "clipGhosts", + "label": "Clip Ghosts" + }, + { + "type": "boolean", + "key": "deformers", + "label": "Deformers" + }, + { + "type": "boolean", + "key": "dimensions", + "label": "Dimensions" + }, + { + "type": "boolean", + "key": "dynamicConstraints", + "label": "Dynamic Constraints" + }, + { + "type": "boolean", + "key": "dynamics", + "label": "Dynamics" + }, + { + "type": "boolean", + "key": "fluids", + "label": "Fluids" + }, + { + "type": "boolean", + "key": "follicles", + "label": "Follicles" + }, + { + "type": "boolean", + "key": "greasePencils", + "label": "Grease Pencil" + }, + { + "type": "boolean", + "key": "grid", + "label": "Grid" + }, + { + "type": "boolean", + "key": "hairSystems", + "label": "Hair Systems" + }, + { + "type": "boolean", + "key": "handles", + "label": "Handles" + }, + { + "type": "boolean", + "key": "headsUpDisplay", + "label": "HUD" + }, + { + "type": "boolean", + "key": "ikHandles", + "label": "IK Handles" + }, + { + "type": "boolean", + "key": "imagePlane", + "label": "Image Planes" + }, + { + "type": "boolean", + "key": "joints", + "label": "Joints" + }, + { + "type": "boolean", + "key": "lights", + "label": "Lights" + }, + { + "type": "boolean", + "key": "locators", + "label": "Locators" + }, + { + "type": "boolean", + "key": "manipulators", + "label": "Manipulators" + }, + { + "type": "boolean", + "key": "motionTrails", + "label": "Motion Trails" + }, + { + "type": "boolean", + "key": "nCloths", + "label": "nCloths" + }, + { + "type": "boolean", + "key": "nParticles", + "label": "nParticles" + }, + { + "type": "boolean", + "key": "nRigids", + "label": "nRigids" + }, + { + "type": "boolean", + "key": "controlVertices", + "label": "NURBS CVs" + }, + { + "type": "boolean", + "key": "nurbsCurves", + "label": "NURBS Curves" + }, + { + "type": "boolean", + "key": "hulls", + "label": "NURBS Hulls" + }, + { + "type": "boolean", + "key": "nurbsSurfaces", + "label": "NURBS Surfaces" + }, + { + "type": "boolean", + "key": "particleInstancers", + "label": "Particle Instancers" + }, + { + "type": "boolean", + "key": "pivots", + "label": "Pivots" + }, + { + "type": "boolean", + "key": "planes", + "label": "Planes" + }, + { + "type": "boolean", + "key": "pluginShapes", + "label": "Plugin Shapes" + }, + { + "type": "boolean", + "key": "polymeshes", + "label": "Polygons" + }, + { + "type": "boolean", + "key": "strokes", + "label": "Strokes" + }, + { + "type": "boolean", + "key": "subdivSurfaces", + "label": "Subdiv Surfaces" + }, + { + "type": "boolean", + "key": "textures", + "label": "Texture Placements" + }, + { + "type": "dict-modifiable", + "key": "pluginObjects", + "label": "Plugin Objects", + "object_type": "boolean" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "Camera Options", + "label": "Camera Options", + "children": [ + { + "type": "boolean", + "key": "displayGateMask", + "label": "Display Gate Mask" + }, + { + "type": "boolean", + "key": "displayResolution", + "label": "Display Resolution" + }, + { + "type": "boolean", + "key": "displayFilmGate", + "label": "Display Film Gate" + }, + { + "type": "boolean", + "key": "displayFieldChart", + "label": "Display Field Chart" + }, + { + "type": "boolean", + "key": "displaySafeAction", + "label": "Display Safe Action" + }, + { + "type": "boolean", + "key": "displaySafeTitle", + "label": "Display Safe Title" + }, + { + "type": "boolean", + "key": "displayFilmPivot", + "label": "Display Film Pivot" + }, + { + "type": "boolean", + "key": "displayFilmOrigin", + "label": "Display Film Origin" + }, + { + "type": "number", + "key": "overscan", + "label": "Overscan", + "decimal": 1, + "minimum": 0, + "maximum": 10 + } + ] + } + ] + }, { "type": "list", "key": "profiles", From 6dd6cc54394f5294b5472cc5e2cee61cbb324d9d Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 5 Apr 2023 17:17:55 +0200 Subject: [PATCH 065/106] :recycle: modify UE launching to use executable from settings --- .../unreal/hooks/pre_workfile_preparation.py | 29 ++++--------------- openpype/hosts/unreal/lib.py | 8 +++++ 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/openpype/hosts/unreal/hooks/pre_workfile_preparation.py b/openpype/hosts/unreal/hooks/pre_workfile_preparation.py index da12bc75de..5dae7eef09 100644 --- a/openpype/hosts/unreal/hooks/pre_workfile_preparation.py +++ b/openpype/hosts/unreal/hooks/pre_workfile_preparation.py @@ -24,7 +24,7 @@ class UnrealPrelaunchHook(PreLaunchHook): """Hook to handle launching Unreal. This hook will check if current workfile path has Unreal - project inside. IF not, it initialize it and finally it pass + project inside. IF not, it initializes it, and finally it pass path to the project by environment variable to Unreal launcher shell script. @@ -141,6 +141,7 @@ class UnrealPrelaunchHook(PreLaunchHook): def execute(self): """Hook entry method.""" workdir = self.launch_context.env["AVALON_WORKDIR"] + executable = str(self.launch_context.executable) engine_version = self.app_name.split("/")[-1].replace("-", ".") try: if int(engine_version.split(".")[0]) < 4 and \ @@ -152,7 +153,7 @@ class UnrealPrelaunchHook(PreLaunchHook): # there can be string in minor version and in that case # int cast is failing. This probably happens only with # early access versions and is of no concert for this check - # so lets keep it quite. + # so let's keep it quiet. ... unreal_project_filename = self._get_work_filename() @@ -183,26 +184,6 @@ class UnrealPrelaunchHook(PreLaunchHook): f"[ {engine_version} ]" )) - detected = unreal_lib.get_engine_versions(self.launch_context.env) - detected_str = ', '.join(detected.keys()) or 'none' - self.log.info(( - f"{self.signature} detected UE versions: " - f"[ {detected_str} ]" - )) - if not detected: - raise ApplicationNotFound("No Unreal Engines are found.") - - engine_version = ".".join(engine_version.split(".")[:2]) - if engine_version not in detected.keys(): - raise ApplicationLaunchFailed(( - f"{self.signature} requested version not " - f"detected [ {engine_version} ]" - )) - - ue_path = unreal_lib.get_editor_exe_path( - Path(detected[engine_version]), engine_version) - - self.launch_context.launch_args = [ue_path.as_posix()] project_path.mkdir(parents=True, exist_ok=True) # Set "OPENPYPE_UNREAL_PLUGIN" to current process environment for @@ -217,7 +198,9 @@ class UnrealPrelaunchHook(PreLaunchHook): if self.launch_context.env.get(env_key): os.environ[env_key] = self.launch_context.env[env_key] - engine_path: Path = Path(detected[engine_version]) + # engine_path points to the specific Unreal Engine root + # so, we are going up from the executable itself 3 levels. + engine_path: Path = Path(executable).parents[3] if not unreal_lib.check_plugin_existence(engine_path): self.exec_plugin_install(engine_path) diff --git a/openpype/hosts/unreal/lib.py b/openpype/hosts/unreal/lib.py index 86ce0bb033..05fc87b318 100644 --- a/openpype/hosts/unreal/lib.py +++ b/openpype/hosts/unreal/lib.py @@ -23,6 +23,8 @@ def get_engine_versions(env=None): Location can be overridden by `UNREAL_ENGINE_LOCATION` environment variable. + .. deprecated:: 3.15.4 + Args: env (dict, optional): Environment to use. @@ -103,6 +105,8 @@ def _win_get_engine_versions(): This file is JSON file listing installed stuff, Unreal engines are marked with `"AppName" = "UE_X.XX"`` like `UE_4.24` + .. deprecated:: 3.15.4 + Returns: dict: version as a key and path as a value. @@ -122,6 +126,8 @@ def _darwin_get_engine_version() -> dict: It works the same as on Windows, just JSON file location is different. + .. deprecated:: 3.15.4 + Returns: dict: version as a key and path as a value. @@ -144,6 +150,8 @@ def _darwin_get_engine_version() -> dict: def _parse_launcher_locations(install_json_path: str) -> dict: """This will parse locations from json file. + .. deprecated:: 3.15.4 + Args: install_json_path (str): Path to `LauncherInstalled.dat`. From cc99791e3eb9c5f92f084fa075b634cccd7ff5fd Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 5 Apr 2023 17:18:44 +0200 Subject: [PATCH 066/106] :art: add settings for unreal executable --- .../system_settings/applications.json | 120 +++++++++++++----- .../host_settings/schema_unreal.json | 7 +- 2 files changed, 92 insertions(+), 35 deletions(-) diff --git a/openpype/settings/defaults/system_settings/applications.json b/openpype/settings/defaults/system_settings/applications.json index eb3a88ce66..d25e21a66e 100644 --- a/openpype/settings/defaults/system_settings/applications.json +++ b/openpype/settings/defaults/system_settings/applications.json @@ -133,7 +133,9 @@ "linux": [] }, "arguments": { - "windows": ["-U MAXScript {OPENPYPE_ROOT}\\openpype\\hosts\\max\\startup\\startup.ms"], + "windows": [ + "-U MAXScript {OPENPYPE_ROOT}\\openpype\\hosts\\max\\startup\\startup.ms" + ], "darwin": [], "linux": [] }, @@ -361,9 +363,15 @@ ] }, "arguments": { - "windows": ["--nukeassist"], - "darwin": ["--nukeassist"], - "linux": ["--nukeassist"] + "windows": [ + "--nukeassist" + ], + "darwin": [ + "--nukeassist" + ], + "linux": [ + "--nukeassist" + ] }, "environment": {} }, @@ -379,9 +387,15 @@ ] }, "arguments": { - "windows": ["--nukeassist"], - "darwin": ["--nukeassist"], - "linux": ["--nukeassist"] + "windows": [ + "--nukeassist" + ], + "darwin": [ + "--nukeassist" + ], + "linux": [ + "--nukeassist" + ] }, "environment": {} }, @@ -397,9 +411,15 @@ ] }, "arguments": { - "windows": ["--nukeassist"], - "darwin": ["--nukeassist"], - "linux": ["--nukeassist"] + "windows": [ + "--nukeassist" + ], + "darwin": [ + "--nukeassist" + ], + "linux": [ + "--nukeassist" + ] }, "environment": {} }, @@ -415,9 +435,15 @@ ] }, "arguments": { - "windows": ["--nukeassist"], - "darwin": ["--nukeassist"], - "linux": ["--nukeassist"] + "windows": [ + "--nukeassist" + ], + "darwin": [ + "--nukeassist" + ], + "linux": [ + "--nukeassist" + ] }, "environment": {} }, @@ -433,9 +459,15 @@ ] }, "arguments": { - "windows": ["--nukeassist"], - "darwin": ["--nukeassist"], - "linux": ["--nukeassist"] + "windows": [ + "--nukeassist" + ], + "darwin": [ + "--nukeassist" + ], + "linux": [ + "--nukeassist" + ] }, "environment": {} }, @@ -449,9 +481,15 @@ "linux": [] }, "arguments": { - "windows": ["--nukeassist"], - "darwin": ["--nukeassist"], - "linux": ["--nukeassist"] + "windows": [ + "--nukeassist" + ], + "darwin": [ + "--nukeassist" + ], + "linux": [ + "--nukeassist" + ] }, "environment": {} }, @@ -1450,21 +1488,45 @@ "label": "Unreal Editor", "icon": "{}/app_icons/ue4.png", "host_name": "unreal", - "environment": {}, + "environment": { + "UE_PYTHONPATH": "{PYTHONPATH}" + }, "variants": { - "4-27": { - "use_python_2": false, - "environment": {} - }, "5-0": { "use_python_2": false, - "environment": { - "UE_PYTHONPATH": "{PYTHONPATH}" - } + "executables": { + "windows": [ + "C:\\Program Files\\Epic Games\\UE_5.0\\Engine\\Binaries\\Win64\\UnrealEditor.exe" + ], + "darwin": [], + "linux": [] + }, + "arguments": { + "windows": [], + "darwin": [], + "linux": [] + }, + "environment": {} + }, + "5-1": { + "use_python_2": false, + "executables": { + "windows": [ + "C:\\Program Files\\Epic Games\\UE_5.1\\Engine\\Binaries\\Win64\\UnrealEditor.exe" + ], + "darwin": [], + "linux": [] + }, + "arguments": { + "windows": [], + "darwin": [], + "linux": [] + }, + "environment": {} }, "__dynamic_keys_labels__": { - "4-27": "4.27", - "5-0": "5.0" + "5-1": "Unreal 5.1", + "5-0": "Unreal 5.0" } } }, diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_unreal.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_unreal.json index 133d6c9eaf..df5ec0e6fa 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_unreal.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_unreal.json @@ -30,12 +30,7 @@ "children": [ { "type": "schema_template", - "name": "template_host_variant_items", - "skip_paths": [ - "executables", - "separator", - "arguments" - ] + "name": "template_host_variant_items" } ] } From 9ed7e00254f42544a51702bcc3fe86e4169f05ff Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 16:59:55 +0100 Subject: [PATCH 067/106] Fix missing camera variable. --- openpype/hosts/maya/plugins/publish/collect_review.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_review.py b/openpype/hosts/maya/plugins/publish/collect_review.py index 0b3799ac13..3652c0aa40 100644 --- a/openpype/hosts/maya/plugins/publish/collect_review.py +++ b/openpype/hosts/maya/plugins/publish/collect_review.py @@ -31,6 +31,7 @@ class CollectReview(pyblish.api.InstancePlugin): members = instance.data['setMembers'] self.log.debug('members: {}'.format(members)) cameras = cmds.ls(members, long=True, dag=True, cameras=True) + camera = cameras[0] if cameras else None context = instance.context objectset = context.data['objectsets'] @@ -62,7 +63,7 @@ class CollectReview(pyblish.api.InstancePlugin): data['families'] = ['review'] data["cameras"] = cameras - data['review_camera'] = cameras[0] if cameras else None + data['review_camera'] = camera data['frameStartFtrack'] = instance.data["frameStartHandle"] data['frameEndFtrack'] = instance.data["frameEndHandle"] data['frameStartHandle'] = instance.data["frameStartHandle"] @@ -97,7 +98,7 @@ class CollectReview(pyblish.api.InstancePlugin): instance.data['subset'] = legacy_subset_name instance.data["cameras"] = cameras - instance.data['review_camera'] = cameras[0] if cameras else None + instance.data['review_camera'] = camera instance.data['frameStartFtrack'] = \ instance.data["frameStartHandle"] instance.data['frameEndFtrack'] = \ @@ -145,6 +146,9 @@ class CollectReview(pyblish.api.InstancePlugin): instance.data["audio"] = audio_data # Collect focal length. + if camera is None: + return + attr = camera + ".focalLength" if get_attribute_input(attr): start = instance.data["frameStart"] From abea98091aa22f1e6949b70832fd654f953375d5 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 17:00:14 +0100 Subject: [PATCH 068/106] Code cosmetics --- openpype/hosts/maya/plugins/create/create_review.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/create/create_review.py b/openpype/hosts/maya/plugins/create/create_review.py index 594faa7978..156f1e3461 100644 --- a/openpype/hosts/maya/plugins/create/create_review.py +++ b/openpype/hosts/maya/plugins/create/create_review.py @@ -45,9 +45,7 @@ class CreateReview(plugin.Creator): )["maya"]["publish"]["ExtractPlayblast"]["profiles"] preset = None - if not profiles: - self.log.warning("No profiles present for extract playblast.") - else: + if profiles: asset_doc = get_asset_by_name(project_name, data["asset"]) task_name = get_current_task_name() task_type = asset_doc["data"]["tasks"][task_name]["type"] @@ -62,6 +60,8 @@ class CreateReview(plugin.Creator): preset = filter_profiles( profiles, filtering_criteria, logger=self.log )["capture_preset"] + else: + self.log.warning("No profiles present for extract playblast.") # Option for using Maya or asset frame range in settings. frame_range = lib.get_frame_range() From f2f42fad308eebdcad7d9ee3267e26a1772bfb33 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 17:03:57 +0100 Subject: [PATCH 069/106] Reinstate backwards compatibility for publishing. --- .../maya/plugins/publish/extract_playblast.py | 20 +++++------ .../maya/plugins/publish/extract_thumbnail.py | 33 +++++++++++-------- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 81007520a8..a9f5062c48 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -34,6 +34,7 @@ class ExtractPlayblast(publish.Extractor): hosts = ["maya"] families = ["review"] optional = True + capture_preset = {} profiles = None def _capture(self, preset): @@ -48,10 +49,6 @@ class ExtractPlayblast(publish.Extractor): self.log.debug("playblast path {}".format(path)) def process(self, instance): - if not self.profiles: - self.log.warning("No profiles present for Extract Playblast") - return - self.log.info("Extracting capture..") # get scene fps @@ -85,12 +82,15 @@ class ExtractPlayblast(publish.Extractor): "task_types": task_type, "subset": subset } - capture_preset = filter_profiles( - self.profiles, filtering_criteria, logger=self.log - )["capture_preset"] - preset = lib.load_capture_preset( - data=capture_preset - ) + capture_preset = self.capture_preset + preset = lib.load_capture_preset(data=self.capture_preset) + if self.profiles: + capture_preset = filter_profiles( + self.profiles, filtering_criteria, logger=self.log + )["capture_preset"] + preset = lib.load_capture_preset(data=capture_preset) + else: + self.log.warning("No profiles present for Extract Playblast") # "isolate_view" will already have been applied at creation, so we'll # ignore it here. diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index cf0f80fa15..8d635d0df2 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -25,13 +25,6 @@ class ExtractThumbnail(publish.Extractor): families = ["review"] def process(self, instance): - maya_settings = instance.context.data["project_settings"]["maya"] - profiles = maya_settings["publish"]["ExtractPlayblast"]["profiles"] - - if not profiles: - self.log.warning("No profiles present for Extract Playblast") - return - self.log.info("Extracting capture..") camera = instance.data["review_camera"] @@ -50,12 +43,26 @@ class ExtractThumbnail(publish.Extractor): "task_types": task_type, "subset": subset } - capture_preset = filter_profiles( - profiles, filtering_criteria, logger=self.log - )["capture_preset"] - preset = lib.load_capture_preset( - data=capture_preset - ) + + maya_settings = instance.context.data["project_settings"]["maya"] + plugin_settings = maya_settings["publish"]["ExtractPlayblast"] + + capture_preset = plugin_settings["capture_preset"] + preset = {} + try: + preset = lib.load_capture_preset(data=capture_preset) + except KeyError as ke: + self.log.error("Error loading capture presets: {}".format(str(ke))) + + if plugin_settings["profiles"]: + capture_preset = filter_profiles( + plugin_settings["profiles"], + filtering_criteria, + logger=self.log + )["capture_preset"] + preset = lib.load_capture_preset(data=capture_preset) + else: + self.log.warning("No profiles present for Extract Playblast") # "isolate_view" will already have been applied at creation, so we'll # ignore it here. From 0b3802d9f27c1def5a8dd07553ca205f88d02a85 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 17:08:19 +0100 Subject: [PATCH 070/106] Remove default profile. --- .../defaults/project_settings/maya.json | 131 +----------------- 1 file changed, 1 insertion(+), 130 deletions(-) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index 234a02c6d4..8c817b5ba0 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -912,136 +912,7 @@ "overscan": 1.0 } }, - "profiles": [ - { - "task_types": [], - "task_names": [], - "subsets": [], - "capture_preset": { - "Codec": { - "compression": "png", - "format": "image", - "quality": 95 - }, - "Display Options": { - "background": [ - 125, - 125, - 125, - 255 - ], - "backgroundBottom": [ - 125, - 125, - 125, - 255 - ], - "backgroundTop": [ - 125, - 125, - 125, - 255 - ], - "override_display": true, - "displayGradient": true - }, - "Generic": { - "isolate_view": true, - "off_screen": true, - "pan_zoom": false - }, - "Renderer": { - "rendererName": "vp2Renderer" - }, - "Resolution": { - "width": 0, - "height": 0 - }, - "Viewport Options": { - "override_viewport_options": true, - "displayLights": "default", - "displayTextures": true, - "textureMaxResolution": 1024, - "renderDepthOfField": true, - "shadows": true, - "twoSidedLighting": true, - "lineAAEnable": true, - "multiSample": 8, - "useDefaultMaterial": false, - "wireframeOnShaded": false, - "xray": false, - "jointXray": false, - "backfaceCulling": false, - "ssaoEnable": false, - "ssaoAmount": 1, - "ssaoRadius": 16, - "ssaoFilterRadius": 16, - "ssaoSamples": 16, - "fogging": false, - "hwFogFalloff": "0", - "hwFogDensity": 0.0, - "hwFogStart": 0, - "hwFogEnd": 100, - "hwFogAlpha": 0, - "hwFogColorR": 1.0, - "hwFogColorG": 1.0, - "hwFogColorB": 1.0, - "motionBlurEnable": false, - "motionBlurSampleCount": 0, - "motionBlurShutterOpenFraction": 0.2, - "cameras": false, - "clipGhosts": false, - "deformers": false, - "dimensions": false, - "dynamicConstraints": false, - "dynamics": false, - "fluids": false, - "follicles": false, - "greasePencils": false, - "grid": false, - "hairSystems": true, - "handles": false, - "headsUpDisplay": false, - "ikHandles": false, - "imagePlane": true, - "joints": false, - "lights": false, - "locators": false, - "manipulators": false, - "motionTrails": false, - "nCloths": false, - "nParticles": false, - "nRigids": false, - "controlVertices": false, - "nurbsCurves": false, - "hulls": false, - "nurbsSurfaces": false, - "particleInstancers": false, - "pivots": false, - "planes": false, - "pluginShapes": false, - "polymeshes": true, - "strokes": false, - "subdivSurfaces": false, - "textures": false, - "pluginObjects": { - "gpuCacheDisplayFilter": false - } - }, - "Camera Options": { - "displayGateMask": false, - "displayResolution": false, - "displayFilmGate": false, - "displayFieldChart": false, - "displaySafeAction": false, - "displaySafeTitle": false, - "displayFilmPivot": false, - "displayFilmOrigin": false, - "overscan": 1.0 - } - } - } - ] + "profiles": [] }, "ExtractMayaSceneRaw": { "enabled": true, From 7d9af1fdb1d8bf4a4d21af61ab45cc051e6c5d45 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 5 Apr 2023 18:09:09 +0200 Subject: [PATCH 071/106] Add addition family filter 'review' to burnin profile with focal length --- openpype/settings/defaults/project_settings/global.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/global.json b/openpype/settings/defaults/project_settings/global.json index 30e56300d1..88a211b512 100644 --- a/openpype/settings/defaults/project_settings/global.json +++ b/openpype/settings/defaults/project_settings/global.json @@ -267,7 +267,9 @@ "BOTTOM_CENTERED": "{asset}", "BOTTOM_RIGHT": "{frame_start}-{current_frame}-{frame_end}", "filter": { - "families": [], + "families": [ + "review" + ], "tags": [] } } From 6048e6e32732f59ebd900492b2aaa7a7a6e5edd7 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 6 Apr 2023 08:12:48 +0100 Subject: [PATCH 072/106] Change family attribute to use. --- openpype/settings/defaults/project_settings/global.json | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/openpype/settings/defaults/project_settings/global.json b/openpype/settings/defaults/project_settings/global.json index 88a211b512..3dcd57ce43 100644 --- a/openpype/settings/defaults/project_settings/global.json +++ b/openpype/settings/defaults/project_settings/global.json @@ -251,7 +251,7 @@ } }, { - "families": [], + "families": ["review"], "hosts": [ "maya" ], @@ -259,7 +259,7 @@ "task_names": [], "subsets": [], "burnins": { - "maya_burnin": { + "maya_review_burnin": { "TOP_LEFT": "{yy}-{mm}-{dd}", "TOP_CENTERED": "{focalLength:.2f} mm", "TOP_RIGHT": "{anatomy[version]}", @@ -267,9 +267,7 @@ "BOTTOM_CENTERED": "{asset}", "BOTTOM_RIGHT": "{frame_start}-{current_frame}-{frame_end}", "filter": { - "families": [ - "review" - ], + "families": [], "tags": [] } } From 7cca37993e5da4cf2a572f1731be8d2843018fab Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 6 Apr 2023 17:32:37 +0800 Subject: [PATCH 073/106] add farm instance to the render colletor --- openpype/hosts/max/plugins/publish/collect_render.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/max/plugins/publish/collect_render.py b/openpype/hosts/max/plugins/publish/collect_render.py index 63e4108c84..bc5987da9a 100644 --- a/openpype/hosts/max/plugins/publish/collect_render.py +++ b/openpype/hosts/max/plugins/publish/collect_render.py @@ -62,6 +62,7 @@ class CollectRender(pyblish.api.InstancePlugin): "frameStart": context.data['frameStart'], "frameEnd": context.data['frameEnd'], "version": version_int, + "farm" : True } self.log.info("data: {0}".format(data)) instance.data.update(data) From 27c957d3f0649e9fe5f734411ade452e95ca651a Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 6 Apr 2023 17:36:55 +0800 Subject: [PATCH 074/106] hound fix --- openpype/hosts/max/plugins/publish/collect_render.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/max/plugins/publish/collect_render.py b/openpype/hosts/max/plugins/publish/collect_render.py index bc5987da9a..b040467522 100644 --- a/openpype/hosts/max/plugins/publish/collect_render.py +++ b/openpype/hosts/max/plugins/publish/collect_render.py @@ -62,7 +62,7 @@ class CollectRender(pyblish.api.InstancePlugin): "frameStart": context.data['frameStart'], "frameEnd": context.data['frameEnd'], "version": version_int, - "farm" : True + "farm": True } self.log.info("data: {0}".format(data)) instance.data.update(data) From 9c9a1c08399184d863f8f5be4c6688bf183e488d Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Thu, 6 Apr 2023 16:47:46 +0100 Subject: [PATCH 075/106] Discard vray proxies and aistandin from same variable. --- openpype/hosts/maya/tools/mayalookassigner/app.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/tools/mayalookassigner/app.py b/openpype/hosts/maya/tools/mayalookassigner/app.py index a8d0f243e9..fe7f460588 100644 --- a/openpype/hosts/maya/tools/mayalookassigner/app.py +++ b/openpype/hosts/maya/tools/mayalookassigner/app.py @@ -250,7 +250,7 @@ class MayaLookAssignerWindow(QtWidgets.QWidget): if vp in nodes: vrayproxy_assign_look(vp, subset_name) - nodes = list(set(item["nodes"]).difference(vray_proxies)) + nodes = list(set(nodes).difference(vray_proxies)) else: self.echo( "Could not assign to VRayProxy because vrayformaya plugin " @@ -260,10 +260,12 @@ class MayaLookAssignerWindow(QtWidgets.QWidget): # Assign Arnold Standin look. if cmds.pluginInfo("mtoa", query=True, loaded=True): arnold_standins = set(cmds.ls(type="aiStandIn", long=True)) + for standin in arnold_standins: if standin in nodes: arnold_standin.assign_look(standin, subset_name) - nodes = list(set(item["nodes"]).difference(arnold_standins)) + + nodes = list(set(nodes).difference(arnold_standins)) else: self.echo( "Could not assign to aiStandIn because mtoa plugin is not " From 0cb647c0b20732ced4c1229429be4d256a98c792 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Thu, 6 Apr 2023 16:48:40 +0100 Subject: [PATCH 076/106] Hound --- openpype/hosts/maya/tools/mayalookassigner/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/tools/mayalookassigner/app.py b/openpype/hosts/maya/tools/mayalookassigner/app.py index fe7f460588..13da999c2d 100644 --- a/openpype/hosts/maya/tools/mayalookassigner/app.py +++ b/openpype/hosts/maya/tools/mayalookassigner/app.py @@ -260,11 +260,11 @@ class MayaLookAssignerWindow(QtWidgets.QWidget): # Assign Arnold Standin look. if cmds.pluginInfo("mtoa", query=True, loaded=True): arnold_standins = set(cmds.ls(type="aiStandIn", long=True)) - + for standin in arnold_standins: if standin in nodes: arnold_standin.assign_look(standin, subset_name) - + nodes = list(set(nodes).difference(arnold_standins)) else: self.echo( From 33a52f1a5282ba308aeb2861a79f8184642ef362 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 7 Apr 2023 10:43:30 +0100 Subject: [PATCH 077/106] Fix No Lights in project settings. --- .../schemas/projects_schema/schemas/schema_maya_capture.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a4a986bad8..d468f098e5 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 @@ -176,7 +176,7 @@ { "all": "All Lights"}, { "selected": "Selected Lights"}, { "flat": "Flat Lighting"}, - { "nolights": "No Lights"} + { "none": "No Lights"} ] }, { From 273d87f8b8dec02b80e07da9eea038ac840f319b Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 7 Apr 2023 10:44:08 +0100 Subject: [PATCH 078/106] Fix flat lighting and sync labels with project settings. --- openpype/hosts/maya/api/lib.py | 12 ++++++++++-- openpype/hosts/maya/plugins/create/create_review.py | 2 +- .../hosts/maya/plugins/publish/collect_review.py | 4 +--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 931c0f9e5b..f94b32d917 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -112,8 +112,16 @@ FLOAT_FPS = {23.98, 23.976, 29.97, 47.952, 59.94} RENDERLIKE_INSTANCE_FAMILIES = ["rendering", "vrayscene"] -DISPLAY_LIGHTS = [ - "project_settings", "default", "all", "selected", "active", "none" +DISPLAY_LIGHTS_VALUES = [ + "project_settings", "default", "all", "selected", "flat", "none" +] +DISPLAY_LIGHTS_LABELS = [ + "Use Project Settings", + "Default Lighting", + "All Lights", + "Selected Lights", + "Flat Lighting", + "No Lights" ] diff --git a/openpype/hosts/maya/plugins/create/create_review.py b/openpype/hosts/maya/plugins/create/create_review.py index de92bbb6b5..094c9ebf8c 100644 --- a/openpype/hosts/maya/plugins/create/create_review.py +++ b/openpype/hosts/maya/plugins/create/create_review.py @@ -47,6 +47,6 @@ class CreateReview(plugin.Creator): data["imagePlane"] = self.imagePlane data["transparency"] = self.transparency data["panZoom"] = self.panZoom - data["displayLights"] = lib.DISPLAY_LIGHTS + data["displayLights"] = lib.DISPLAY_LIGHTS_LABELS self.data = data diff --git a/openpype/hosts/maya/plugins/publish/collect_review.py b/openpype/hosts/maya/plugins/publish/collect_review.py index 516a83de64..3ca45deb3a 100644 --- a/openpype/hosts/maya/plugins/publish/collect_review.py +++ b/openpype/hosts/maya/plugins/publish/collect_review.py @@ -150,10 +150,8 @@ class CollectReview(pyblish.api.InstancePlugin): # Convert enum attribute index to string. index = instance.data.get("displayLights", 0) - display_lights = lib.DISPLAY_LIGHTS[index] + display_lights = lib.DISPLAY_LIGHTS_VALUES[index] if display_lights == "project_settings": - # project_settings/maya/publish/ExtractPlayblast/capture_preset - # /Viewport Options/displayLights settings = instance.context.data["project_settings"] settings = settings["maya"]["publish"]["ExtractPlayblast"] settings = settings["capture_preset"]["Viewport Options"] From 986def10adf225e1169e532d583835b537eab493 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Sat, 8 Apr 2023 17:23:24 +0200 Subject: [PATCH 079/106] text entity can have minimum lines count --- openpype/settings/entities/input_entities.py | 2 ++ openpype/settings/entities/schemas/README.md | 1 + 2 files changed, 3 insertions(+) diff --git a/openpype/settings/entities/input_entities.py b/openpype/settings/entities/input_entities.py index 89f12afd9b..adc600bccb 100644 --- a/openpype/settings/entities/input_entities.py +++ b/openpype/settings/entities/input_entities.py @@ -448,6 +448,8 @@ class TextEntity(InputEntity): self.multiline = self.schema_data.get("multiline", False) self.placeholder_text = self.schema_data.get("placeholder") self.value_hints = self.schema_data.get("value_hints") or [] + self.minimum_lines_count = ( + self.schema_data.get("minimum_lines_count") or 0) def schema_validations(self): if self.multiline and self.value_hints: diff --git a/openpype/settings/entities/schemas/README.md b/openpype/settings/entities/schemas/README.md index cff614a4bb..c333628b25 100644 --- a/openpype/settings/entities/schemas/README.md +++ b/openpype/settings/entities/schemas/README.md @@ -380,6 +380,7 @@ How output of the schema could look like on save: - simple text input - key `"multiline"` allows to enter multiple lines of text (Default: `False`) - key `"placeholder"` allows to show text inside input when is empty (Default: `None`) + - key `"minimum_lines_count"` allows to define minimum size hint for UI. Can be 0-n lines. ``` { From e4e6b8dc9ad4ba70d815268f509998648a58a48d Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Sat, 8 Apr 2023 17:24:07 +0200 Subject: [PATCH 080/106] Use minimum lines to affect minimum size hint --- .../tools/settings/settings/item_widgets.py | 10 +++++---- openpype/tools/settings/settings/widgets.py | 21 +++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/openpype/tools/settings/settings/item_widgets.py b/openpype/tools/settings/settings/item_widgets.py index d51f9b9684..117eca7d6b 100644 --- a/openpype/tools/settings/settings/item_widgets.py +++ b/openpype/tools/settings/settings/item_widgets.py @@ -360,14 +360,16 @@ class TextWidget(InputWidget): def _add_inputs_to_layout(self): multiline = self.entity.multiline if multiline: - self.input_field = SettingsPlainTextEdit(self.content_widget) + input_field = SettingsPlainTextEdit(self.content_widget) + if self.entity.minimum_lines_count: + input_field.set_minimum_lines(self.entity.minimum_lines_count) else: - self.input_field = SettingsLineEdit(self.content_widget) - + input_field = SettingsLineEdit(self.content_widget) placeholder_text = self.entity.placeholder_text if placeholder_text: - self.input_field.setPlaceholderText(placeholder_text) + input_field.setPlaceholderText(placeholder_text) + self.input_field = input_field self.setFocusProxy(self.input_field) layout_kwargs = {} diff --git a/openpype/tools/settings/settings/widgets.py b/openpype/tools/settings/settings/widgets.py index fd04cb0a23..08ffaac0a1 100644 --- a/openpype/tools/settings/settings/widgets.py +++ b/openpype/tools/settings/settings/widgets.py @@ -300,11 +300,32 @@ class SettingsLineEdit(PlaceholderLineEdit): class SettingsPlainTextEdit(QtWidgets.QPlainTextEdit): focused_in = QtCore.Signal() + _min_lines = 0 def focusInEvent(self, event): super(SettingsPlainTextEdit, self).focusInEvent(event) self.focused_in.emit() + def set_minimum_lines(self, lines): + self._min_lines = lines + self.update() + + def minimumSizeHint(self): + result = super(SettingsPlainTextEdit, self).minimumSizeHint() + if self._min_lines < 1: + return result + document = self.document() + margins = self.contentsMargins() + d_margin = ( + ((document.documentMargin() + self.frameWidth()) * 2) + + margins.top() + margins.bottom() + ) + font = document.defaultFont() + font_metrics = QtGui.QFontMetrics(font) + result.setHeight( + d_margin + (font_metrics.lineSpacing() * self._min_lines)) + return result + class SettingsToolBtn(ImageButton): _mask_pixmap = None From eeaa7fdc55bf2adbd13ef01808559f21c63179b1 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Tue, 11 Apr 2023 10:22:22 +0100 Subject: [PATCH 081/106] Update openpype/hosts/maya/plugins/publish/extract_playblast.py --- openpype/hosts/maya/plugins/publish/extract_playblast.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index a9f5062c48..b2deb71d0b 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -85,12 +85,13 @@ class ExtractPlayblast(publish.Extractor): capture_preset = self.capture_preset preset = lib.load_capture_preset(data=self.capture_preset) if self.profiles: - capture_preset = filter_profiles( + profile = filter_profiles( self.profiles, filtering_criteria, logger=self.log - )["capture_preset"] - preset = lib.load_capture_preset(data=capture_preset) + ) + capture_preset = profile.get("capture_preset) or capture_preset else: self.log.warning("No profiles present for Extract Playblast") + preset = lib.load_capture_preset(data=capture_preset) # "isolate_view" will already have been applied at creation, so we'll # ignore it here. From 97d1829b0faba2ba862bb1beaa997368a75d5b60 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Tue, 11 Apr 2023 10:24:18 +0100 Subject: [PATCH 082/106] Update openpype/hosts/maya/plugins/publish/extract_playblast.py --- openpype/hosts/maya/plugins/publish/extract_playblast.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index b2deb71d0b..13e6fb2f0d 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -88,7 +88,7 @@ class ExtractPlayblast(publish.Extractor): profile = filter_profiles( self.profiles, filtering_criteria, logger=self.log ) - capture_preset = profile.get("capture_preset) or capture_preset + capture_preset = profile.get("capture_preset") or capture_preset else: self.log.warning("No profiles present for Extract Playblast") preset = lib.load_capture_preset(data=capture_preset) From 06a94f09370b4e359f909f14a1be862364cbafc4 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Tue, 11 Apr 2023 21:24:57 +0100 Subject: [PATCH 083/106] BigRoy feedback --- .../maya/plugins/create/create_review.py | 7 +++-- .../maya/plugins/publish/extract_playblast.py | 11 +++++-- .../maya/plugins/publish/extract_thumbnail.py | 31 +++++++++---------- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/openpype/hosts/maya/plugins/create/create_review.py b/openpype/hosts/maya/plugins/create/create_review.py index 156f1e3461..972b3a0160 100644 --- a/openpype/hosts/maya/plugins/create/create_review.py +++ b/openpype/hosts/maya/plugins/create/create_review.py @@ -42,7 +42,7 @@ class CreateReview(plugin.Creator): project_name = get_current_project_name() profiles = get_project_settings( project_name - )["maya"]["publish"]["ExtractPlayblast"]["profiles"] + )["maya"]["publish"]["ExtractPlayblast"].get("profiles") preset = None if profiles: @@ -57,9 +57,10 @@ class CreateReview(plugin.Creator): "task_types": task_type, "subset": data["subset"] } - preset = filter_profiles( + profile = filter_profiles( profiles, filtering_criteria, logger=self.log - )["capture_preset"] + ) + preset = profile["capture_preset"] if profile else None else: self.log.warning("No profiles present for extract playblast.") diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 13e6fb2f0d..0ce5aa883e 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -82,15 +82,20 @@ class ExtractPlayblast(publish.Extractor): "task_types": task_type, "subset": subset } - capture_preset = self.capture_preset - preset = lib.load_capture_preset(data=self.capture_preset) + if self.profiles: profile = filter_profiles( self.profiles, filtering_criteria, logger=self.log ) - capture_preset = profile.get("capture_preset") or capture_preset + capture_preset = profile.get("capture_preset") else: self.log.warning("No profiles present for Extract Playblast") + + # Backward compatibility for deprecated Extract Playblast settings + # without profiles. + if capture_preset is None: + capture_preset = self.capture_preset + preset = lib.load_capture_preset(data=capture_preset) # "isolate_view" will already have been applied at creation, so we'll diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 8d635d0df2..cd4e4694ba 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -44,26 +44,23 @@ class ExtractThumbnail(publish.Extractor): "subset": subset } - maya_settings = instance.context.data["project_settings"]["maya"] - plugin_settings = maya_settings["publish"]["ExtractPlayblast"] - - capture_preset = plugin_settings["capture_preset"] - preset = {} - try: - preset = lib.load_capture_preset(data=capture_preset) - except KeyError as ke: - self.log.error("Error loading capture presets: {}".format(str(ke))) - - if plugin_settings["profiles"]: - capture_preset = filter_profiles( - plugin_settings["profiles"], - filtering_criteria, - logger=self.log - )["capture_preset"] - preset = lib.load_capture_preset(data=capture_preset) + if self.profiles: + profile = filter_profiles( + self.profiles, filtering_criteria, logger=self.log + ) + capture_preset = profile.get("capture_preset") else: self.log.warning("No profiles present for Extract Playblast") + # Backward compatibility for deprecated Extract Playblast settings + # without profiles. + if capture_preset is None: + maya_settings = instance.context.data["project_settings"]["maya"] + plugin_settings = maya_settings["publish"]["ExtractPlayblast"] + capture_preset = plugin_settings["capture_preset"] + + 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") From ef5658ce09bbc6d96bb45525063915cdff63bc7a Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 12 Apr 2023 08:45:53 +0100 Subject: [PATCH 084/106] Refactor fetching capture preset to lib. --- openpype/hosts/maya/api/lib.py | 45 ++++++++++++++ .../maya/plugins/create/create_review.py | 60 ++++++------------- .../maya/plugins/publish/extract_playblast.py | 34 +++-------- .../maya/plugins/publish/extract_thumbnail.py | 36 +++-------- 4 files changed, 78 insertions(+), 97 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 22803a2e3a..a79e7ade0c 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -33,6 +33,7 @@ from openpype.pipeline import ( registered_host, ) from openpype.pipeline.context_tools import get_current_project_asset +from openpype.lib.profiles_filtering import filter_profiles self = sys.modules[__name__] @@ -3812,3 +3813,47 @@ def get_all_children(nodes): iterator.next() # noqa: B305 return list(traversed) + + +def get_capture_preset(task_name, task_type, subset, project_settings, log): + """Get capture preset for playblasting. + + Logic for transitioning from old style capture preset to new capture preset + profiles. + + Args: + task_name (str): Task name. + take_type (str): Task type. + subset (str): Subset name. + project_settings (dict): Project settings. + log (object): Logging object. + """ + filtering_criteria = { + "hosts": "maya", + "families": "review", + "task_names": task_name, + "task_types": task_type, + "subset": subset + } + + plugin_settings = project_settings["maya"]["publish"]["ExtractPlayblast"] + if plugin_settings["profiles"]: + profile = filter_profiles( + plugin_settings["profiles"], + filtering_criteria, + logger=log + ) + capture_preset = profile.get("capture_preset") + else: + log.warning("No profiles present for Extract Playblast") + + # Backward compatibility for deprecated Extract Playblast settings + # without profiles. + if capture_preset is None: + log.debug( + "Falling back to deprecated Extract Playblast capture preset " + "because no new style playblast profiles are defined." + ) + capture_preset = plugin_settings["capture_preset"] + + return capture_preset diff --git a/openpype/hosts/maya/plugins/create/create_review.py b/openpype/hosts/maya/plugins/create/create_review.py index 972b3a0160..eb68bbb257 100644 --- a/openpype/hosts/maya/plugins/create/create_review.py +++ b/openpype/hosts/maya/plugins/create/create_review.py @@ -8,7 +8,6 @@ from openpype.hosts.maya.api import ( ) from openpype.settings import get_project_settings from openpype.pipeline import get_current_project_name, get_current_task_name -from openpype.lib.profiles_filtering import filter_profiles from openpype.client import get_asset_by_name @@ -40,29 +39,21 @@ class CreateReview(plugin.Creator): data = OrderedDict(**self.data) project_name = get_current_project_name() - profiles = get_project_settings( - project_name - )["maya"]["publish"]["ExtractPlayblast"].get("profiles") - - preset = None - if profiles: - asset_doc = get_asset_by_name(project_name, data["asset"]) - task_name = get_current_task_name() - task_type = asset_doc["data"]["tasks"][task_name]["type"] - - filtering_criteria = { - "hosts": "maya", - "families": "review", - "task_names": task_name, - "task_types": task_type, - "subset": data["subset"] - } - profile = filter_profiles( - profiles, filtering_criteria, logger=self.log + asset_doc = get_asset_by_name(project_name, data["asset"]) + task_name = get_current_task_name() + preset = lib.get_capture_preset( + task_name, + asset_doc["data"]["tasks"][task_name]["type"], + data["subset"], + get_project_settings(project_name), + self.log + ) + if os.environ.get("OPENPYPE_DEBUG") == "1": + self.log.debug( + "Using preset: {}".format( + json.dumps(preset, indent=4, sort_keys=True) + ) ) - preset = profile["capture_preset"] if profile else None - else: - self.log.warning("No profiles present for extract playblast.") # Option for using Maya or asset frame range in settings. frame_range = lib.get_frame_range() @@ -73,25 +64,12 @@ class CreateReview(plugin.Creator): data["fps"] = lib.collect_animation_data(fps=True)["fps"] - data["review_width"] = self.Width - data["review_height"] = self.Height - data["isolate"] = self.isolate data["keepImages"] = self.keepImages - data["imagePlane"] = self.imagePlane data["transparency"] = self.transparency - data["panZoom"] = self.panZoom - - if preset: - if os.environ.get("OPENPYPE_DEBUG") == "1": - self.log.debug( - "Using preset: {}".format( - json.dumps(preset, indent=4, sort_keys=True) - ) - ) - data["review_width"] = preset["Resolution"]["width"] - data["review_height"] = preset["Resolution"]["height"] - data["isolate"] = preset["Generic"]["isolate_view"] - data["imagePlane"] = preset["Viewport Options"]["imagePlane"] - data["panZoom"] = preset["Generic"]["pan_zoom"] + data["review_width"] = preset["Resolution"]["width"] + data["review_height"] = preset["Resolution"]["height"] + data["isolate"] = preset["Generic"]["isolate_view"] + data["imagePlane"] = preset["Viewport Options"]["imagePlane"] + data["panZoom"] = preset["Generic"]["pan_zoom"] self.data = data diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 0ce5aa883e..78a8106444 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -7,7 +7,6 @@ import capture from openpype.pipeline import publish from openpype.hosts.maya.api import lib -from openpype.lib.profiles_filtering import filter_profiles from maya import cmds @@ -68,33 +67,14 @@ class ExtractPlayblast(publish.Extractor): # get cameras camera = instance.data["review_camera"] - host_name = instance.context.data["hostName"] - family = instance.data["family"] task_data = instance.data["anatomyData"].get("task", {}) - task_name = task_data.get("name") - task_type = task_data.get("type") - subset = instance.data["subset"] - - filtering_criteria = { - "hosts": host_name, - "families": family, - "task_names": task_name, - "task_types": task_type, - "subset": subset - } - - if self.profiles: - profile = filter_profiles( - self.profiles, filtering_criteria, logger=self.log - ) - capture_preset = profile.get("capture_preset") - else: - self.log.warning("No profiles present for Extract Playblast") - - # Backward compatibility for deprecated Extract Playblast settings - # without profiles. - if capture_preset is None: - capture_preset = self.capture_preset + capture_preset = lib.get_capture_preset( + task_data.get("name"), + task_data.get("type"), + instance.data["subset"], + instance.context.data["project_settings"], + self.log + ) preset = lib.load_capture_preset(data=capture_preset) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index cd4e4694ba..e2125e7c44 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -7,7 +7,6 @@ import capture from openpype.pipeline import publish from openpype.hosts.maya.api import lib -from openpype.lib.profiles_filtering import filter_profiles from maya import cmds @@ -29,35 +28,14 @@ class ExtractThumbnail(publish.Extractor): camera = instance.data["review_camera"] - host_name = instance.context.data["hostName"] - family = instance.data["family"] task_data = instance.data["anatomyData"].get("task", {}) - task_name = task_data.get("name") - task_type = task_data.get("type") - subset = instance.data["subset"] - - filtering_criteria = { - "hosts": host_name, - "families": family, - "task_names": task_name, - "task_types": task_type, - "subset": subset - } - - if self.profiles: - profile = filter_profiles( - self.profiles, filtering_criteria, logger=self.log - ) - capture_preset = profile.get("capture_preset") - else: - self.log.warning("No profiles present for Extract Playblast") - - # Backward compatibility for deprecated Extract Playblast settings - # without profiles. - if capture_preset is None: - maya_settings = instance.context.data["project_settings"]["maya"] - plugin_settings = maya_settings["publish"]["ExtractPlayblast"] - capture_preset = plugin_settings["capture_preset"] + capture_preset = lib.get_capture_preset( + task_data.get("name"), + task_data.get("type"), + instance.data["subset"], + instance.context.data["project_settings"], + self.log + ) preset = lib.load_capture_preset(data=capture_preset) From 1663a309a67e4abc78435d9b7189cc70bcff6160 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 12 Apr 2023 12:06:54 +0100 Subject: [PATCH 085/106] Fix tile rendering --- .../plugins/publish/submit_maya_deadline.py | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py index 062732c059..5542435387 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -327,6 +327,11 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): job_info = copy.deepcopy(payload_job_info) plugin_info = copy.deepcopy(payload_plugin_info) + # Force plugin reload for vray cause the region does not get flushed + # between tile renders. + if plugin_info["Renderer"] == "vray": + job_info.ForceReloadPlugin = True + # if we have sequence of files, we need to create tile job for # every frame job_info.TileJob = True @@ -436,6 +441,7 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): assembly_payloads = [] output_dir = self.job_info.OutputDirectory[0] + config_files = [] for file in assembly_files: frame = re.search(R_FRAME_NUMBER, file).group("frame") @@ -461,6 +467,7 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): datetime.now().strftime("%Y_%m_%d_%H_%M_%S") ) ) + config_files.append(config_file) try: if not os.path.isdir(output_dir): os.makedirs(output_dir) @@ -469,8 +476,6 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): self.log.warning("Path is unreachable: " "`{}`".format(output_dir)) - assembly_plugin_info["ConfigFile"] = config_file - with open(config_file, "w") as cf: print("TileCount={}".format(tiles_count), file=cf) print("ImageFileName={}".format(file), file=cf) @@ -479,6 +484,10 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): print("ImageHeight={}".format( instance.data.get("resolutionHeight")), file=cf) + reversed_y = False + if plugin_info["Renderer"] == "arnold": + reversed_y = True + with open(config_file, "a") as cf: # Need to reverse the order of the y tiles, because image # coordinates are calculated from bottom left corner. @@ -489,7 +498,7 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): instance.data.get("resolutionWidth"), instance.data.get("resolutionHeight"), payload_plugin_info["OutputFilePrefix"], - reversed_y=True + reversed_y=reversed_y )[1] for k, v in sorted(tiles.items()): print("{}={}".format(k, v), file=cf) @@ -518,6 +527,11 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): instance.data["assemblySubmissionJobs"] = assembly_job_ids + # Remove config files to avoid confusion about where data is coming + # from in Deadline. + for config_file in config_files: + os.remove(config_file) + def _get_maya_payload(self, data): job_info = copy.deepcopy(self.job_info) @@ -878,8 +892,6 @@ def _format_tiles( out["PluginInfo"]["RegionRight{}".format(tile)] = right # Tile config - cfg["Tile{}".format(tile)] = new_filename - cfg["Tile{}Tile".format(tile)] = new_filename cfg["Tile{}FileName".format(tile)] = new_filename cfg["Tile{}X".format(tile)] = left cfg["Tile{}Y".format(tile)] = top From f70ec0912b04e96a2c6f1d93d1471bb0a2b4897e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 12 Apr 2023 16:43:39 +0200 Subject: [PATCH 086/106] removing default workfile template builder presets --- .../defaults/project_settings/nuke.json | 39 +------------------ 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 19071e1d21..85dee73176 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -542,45 +542,10 @@ "create_first_version": false, "custom_templates": [], "builder_on_start": false, - "profiles": [ - { - "task_types": [], - "tasks": [], - "current_context": [ - { - "subset_name_filters": [], - "families": [ - "render", - "plate" - ], - "repre_names": [ - "exr", - "dpx", - "mov", - "mp4", - "h264" - ], - "loaders": [ - "LoadClip" - ] - } - ], - "linked_assets": [] - } - ] + "profiles": [] }, "templated_workfile_build": { - "profiles": [ - { - "task_types": [ - "Compositing" - ], - "task_names": [], - "path": "{project[name]}/templates/comp.nk", - "keep_placeholder": true, - "create_first_version": true - } - ] + "profiles": [] }, "filters": {} } From de2423b8304d19350104d69fb61542147c254b25 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 13 Apr 2023 01:00:08 +0200 Subject: [PATCH 087/106] Add extra terminology to the key concepts glossary --- website/docs/artist_concepts.md | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/website/docs/artist_concepts.md b/website/docs/artist_concepts.md index 7582540811..13c0691218 100644 --- a/website/docs/artist_concepts.md +++ b/website/docs/artist_concepts.md @@ -14,13 +14,25 @@ OpenPype has a limitation regarding duplicated names. Name of assets must be uni ### Subset -Usually, an asset needs to be created in multiple *'flavours'*. A character might have multiple different looks, model needs to be published in different resolutions, a standard animation rig might not be usable in a crowd system and so on. 'Subsets' are here to accommodate all this variety that might be needed within a single asset. A model might have subset: *'main'*, *'proxy'*, *'sculpt'*, while data of *'look'* family could have subsets *'main'*, *'dirty'*, *'damaged'*. Subsets have some recommendations for their names, but ultimately it's up to the artist to use them for separation of publishes when needed. +A published output from an asset results in a subset + +The subset type is referred to as [family](#family), for example a rig, pointcache, look. +A single asset can have many subsets, even of a single family, named [variants](#variant). +By default a subset is named as a combination of family + variant, sometimes prefixed with the task name (like workfile) + +### Variant + +Usually, an asset needs to be created in multiple *'flavours'*. A character might have multiple different looks, model needs to be published in different resolutions, a standard animation rig might not be usable in a crowd system and so on. 'Variants' are here to accommodate all this variety that might be needed within a single asset. A model might have variant: *'main'*, *'proxy'*, *'sculpt'*, while data of *'look'* family could have subsets *'main'*, *'dirty'*, *'damaged'*. Variants have some recommendations for their names, but ultimately it's up to the artist to use them for separation of publishes when needed. ### Version -A numbered iteration of a given subset. Each version contains at least one [representation][daa74ebf]. +A numbered iteration of a given subset. Each version contains at least one [representation][#representation]. - [daa74ebf]: #representation "representation" +#### Hero version + +A hero version is a version that is always the latest published version. When a new publish is generated its written over the previous hero version replacing it in-place as opposed to regular versions where each new publish is a higher version number. + +This is an optional feature. The generation of hero versions can be completely disabled in OpenPype by an admin through the Studio Settings. ### Representation @@ -33,18 +45,22 @@ At this moment names of assets, tasks, subsets or representations can contain on ### Family -Each published [subset][3b89d8e0] can have exactly one family assigned to it. Family determines the type of data that the subset holds. Family doesn't dictate the file type, but can enforce certain technical specifications. For example OpenPype default configuration expects `model` family to only contain geometry without any shaders or joints when it is published. +Each published [subset][#subset] can have exactly one family assigned to it. Family determines the type of data that the subset holds. Family doesn't dictate the file type, but can enforce certain technical specifications. For example OpenPype default configuration expects `model` family to only contain geometry without any shaders or joints when it is published. +### Task - [3b89d8e0]: #subset "subset" +A task defines a work area for an asset an artist can work in. For example asset *hero* can have tasks *modeling* and *rigging*. Tasks also have types. Multiple tasks of the same type may exist in an asset. A task with type FX could for example appear twice as *fx_fire* and *fx_cloth*. +Without a task you cannot launch a host application. +### Workfile + +The source scene file an artist works in within their task. These are versioned scene files and can be loaded and saved (automatically named) through the [workfiles tool](artist_tools_workfiles.md). ### Host General term for Software or Application supported by OpenPype and Avalon. These are usually DCC applications like Maya, Houdini or Nuke, but can also be a web based service like Ftrack or Clockify. - ### Tool Small piece of software usually dedicated to a particular purpose. Most of OpenPype and Avalon tools have GUI, but some are command line only. @@ -54,6 +70,10 @@ Small piece of software usually dedicated to a particular purpose. Most of OpenP Process of exporting data from your work scene to versioned, immutable file that can be used by other artists in the studio. +#### (Publish) Instance + +A publish instance is a single entry which defines a publish output. Publish instances persist with the workfile. This way we can expect that a publish from a newer workfile will produce similar consistent versioned outputs. + ### Load Process of importing previously published subsets into your current scene, using any of the OpenPype tools. From 30d12155938caadac47fec4b9ea2a572883c4782 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 13 Apr 2023 09:07:29 +0200 Subject: [PATCH 088/106] Apply suggestions from code review Co-authored-by: Toke Jepsen --- website/docs/artist_concepts.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/website/docs/artist_concepts.md b/website/docs/artist_concepts.md index 13c0691218..52a6d0d233 100644 --- a/website/docs/artist_concepts.md +++ b/website/docs/artist_concepts.md @@ -14,11 +14,11 @@ OpenPype has a limitation regarding duplicated names. Name of assets must be uni ### Subset -A published output from an asset results in a subset +A published output from an asset results in a subset. The subset type is referred to as [family](#family), for example a rig, pointcache, look. A single asset can have many subsets, even of a single family, named [variants](#variant). -By default a subset is named as a combination of family + variant, sometimes prefixed with the task name (like workfile) +By default a subset is named as a combination of family + variant, sometimes prefixed with the task name (like workfile). ### Variant @@ -49,7 +49,7 @@ Each published [subset][#subset] can have exactly one family assigned to it. Fam ### Task -A task defines a work area for an asset an artist can work in. For example asset *hero* can have tasks *modeling* and *rigging*. Tasks also have types. Multiple tasks of the same type may exist in an asset. A task with type FX could for example appear twice as *fx_fire* and *fx_cloth*. +A task defines a work area for an asset where an artist can work in. For example asset *characterA* can have tasks named *modeling* and *rigging*. Tasks also have types. Multiple tasks of the same type may exist on an asset. A task with type `fx` could for example appear twice as *fx_fire* and *fx_cloth*. Without a task you cannot launch a host application. @@ -72,7 +72,7 @@ Process of exporting data from your work scene to versioned, immutable file that #### (Publish) Instance -A publish instance is a single entry which defines a publish output. Publish instances persist with the workfile. This way we can expect that a publish from a newer workfile will produce similar consistent versioned outputs. +A publish instance is a single entry which defines a publish output. Publish instances persist within the workfile. This way we can expect that a publish from a newer workfile will produce similar consistent versioned outputs. ### Load From a016f34c54cb9607c5cea52754d65b3d9630a0f2 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 13 Apr 2023 09:11:27 +0200 Subject: [PATCH 089/106] Fix links --- website/docs/artist_concepts.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/artist_concepts.md b/website/docs/artist_concepts.md index 52a6d0d233..c968d34a6d 100644 --- a/website/docs/artist_concepts.md +++ b/website/docs/artist_concepts.md @@ -26,7 +26,7 @@ Usually, an asset needs to be created in multiple *'flavours'*. A character migh ### Version -A numbered iteration of a given subset. Each version contains at least one [representation][#representation]. +A numbered iteration of a given subset. Each version contains at least one [representation](#representation). #### Hero version @@ -45,7 +45,7 @@ At this moment names of assets, tasks, subsets or representations can contain on ### Family -Each published [subset][#subset] can have exactly one family assigned to it. Family determines the type of data that the subset holds. Family doesn't dictate the file type, but can enforce certain technical specifications. For example OpenPype default configuration expects `model` family to only contain geometry without any shaders or joints when it is published. +Each published [subset](#subset) can have exactly one family assigned to it. Family determines the type of data that the subset holds. Family doesn't dictate the file type, but can enforce certain technical specifications. For example OpenPype default configuration expects `model` family to only contain geometry without any shaders or joints when it is published. ### Task From 818382afed10c766952aa83e0dbdf32895d4dbf2 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 13 Apr 2023 09:12:28 +0200 Subject: [PATCH 090/106] Avoid confusion with variant --- website/docs/artist_concepts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/artist_concepts.md b/website/docs/artist_concepts.md index c968d34a6d..1e55c8139d 100644 --- a/website/docs/artist_concepts.md +++ b/website/docs/artist_concepts.md @@ -36,7 +36,7 @@ This is an optional feature. The generation of hero versions can be completely d ### Representation -Each published variant can come out of the software in multiple representations. All of them hold exactly the same data, but in different formats. A model, for example, might be saved as `.OBJ`, Alembic, Maya geometry or as all of them, to be ready for pickup in any other applications supporting these formats. +Each published subset version can come out of the software in multiple representations. All of them hold exactly the same data, but in different formats. A model, for example, might be saved as `.OBJ`, Alembic, Maya geometry or as all of them, to be ready for pickup in any other applications supporting these formats. #### Naming convention From 19d4e35543d44a8300921c4edc47d2c0b417efa4 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 13 Apr 2023 12:25:34 +0200 Subject: [PATCH 091/106] adding discussions to issue crosswalk --- .github/ISSUE_TEMPLATE/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index a2896f77de..cc61bfd04a 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,8 @@ blank_issues_enabled: false contact_links: + - name: Ynput Community Discussions + url: https://community.ynput.io + about: Please ask and answer questions here. - name: Ynput Discord Server url: https://discord.gg/ynput about: For community quick chats. \ No newline at end of file From 55ccf73ebb7a82ca9e8d8293225f6357426d9707 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 13 Apr 2023 13:31:16 +0200 Subject: [PATCH 092/106] Remove single assembly validation for animation instances --- openpype/hosts/maya/plugins/publish/validate_single_assembly.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_single_assembly.py b/openpype/hosts/maya/plugins/publish/validate_single_assembly.py index 8771ca58d1..b768c9c4e8 100644 --- a/openpype/hosts/maya/plugins/publish/validate_single_assembly.py +++ b/openpype/hosts/maya/plugins/publish/validate_single_assembly.py @@ -19,7 +19,7 @@ class ValidateSingleAssembly(pyblish.api.InstancePlugin): order = ValidateContentsOrder hosts = ['maya'] - families = ['rig', 'animation'] + families = ['rig'] label = 'Single Assembly' def process(self, instance): From ce18ab98b9ddd5d4c3c46ef9cf7636cd9d74079e Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 13 Apr 2023 16:42:05 +0200 Subject: [PATCH 093/106] TrayPublisher: Move 'BatchMovieCreator' settings to 'create' subcategory (#4827) * move 'BatchMovieCreator' settings to 'create' subcategory * change label of simple creators * added label to create plugins --- .../plugins/create/create_movie_batch.py | 7 +- .../project_settings/traypublisher.json | 22 +++--- .../schema_project_traypublisher.json | 68 +++++++++++-------- 3 files changed, 52 insertions(+), 45 deletions(-) diff --git a/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py b/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py index d077131e4c..1bed07f785 100644 --- a/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py +++ b/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py @@ -36,11 +36,9 @@ class BatchMovieCreator(TrayPublishCreator): # Position batch creator after simple creators order = 110 - def __init__(self, project_settings, *args, **kwargs): - super(BatchMovieCreator, self).__init__(project_settings, - *args, **kwargs) + def apply_settings(self, project_settings, system_settings): creator_settings = ( - project_settings["traypublisher"]["BatchMovieCreator"] + project_settings["traypublisher"]["create"]["BatchMovieCreator"] ) self.default_variants = creator_settings["default_variants"] self.default_tasks = creator_settings["default_tasks"] @@ -151,4 +149,3 @@ class BatchMovieCreator(TrayPublishCreator): File names must then contain only asset name, or asset name + version. (eg. 'chair.mov', 'chair_v001.mov', not really safe `my_chair_v001.mov` """ - diff --git a/openpype/settings/defaults/project_settings/traypublisher.json b/openpype/settings/defaults/project_settings/traypublisher.json index fdea4aeaba..1b4253a1f8 100644 --- a/openpype/settings/defaults/project_settings/traypublisher.json +++ b/openpype/settings/defaults/project_settings/traypublisher.json @@ -303,16 +303,18 @@ ] } }, - "BatchMovieCreator": { - "default_variants": [ - "Main" - ], - "default_tasks": [ - "Compositing" - ], - "extensions": [ - ".mov" - ] + "create": { + "BatchMovieCreator": { + "default_variants": [ + "Main" + ], + "default_tasks": [ + "Compositing" + ], + "extensions": [ + ".mov" + ] + } }, "publish": { "ValidateFrameRange": { diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json b/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json index 2ef1d2a414..f05f3433b0 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json @@ -26,7 +26,7 @@ "type": "list", "collapsible": true, "key": "simple_creators", - "label": "Creator plugins", + "label": "Simple Create Plugins", "use_label_wrap": true, "collapsible_key": true, "object_type": { @@ -292,40 +292,48 @@ ] }, { + "key": "create", + "label": "Create plugins", "type": "dict", "collapsible": true, - "key": "BatchMovieCreator", - "label": "Batch Movie Creator", - "collapsible_key": true, "children": [ { - "type": "label", - "label": "Allows to publish multiple video files in one go.
Name of matching asset is parsed from file names ('asset.mov', 'asset_v001.mov', 'my_asset_to_publish.mov')" - }, - { - "type": "list", - "key": "default_variants", - "label": "Default variants", - "object_type": { - "type": "text" - } - }, - { - "type": "list", - "key": "default_tasks", - "label": "Default tasks", - "object_type": { - "type": "text" - } - }, - { - "type": "list", - "key": "extensions", - "label": "Extensions", - "use_label_wrap": true, + "type": "dict", + "collapsible": true, + "key": "BatchMovieCreator", + "label": "Batch Movie Creator", "collapsible_key": true, - "collapsed": false, - "object_type": "text" + "children": [ + { + "type": "label", + "label": "Allows to publish multiple video files in one go.
Name of matching asset is parsed from file names ('asset.mov', 'asset_v001.mov', 'my_asset_to_publish.mov')" + }, + { + "type": "list", + "key": "default_variants", + "label": "Default variants", + "object_type": { + "type": "text" + } + }, + { + "type": "list", + "key": "default_tasks", + "label": "Default tasks", + "object_type": { + "type": "text" + } + }, + { + "type": "list", + "key": "extensions", + "label": "Extensions", + "use_label_wrap": true, + "collapsible_key": true, + "collapsed": false, + "object_type": "text" + } + ] } ] }, From 9a96a6b2e0c74aadb1561733a1aec857cd63d2cd Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 13 Apr 2023 16:47:19 +0100 Subject: [PATCH 094/106] KnownPublishError > PublishValidationError --- openpype/hosts/maya/plugins/publish/validate_review.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_review.py b/openpype/hosts/maya/plugins/publish/validate_review.py index 346fb54ac4..12a2e7f86f 100644 --- a/openpype/hosts/maya/plugins/publish/validate_review.py +++ b/openpype/hosts/maya/plugins/publish/validate_review.py @@ -1,7 +1,7 @@ import pyblish.api from openpype.pipeline.publish import ( - ValidateContentsOrder, KnownPublishError + ValidateContentsOrder, PublishValidationError ) @@ -17,11 +17,11 @@ class ValidateReview(pyblish.api.InstancePlugin): # validate required settings if len(cameras) == 0: - raise KnownPublishError( + raise PublishValidationError( "No camera found in review instance: {}".format(instance) ) elif len(cameras) > 2: - raise KnownPublishError( + raise PublishValidationError( "Only a single camera is allowed for a review instance but " "more than one camera found in review instance: {}. " "Cameras found: {}".format(instance, ", ".join(cameras)) From 9a5f86ea1b065a7cf847836b8148e2bc4cb79c59 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 13 Apr 2023 18:42:50 +0200 Subject: [PATCH 095/106] add review tag to output of extract sequence if instance is marked for review (#4843) --- openpype/hosts/tvpaint/plugins/publish/extract_sequence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/tvpaint/plugins/publish/extract_sequence.py b/openpype/hosts/tvpaint/plugins/publish/extract_sequence.py index 1a21715aa2..8a610cf388 100644 --- a/openpype/hosts/tvpaint/plugins/publish/extract_sequence.py +++ b/openpype/hosts/tvpaint/plugins/publish/extract_sequence.py @@ -144,7 +144,7 @@ class ExtractSequence(pyblish.api.Extractor): # Fill tags and new families from project settings tags = [] - if family_lowered == "review": + if "review" in instance.data["families"]: tags.append("review") # Sequence of one frame From a061c897794a5617e746d2c3387bfb8f81d55569 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 14 Apr 2023 08:38:18 +0100 Subject: [PATCH 096/106] Update openpype/hosts/maya/api/lib.py --- openpype/hosts/maya/api/lib.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 2ac9f06fcd..46f423023f 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -3871,6 +3871,8 @@ def get_capture_preset(task_name, task_type, subset, project_settings, log): project_settings (dict): Project settings. log (object): Logging object. """ + capture_preset = {} + filtering_criteria = { "hosts": "maya", "families": "review", From 119df6d24e7b9ba6865cb854a0089c71fe3e58e4 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 14 Apr 2023 08:39:42 +0100 Subject: [PATCH 097/106] Update openpype/hosts/maya/api/lib.py --- 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 46f423023f..8ca6ade2ec 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -3872,7 +3872,6 @@ def get_capture_preset(task_name, task_type, subset, project_settings, log): log (object): Logging object. """ capture_preset = {} - filtering_criteria = { "hosts": "maya", "families": "review", From 2ee9c1727045d0c234f9051b9847cd82f58f7ce3 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 14 Apr 2023 12:28:26 +0100 Subject: [PATCH 098/106] Update openpype/hosts/maya/api/lib.py --- 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 8ca6ade2ec..39db06f70f 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -3871,7 +3871,7 @@ def get_capture_preset(task_name, task_type, subset, project_settings, log): project_settings (dict): Project settings. log (object): Logging object. """ - capture_preset = {} + capture_preset = None filtering_criteria = { "hosts": "maya", "families": "review", @@ -3900,4 +3900,4 @@ def get_capture_preset(task_name, task_type, subset, project_settings, log): ) capture_preset = plugin_settings["capture_preset"] - return capture_preset + return capture_preset or {} From bcdaf5c129c0c7a9dabe2d4a29d1c4768d8daf4c Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Apr 2023 17:06:16 +0200 Subject: [PATCH 099/106] fixing passing CU secrets in release workflow --- .github/workflows/miletone_release_trigger.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/miletone_release_trigger.yml b/.github/workflows/miletone_release_trigger.yml index 26a2d5833d..4a031be7f9 100644 --- a/.github/workflows/miletone_release_trigger.yml +++ b/.github/workflows/miletone_release_trigger.yml @@ -45,3 +45,6 @@ jobs: token: ${{ secrets.YNPUT_BOT_TOKEN }} user_email: ${{ secrets.CI_EMAIL }} user_name: ${{ secrets.CI_USER }} + cu_api_key: ${{ secrets.CLICKUP_API_KEY }} + cu_team_id: ${{ secrets.CLICKUP_TEAM_ID }} + cu_field_id: ${{ secrets.CLICKUP_RELEASE_FIELD_ID }} From a14f9196bb74ad39d40a07c3db38c666a38a830a Mon Sep 17 00:00:00 2001 From: Ynbot Date: Fri, 14 Apr 2023 15:15:13 +0000 Subject: [PATCH 100/106] [Automated] Release --- CHANGELOG.md | 943 ++++++++++++++++++++++++++++++++++++++++++++ openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 945 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e22b783c4..5aeb546c14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,948 @@ # Changelog + +## [3.15.4](https://github.com/ynput/OpenPype/tree/3.15.4) + + +[Full Changelog](https://github.com/ynput/OpenPype/compare/3.15.3...3.15.4) + +### **🆕 New features** + + +
+Maya: Cant assign shaders to the ass file - OP-4859 #4460 + +Support AiStandIn nodes for look assignment. + +Using operators we assign shaders and attribute/parameters to nodes within standins. Initially there is only support for a limited mount of attributes but we can add support as needed; +``` +primaryVisibility +castsShadows +receiveShadows +aiSelfShadows +aiOpaque +aiMatte +aiVisibleInDiffuseTransmission +aiVisibleInSpecularTransmission +aiVisibleInVolume +aiVisibleInDiffuseReflection +aiVisibleInSpecularReflection +aiSubdivUvSmoothing +aiDispHeight +aiDispPadding +aiDispZeroValue +aiStepSize +aiVolumePadding +aiSubdivType +aiSubdivIterations +``` + + +___ + +
+ + +
+Maya: GPU cache representation #4649 + +Implement GPU cache for model, animation and pointcache. + + +___ + +
+ + +
+Houdini: Implement review family with opengl node #3839 + +Implements a first pass for Reviews publishing in Houdini. Resolves #2720 + +Uses the `opengl` ROP node to produce PNG images. + + +___ + +
+ + +
+Maya: Camera focal length visible in review - OP-3278 #4531 + +Camera focal length visible in review. + +Support camera focal length in review; static and dynamic.Resolves #3220 + + +___ + +
+ + +
+Maya: Defining plugins to load on Maya start - OP-4994 #4714 + +Feature to define plugins to load on Maya launch. + + +___ + +
+ + +
+Nuke, DL: Returning Suspended Publishing attribute #4715 + +Old Nuke Publisher's feature for suspended publishing job on render farm was added back to the current Publisher. + + +___ + +
+ + +
+Settings UI: Allow setting a size hint for text fields #4821 + +Text entity have `minimum_lines_count` which allows to change minimum size hint of UI input. + + +___ + +
+ + +
+TrayPublisher: Move 'BatchMovieCreator' settings to 'create' subcategory #4827 + +Moved settings for `BatchMoviewCreator` into subcategory `create` in settings. Changes are made to match other hosts settings chema and structure. + + +___ + +
+ +### **🚀 Enhancements** + + +
+Maya looks: support for native Redshift texture format #2971 + +Add support for native Redshift textures handling. Closes #2599 + +Uses Redshift's Texture Processor executable to convert textures being used in renders to the Redshift ".rstexbin" format. + + +___ + +
+ + +
+Maya: custom namespace for references #4511 + +Adding an option in Project Settings > Maya > Loader plugins to set custom namespace. If no namespace is set, the default one is used. + + +___ + +
+ + +
+Maya: Set correct framerange with handles on file opening #4664 + +Set the range of playback from the asset data, counting handles, to get the correct data when calling the "collect_animation_data" function. + + +___ + +
+ + +
+Maya: Fix camera update #4751 + +Fix resetting any modelPanel to a different camera when loading a camera and updating. + + +___ + +
+ + +
+Maya: Remove single assembly validation for animation instances #4840 + +Rig groups may now be parented to others groups when `includeParentHierarchy` attribute on the instance is "off". + + +___ + +
+ + +
+Maya: Optional control of display lights on playblast. #4145 + +Optional control of display lights on playblast. + +Giving control to what display lights are on the playblasts. + + +___ + +
+ + +
+Kitsu: note family requirements #4551 + +Allowing to add family requirements to `IntegrateKitsuNote` task status change. + +Adds a `Family requirements` setting to `Integrate Kitsu Note`, so you can add requirements to determine if kitsu task status should be changed based on which families are published or not. For instance you could have the status change only if another subset than workfile is published (but workfile can still be included) by adding an item set to `Not equal` and `workfile`. + + +___ + +
+ + +
+Deactivate closed Kitsu projects on OP #4619 + +Deactivate project on OP when the project is closed on Kitsu. + + +___ + +
+ + +
+Maya: Suggestion to change capture labels. #4691 + +Change capture labels. + + +___ + +
+ + +
+Houdini: Change node type for OpenPypeContext `null` -> `subnet` #4745 + +Change the node type for OpenPype's hidden context node in Houdini from `null` to `subnet`. This fixes #4734 + + +___ + +
+ + +
+General: Extract burnin hosts filters #4749 + +Removed hosts filter from ExtractBurnin plugin. Instance without representations won't cause crash but just skip the instance. We've discovered because Blender already has review but did not create burnins. + + +___ + +
+ + +
+Global: Improve speed of Collect Custom Staging Directory #4768 + +Improve speed of Collect Custom Staging Directory. + + +___ + +
+ + +
+General: Anatomy templates formatting #4773 + +Added option to format only single template from anatomy instead of formatting all of them all the time. Formatting of all templates is causing slowdowns e.g. during publishing of hundreds of instances. + + +___ + +
+ + +
+Harmony: Handle zip files with deeper structure #4782 + +External Harmony zip files might contain one additional level with scene name. + + +___ + +
+ + +
+Unreal: Use common logic to configure executable #4788 + +Unreal Editor location and version was autodetected. This easied configuration in some cases but was not flexible enought. This PR is changing the way Unreal Editor location is set, unifying it with the logic other hosts are using. + + +___ + +
+ + +
+Github: Grammar tweaks + uppercase issue title #4813 + +Tweak some of the grammar in the issue form templates. + + +___ + +
+ + +
+Houdini: Allow creation of publish instances via Houdini TAB menu #4831 + +Register the available Creator's as houdini tools so an artist can add publish instances via the Houdini TAB node search menu from within the network editor. + + +___ + +
+ +### **🐛 Bug fixes** + + +
+Maya: Fix Collect Render for V-Ray, Redshift and Renderman for missing colorspace #4650 + +Fix Collect Render not working for Redshift, V-Ray and Renderman due to missing `colorspace` argument to `RenderProduct` dataclass. + + +___ + +
+ + +
+Maya: Xgen fixes #4707 + +Fix for Xgen extraction of world parented nodes and validation for required namespace. + + +___ + +
+ + +
+Maya: Fix extract review and thumbnail for Maya 2020 #4744 + +Fix playblasting in Maya 2020 with override viewport options enabled. Fixes #4730. + + +___ + +
+ + +
+Maya: local variable 'arnold_standins' referenced before assignment - OP-5542 #4778 + +MayaLookAssigner erroring when MTOA is not loaded: +``` +# Traceback (most recent call last): +# File "\openpype\hosts\maya\tools\mayalookassigner\app.py", line 272, in on_process_selected +# nodes = list(set(item["nodes"]).difference(arnold_standins)) +# UnboundLocalError: local variable 'arnold_standins' referenced before assignment +``` + + +___ + +
+ + +
+Maya: Fix getting view and display in Maya 2020 - OP-5035 #4795 + +The `view_transform` returns a different format in Maya 2020. Fixes #4540 (hopefully). + + +___ + +
+ + +
+Maya: Fix Look Maya 2020 Py2 support for Extract Look #4808 + +Fix Extract Look supporting python 2.7 for Maya 2020. + + +___ + +
+ + +
+Maya: Fix Validate Mesh Overlapping UVs plugin #4816 + +Fix typo in the code where a maya command returns a `list` instead of `str`. + + +___ + +
+ + +
+Maya: Fix tile rendering with Vray - OP-5566 #4832 + +Fixes tile rendering with Vray. + + +___ + +
+ + +
+Deadline: checking existing frames fails when there is number in file name #4698 + +Previous implementation of validator failed on files with any other number in rendered file names.Used regular expression pattern now handles numbers in the file names (eg "Main_beauty.v001.1001.exr", "Main_beauty_v001.1001.exr", "Main_beauty.1001.1001.exr") but not numbers behind frames (eg. "Main_beauty.1001.v001.exr") + + +___ + +
+ + +
+Maya: Validate Render Settings. #4735 + +Fixes error message when using attribute validation. + + +___ + +
+ + +
+General: Hero version sites recalculation #4737 + +Sites recalculation in integrate hero version did expect that it is integrated exactly same amount of files as in previous integration. This is not the case in many cases, so the sites recalculation happens in a different way, first are prepared all sites from previous representation files, and all of them are added to each file in new representation. + + +___ + +
+ + +
+Houdini: Fix collect current file #4739 + +Fixes the Workfile publishing getting added into every instance being published from Houdini + + +___ + +
+ + +
+Global: Fix Extract Burnin + Colorspace functions for conflicting python environments with PYTHONHOME #4740 + +This fixes the running of openpype processes from e.g. a host with conflicting python versions that had `PYTHONHOME` said additionally to `PYTHONPATH`, like e.g. Houdini Py3.7 together with OpenPype Py3.9 when using Extract Burnin for a review in #3839This fix applies to Extract Burnin and some of the colorspace functions that use `run_openpype_process` + + +___ + +
+ + +
+Harmony: render what is in timeline in Harmony locally #4741 + +Previously it wasn't possible to render according to what was set in Timeline in scene start/end, just by what it was set in whole timeline.This allows artist to override what is in DB with what they require (with disabled `Validate Scene Settings`). Now artist can extend scene by additional frames, that shouldn't be rendered, but which might be desired.Removed explicit set scene settings (eg. applying frames and resolution directly to the scene after launch), added separate menu item to allow artist to do it themselves. + + +___ + +
+ + +
+Maya: Extract Review settings add Use Background Gradient #4747 + +Add Display Gradient Background toggle in settings to fix support for setting flat background color for reviews. + + +___ + +
+ + +
+Nuke: publisher is offering review on write families on demand #4755 + +Original idea where reviewable toggle will be offered in publisher on demand is fixed and now `review` attribute can be disabled in settings. + + +___ + +
+ + +
+Workfiles: keep Browse always enabled #4766 + +Browse might make sense even if there are no workfiles present, actually in that case it makes the most sense (eg. I want to locate workfile from outside - from Desktop for example). + + +___ + +
+ + +
+Global: label key in instance data is optional #4779 + +Collect OTIO review plugin is not crashing if `label` key is missing in instance data. + + +___ + +
+ + +
+Loader: Fix missing variable #4781 + +There is missing variable `handles` in loader tool after https://github.com/ynput/OpenPype/pull/4746. The variable was renamed to `handles_label` and is initialized to `None` if handles are not available. + + +___ + +
+ + +
+Nuke: Workfile Template builder fixes #4783 + +Popup window after Nuke start is not showing. Knobs with X/Y coordination on nodes where were converted from placeholders are not added if `keepPlaceholders` is witched off. + + +___ + +
+ + +
+Maya: Add family filter 'review' to burnin profile with focal length #4791 + +Avoid profile burnin with `focalLength` key for renders, but use only for playblast reviews. + + +___ + +
+ + +
+add farm instance to the render collector in 3dsMax #4794 + +bug fix for the failure of submitting publish job in 3dsmax + + +___ + +
+ + +
+Publisher: Plugin active attribute is respected #4798 + +Publisher consider plugin's `active` attribute, so the plugin is not processed when `active` is set to `False`. But we use the attribute in `OptionalPyblishPluginMixin` for different purposes, so I've added hack bypass of the active state validation when plugin inherit from the mixin. This is temporary solution which cannot be changed until all hosts use Publisher otherwise global plugins would be broken. Also plugins which have `enabled` set to `False` are filtered out -> this happened only when automated settings were applied and the settings contained `"enabled"` key se to `False`. + + +___ + +
+ + +
+Nuke: settings and optional attribute in publisher for some validators #4811 + +New publisher is supporting optional switch for plugins which is offered in Publisher in Right panel. Some plugins were missing this switch and also settings which would offer the optionality. + + +___ + +
+ + +
+Settings: Version settings popup fix #4822 + +Version completer popup have issues on some platforms, this should fix those edge cases. Also fixed issue when completer stayed shown fater reset (save). + + +___ + +
+ + +
+Hiero/Nuke: adding monitorOut key to settings #4826 + +New versions of Hiero were introduced with new colorspace property for Monitor Out. It have been added into project settings. Also added new config names into settings enumerator option. + + +___ + +
+ + +
+Nuke: removed default workfile template builder preset #4835 + +Default for workfile template builder should have been empty. + + +___ + +
+ + +
+TVPaint: Review can be made from any instance #4843 + +Add `"review"` tag to output of extract sequence if instance is marked for review. At this moment only instances with family `"review"` were able to define input for `ExtractReview` plugin which is not right. + + +___ + +
+ +### **🔀 Refactored code** + + +
+Deadline: Remove unused FramesPerTask job info submission #4657 + +Remove unused `FramesPerTask` job info submission to Deadline. + + +___ + +
+ + +
+Maya: Remove pymel dependency #4724 + +Refactors code written using `pymel` to use standard maya python libraries instead like `maya.cmds` or `maya.api.OpenMaya` + + +___ + +
+ + +
+Remove "preview" data from representation #4759 + +Remove "preview" data from representation + + +___ + +
+ + +
+Maya: Collect Review cleanup code for attached subsets #4720 + +Refactor some code for Maya: Collect Review for attached subsets. + + +___ + +
+ + +
+Refactor: Remove `handles`, `edit_in` and `edit_out` backwards compatibility #4746 + +Removes backward compatibiliy fallback for data called `handles`, `edit_in` and `edit_out`. + + +___ + +
+ +### **📃 Documentation** + + +
+Bump webpack from 5.69.1 to 5.76.1 in /website #4624 + +Bumps [webpack](https://github.com/webpack/webpack) from 5.69.1 to 5.76.1. +
+Release notes +

Sourced from webpack's releases.

+
+

v5.76.1

+

Fixed

+
    +
  • Added assert/strict built-in to NodeTargetPlugin
  • +
+

Revert

+ +

v5.76.0

+

Bugfixes

+ +

Features

+ +

Security

+ +

Repo Changes

+ +

New Contributors

+ +

Full Changelog: https://github.com/webpack/webpack/compare/v5.75.0...v5.76.0

+

v5.75.0

+

Bugfixes

+
    +
  • experiments.* normalize to false when opt-out
  • +
  • avoid NaN%
  • +
  • show the correct error when using a conflicting chunk name in code
  • +
  • HMR code tests existance of window before trying to access it
  • +
  • fix eval-nosources-* actually exclude sources
  • +
  • fix race condition where no module is returned from processing module
  • +
  • fix position of standalong semicolon in runtime code
  • +
+

Features

+
    +
  • add support for @import to extenal CSS when using experimental CSS in node
  • +
+ +
+

... (truncated)

+
+
+Commits +
    +
  • 21be52b Merge pull request #16804 from webpack/chore-patch-release
  • +
  • 1cce945 chore(release): 5.76.1
  • +
  • e76ad9e Merge pull request #16803 from ryanwilsonperkin/revert-16759-real-content-has...
  • +
  • 52b1b0e Revert "Improve performance of hashRegExp lookup"
  • +
  • c989143 Merge pull request #16766 from piranna/patch-1
  • +
  • 710eaf4 Merge pull request #16789 from dmichon-msft/contenthash-hashsalt
  • +
  • 5d64468 Merge pull request #16792 from webpack/update-version
  • +
  • 67af5ec chore(release): 5.76.0
  • +
  • 97b1718 Merge pull request #16781 from askoufis/loader-context-target-type
  • +
  • b84efe6 Merge pull request #16759 from ryanwilsonperkin/real-content-hash-regex-perf
  • +
  • Additional commits viewable in compare view
  • +
+
+
+Maintainer changes +

This version was pushed to npm by evilebottnawi, a new releaser for webpack since your current version.

+
+
+ + +[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=webpack&package-manager=npm_and_yarn&previous-version=5.69.1&new-version=5.76.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) + +Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. + +[//]: # (dependabot-automerge-start) +[//]: # (dependabot-automerge-end) + +--- + +
+Dependabot commands and options +
+ +You can trigger Dependabot actions by commenting on this PR: +- `@dependabot rebase` will rebase this PR +- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it +- `@dependabot merge` will merge this PR after your CI passes on it +- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it +- `@dependabot cancel merge` will cancel a previously requested merge and block automerging +- `@dependabot reopen` will reopen this PR if it is closed +- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually +- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) +- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) +- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) +- `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language +- `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language +- `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language +- `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language + +You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/ynput/OpenPype/network/alerts). + +
+___ + +
+ + +
+Documentation: Add Extract Burnin documentation #4765 + +Add documentation for Extract Burnin global plugin settings. + + +___ + +
+ + +
+Documentation: Move publisher related tips to publisher area #4772 + +Move publisher related tips for After Effects artist documentation to the correct position. + + +___ + +
+ + +
+Documentation: Add extra terminology to the key concepts glossary #4838 + +Tweak some of the key concepts in the documentation. + + +___ + +
+ +### **Merged pull requests** + + +
+Maya: Refactor Extract Look with dedicated processors for maketx #4711 + +Refactor Maya extract look to fix some issues: +- [x] Allow Extraction with maketx with OCIO Color Management enabled in Maya. +- [x] Fix file hashing so it includes arguments to maketx, so that when arguments change it correctly generates a new hash +- [x] Fix maketx destination colorspace when OCIO is enabled +- [x] Use pre-collected colorspaces of the resources instead of trying to retrieve again in Extract Look +- [x] Fix colorspace attributes being reinterpreted by maya on export (fix remapping) - goal is to resolve #2337 +- [x] Fix support for checking config path of maya default OCIO config (due to using `lib.get_color_management_preferences` which remaps that path) +- [x] Merged in #2971 to refactor MakeTX into TextureProcessor and also support generating Redshift `.rstexbin` files. - goal is to resolve #2599 +- [x] Allow custom arguments to `maketx` from OpenPype Settings like mentioned here by @fabiaserra for arguments like: `--monochrome-detect`, `--opaque-detect`, `--checknan`. +- [x] Actually fix the code and make it work. :) (I'll try to keep below checkboxes in sync with my code changes) +- [x] Publishing without texture processor should work (no maketx + no rstexbin) +- [x] Publishing with maketx should work +- [x] Publishing with rstexbin should work +- [x] Test it. (This is just me doing some test-runs, please still test the PR!) + + +___ + +
+ + +
+Maya template builder load all assets linked to the shot #4761 + +Problem +All the assets of the ftrack project are loaded and not those linked to the shot + +How get error +Open maya in the context of shot, then build a new scene with the "Build Workfile from template" button in "OpenPype" menu. +![image](https://user-images.githubusercontent.com/7068597/229124652-573a23d7-a2b2-4d50-81bf-7592c00d24dc.png) + + +___ + +
+ + +
+Global: Do not force instance data with frame ranges of the asset #4383 + +This aims to resolve #4317 + + +___ + +
+ + +
+Cosmetics: Fix some grammar in docstrings and messages (and some code) #4752 + +Tweak some grammar in codebase + + +___ + +
+ + +
+Deadline: Submit publish job fails due root work hardcode - OP-5528 #4775 + +Generating config templates was hardcoded to `root[work]`. This PR fixes that. + + +___ + +
+ + +
+CreateContext: Added option to remove Unknown attributes #4776 + +Added option to remove attributes with UnkownAttrDef on instances. Pop of key will also remove the attribute definition from attribute values, so they're not recreated again. + + +___ + +
+ + + ## [3.15.3](https://github.com/ynput/OpenPype/tree/3.15.3) diff --git a/openpype/version.py b/openpype/version.py index d9e29d691e..1d41f1aa5d 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.15.4-nightly.3" +__version__ = "3.15.4" diff --git a/pyproject.toml b/pyproject.toml index 42ce5aa32c..b97ad8923c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.15.3" # OpenPype +version = "3.15.4" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From fcffb919486dfdef7474ccf5aefd264f34c7a8f2 Mon Sep 17 00:00:00 2001 From: Thomas Fricard <51854004+friquette@users.noreply.github.com> Date: Fri, 14 Apr 2023 17:39:53 +0200 Subject: [PATCH 101/106] After Effects: fix handles KeyError (#4727) * get handles from context if not in asset * fix linting errors * get frameStart, frameEnd, handleStart and handleEnd from context --------- Co-authored-by: clement hector Co-authored-by: Thomas Fricard --- .../aftereffects/plugins/publish/collect_workfile.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py b/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py index 3c5013b3bd..c21c3623c3 100644 --- a/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py +++ b/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py @@ -53,10 +53,10 @@ class CollectWorkfile(pyblish.api.ContextPlugin): "active": True, "asset": asset_entity["name"], "task": task, - "frameStart": asset_entity["data"]["frameStart"], - "frameEnd": asset_entity["data"]["frameEnd"], - "handleStart": asset_entity["data"]["handleStart"], - "handleEnd": asset_entity["data"]["handleEnd"], + "frameStart": context.data['frameStart'], + "frameEnd": context.data['frameEnd'], + "handleStart": context.data['handleStart'], + "handleEnd": context.data['handleEnd'], "fps": asset_entity["data"]["fps"], "resolutionWidth": asset_entity["data"].get( "resolutionWidth", From ef55dd932d57694d5e872a3f6a9fe4f0cb77370b Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Mon, 17 Apr 2023 13:00:01 +0200 Subject: [PATCH 102/106] :art: move startup script logic to hook --- .../hosts/max/hooks/force_startup_script.py | 24 +++++++++++++++++++ .../system_settings/applications.json | 4 +--- 2 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 openpype/hosts/max/hooks/force_startup_script.py diff --git a/openpype/hosts/max/hooks/force_startup_script.py b/openpype/hosts/max/hooks/force_startup_script.py new file mode 100644 index 0000000000..4fcf4fef21 --- /dev/null +++ b/openpype/hosts/max/hooks/force_startup_script.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +"""Pre-launch to force 3ds max startup script.""" +from openpype.lib import PreLaunchHook +import os + + +class ForceStartupScript(PreLaunchHook): + """Inject OpenPype environment to 3ds max. + + Note that this works in combination whit 3dsmax startup script that + is translating it back to PYTHONPATH for cases when 3dsmax drops PYTHONPATH + environment. + + Hook `GlobalHostDataHook` must be executed before this hook. + """ + app_groups = ["3dsmax"] + order = 11 + + def execute(self): + startup_args = [ + "-U", + "MAXScript", + f"{os.getenv('OPENPYPE_ROOT')}\\openpype\\hosts\\max\\startup\\startup.ms"] # noqa + self.launch_context.launch_args.append(startup_args) diff --git a/openpype/settings/defaults/system_settings/applications.json b/openpype/settings/defaults/system_settings/applications.json index d25e21a66e..6a0fb45698 100644 --- a/openpype/settings/defaults/system_settings/applications.json +++ b/openpype/settings/defaults/system_settings/applications.json @@ -133,9 +133,7 @@ "linux": [] }, "arguments": { - "windows": [ - "-U MAXScript {OPENPYPE_ROOT}\\openpype\\hosts\\max\\startup\\startup.ms" - ], + "windows": [], "darwin": [], "linux": [] }, From f7026c46948b22128ea43a3bf3a6558fa3215453 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Mon, 17 Apr 2023 13:06:07 +0200 Subject: [PATCH 103/106] :recycle: delete ADSK_3DSMAX_STARTUPSCRIPTS_ADDON_DIR --- openpype/settings/defaults/system_settings/applications.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/settings/defaults/system_settings/applications.json b/openpype/settings/defaults/system_settings/applications.json index 6a0fb45698..df5b5e07c6 100644 --- a/openpype/settings/defaults/system_settings/applications.json +++ b/openpype/settings/defaults/system_settings/applications.json @@ -119,9 +119,7 @@ "label": "3ds max", "icon": "{}/app_icons/3dsmax.png", "host_name": "max", - "environment": { - "ADSK_3DSMAX_STARTUPSCRIPTS_ADDON_DIR": "{OPENPYPE_ROOT}\\openpype\\hosts\\max\\startup" - }, + "environment": {}, "variants": { "2023": { "use_python_2": false, From b05afaa8371d211d20431e4d4b245807438ef784 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 17 Apr 2023 14:53:15 +0200 Subject: [PATCH 104/106] Global: Optimize anatomy formatting by only formatting used templates instead (#4784) * TemplatesDict can create different type of template * anatomy templates can be formatted on their own * return objected templates on get item * '_rootless_path' is public classmethod 'rootless_path_from_result' * 'AnatomyStringTemplate' expect anatomy templates * remove key getters * fix typo 'create_ojected_templates' -> 'create_objected_templates' * Fix type of argument * Fix long line * Optimize formatting to use single template formatting instead of formatting full anatomy * Optimize formatting to use single template formatting instead of formatting full anatomy * Optimize formatting to use single template formatting instead of formatting full anatomy * Optimize formatting to use single template formatting instead of formatting full anatomy * Optimize formatting to use single template formatting instead of formatting full anatomy * Optimize formatting to use single template formatting instead of formatting full anatomy * Optimize formatting to use single template formatting instead of formatting full anatomy * Use format strict + code cosmetics * Get template from the formatted data * Update openpype/plugins/publish/integrate_legacy.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> * Cosmetics * Move template obj definition for path up + rename to `path_template_obj` * Refactor more cases from `anatomy.format` to template obj `.format_strict` * Refactor more cases from `anatomy.format` to template obj `.format_strict` * Refactor more cases from `anatomy.format` to template obj `.format_strict` --------- Co-authored-by: Jakub Trllo Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../avalon_uri_processor.py | 4 +-- .../publish/extract_workfile_location.py | 5 ++-- .../unreal/hooks/pre_workfile_preparation.py | 4 +-- openpype/lib/usdlib.py | 4 +-- .../deadline/abstract_submit_deadline.py | 4 +-- .../plugins/publish/submit_publish_job.py | 12 ++++---- openpype/pipeline/context_tools.py | 7 +++-- openpype/pipeline/delivery.py | 20 ++++++------- openpype/pipeline/workfile/path_resolving.py | 4 +-- .../plugins/publish/collect_resources_path.py | 12 ++++---- openpype/plugins/publish/integrate.py | 22 ++++++-------- .../plugins/publish/integrate_hero_version.py | 30 +++++++++---------- openpype/plugins/publish/integrate_legacy.py | 13 ++++---- .../plugins/publish/integrate_thumbnail.py | 6 ++-- .../push_to_project/control_integrate.py | 4 +-- openpype/tools/texture_copy/app.py | 4 +-- openpype/tools/workfiles/save_as_dialog.py | 8 ++--- 17 files changed, 79 insertions(+), 84 deletions(-) diff --git a/openpype/hosts/houdini/vendor/husdoutputprocessors/avalon_uri_processor.py b/openpype/hosts/houdini/vendor/husdoutputprocessors/avalon_uri_processor.py index d7d1c79d73..48019e0a82 100644 --- a/openpype/hosts/houdini/vendor/husdoutputprocessors/avalon_uri_processor.py +++ b/openpype/hosts/houdini/vendor/husdoutputprocessors/avalon_uri_processor.py @@ -128,14 +128,14 @@ class AvalonURIOutputProcessor(base.OutputProcessorBase): if not asset_doc: raise RuntimeError("Invalid asset name: '%s'" % asset) - formatted_anatomy = anatomy.format({ + template_obj = anatomy.templates_obj["publish"]["path"] + path = template_obj.format_strict({ "project": PROJECT, "asset": asset_doc["name"], "subset": subset, "representation": ext, "version": 0 # stub version zero }) - path = formatted_anatomy["publish"]["path"] # Remove the version folder subset_folder = os.path.dirname(os.path.dirname(path)) diff --git a/openpype/hosts/standalonepublisher/plugins/publish/extract_workfile_location.py b/openpype/hosts/standalonepublisher/plugins/publish/extract_workfile_location.py index 18bf0394ae..9ff84e32fb 100644 --- a/openpype/hosts/standalonepublisher/plugins/publish/extract_workfile_location.py +++ b/openpype/hosts/standalonepublisher/plugins/publish/extract_workfile_location.py @@ -27,11 +27,12 @@ class ExtractWorkfileUrl(pyblish.api.ContextPlugin): rep_name = instance.data.get("representations")[0].get("name") template_data["representation"] = rep_name template_data["ext"] = rep_name - anatomy_filled = anatomy.format(template_data) - template_filled = anatomy_filled["publish"]["path"] + template_obj = anatomy.templates_obj["publish"]["path"] + template_filled = template_obj.format_strict(template_data) filepath = os.path.normpath(template_filled) self.log.info("Using published scene for render {}".format( filepath)) + break if not filepath: self.log.info("Texture batch doesn't contain workfile.") diff --git a/openpype/hosts/unreal/hooks/pre_workfile_preparation.py b/openpype/hosts/unreal/hooks/pre_workfile_preparation.py index 5dae7eef09..efbacc3b16 100644 --- a/openpype/hosts/unreal/hooks/pre_workfile_preparation.py +++ b/openpype/hosts/unreal/hooks/pre_workfile_preparation.py @@ -61,10 +61,10 @@ class UnrealPrelaunchHook(PreLaunchHook): project_name=project_doc["name"] ) # Fill templates - filled_anatomy = anatomy.format(workdir_data) + template_obj = anatomy.templates_obj[workfile_template_key]["file"] # Return filename - return filled_anatomy[workfile_template_key]["file"] + return template_obj.format_strict(workdir_data) def exec_plugin_install(self, engine_path: Path, env: dict = None): # set up the QThread and worker with necessary signals diff --git a/openpype/lib/usdlib.py b/openpype/lib/usdlib.py index 20703ee308..5ef1d38f87 100644 --- a/openpype/lib/usdlib.py +++ b/openpype/lib/usdlib.py @@ -327,7 +327,8 @@ def get_usd_master_path(asset, subset, representation): else: asset_doc = get_asset_by_name(project_name, asset, fields=["name"]) - formatted_result = anatomy.format( + template_obj = anatomy.templates_obj["publish"]["path"] + path = template_obj.format_strict( { "project": { "name": project_name, @@ -340,7 +341,6 @@ def get_usd_master_path(asset, subset, representation): } ) - path = formatted_result["publish"]["path"] # Remove the version folder subset_folder = os.path.dirname(os.path.dirname(path)) master_folder = os.path.join(subset_folder, "master") diff --git a/openpype/modules/deadline/abstract_submit_deadline.py b/openpype/modules/deadline/abstract_submit_deadline.py index 648eb77007..558a637e4b 100644 --- a/openpype/modules/deadline/abstract_submit_deadline.py +++ b/openpype/modules/deadline/abstract_submit_deadline.py @@ -534,8 +534,8 @@ class AbstractSubmitDeadline(pyblish.api.InstancePlugin): template_data["comment"] = None anatomy = instance.context.data['anatomy'] - anatomy_filled = anatomy.format(template_data) - template_filled = anatomy_filled["publish"]["path"] + template_obj = anatomy.templates_obj["publish"]["path"] + template_filled = template_obj.format_strict(template_data) file_path = os.path.normpath(template_filled) self.log.info("Using published scene for render {}".format(file_path)) diff --git a/openpype/modules/deadline/plugins/publish/submit_publish_job.py b/openpype/modules/deadline/plugins/publish/submit_publish_job.py index 4765772bcf..f80bd40133 100644 --- a/openpype/modules/deadline/plugins/publish/submit_publish_job.py +++ b/openpype/modules/deadline/plugins/publish/submit_publish_job.py @@ -1202,10 +1202,11 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): template_data["family"] = "render" template_data["version"] = version - anatomy_filled = anatomy.format(template_data) - - if "folder" in anatomy.templates["render"]: - publish_folder = anatomy_filled["render"]["folder"] + render_templates = anatomy.templates_obj["render"] + if "folder" in render_templates: + publish_folder = render_templates["folder"].format_strict( + template_data + ) else: # solve deprecated situation when `folder` key is not underneath # `publish` anatomy @@ -1215,8 +1216,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): " key underneath `publish` (in global of for project `{}`)." ).format(project_name)) - file_path = anatomy_filled["render"]["path"] - # Directory + file_path = render_templates["path"].format_strict(template_data) publish_folder = os.path.dirname(file_path) return publish_folder diff --git a/openpype/pipeline/context_tools.py b/openpype/pipeline/context_tools.py index 6610fd7da7..dede2b8fce 100644 --- a/openpype/pipeline/context_tools.py +++ b/openpype/pipeline/context_tools.py @@ -463,9 +463,7 @@ def get_workdir_from_session(session=None, template_key=None): session = legacy_io.Session project_name = session["AVALON_PROJECT"] host_name = session["AVALON_APP"] - anatomy = Anatomy(project_name) template_data = get_template_data_from_session(session) - anatomy_filled = anatomy.format(template_data) if not template_key: task_type = template_data["task"]["type"] @@ -474,7 +472,10 @@ def get_workdir_from_session(session=None, template_key=None): host_name, project_name=project_name ) - path = anatomy_filled[template_key]["folder"] + + anatomy = Anatomy(project_name) + template_obj = anatomy.templates_obj[template_key]["folder"] + path = template_obj.format_strict(template_data) if path: path = os.path.normpath(path) return path diff --git a/openpype/pipeline/delivery.py b/openpype/pipeline/delivery.py index 8cf9a43aac..500f54040a 100644 --- a/openpype/pipeline/delivery.py +++ b/openpype/pipeline/delivery.py @@ -1,5 +1,6 @@ """Functions useful for delivery of published representations.""" import os +import copy import shutil import glob import clique @@ -146,12 +147,11 @@ def deliver_single_file( report_items["Source file was not found"].append(msg) return report_items, 0 - anatomy_filled = anatomy.format(anatomy_data) if format_dict: - template_result = anatomy_filled["delivery"][template_name] - delivery_path = template_result.rootless.format(**format_dict) - else: - delivery_path = anatomy_filled["delivery"][template_name] + anatomy_data = copy.deepcopy(anatomy_data) + anatomy_data["root"] = format_dict["root"] + template_obj = anatomy.templates_obj["delivery"][template_name] + delivery_path = template_obj.format_strict(anatomy_data) # Backwards compatibility when extension contained `.` delivery_path = delivery_path.replace("..", ".") @@ -269,14 +269,12 @@ def deliver_sequence( frame_indicator = "@####@" + anatomy_data = copy.deepcopy(anatomy_data) anatomy_data["frame"] = frame_indicator - anatomy_filled = anatomy.format(anatomy_data) - if format_dict: - template_result = anatomy_filled["delivery"][template_name] - delivery_path = template_result.rootless.format(**format_dict) - else: - delivery_path = anatomy_filled["delivery"][template_name] + anatomy_data["root"] = format_dict["root"] + template_obj = anatomy.templates_obj["delivery"][template_name] + delivery_path = template_obj.format_strict(anatomy_data) delivery_path = os.path.normpath(delivery_path.replace("\\", "/")) delivery_folder = os.path.dirname(delivery_path) diff --git a/openpype/pipeline/workfile/path_resolving.py b/openpype/pipeline/workfile/path_resolving.py index 801cb7223c..15689f4d99 100644 --- a/openpype/pipeline/workfile/path_resolving.py +++ b/openpype/pipeline/workfile/path_resolving.py @@ -132,9 +132,9 @@ def get_workdir_with_workdir_data( project_settings ) - anatomy_filled = anatomy.format(workdir_data) + template_obj = anatomy.templates_obj[template_key]["folder"] # Output is TemplateResult object which contain useful data - output = anatomy_filled[template_key]["folder"] + output = template_obj.format_strict(workdir_data) if output: return output.normalized() return output diff --git a/openpype/plugins/publish/collect_resources_path.py b/openpype/plugins/publish/collect_resources_path.py index 4a5f9f1cc2..f96dd0ae18 100644 --- a/openpype/plugins/publish/collect_resources_path.py +++ b/openpype/plugins/publish/collect_resources_path.py @@ -83,10 +83,11 @@ class CollectResourcesPath(pyblish.api.InstancePlugin): "hierarchy": instance.data["hierarchy"] }) - anatomy_filled = anatomy.format(template_data) - - if "folder" in anatomy.templates["publish"]: - publish_folder = anatomy_filled["publish"]["folder"] + publish_templates = anatomy.templates_obj["publish"] + if "folder" in publish_templates: + publish_folder = publish_templates["folder"].format_strict( + template_data + ) else: # solve deprecated situation when `folder` key is not underneath # `publish` anatomy @@ -95,8 +96,7 @@ class CollectResourcesPath(pyblish.api.InstancePlugin): " key underneath `publish` (in global of for project `{}`)." ).format(anatomy.project_name)) - file_path = anatomy_filled["publish"]["path"] - # Directory + file_path = publish_templates["path"].format_strict(template_data) publish_folder = os.path.dirname(file_path) publish_folder = os.path.normpath(publish_folder) diff --git a/openpype/plugins/publish/integrate.py b/openpype/plugins/publish/integrate.py index 07131ec3ae..65ce30412c 100644 --- a/openpype/plugins/publish/integrate.py +++ b/openpype/plugins/publish/integrate.py @@ -665,8 +665,7 @@ class IntegrateAsset(pyblish.api.InstancePlugin): # - template_data (Dict[str, Any]): source data used to fill template # - to add required data to 'repre_context' not used for # formatting - # - anatomy_filled (Dict[str, Any]): filled anatomy of last file - # - to fill 'publishDir' on instance.data -> not ideal + path_template_obj = anatomy.templates_obj[template_name]["path"] # Treat template with 'orignalBasename' in special way if "{originalBasename}" in template: @@ -700,8 +699,7 @@ class IntegrateAsset(pyblish.api.InstancePlugin): template_data["originalBasename"], _ = os.path.splitext( src_file_name) - anatomy_filled = anatomy.format(template_data) - dst = anatomy_filled[template_name]["path"] + dst = path_template_obj.format_strict(template_data) src = os.path.join(stagingdir, src_file_name) transfers.append((src, dst)) if repre_context is None: @@ -761,8 +759,9 @@ class IntegrateAsset(pyblish.api.InstancePlugin): template_data["udim"] = index else: template_data["frame"] = index - anatomy_filled = anatomy.format(template_data) - template_filled = anatomy_filled[template_name]["path"] + template_filled = path_template_obj.format_strict( + template_data + ) dst_filepaths.append(template_filled) if repre_context is None: self.log.debug( @@ -798,8 +797,7 @@ class IntegrateAsset(pyblish.api.InstancePlugin): if is_udim: template_data["udim"] = repre["udim"][0] # Construct destination filepath from template - anatomy_filled = anatomy.format(template_data) - template_filled = anatomy_filled[template_name]["path"] + template_filled = path_template_obj.format_strict(template_data) repre_context = template_filled.used_values dst = os.path.normpath(template_filled) @@ -810,11 +808,9 @@ class IntegrateAsset(pyblish.api.InstancePlugin): # todo: Are we sure the assumption each representation # ends up in the same folder is valid? if not instance.data.get("publishDir"): - instance.data["publishDir"] = ( - anatomy_filled - [template_name] - ["folder"] - ) + template_obj = anatomy.templates_obj[template_name]["folder"] + template_filled = template_obj.format_strict(template_data) + instance.data["publishDir"] = template_filled for key in self.db_representation_context_keys: # Also add these values to the context even if not used by the diff --git a/openpype/plugins/publish/integrate_hero_version.py b/openpype/plugins/publish/integrate_hero_version.py index 80141e88fe..b71207c24f 100644 --- a/openpype/plugins/publish/integrate_hero_version.py +++ b/openpype/plugins/publish/integrate_hero_version.py @@ -291,6 +291,7 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin): )) try: src_to_dst_file_paths = [] + path_template_obj = anatomy.templates_obj[template_key]["path"] for repre_info in published_repres.values(): # Skip if new repre does not have published repre files @@ -303,9 +304,7 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin): anatomy_data.pop("version", None) # Get filled path to repre context - anatomy_filled = anatomy.format(anatomy_data) - template_filled = anatomy_filled[template_key]["path"] - + template_filled = path_template_obj.format_strict(anatomy_data) repre_data = { "path": str(template_filled), "template": hero_template @@ -343,8 +342,9 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin): # Get head and tail for collection frame_splitter = "_-_FRAME_SPLIT_-_" anatomy_data["frame"] = frame_splitter - _anatomy_filled = anatomy.format(anatomy_data) - _template_filled = _anatomy_filled[template_key]["path"] + _template_filled = path_template_obj.format_strict( + anatomy_data + ) head, tail = _template_filled.split(frame_splitter) padding = int( anatomy.templates[template_key]["frame_padding"] @@ -520,24 +520,24 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin): }) if "folder" in anatomy.templates[template_key]: - anatomy_filled = anatomy.format(template_data) - publish_folder = anatomy_filled[template_key]["folder"] + template_obj = anatomy.templates_obj[template_key]["folder"] + publish_folder = template_obj.format_strict(template_data) else: # This is for cases of Deprecated anatomy without `folder` # TODO remove when all clients have solved this issue - template_data.update({ - "frame": "FRAME_TEMP", - "representation": "TEMP" - }) - anatomy_filled = anatomy.format(template_data) - # solve deprecated situation when `folder` key is not underneath - # `publish` anatomy self.log.warning(( "Deprecation warning: Anatomy does not have set `folder`" " key underneath `publish` (in global of for project `{}`)." ).format(anatomy.project_name)) + # solve deprecated situation when `folder` key is not underneath + # `publish` anatomy + template_data.update({ + "frame": "FRAME_TEMP", + "representation": "TEMP" + }) + template_obj = anatomy.templates_obj[template_key]["path"] + file_path = template_obj.format_strict(template_data) - file_path = anatomy_filled[template_key]["path"] # Directory publish_folder = os.path.dirname(file_path) diff --git a/openpype/plugins/publish/integrate_legacy.py b/openpype/plugins/publish/integrate_legacy.py index 3f1f6ad0c9..c67ce62bf6 100644 --- a/openpype/plugins/publish/integrate_legacy.py +++ b/openpype/plugins/publish/integrate_legacy.py @@ -480,8 +480,8 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): else: template_data["udim"] = src_padding_exp % i - anatomy_filled = anatomy.format(template_data) - template_filled = anatomy_filled[template_name]["path"] + template_obj = anatomy.templates_obj[template_name]["path"] + template_filled = template_obj.format_strict(template_data) if repre_context is None: repre_context = template_filled.used_values test_dest_files.append( @@ -587,8 +587,8 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): if repre.get("udim"): template_data["udim"] = repre["udim"][0] src = os.path.join(stagingdir, fname) - anatomy_filled = anatomy.format(template_data) - template_filled = anatomy_filled[template_name]["path"] + template_obj = anatomy.templates_obj[template_name]["path"] + template_filled = template_obj.format_strict(template_data) repre_context = template_filled.used_values dst = os.path.normpath(template_filled) @@ -600,9 +600,8 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): if not instance.data.get("publishDir"): instance.data["publishDir"] = ( - anatomy_filled - [template_name] - ["folder"] + anatomy.templates_obj[template_name]["folder"] + .format_strict(template_data) ) if repre.get("udim"): repre_context["udim"] = repre.get("udim") # store list diff --git a/openpype/plugins/publish/integrate_thumbnail.py b/openpype/plugins/publish/integrate_thumbnail.py index 809a1782e0..16cc47d432 100644 --- a/openpype/plugins/publish/integrate_thumbnail.py +++ b/openpype/plugins/publish/integrate_thumbnail.py @@ -271,9 +271,9 @@ class IntegrateThumbnails(pyblish.api.ContextPlugin): "thumbnail_type": "thumbnail" }) - anatomy_filled = anatomy.format(template_data) - thumbnail_template = anatomy.templates["publish"]["thumbnail"] - template_filled = anatomy_filled["publish"]["thumbnail"] + template_obj = anatomy.templates_obj["publish"]["thumbnail"] + template_filled = template_obj.format_strict(template_data) + thumbnail_template = template_filled.template dst_full_path = os.path.normpath(str(template_filled)) self.log.debug("Copying file .. {} -> {}".format( diff --git a/openpype/tools/push_to_project/control_integrate.py b/openpype/tools/push_to_project/control_integrate.py index bb95fdb26f..37a0512d59 100644 --- a/openpype/tools/push_to_project/control_integrate.py +++ b/openpype/tools/push_to_project/control_integrate.py @@ -1050,8 +1050,8 @@ class ProjectPushItemProcess: repre_format_data["ext"] = ext[1:] break - tmp_result = anatomy.format(formatting_data) - folder_path = tmp_result[template_name]["folder"] + template_obj = anatomy.templates_obj[template_name]["folder"] + folder_path = template_obj.format_strict(formatting_data) repre_context = folder_path.used_values folder_path_rootless = folder_path.rootless repre_filepaths = [] diff --git a/openpype/tools/texture_copy/app.py b/openpype/tools/texture_copy/app.py index a695bb8c4d..a5a9f7349a 100644 --- a/openpype/tools/texture_copy/app.py +++ b/openpype/tools/texture_copy/app.py @@ -47,8 +47,8 @@ class TextureCopy: "hierarchy": hierarchy } anatomy = Anatomy(project_name) - anatomy_filled = anatomy.format(template_data) - return anatomy_filled['texture']['path'] + template_obj = anatomy.templates_obj["texture"]["path"] + return template_obj.format_strict(template_data) def _get_version(self, path): versions = [0] diff --git a/openpype/tools/workfiles/save_as_dialog.py b/openpype/tools/workfiles/save_as_dialog.py index aa881e7946..9f1d1060da 100644 --- a/openpype/tools/workfiles/save_as_dialog.py +++ b/openpype/tools/workfiles/save_as_dialog.py @@ -60,8 +60,8 @@ class CommentMatcher(object): temp_data["version"] = "<>" temp_data["ext"] = "<>" - formatted = anatomy.format(temp_data) - fname_pattern = formatted[template_key]["file"] + template_obj = anatomy.templates_obj[template_key]["file"] + fname_pattern = template_obj.format_strict(temp_data) fname_pattern = re.escape(fname_pattern) # Replace comment and version with something we can match with regex @@ -375,8 +375,8 @@ class SaveAsDialog(QtWidgets.QDialog): data["ext"] = data["ext"].lstrip(".") - anatomy_filled = self.anatomy.format(data) - return anatomy_filled[self.template_key]["file"] + template_obj = self.anatomy.templates_obj[self.template_key]["file"] + return template_obj.format_strict(data) def refresh(self): extensions = list(self._extensions) From 9d8ed55ea5577aa3abbbad768573778f1e3cf03a Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Tue, 18 Apr 2023 11:07:07 +0100 Subject: [PATCH 105/106] Fix nested model instances. --- .../maya/plugins/publish/collect_review.py | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_review.py b/openpype/hosts/maya/plugins/publish/collect_review.py index fcb188734f..7ea91afdfc 100644 --- a/openpype/hosts/maya/plugins/publish/collect_review.py +++ b/openpype/hosts/maya/plugins/publish/collect_review.py @@ -36,6 +36,30 @@ class CollectReview(pyblish.api.InstancePlugin): context = instance.context objectset = context.data['objectsets'] + # Convert enum attribute index to string for Display Lights. + index = instance.data.get("displayLights", 0) + display_lights = lib.DISPLAY_LIGHTS_VALUES[index] + if display_lights == "project_settings": + settings = instance.context.data["project_settings"] + settings = settings["maya"]["publish"]["ExtractPlayblast"] + settings = settings["capture_preset"]["Viewport Options"] + display_lights = settings["displayLights"] + + # Collect camera focal length. + burninDataMembers = instance.data.get("burninDataMembers", {}) + if camera is not None: + attr = camera + ".focalLength" + if lib.get_attribute_input(attr): + start = instance.data["frameStart"] + end = instance.data["frameEnd"] + 1 + time_range = range(int(start), int(end)) + focal_length = [cmds.getAttr(attr, time=t) for t in time_range] + else: + focal_length = cmds.getAttr(attr) + + burninDataMembers["focalLength"] = focal_length + + # Account for nested instances like model. reviewable_subsets = list(set(members) & set(objectset)) if reviewable_subsets: if len(reviewable_subsets) > 1: @@ -77,6 +101,8 @@ class CollectReview(pyblish.api.InstancePlugin): data["isolate"] = instance.data["isolate"] data["panZoom"] = instance.data.get("panZoom", False) data["panel"] = instance.data["panel"] + data["displayLights"] = display_lights + data["burninDataMembers"] = burninDataMembers # The review instance must be active cmds.setAttr(str(instance) + '.active', 1) @@ -103,6 +129,8 @@ class CollectReview(pyblish.api.InstancePlugin): instance.data["frameStartHandle"] instance.data['frameEndFtrack'] = \ instance.data["frameEndHandle"] + instance.data["displayLights"] = display_lights + instance.data["burninDataMembers"] = burninDataMembers # make ftrack publishable instance.data.setdefault("families", []).append('ftrack') @@ -144,33 +172,3 @@ class CollectReview(pyblish.api.InstancePlugin): audio_data.append(get_audio_node_data(node)) instance.data["audio"] = audio_data - - # Convert enum attribute index to string. - index = instance.data.get("displayLights", 0) - display_lights = lib.DISPLAY_LIGHTS_VALUES[index] - if display_lights == "project_settings": - settings = instance.context.data["project_settings"] - settings = settings["maya"]["publish"]["ExtractPlayblast"] - settings = settings["capture_preset"]["Viewport Options"] - display_lights = settings["displayLights"] - instance.data["displayLights"] = display_lights - - # Collect focal length. - if camera is None: - return - - attr = camera + ".focalLength" - if lib.get_attribute_input(attr): - start = instance.data["frameStart"] - end = instance.data["frameEnd"] + 1 - focal_length = [ - cmds.getAttr(attr, time=t) for t in range(int(start), int(end)) - ] - else: - focal_length = cmds.getAttr(attr) - - key = "focalLength" - try: - instance.data["burninDataMembers"][key] = focal_length - except KeyError: - instance.data["burninDataMembers"] = {key: focal_length} From 38cc309d43613e78d94ee7e9bbf53b1044b713be Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Tue, 18 Apr 2023 11:34:35 +0100 Subject: [PATCH 106/106] Fix #4851 --- openpype/hosts/maya/plugins/publish/collect_review.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/maya/plugins/publish/collect_review.py b/openpype/hosts/maya/plugins/publish/collect_review.py index 7ea91afdfc..5c190a4a7b 100644 --- a/openpype/hosts/maya/plugins/publish/collect_review.py +++ b/openpype/hosts/maya/plugins/publish/collect_review.py @@ -92,6 +92,8 @@ class CollectReview(pyblish.api.InstancePlugin): data['frameEndFtrack'] = instance.data["frameEndHandle"] data['frameStartHandle'] = instance.data["frameStartHandle"] data['frameEndHandle'] = instance.data["frameEndHandle"] + data['handleStart'] = instance.data["handleStart"] + data['handleEnd'] = instance.data["handleEnd"] data["frameStart"] = instance.data["frameStart"] data["frameEnd"] = instance.data["frameEnd"] data['step'] = instance.data['step']