From 038cdfa80e84052f303bc7c0739c5986c0dc7b04 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 24 Oct 2023 19:34:56 +0800 Subject: [PATCH 1/6] allows users to enable custom attributes for abc depending on their preferences and supsended refresh for abc & obj extractor for optimization --- openpype/hosts/max/api/lib.py | 13 ++++++ .../hosts/max/plugins/create/create_camera.py | 18 ++++++++ .../hosts/max/plugins/create/create_model.py | 18 ++++++++ .../max/plugins/create/create_pointcache.py | 18 ++++++++ .../max/plugins/publish/extract_camera_abc.py | 39 ++++++++---------- .../max/plugins/publish/extract_camera_fbx.py | 3 -- .../plugins/publish/extract_max_scene_raw.py | 1 - .../max/plugins/publish/extract_model.py | 41 +++++++++---------- .../max/plugins/publish/extract_model_fbx.py | 4 -- .../max/plugins/publish/extract_model_obj.py | 27 ++++++------ .../max/plugins/publish/extract_pointcache.py | 37 ++++++++--------- 11 files changed, 134 insertions(+), 85 deletions(-) diff --git a/openpype/hosts/max/api/lib.py b/openpype/hosts/max/api/lib.py index 8b70b3ced7..f02e3372b0 100644 --- a/openpype/hosts/max/api/lib.py +++ b/openpype/hosts/max/api/lib.py @@ -497,3 +497,16 @@ def get_plugins() -> list: plugin_info_list.append(plugin_info) return plugin_info_list + + +@contextlib.contextmanager +def suspended_refresh(): + rt.disableSceneRedraw() + rt.suspendEditing() + + try: + yield + + finally: + rt.enableSceneRedraw() + rt.resumeEditing() diff --git a/openpype/hosts/max/plugins/create/create_camera.py b/openpype/hosts/max/plugins/create/create_camera.py index 804d629ec7..8277581d31 100644 --- a/openpype/hosts/max/plugins/create/create_camera.py +++ b/openpype/hosts/max/plugins/create/create_camera.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- """Creator plugin for creating camera.""" from openpype.hosts.max.api import plugin +from openpype.lib import BoolDef class CreateCamera(plugin.MaxCreator): @@ -9,3 +10,20 @@ class CreateCamera(plugin.MaxCreator): label = "Camera" family = "camera" icon = "gear" + + def create(self, subset_name, instance_data, pre_create_data): + instance_data["custom_attrs"] = pre_create_data.get( + "custom_attrs") + + super(CreateCamera, self).create( + subset_name, + instance_data, + pre_create_data) + + def get_pre_create_attr_defs(self): + attrs = super().get_pre_create_attr_defs() + return attrs + [ + BoolDef("custom_attrs", + label="Custom Attributes", + default=False), + ] diff --git a/openpype/hosts/max/plugins/create/create_model.py b/openpype/hosts/max/plugins/create/create_model.py index fc09d475ef..9c459a184e 100644 --- a/openpype/hosts/max/plugins/create/create_model.py +++ b/openpype/hosts/max/plugins/create/create_model.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- """Creator plugin for model.""" from openpype.hosts.max.api import plugin +from openpype.lib import BoolDef class CreateModel(plugin.MaxCreator): @@ -9,3 +10,20 @@ class CreateModel(plugin.MaxCreator): label = "Model" family = "model" icon = "gear" + + def create(self, subset_name, instance_data, pre_create_data): + instance_data["custom_attrs"] = pre_create_data.get( + "custom_attrs") + + super(CreateModel, self).create( + subset_name, + instance_data, + pre_create_data) + + def get_pre_create_attr_defs(self): + attrs = super().get_pre_create_attr_defs() + return attrs + [ + BoolDef("custom_attrs", + label="Custom Attributes", + default=False), + ] diff --git a/openpype/hosts/max/plugins/create/create_pointcache.py b/openpype/hosts/max/plugins/create/create_pointcache.py index c2d11f4c32..2790ceeefc 100644 --- a/openpype/hosts/max/plugins/create/create_pointcache.py +++ b/openpype/hosts/max/plugins/create/create_pointcache.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- """Creator plugin for creating pointcache alembics.""" from openpype.hosts.max.api import plugin +from openpype.lib import BoolDef class CreatePointCache(plugin.MaxCreator): @@ -9,3 +10,20 @@ class CreatePointCache(plugin.MaxCreator): label = "Point Cache" family = "pointcache" icon = "gear" + + def create(self, subset_name, instance_data, pre_create_data): + instance_data["custom_attrs"] = pre_create_data.get( + "custom_attrs") + + super(CreatePointCache, self).create( + subset_name, + instance_data, + pre_create_data) + + def get_pre_create_attr_defs(self): + attrs = super().get_pre_create_attr_defs() + return attrs + [ + BoolDef("custom_attrs", + label="Custom Attributes", + default=False), + ] diff --git a/openpype/hosts/max/plugins/publish/extract_camera_abc.py b/openpype/hosts/max/plugins/publish/extract_camera_abc.py index b1918c53e0..d7c2e6a557 100644 --- a/openpype/hosts/max/plugins/publish/extract_camera_abc.py +++ b/openpype/hosts/max/plugins/publish/extract_camera_abc.py @@ -4,6 +4,7 @@ import pyblish.api from pymxs import runtime as rt from openpype.hosts.max.api import maintained_selection +from openpype.hosts.max.api.lib import suspended_refresh from openpype.pipeline import OptionalPyblishPluginMixin, publish @@ -22,33 +23,29 @@ class ExtractCameraAlembic(publish.Extractor, OptionalPyblishPluginMixin): start = float(instance.data.get("frameStartHandle", 1)) end = float(instance.data.get("frameEndHandle", 1)) - self.log.info("Extracting Camera ...") - stagingdir = self.staging_dir(instance) filename = "{name}.abc".format(**instance.data) path = os.path.join(stagingdir, filename) - # We run the render - self.log.info(f"Writing alembic '{filename}' to '{stagingdir}'") + with suspended_refresh(): + rt.AlembicExport.ArchiveType = rt.Name("ogawa") + rt.AlembicExport.CoordinateSystem = rt.Name("maya") + rt.AlembicExport.StartFrame = start + rt.AlembicExport.EndFrame = end + rt.AlembicExport.CustomAttributes = instance.data.get( + "custom_attrs", False) - rt.AlembicExport.ArchiveType = rt.Name("ogawa") - rt.AlembicExport.CoordinateSystem = rt.Name("maya") - rt.AlembicExport.StartFrame = start - rt.AlembicExport.EndFrame = end - rt.AlembicExport.CustomAttributes = True + with maintained_selection(): + # select and export + node_list = instance.data["members"] + rt.Select(node_list) + rt.ExportFile( + path, + rt.Name("noPrompt"), + selectedOnly=True, + using=rt.AlembicExport, + ) - with maintained_selection(): - # select and export - node_list = instance.data["members"] - rt.Select(node_list) - rt.ExportFile( - path, - rt.Name("noPrompt"), - selectedOnly=True, - using=rt.AlembicExport, - ) - - self.log.info("Performing Extraction ...") if "representations" not in instance.data: instance.data["representations"] = [] diff --git a/openpype/hosts/max/plugins/publish/extract_camera_fbx.py b/openpype/hosts/max/plugins/publish/extract_camera_fbx.py index 537c88eb4d..4b5631b05f 100644 --- a/openpype/hosts/max/plugins/publish/extract_camera_fbx.py +++ b/openpype/hosts/max/plugins/publish/extract_camera_fbx.py @@ -20,13 +20,10 @@ class ExtractCameraFbx(publish.Extractor, OptionalPyblishPluginMixin): if not self.is_active(instance.data): return - self.log.debug("Extracting Camera ...") stagingdir = self.staging_dir(instance) filename = "{name}.fbx".format(**instance.data) filepath = os.path.join(stagingdir, filename) - self.log.info(f"Writing fbx file '{filename}' to '{filepath}'") - rt.FBXExporterSetParam("Animation", True) rt.FBXExporterSetParam("Cameras", True) rt.FBXExporterSetParam("AxisConversionMethod", "Animation") diff --git a/openpype/hosts/max/plugins/publish/extract_max_scene_raw.py b/openpype/hosts/max/plugins/publish/extract_max_scene_raw.py index a7a889c587..791cc65fcd 100644 --- a/openpype/hosts/max/plugins/publish/extract_max_scene_raw.py +++ b/openpype/hosts/max/plugins/publish/extract_max_scene_raw.py @@ -26,7 +26,6 @@ class ExtractMaxSceneRaw(publish.Extractor, OptionalPyblishPluginMixin): filename = "{name}.max".format(**instance.data) max_path = os.path.join(stagingdir, filename) - self.log.info("Writing max file '%s' to '%s'" % (filename, max_path)) if "representations" not in instance.data: instance.data["representations"] = [] diff --git a/openpype/hosts/max/plugins/publish/extract_model.py b/openpype/hosts/max/plugins/publish/extract_model.py index 38f4848c5e..36e789d180 100644 --- a/openpype/hosts/max/plugins/publish/extract_model.py +++ b/openpype/hosts/max/plugins/publish/extract_model.py @@ -3,6 +3,7 @@ import pyblish.api from openpype.pipeline import publish, OptionalPyblishPluginMixin from pymxs import runtime as rt from openpype.hosts.max.api import maintained_selection +from openpype.hosts.max.api.lib import suspended_refresh class ExtractModel(publish.Extractor, OptionalPyblishPluginMixin): @@ -20,34 +21,30 @@ class ExtractModel(publish.Extractor, OptionalPyblishPluginMixin): if not self.is_active(instance.data): return - self.log.debug("Extracting Geometry ...") - stagingdir = self.staging_dir(instance) filename = "{name}.abc".format(**instance.data) filepath = os.path.join(stagingdir, filename) - # We run the render - self.log.info("Writing alembic '%s' to '%s'" % (filename, stagingdir)) + with suspended_refresh(): + rt.AlembicExport.ArchiveType = rt.name("ogawa") + rt.AlembicExport.CoordinateSystem = rt.name("maya") + rt.AlembicExport.CustomAttributes = instance.data.get( + "custom_attrs", False) + rt.AlembicExport.UVs = True + rt.AlembicExport.VertexColors = True + rt.AlembicExport.PreserveInstances = True - rt.AlembicExport.ArchiveType = rt.name("ogawa") - rt.AlembicExport.CoordinateSystem = rt.name("maya") - rt.AlembicExport.CustomAttributes = True - rt.AlembicExport.UVs = True - rt.AlembicExport.VertexColors = True - rt.AlembicExport.PreserveInstances = True + with maintained_selection(): + # select and export + node_list = instance.data["members"] + rt.Select(node_list) + rt.exportFile( + filepath, + rt.name("noPrompt"), + selectedOnly=True, + using=rt.AlembicExport, + ) - with maintained_selection(): - # select and export - node_list = instance.data["members"] - rt.Select(node_list) - rt.exportFile( - filepath, - rt.name("noPrompt"), - selectedOnly=True, - using=rt.AlembicExport, - ) - - self.log.info("Performing Extraction ...") if "representations" not in instance.data: instance.data["representations"] = [] diff --git a/openpype/hosts/max/plugins/publish/extract_model_fbx.py b/openpype/hosts/max/plugins/publish/extract_model_fbx.py index fd48ed5007..6c42fd5364 100644 --- a/openpype/hosts/max/plugins/publish/extract_model_fbx.py +++ b/openpype/hosts/max/plugins/publish/extract_model_fbx.py @@ -20,12 +20,9 @@ class ExtractModelFbx(publish.Extractor, OptionalPyblishPluginMixin): if not self.is_active(instance.data): return - self.log.debug("Extracting Geometry ...") - stagingdir = self.staging_dir(instance) filename = "{name}.fbx".format(**instance.data) filepath = os.path.join(stagingdir, filename) - self.log.info("Writing FBX '%s' to '%s'" % (filepath, stagingdir)) rt.FBXExporterSetParam("Animation", False) rt.FBXExporterSetParam("Cameras", False) @@ -46,7 +43,6 @@ class ExtractModelFbx(publish.Extractor, OptionalPyblishPluginMixin): using=rt.FBXEXP, ) - self.log.info("Performing Extraction ...") if "representations" not in instance.data: instance.data["representations"] = [] diff --git a/openpype/hosts/max/plugins/publish/extract_model_obj.py b/openpype/hosts/max/plugins/publish/extract_model_obj.py index a5d9ad6597..8464353164 100644 --- a/openpype/hosts/max/plugins/publish/extract_model_obj.py +++ b/openpype/hosts/max/plugins/publish/extract_model_obj.py @@ -3,6 +3,7 @@ import pyblish.api from openpype.pipeline import publish, OptionalPyblishPluginMixin from pymxs import runtime as rt from openpype.hosts.max.api import maintained_selection +from openpype.hosts.max.api.lib import suspended_refresh from openpype.pipeline.publish import KnownPublishError @@ -21,25 +22,21 @@ class ExtractModelObj(publish.Extractor, OptionalPyblishPluginMixin): if not self.is_active(instance.data): return - self.log.debug("Extracting Geometry ...") - stagingdir = self.staging_dir(instance) filename = "{name}.obj".format(**instance.data) filepath = os.path.join(stagingdir, filename) - self.log.info("Writing OBJ '%s' to '%s'" % (filepath, stagingdir)) - - self.log.info("Performing Extraction ...") - with maintained_selection(): - # select and export - node_list = instance.data["members"] - rt.Select(node_list) - rt.exportFile( - filepath, - rt.name("noPrompt"), - selectedOnly=True, - using=rt.ObjExp, - ) + with suspended_refresh(): + with maintained_selection(): + # select and export + node_list = instance.data["members"] + rt.Select(node_list) + rt.exportFile( + filepath, + rt.name("noPrompt"), + selectedOnly=True, + using=rt.ObjExp, + ) if not os.path.exists(filepath): raise KnownPublishError( "File {} wasn't produced by 3ds max, please check the logs.") diff --git a/openpype/hosts/max/plugins/publish/extract_pointcache.py b/openpype/hosts/max/plugins/publish/extract_pointcache.py index c3de623bc0..71dc667d7e 100644 --- a/openpype/hosts/max/plugins/publish/extract_pointcache.py +++ b/openpype/hosts/max/plugins/publish/extract_pointcache.py @@ -42,6 +42,7 @@ import pyblish.api from openpype.pipeline import publish from pymxs import runtime as rt from openpype.hosts.max.api import maintained_selection +from openpype.hosts.max.api.lib import suspended_refresh class ExtractAlembic(publish.Extractor): @@ -54,30 +55,28 @@ class ExtractAlembic(publish.Extractor): start = float(instance.data.get("frameStartHandle", 1)) end = float(instance.data.get("frameEndHandle", 1)) - self.log.debug("Extracting pointcache ...") - parent_dir = self.staging_dir(instance) file_name = "{name}.abc".format(**instance.data) path = os.path.join(parent_dir, file_name) - # We run the render - self.log.info("Writing alembic '%s' to '%s'" % (file_name, parent_dir)) + with suspended_refresh(): + rt.AlembicExport.ArchiveType = rt.name("ogawa") + rt.AlembicExport.CoordinateSystem = rt.name("maya") + rt.AlembicExport.StartFrame = start + rt.AlembicExport.EndFrame = end + rt.AlembicExport.CustomAttributes = instance.data.get( + "custom_attrs", False) - rt.AlembicExport.ArchiveType = rt.name("ogawa") - rt.AlembicExport.CoordinateSystem = rt.name("maya") - rt.AlembicExport.StartFrame = start - rt.AlembicExport.EndFrame = end - - with maintained_selection(): - # select and export - node_list = instance.data["members"] - rt.Select(node_list) - rt.exportFile( - path, - rt.name("noPrompt"), - selectedOnly=True, - using=rt.AlembicExport, - ) + with maintained_selection(): + # select and export + node_list = instance.data["members"] + rt.Select(node_list) + rt.exportFile( + path, + rt.name("noPrompt"), + selectedOnly=True, + using=rt.AlembicExport, + ) if "representations" not in instance.data: instance.data["representations"] = [] From a320c30d437b59c0d2cd83c07e5b477f9cdb8291 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 24 Oct 2023 19:52:54 +0800 Subject: [PATCH 2/6] update docstring --- openpype/hosts/max/api/lib.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/max/api/lib.py b/openpype/hosts/max/api/lib.py index f02e3372b0..051076c418 100644 --- a/openpype/hosts/max/api/lib.py +++ b/openpype/hosts/max/api/lib.py @@ -501,6 +501,8 @@ def get_plugins() -> list: @contextlib.contextmanager def suspended_refresh(): + """Suspended refresh for scene and modify panel redraw. + """ rt.disableSceneRedraw() rt.suspendEditing() From 92bab3491afa798dfd646555286af1031b225e84 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 24 Oct 2023 21:44:36 +0800 Subject: [PATCH 3/6] add to check if the max is in headless mode for suspend refreshing and optimized the abc extractors --- openpype/hosts/max/api/lib.py | 4 +- .../hosts/max/plugins/create/create_camera.py | 18 ----- .../hosts/max/plugins/create/create_model.py | 18 ----- .../max/plugins/create/create_pointcache.py | 18 ----- .../max/plugins/publish/extract_camera_abc.py | 61 ---------------- .../max/plugins/publish/extract_model.py | 60 ---------------- .../max/plugins/publish/extract_pointcache.py | 70 ++++++++++++++++--- 7 files changed, 62 insertions(+), 187 deletions(-) delete mode 100644 openpype/hosts/max/plugins/publish/extract_camera_abc.py delete mode 100644 openpype/hosts/max/plugins/publish/extract_model.py diff --git a/openpype/hosts/max/api/lib.py b/openpype/hosts/max/api/lib.py index 0c0aa6ad2c..61a2d938a1 100644 --- a/openpype/hosts/max/api/lib.py +++ b/openpype/hosts/max/api/lib.py @@ -517,7 +517,9 @@ def suspended_refresh(): """ rt.disableSceneRedraw() rt.suspendEditing() - + if is_headless(): + yield + return try: yield diff --git a/openpype/hosts/max/plugins/create/create_camera.py b/openpype/hosts/max/plugins/create/create_camera.py index 8277581d31..804d629ec7 100644 --- a/openpype/hosts/max/plugins/create/create_camera.py +++ b/openpype/hosts/max/plugins/create/create_camera.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- """Creator plugin for creating camera.""" from openpype.hosts.max.api import plugin -from openpype.lib import BoolDef class CreateCamera(plugin.MaxCreator): @@ -10,20 +9,3 @@ class CreateCamera(plugin.MaxCreator): label = "Camera" family = "camera" icon = "gear" - - def create(self, subset_name, instance_data, pre_create_data): - instance_data["custom_attrs"] = pre_create_data.get( - "custom_attrs") - - super(CreateCamera, self).create( - subset_name, - instance_data, - pre_create_data) - - def get_pre_create_attr_defs(self): - attrs = super().get_pre_create_attr_defs() - return attrs + [ - BoolDef("custom_attrs", - label="Custom Attributes", - default=False), - ] diff --git a/openpype/hosts/max/plugins/create/create_model.py b/openpype/hosts/max/plugins/create/create_model.py index 9c459a184e..fc09d475ef 100644 --- a/openpype/hosts/max/plugins/create/create_model.py +++ b/openpype/hosts/max/plugins/create/create_model.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- """Creator plugin for model.""" from openpype.hosts.max.api import plugin -from openpype.lib import BoolDef class CreateModel(plugin.MaxCreator): @@ -10,20 +9,3 @@ class CreateModel(plugin.MaxCreator): label = "Model" family = "model" icon = "gear" - - def create(self, subset_name, instance_data, pre_create_data): - instance_data["custom_attrs"] = pre_create_data.get( - "custom_attrs") - - super(CreateModel, self).create( - subset_name, - instance_data, - pre_create_data) - - def get_pre_create_attr_defs(self): - attrs = super().get_pre_create_attr_defs() - return attrs + [ - BoolDef("custom_attrs", - label="Custom Attributes", - default=False), - ] diff --git a/openpype/hosts/max/plugins/create/create_pointcache.py b/openpype/hosts/max/plugins/create/create_pointcache.py index 2790ceeefc..c2d11f4c32 100644 --- a/openpype/hosts/max/plugins/create/create_pointcache.py +++ b/openpype/hosts/max/plugins/create/create_pointcache.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- """Creator plugin for creating pointcache alembics.""" from openpype.hosts.max.api import plugin -from openpype.lib import BoolDef class CreatePointCache(plugin.MaxCreator): @@ -10,20 +9,3 @@ class CreatePointCache(plugin.MaxCreator): label = "Point Cache" family = "pointcache" icon = "gear" - - def create(self, subset_name, instance_data, pre_create_data): - instance_data["custom_attrs"] = pre_create_data.get( - "custom_attrs") - - super(CreatePointCache, self).create( - subset_name, - instance_data, - pre_create_data) - - def get_pre_create_attr_defs(self): - attrs = super().get_pre_create_attr_defs() - return attrs + [ - BoolDef("custom_attrs", - label="Custom Attributes", - default=False), - ] diff --git a/openpype/hosts/max/plugins/publish/extract_camera_abc.py b/openpype/hosts/max/plugins/publish/extract_camera_abc.py deleted file mode 100644 index 934c6b9d99..0000000000 --- a/openpype/hosts/max/plugins/publish/extract_camera_abc.py +++ /dev/null @@ -1,61 +0,0 @@ -import os - -import pyblish.api -from pymxs import runtime as rt - -from openpype.hosts.max.api import maintained_selection -from openpype.hosts.max.api.lib import suspended_refresh -from openpype.pipeline import OptionalPyblishPluginMixin, publish - - -class ExtractCameraAlembic(publish.Extractor, OptionalPyblishPluginMixin): - """Extract Camera with AlembicExport.""" - - order = pyblish.api.ExtractorOrder - 0.1 - label = "Extract Alembic Camera" - hosts = ["max"] - families = ["camera"] - optional = True - - def process(self, instance): - if not self.is_active(instance.data): - return - start = instance.data["frameStartHandle"] - end = instance.data["frameEndHandle"] - - stagingdir = self.staging_dir(instance) - filename = "{name}.abc".format(**instance.data) - path = os.path.join(stagingdir, filename) - - with suspended_refresh(): - rt.AlembicExport.ArchiveType = rt.Name("ogawa") - rt.AlembicExport.CoordinateSystem = rt.Name("maya") - rt.AlembicExport.StartFrame = start - rt.AlembicExport.EndFrame = end - rt.AlembicExport.CustomAttributes = instance.data.get( - "custom_attrs", False) - - with maintained_selection(): - # select and export - node_list = instance.data["members"] - rt.Select(node_list) - rt.ExportFile( - path, - rt.Name("noPrompt"), - selectedOnly=True, - using=rt.AlembicExport, - ) - - if "representations" not in instance.data: - instance.data["representations"] = [] - - representation = { - "name": "abc", - "ext": "abc", - "files": filename, - "stagingDir": stagingdir, - "frameStart": start, - "frameEnd": end, - } - instance.data["representations"].append(representation) - self.log.info(f"Extracted instance '{instance.name}' to: {path}") diff --git a/openpype/hosts/max/plugins/publish/extract_model.py b/openpype/hosts/max/plugins/publish/extract_model.py deleted file mode 100644 index 36e789d180..0000000000 --- a/openpype/hosts/max/plugins/publish/extract_model.py +++ /dev/null @@ -1,60 +0,0 @@ -import os -import pyblish.api -from openpype.pipeline import publish, OptionalPyblishPluginMixin -from pymxs import runtime as rt -from openpype.hosts.max.api import maintained_selection -from openpype.hosts.max.api.lib import suspended_refresh - - -class ExtractModel(publish.Extractor, OptionalPyblishPluginMixin): - """ - Extract Geometry in Alembic Format - """ - - order = pyblish.api.ExtractorOrder - 0.1 - label = "Extract Geometry (Alembic)" - hosts = ["max"] - families = ["model"] - optional = True - - def process(self, instance): - if not self.is_active(instance.data): - return - - stagingdir = self.staging_dir(instance) - filename = "{name}.abc".format(**instance.data) - filepath = os.path.join(stagingdir, filename) - - with suspended_refresh(): - rt.AlembicExport.ArchiveType = rt.name("ogawa") - rt.AlembicExport.CoordinateSystem = rt.name("maya") - rt.AlembicExport.CustomAttributes = instance.data.get( - "custom_attrs", False) - rt.AlembicExport.UVs = True - rt.AlembicExport.VertexColors = True - rt.AlembicExport.PreserveInstances = True - - with maintained_selection(): - # select and export - node_list = instance.data["members"] - rt.Select(node_list) - rt.exportFile( - filepath, - rt.name("noPrompt"), - selectedOnly=True, - using=rt.AlembicExport, - ) - - if "representations" not in instance.data: - instance.data["representations"] = [] - - representation = { - "name": "abc", - "ext": "abc", - "files": filename, - "stagingDir": stagingdir, - } - instance.data["representations"].append(representation) - self.log.info( - "Extracted instance '%s' to: %s" % (instance.name, filepath) - ) diff --git a/openpype/hosts/max/plugins/publish/extract_pointcache.py b/openpype/hosts/max/plugins/publish/extract_pointcache.py index fca318a43f..4b3407274c 100644 --- a/openpype/hosts/max/plugins/publish/extract_pointcache.py +++ b/openpype/hosts/max/plugins/publish/extract_pointcache.py @@ -39,34 +39,31 @@ Note: """ import os import pyblish.api -from openpype.pipeline import publish +from openpype.pipeline import publish, OptionalPyblishPluginMixin from pymxs import runtime as rt from openpype.hosts.max.api import maintained_selection from openpype.hosts.max.api.lib import suspended_refresh +from openpype.lib import BoolDef -class ExtractAlembic(publish.Extractor): +class ExtractAlembic(publish.Extractor, + OptionalPyblishPluginMixin): order = pyblish.api.ExtractorOrder label = "Extract Pointcache" hosts = ["max"] families = ["pointcache"] + optional = False def process(self, instance): - start = instance.data["frameStartHandle"] - end = instance.data["frameEndHandle"] + if not self.is_active(instance.data): + return parent_dir = self.staging_dir(instance) file_name = "{name}.abc".format(**instance.data) path = os.path.join(parent_dir, file_name) with suspended_refresh(): - rt.AlembicExport.ArchiveType = rt.name("ogawa") - rt.AlembicExport.CoordinateSystem = rt.name("maya") - rt.AlembicExport.StartFrame = start - rt.AlembicExport.EndFrame = end - rt.AlembicExport.CustomAttributes = instance.data.get( - "custom_attrs", False) - + self._set_abc_attributes(instance) with maintained_selection(): # select and export node_list = instance.data["members"] @@ -88,3 +85,54 @@ class ExtractAlembic(publish.Extractor): "stagingDir": parent_dir, } instance.data["representations"].append(representation) + + def _set_abc_attributes(self, instance): + start = instance.data["frameStartHandle"] + end = instance.data["frameEndHandle"] + attr_values = self.get_attr_values_from_data(instance.data) + custom_attrs = attr_values.get("custom_attrs", False) + rt.AlembicExport.ArchiveType = rt.Name("ogawa") + rt.AlembicExport.CoordinateSystem = rt.Name("maya") + rt.AlembicExport.StartFrame = start + rt.AlembicExport.EndFrame = end + rt.AlembicExport.CustomAttributes = custom_attrs + + @classmethod + def get_attribute_defs(cls): + return [ + BoolDef("custom_attrs", + label="Custom Attributes", + default=False), + ] + + +class ExtractCameraAlembic(ExtractAlembic): + """Extract Camera with AlembicExport.""" + + order = pyblish.api.ExtractorOrder - 0.1 + label = "Extract Alembic Camera" + hosts = ["max"] + families = ["camera"] + optional = True + + +class ExtractModel(ExtractAlembic): + """ + Extract Geometry in Alembic Format + """ + + order = pyblish.api.ExtractorOrder - 0.1 + label = "Extract Geometry (Alembic)" + hosts = ["max"] + families = ["model"] + optional = True + + def _set_abc_attributes(self, instance): + attr_values = self.get_attr_values_from_data(instance.data) + custom_attrs = attr_values.get("custom_attrs", False) + rt.AlembicExport.ArchiveType = rt.name("ogawa") + rt.AlembicExport.CoordinateSystem = rt.name("maya") + rt.AlembicExport.CustomAttributes = custom_attrs + rt.AlembicExport.UVs = True + rt.AlembicExport.VertexColors = True + rt.AlembicExport.PreserveInstances = True From a22d1baa15c03e9889dbf836a5f975c05b8751e7 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 25 Oct 2023 12:31:54 +0800 Subject: [PATCH 4/6] clean up the codes --- openpype/hosts/max/api/lib.py | 4 ++-- openpype/hosts/max/plugins/publish/extract_pointcache.py | 9 +-------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/max/api/lib.py b/openpype/hosts/max/api/lib.py index 61a2d938a1..e44cea42ad 100644 --- a/openpype/hosts/max/api/lib.py +++ b/openpype/hosts/max/api/lib.py @@ -515,11 +515,11 @@ def get_plugins() -> list: def suspended_refresh(): """Suspended refresh for scene and modify panel redraw. """ - rt.disableSceneRedraw() - rt.suspendEditing() if is_headless(): yield return + rt.disableSceneRedraw() + rt.suspendEditing() try: yield diff --git a/openpype/hosts/max/plugins/publish/extract_pointcache.py b/openpype/hosts/max/plugins/publish/extract_pointcache.py index 4b3407274c..d15cd676f2 100644 --- a/openpype/hosts/max/plugins/publish/extract_pointcache.py +++ b/openpype/hosts/max/plugins/publish/extract_pointcache.py @@ -109,21 +109,14 @@ class ExtractAlembic(publish.Extractor, class ExtractCameraAlembic(ExtractAlembic): """Extract Camera with AlembicExport.""" - order = pyblish.api.ExtractorOrder - 0.1 label = "Extract Alembic Camera" - hosts = ["max"] families = ["camera"] optional = True class ExtractModel(ExtractAlembic): - """ - Extract Geometry in Alembic Format - """ - - order = pyblish.api.ExtractorOrder - 0.1 + """Extract Geometry in Alembic Format""" label = "Extract Geometry (Alembic)" - hosts = ["max"] families = ["model"] optional = True From d108641aa7d9575d03de750945cdd4608c857361 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 25 Oct 2023 12:48:33 +0800 Subject: [PATCH 5/6] remove optional=ture in children class of abc extractor --- openpype/hosts/max/plugins/publish/extract_pointcache.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/extract_pointcache.py b/openpype/hosts/max/plugins/publish/extract_pointcache.py index d15cd676f2..0097432f43 100644 --- a/openpype/hosts/max/plugins/publish/extract_pointcache.py +++ b/openpype/hosts/max/plugins/publish/extract_pointcache.py @@ -52,7 +52,7 @@ class ExtractAlembic(publish.Extractor, label = "Extract Pointcache" hosts = ["max"] families = ["pointcache"] - optional = False + optional = True def process(self, instance): if not self.is_active(instance.data): @@ -111,14 +111,12 @@ class ExtractCameraAlembic(ExtractAlembic): label = "Extract Alembic Camera" families = ["camera"] - optional = True class ExtractModel(ExtractAlembic): """Extract Geometry in Alembic Format""" label = "Extract Geometry (Alembic)" families = ["model"] - optional = True def _set_abc_attributes(self, instance): attr_values = self.get_attr_values_from_data(instance.data) From 394a8a5850fedc73fb7c9ba23257e20de7837a35 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 12 Dec 2023 11:06:46 +0800 Subject: [PATCH 6/6] rename extract_pointcache to extract_alembic --- .../plugins/publish/{extract_pointcache.py => extract_alembic.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename openpype/hosts/max/plugins/publish/{extract_pointcache.py => extract_alembic.py} (100%) diff --git a/openpype/hosts/max/plugins/publish/extract_pointcache.py b/openpype/hosts/max/plugins/publish/extract_alembic.py similarity index 100% rename from openpype/hosts/max/plugins/publish/extract_pointcache.py rename to openpype/hosts/max/plugins/publish/extract_alembic.py