From c72c8f332cbfbf3ded76ba9c6b2fcb9cbd9b1522 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 8 Aug 2023 15:00:17 +0800 Subject: [PATCH 01/13] switching asset can maintain linkages on the modifiers and other data --- openpype/hosts/max/plugins/load/load_max_scene.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/max/plugins/load/load_max_scene.py b/openpype/hosts/max/plugins/load/load_max_scene.py index 76cd3bf367..c98b7909ee 100644 --- a/openpype/hosts/max/plugins/load/load_max_scene.py +++ b/openpype/hosts/max/plugins/load/load_max_scene.py @@ -24,7 +24,9 @@ class MaxSceneLoader(load.LoaderPlugin): path = os.path.normpath(path) # import the max scene by using "merge file" path = path.replace('\\', '/') - rt.MergeMaxFile(path) + rt.MergeMaxFile( + path, rt.Name("autoRenameDups"), + includeFullGroup=True) max_objects = rt.getLastMergedNodes() max_container = rt.Container(name=f"{name}") for max_object in max_objects: @@ -38,11 +40,11 @@ class MaxSceneLoader(load.LoaderPlugin): path = get_representation_path(representation) node_name = container["instance_node"] - - rt.MergeMaxFile(path, - rt.Name("noRedraw"), - rt.Name("deleteOldDups"), - rt.Name("useSceneMtlDups")) + merged_max_objects = rt.getLastMergedNodes() + rt.MergeMaxFile( + path, rt.Name("autoRenameDups"), + mergedNodes=merged_max_objects, + includeFullGroup=True) max_objects = rt.getLastMergedNodes() container_node = rt.GetNodeByName(node_name) From d51c1fa9fb3ba534d9b2ba5b0cd3c6254c465290 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 8 Aug 2023 15:11:13 +0800 Subject: [PATCH 02/13] do not use autorename duplicate when updating or switching version --- openpype/hosts/max/plugins/load/load_max_scene.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openpype/hosts/max/plugins/load/load_max_scene.py b/openpype/hosts/max/plugins/load/load_max_scene.py index c98b7909ee..3af4613d1a 100644 --- a/openpype/hosts/max/plugins/load/load_max_scene.py +++ b/openpype/hosts/max/plugins/load/load_max_scene.py @@ -42,8 +42,7 @@ class MaxSceneLoader(load.LoaderPlugin): node_name = container["instance_node"] merged_max_objects = rt.getLastMergedNodes() rt.MergeMaxFile( - path, rt.Name("autoRenameDups"), - mergedNodes=merged_max_objects, + path, mergedNodes=merged_max_objects, includeFullGroup=True) max_objects = rt.getLastMergedNodes() From ab1172b277eaa396f3c3e992b3ad5759ff1635bf Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 8 Aug 2023 15:54:35 +0800 Subject: [PATCH 03/13] delete old duplicates --- .../hosts/max/plugins/load/load_max_scene.py | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/openpype/hosts/max/plugins/load/load_max_scene.py b/openpype/hosts/max/plugins/load/load_max_scene.py index 3af4613d1a..92e1bdc59a 100644 --- a/openpype/hosts/max/plugins/load/load_max_scene.py +++ b/openpype/hosts/max/plugins/load/load_max_scene.py @@ -25,31 +25,27 @@ class MaxSceneLoader(load.LoaderPlugin): # import the max scene by using "merge file" path = path.replace('\\', '/') rt.MergeMaxFile( - path, rt.Name("autoRenameDups"), + path, rt.Name("mergeDups"), includeFullGroup=True) max_objects = rt.getLastMergedNodes() - max_container = rt.Container(name=f"{name}") - for max_object in max_objects: - max_object.Parent = max_container return containerise( - name, [max_container], context, loader=self.__class__.__name__) + name, [max_objects], context, loader=self.__class__.__name__) def update(self, container, representation): from pymxs import runtime as rt path = get_representation_path(representation) - node_name = container["instance_node"] - merged_max_objects = rt.getLastMergedNodes() + prev_max_objects = rt.getLastMergedNodes() + merged_max_objects = [obj.name for obj + in prev_max_objects] rt.MergeMaxFile( - path, mergedNodes=merged_max_objects, + path, merged_max_objects, + rt.Name("deleteOldDups"), + quiet=True, + mergedNodes=prev_max_objects, includeFullGroup=True) - max_objects = rt.getLastMergedNodes() - container_node = rt.GetNodeByName(node_name) - for max_object in max_objects: - max_object.Parent = container_node - lib.imprint(container["instance_node"], { "representation": str(representation["_id"]) }) From 70cb60a17eb98ca7796674f4555f115019e27abe Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 8 Aug 2023 17:19:42 +0800 Subject: [PATCH 04/13] deletion of the old objects --- openpype/hosts/max/plugins/load/load_max_scene.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openpype/hosts/max/plugins/load/load_max_scene.py b/openpype/hosts/max/plugins/load/load_max_scene.py index 92e1bdc59a..1d105f1bc0 100644 --- a/openpype/hosts/max/plugins/load/load_max_scene.py +++ b/openpype/hosts/max/plugins/load/load_max_scene.py @@ -45,6 +45,11 @@ class MaxSceneLoader(load.LoaderPlugin): quiet=True, mergedNodes=prev_max_objects, includeFullGroup=True) + current_max_objects = rt.getLastMergedNodes() + for current_object in current_max_objects: + prev_max_objects = prev_max_objects.remove(current_object) + for prev_object in prev_max_objects: + rt.Delete(prev_object) lib.imprint(container["instance_node"], { "representation": str(representation["_id"]) From 444cca4213128d470641a58ffac4602b9ac5f833 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 21 Aug 2023 15:30:46 +0800 Subject: [PATCH 05/13] load max scene wip --- .../hosts/max/plugins/load/load_max_scene.py | 66 +++++++++++++------ 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/openpype/hosts/max/plugins/load/load_max_scene.py b/openpype/hosts/max/plugins/load/load_max_scene.py index 1d105f1bc0..6dfb3d0115 100644 --- a/openpype/hosts/max/plugins/load/load_max_scene.py +++ b/openpype/hosts/max/plugins/load/load_max_scene.py @@ -1,7 +1,11 @@ import os from openpype.hosts.max.api import lib -from openpype.hosts.max.api.pipeline import containerise +from openpype.hosts.max.api.lib import unique_namespace +from openpype.hosts.max.api.pipeline import ( + containerise, import_custom_attribute_data, + update_custom_attribute_data +) from openpype.pipeline import get_representation_path, load @@ -19,37 +23,61 @@ class MaxSceneLoader(load.LoaderPlugin): def load(self, context, name=None, namespace=None, data=None): from pymxs import runtime as rt - path = self.filepath_from_context(context) path = os.path.normpath(path) # import the max scene by using "merge file" path = path.replace('\\', '/') - rt.MergeMaxFile( - path, rt.Name("mergeDups"), - includeFullGroup=True) + rt.MergeMaxFile(path, quiet=True, includeFullGroup=True) max_objects = rt.getLastMergedNodes() + # implement the OP/AYON custom attributes before load + max_container = [] + namespace = unique_namespace( + name + "_", + suffix="_", + ) + container = rt.Container(name=f"{namespace}:{name}") + import_custom_attribute_data(container, max_objects) + max_container.append(container) + max_container.extend(max_objects) return containerise( - name, [max_objects], context, loader=self.__class__.__name__) + name, max_container, context, + namespace, loader=self.__class__.__name__) def update(self, container, representation): from pymxs import runtime as rt path = get_representation_path(representation) - prev_max_objects = rt.getLastMergedNodes() - merged_max_objects = [obj.name for obj - in prev_max_objects] - rt.MergeMaxFile( - path, merged_max_objects, - rt.Name("deleteOldDups"), - quiet=True, - mergedNodes=prev_max_objects, - includeFullGroup=True) + node_name = container["instance_node"] + + node = rt.getNodeByName(node_name) + param_container = node_name.split("_CON")[0] + + # delete the old container with attribute + # delete old duplicate + prev_max_object_names = [obj.name for obj + in rt.getLastMergedNodes()] + rt.MergeMaxFile(path, rt.Name("deleteOldDups")) + current_max_objects = rt.getLastMergedNodes() - for current_object in current_max_objects: - prev_max_objects = prev_max_objects.remove(current_object) - for prev_object in prev_max_objects: - rt.Delete(prev_object) + current_max_object_names = [obj.name for obj + in current_max_objects] + for name in current_max_object_names: + idx = rt.findItem(prev_max_object_names, name) + if idx: + prev_max_object_names = rt.deleteItem( + prev_max_object_names, idx) + for object_name in prev_max_object_names: + prev_max_object = rt.getNodeByName(object_name) + rt.Delete(prev_max_object) + + for max_object in current_max_objects: + max_object.Parent = node + for children in node.Children: + if rt.classOf(children) == rt.Container: + if children.name == param_container: + update_custom_attribute_data( + children, current_max_objects) lib.imprint(container["instance_node"], { "representation": str(representation["_id"]) From e5bdb9e98d5c1291c4db2b573f26c34896100b2d Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 13 Sep 2023 18:16:35 +0800 Subject: [PATCH 06/13] unparenting all the objects to the containers & uses the OP data to get previous objects --- openpype/hosts/max/api/pipeline.py | 23 ++++++-- .../hosts/max/plugins/load/load_camera_fbx.py | 38 +++++------- .../hosts/max/plugins/load/load_max_scene.py | 40 ++++++------- openpype/hosts/max/plugins/load/load_model.py | 20 +++---- .../hosts/max/plugins/load/load_model_fbx.py | 59 ++++++++----------- .../hosts/max/plugins/load/load_model_obj.py | 32 +++++----- .../hosts/max/plugins/load/load_model_usd.py | 55 ++++++++--------- .../hosts/max/plugins/load/load_pointcache.py | 21 +++---- .../hosts/max/plugins/load/load_pointcloud.py | 20 +++---- .../max/plugins/load/load_redshift_proxy.py | 24 +++----- 10 files changed, 148 insertions(+), 184 deletions(-) diff --git a/openpype/hosts/max/api/pipeline.py b/openpype/hosts/max/api/pipeline.py index 72163f5ecf..6c40acc56b 100644 --- a/openpype/hosts/max/api/pipeline.py +++ b/openpype/hosts/max/api/pipeline.py @@ -164,12 +164,11 @@ def containerise(name: str, nodes: list, context, "loader": loader, "representation": context["representation"]["_id"], } - container_name = f"{namespace}:{name}{suffix}" container = rt.container(name=container_name) - for node in nodes: - node.Parent = container - + #for node in nodes: + # node.Parent = container + import_custom_attribute_data(container, nodes) if not lib.imprint(container_name, data): print(f"imprinting of {container_name} failed.") return container @@ -223,3 +222,19 @@ def update_custom_attribute_data(container: str, selections: list): if container.modifiers[0].name == "OP Data": rt.deleteModifier(container, container.modifiers[0]) import_custom_attribute_data(container, selections) + +def get_previous_loaded_object(container: str): + """Get previous loaded_object through the OP data + + Args: + container (str): the container which stores the OP data + + Returns: + node_list(list): list of nodes which are previously loaded + """ + node_list = [] + sel_list = rt.getProperty(container.modifiers[0].openPypeData, "sel_list") + for obj in rt.Objects: + if str(obj) in sel_list: + node_list.append(obj) + return node_list diff --git a/openpype/hosts/max/plugins/load/load_camera_fbx.py b/openpype/hosts/max/plugins/load/load_camera_fbx.py index f040115417..39bbf79d0f 100644 --- a/openpype/hosts/max/plugins/load/load_camera_fbx.py +++ b/openpype/hosts/max/plugins/load/load_camera_fbx.py @@ -8,7 +8,7 @@ from openpype.hosts.max.api.lib import ( ) from openpype.hosts.max.api.pipeline import ( containerise, - import_custom_attribute_data, + get_previous_loaded_object, update_custom_attribute_data ) from openpype.pipeline import get_representation_path, load @@ -22,7 +22,6 @@ class FbxLoader(load.LoaderPlugin): order = -9 icon = "code-fork" color = "white" - postfix = "param" def load(self, context, name=None, namespace=None, data=None): from pymxs import runtime as rt @@ -42,17 +41,13 @@ class FbxLoader(load.LoaderPlugin): name + "_", suffix="_", ) - container = rt.container( - name=f"{namespace}:{name}_{self.postfix}") selections = rt.GetCurrentSelection() - import_custom_attribute_data(container, selections) for selection in selections: - selection.Parent = container selection.name = f"{namespace}:{selection.name}" return containerise( - name, [container], context, + name, selections, context, namespace, loader=self.__class__.__name__) def update(self, container, representation): @@ -61,12 +56,13 @@ class FbxLoader(load.LoaderPlugin): path = get_representation_path(representation) node_name = container["instance_node"] node = rt.getNodeByName(node_name) - namespace, name = get_namespace(node_name) - sub_node_name = f"{namespace}:{name}_{self.postfix}" - inst_container = rt.getNodeByName(sub_node_name) - rt.Select(inst_container.Children) - transform_data = object_transform_set(inst_container.Children) - for prev_fbx_obj in rt.selection: + namespace, _ = get_namespace(node_name) + + node_list = get_previous_loaded_object(node) + rt.Select(node_list) + prev_fbx_objects = rt.GetCurrentSelection() + transform_data = object_transform_set(prev_fbx_objects) + for prev_fbx_obj in prev_fbx_objects: if rt.isValidNode(prev_fbx_obj): rt.Delete(prev_fbx_obj) @@ -78,20 +74,14 @@ class FbxLoader(load.LoaderPlugin): rt.ImportFile( path, rt.name("noPrompt"), using=rt.FBXIMP) current_fbx_objects = rt.GetCurrentSelection() + update_custom_attribute_data(node, current_fbx_objects) for fbx_object in current_fbx_objects: - if fbx_object.Parent != inst_container: - fbx_object.Parent = inst_container - fbx_object.name = f"{namespace}:{fbx_object.name}" + fbx_object.name = f"{namespace}:{fbx_object.name}" + if fbx_object in node_list: fbx_object.pos = transform_data[ - f"{fbx_object.name}.transform"] + f"{fbx_object.name}.transform"] or fbx_object.pos fbx_object.scale = transform_data[ - f"{fbx_object.name}.scale"] - - for children in node.Children: - if rt.classOf(children) == rt.Container: - if children.name == sub_node_name: - update_custom_attribute_data( - children, current_fbx_objects) + f"{fbx_object.name}.scale"] or fbx_object.scale with maintained_selection(): rt.Select(node) diff --git a/openpype/hosts/max/plugins/load/load_max_scene.py b/openpype/hosts/max/plugins/load/load_max_scene.py index 98e9be96e1..86b7637c90 100644 --- a/openpype/hosts/max/plugins/load/load_max_scene.py +++ b/openpype/hosts/max/plugins/load/load_max_scene.py @@ -7,7 +7,7 @@ from openpype.hosts.max.api.lib import ( object_transform_set ) from openpype.hosts.max.api.pipeline import ( - containerise, import_custom_attribute_data, + containerise, get_previous_loaded_object, update_custom_attribute_data ) from openpype.pipeline import get_representation_path, load @@ -24,7 +24,6 @@ class MaxSceneLoader(load.LoaderPlugin): order = -8 icon = "code-fork" color = "green" - postfix = "param" def load(self, context, name=None, namespace=None, data=None): from pymxs import runtime as rt @@ -37,18 +36,14 @@ class MaxSceneLoader(load.LoaderPlugin): max_object_names = [obj.name for obj in max_objects] # implement the OP/AYON custom attributes before load max_container = [] - namespace = unique_namespace( name + "_", suffix="_", ) - container_name = f"{namespace}:{name}_{self.postfix}" - container = rt.Container(name=container_name) - import_custom_attribute_data(container, max_objects) - max_container.append(container) - max_container.extend(max_objects) for max_obj, obj_name in zip(max_objects, max_object_names): max_obj.name = f"{namespace}:{obj_name}" + max_container.append(rt.getNodeByName(max_obj.name)) + return containerise( name, max_container, context, namespace, loader=self.__class__.__name__) @@ -60,32 +55,31 @@ class MaxSceneLoader(load.LoaderPlugin): node_name = container["instance_node"] node = rt.getNodeByName(node_name) - namespace, name = get_namespace(node_name) - sub_container_name = f"{namespace}:{name}_{self.postfix}" + namespace, _ = get_namespace(node_name) # delete the old container with attribute # delete old duplicate - rt.Select(node.Children) - transform_data = object_transform_set(node.Children) - for prev_max_obj in rt.GetCurrentSelection(): - if rt.isValidNode(prev_max_obj) and prev_max_obj.name != sub_container_name: # noqa + # use the modifier OP data to delete the data + node_list = get_previous_loaded_object(node) + rt.Select(node_list) + prev_max_objects = rt.GetCurrentSelection() + transform_data = object_transform_set(prev_max_objects) + for prev_max_obj in prev_max_objects: + if rt.isValidNode(prev_max_obj): # noqa rt.Delete(prev_max_obj) rt.MergeMaxFile(path, rt.Name("deleteOldDups")) current_max_objects = rt.getLastMergedNodes() current_max_object_names = [obj.name for obj in current_max_objects] - sub_container = rt.getNodeByName(sub_container_name) - update_custom_attribute_data(sub_container, current_max_objects) - for max_object in current_max_objects: - max_object.Parent = node + update_custom_attribute_data(node, current_max_objects) for max_obj, obj_name in zip(current_max_objects, current_max_object_names): max_obj.name = f"{namespace}:{obj_name}" - max_obj.pos = transform_data[ - f"{max_obj.name}.transform"] - max_obj.scale = transform_data[ - f"{max_obj.name}.scale"] - + if max_obj in node_list: + max_obj.pos = transform_data[ + f"{max_obj.name}.transform"] or max_obj.pos + max_obj.scale = transform_data[ + f"{max_obj.name}.scale"] or max_obj.scale lib.imprint(container["instance_node"], { "representation": str(representation["_id"]) }) diff --git a/openpype/hosts/max/plugins/load/load_model.py b/openpype/hosts/max/plugins/load/load_model.py index c5a73b4327..5acb57b923 100644 --- a/openpype/hosts/max/plugins/load/load_model.py +++ b/openpype/hosts/max/plugins/load/load_model.py @@ -2,8 +2,7 @@ import os from openpype.pipeline import load, get_representation_path from openpype.hosts.max.api.pipeline import ( containerise, - import_custom_attribute_data, - update_custom_attribute_data + get_previous_loaded_object ) from openpype.hosts.max.api import lib from openpype.hosts.max.api.lib import ( @@ -20,7 +19,6 @@ class ModelAbcLoader(load.LoaderPlugin): order = -10 icon = "code-fork" color = "orange" - postfix = "param" def load(self, context, name=None, namespace=None, data=None): from pymxs import runtime as rt @@ -52,21 +50,22 @@ class ModelAbcLoader(load.LoaderPlugin): self.log.error("Something failed when loading.") abc_container = abc_containers.pop() - import_custom_attribute_data( - abc_container, abc_container.Children) namespace = unique_namespace( name + "_", suffix="_", ) + abc_objects = [] for abc_object in abc_container.Children: abc_object.name = f"{namespace}:{abc_object.name}" + abc_objects.append(abc_object) # rename the abc container with namespace - abc_container_name = f"{namespace}:{name}_{self.postfix}" + abc_container_name = f"{namespace}:{name}" abc_container.name = abc_container_name + abc_objects.append(abc_container) return containerise( - name, [abc_container], context, + name, abc_objects, context, namespace, loader=self.__class__.__name__ ) @@ -75,20 +74,19 @@ class ModelAbcLoader(load.LoaderPlugin): path = get_representation_path(representation) node = rt.GetNodeByName(container["instance_node"]) - + node_list = [n for n in get_previous_loaded_object(node) + if rt.ClassOf(n) == rt.AlembicContainer] with maintained_selection(): - rt.Select(node.Children) + rt.Select(node_list) for alembic in rt.Selection: abc = rt.GetNodeByName(alembic.name) - update_custom_attribute_data(abc, abc.Children) rt.Select(abc.Children) for abc_con in abc.Children: abc_con.source = path rt.Select(abc_con.Children) for abc_obj in abc_con.Children: abc_obj.source = path - lib.imprint( container["instance_node"], {"representation": str(representation["_id"])}, diff --git a/openpype/hosts/max/plugins/load/load_model_fbx.py b/openpype/hosts/max/plugins/load/load_model_fbx.py index 56c8768675..a8f6ea90d6 100644 --- a/openpype/hosts/max/plugins/load/load_model_fbx.py +++ b/openpype/hosts/max/plugins/load/load_model_fbx.py @@ -1,7 +1,7 @@ import os from openpype.pipeline import load, get_representation_path from openpype.hosts.max.api.pipeline import ( - containerise, import_custom_attribute_data, + containerise, get_previous_loaded_object, update_custom_attribute_data ) from openpype.hosts.max.api import lib @@ -21,79 +21,68 @@ class FbxModelLoader(load.LoaderPlugin): order = -9 icon = "code-fork" color = "white" - postfix = "param" def load(self, context, name=None, namespace=None, data=None): from pymxs import runtime as rt - - filepath = os.path.normpath(self.filepath_from_context(context)) + filepath = self.filepath_from_context(context) + filepath = os.path.normpath(filepath) rt.FBXImporterSetParam("Animation", False) rt.FBXImporterSetParam("Cameras", False) rt.FBXImporterSetParam("Mode", rt.Name("create")) rt.FBXImporterSetParam("Preserveinstances", True) - rt.importFile(filepath, rt.name("noPrompt"), using=rt.FBXIMP) + rt.importFile( + filepath, rt.name("noPrompt"), using=rt.FBXIMP) namespace = unique_namespace( name + "_", suffix="_", ) - container = rt.container( - name=f"{namespace}:{name}_{self.postfix}") selections = rt.GetCurrentSelection() - import_custom_attribute_data(container, selections) for selection in selections: - selection.Parent = container selection.name = f"{namespace}:{selection.name}" return containerise( - name, [container], context, - namespace, loader=self.__class__.__name__ - ) + name, selections, context, + namespace, loader=self.__class__.__name__) def update(self, container, representation): from pymxs import runtime as rt + path = get_representation_path(representation) node_name = container["instance_node"] node = rt.getNodeByName(node_name) - namespace, name = get_namespace(node_name) - sub_node_name = f"{namespace}:{name}_{self.postfix}" - inst_container = rt.getNodeByName(sub_node_name) - rt.Select(inst_container.Children) - transform_data = object_transform_set(inst_container.Children) - for prev_fbx_obj in rt.selection: + namespace, _ = get_namespace(node_name) + + node_list = get_previous_loaded_object(node) + rt.Select(node_list) + prev_fbx_objects = rt.GetCurrentSelection() + transform_data = object_transform_set(prev_fbx_objects) + for prev_fbx_obj in prev_fbx_objects: if rt.isValidNode(prev_fbx_obj): rt.Delete(prev_fbx_obj) rt.FBXImporterSetParam("Animation", False) rt.FBXImporterSetParam("Cameras", False) - rt.FBXImporterSetParam("Mode", rt.Name("merge")) - rt.FBXImporterSetParam("AxisConversionMethod", True) + rt.FBXImporterSetParam("Mode", rt.Name("create")) rt.FBXImporterSetParam("Preserveinstances", True) rt.importFile(path, rt.name("noPrompt"), using=rt.FBXIMP) current_fbx_objects = rt.GetCurrentSelection() + update_custom_attribute_data(node, current_fbx_objects) for fbx_object in current_fbx_objects: - if fbx_object.Parent != inst_container: - fbx_object.Parent = inst_container - fbx_object.name = f"{namespace}:{fbx_object.name}" + fbx_object.name = f"{namespace}:{fbx_object.name}" + if fbx_object in node_list: fbx_object.pos = transform_data[ - f"{fbx_object.name}.transform"] + f"{fbx_object.name}.transform"] or fbx_object.pos fbx_object.scale = transform_data[ - f"{fbx_object.name}.scale"] - - for children in node.Children: - if rt.classOf(children) == rt.Container: - if children.name == sub_node_name: - update_custom_attribute_data( - children, current_fbx_objects) + f"{fbx_object.name}.scale"] or fbx_object.scale with maintained_selection(): rt.Select(node) - lib.imprint( - node_name, - {"representation": str(representation["_id"])}, - ) + lib.imprint(container["instance_node"], { + "representation": str(representation["_id"]) + }) def switch(self, container, representation): self.update(container, representation) diff --git a/openpype/hosts/max/plugins/load/load_model_obj.py b/openpype/hosts/max/plugins/load/load_model_obj.py index 314889e6ec..421bd34e62 100644 --- a/openpype/hosts/max/plugins/load/load_model_obj.py +++ b/openpype/hosts/max/plugins/load/load_model_obj.py @@ -10,7 +10,7 @@ from openpype.hosts.max.api.lib import ( from openpype.hosts.max.api.lib import maintained_selection from openpype.hosts.max.api.pipeline import ( containerise, - import_custom_attribute_data, + get_previous_loaded_object, update_custom_attribute_data ) from openpype.pipeline import get_representation_path, load @@ -24,7 +24,6 @@ class ObjLoader(load.LoaderPlugin): order = -9 icon = "code-fork" color = "white" - postfix = "param" def load(self, context, name=None, namespace=None, data=None): from pymxs import runtime as rt @@ -39,15 +38,12 @@ class ObjLoader(load.LoaderPlugin): suffix="_", ) # create "missing" container for obj import - container = rt.Container(name=f"{namespace}:{name}_{self.postfix}") selections = rt.GetCurrentSelection() - import_custom_attribute_data(container, selections) # get current selection for selection in selections: - selection.Parent = container selection.name = f"{namespace}:{selection.name}" return containerise( - name, [container], context, + name, selections, context, namespace, loader=self.__class__.__name__) def update(self, container, representation): @@ -56,26 +52,26 @@ class ObjLoader(load.LoaderPlugin): path = get_representation_path(representation) node_name = container["instance_node"] node = rt.getNodeByName(node_name) - namespace, name = get_namespace(node_name) - sub_node_name = f"{namespace}:{name}_{self.postfix}" - inst_container = rt.getNodeByName(sub_node_name) - rt.Select(inst_container.Children) - transform_data = object_transform_set(inst_container.Children) - for prev_obj in rt.selection: + namespace, _ = get_namespace(node_name) + node_list = get_previous_loaded_object(node) + rt.Select(node_list) + previous_objects = rt.GetCurrentSelection() + transform_data = object_transform_set(previous_objects) + for prev_obj in previous_objects: if rt.isValidNode(prev_obj): rt.Delete(prev_obj) rt.Execute(f'importFile @"{path}" #noPrompt using:ObjImp') # get current selection selections = rt.GetCurrentSelection() - update_custom_attribute_data(inst_container, selections) for selection in selections: - selection.Parent = inst_container selection.name = f"{namespace}:{selection.name}" - selection.pos = transform_data[ - f"{selection.name}.transform"] - selection.scale = transform_data[ - f"{selection.name}.scale"] + if selection in node_list: + selection.pos = transform_data[ + f"{selection.name}.transform"] or selection.pos + selection.scale = transform_data[ + f"{selection.name}.scale"] or selection.scale + update_custom_attribute_data(node, selections) with maintained_selection(): rt.Select(node) diff --git a/openpype/hosts/max/plugins/load/load_model_usd.py b/openpype/hosts/max/plugins/load/load_model_usd.py index f35d8e6327..09566c2e78 100644 --- a/openpype/hosts/max/plugins/load/load_model_usd.py +++ b/openpype/hosts/max/plugins/load/load_model_usd.py @@ -1,5 +1,7 @@ import os +from pymxs import runtime as rt + from openpype.hosts.max.api import lib from openpype.hosts.max.api.lib import ( unique_namespace, @@ -9,7 +11,8 @@ from openpype.hosts.max.api.lib import ( from openpype.hosts.max.api.lib import maintained_selection from openpype.hosts.max.api.pipeline import ( containerise, - import_custom_attribute_data + get_previous_loaded_object, + update_custom_attribute_data ) from openpype.pipeline import get_representation_path, load @@ -23,16 +26,13 @@ class ModelUSDLoader(load.LoaderPlugin): order = -10 icon = "code-fork" color = "orange" - postfix = "param" def load(self, context, name=None, namespace=None, data=None): - from pymxs import runtime as rt - # asset_filepath filepath = os.path.normpath(self.filepath_from_context(context)) import_options = rt.USDImporter.CreateOptions() base_filename = os.path.basename(filepath) - filename, ext = os.path.splitext(base_filename) + _, ext = os.path.splitext(base_filename) log_filepath = filepath.replace(ext, "txt") rt.LogPath = log_filepath @@ -44,35 +44,32 @@ class ModelUSDLoader(load.LoaderPlugin): suffix="_", ) asset = rt.GetNodeByName(name) - import_custom_attribute_data(asset, asset.Children) + usd_objects = [] + for usd_asset in asset.Children: usd_asset.name = f"{namespace}:{usd_asset.name}" + usd_objects.append(usd_asset) - asset_name = f"{namespace}:{name}_{self.postfix}" + asset_name = f"{namespace}:{name}" asset.name = asset_name # need to get the correct container after renamed asset = rt.GetNodeByName(asset_name) - + usd_objects.append(asset) return containerise( - name, [asset], context, + name, usd_objects, context, namespace, loader=self.__class__.__name__) def update(self, container, representation): - from pymxs import runtime as rt - path = get_representation_path(representation) node_name = container["instance_node"] node = rt.GetNodeByName(node_name) namespace, name = get_namespace(node_name) - sub_node_name = f"{namespace}:{name}_{self.postfix}" - transform_data = None - for n in node.Children: - rt.Select(n.Children) - transform_data = object_transform_set(n.Children) - for prev_usd_asset in rt.selection: - if rt.isValidNode(prev_usd_asset): - rt.Delete(prev_usd_asset) + node_list = get_previous_loaded_object(node) + rt.Select(node_list) + prev_objects = rt.GetCurrentSelection() + transform_data = object_transform_set(prev_objects) + for n in prev_objects: rt.Delete(n) import_options = rt.USDImporter.CreateOptions() @@ -86,17 +83,19 @@ class ModelUSDLoader(load.LoaderPlugin): path, importOptions=import_options) asset = rt.GetNodeByName(name) - asset.Parent = node - import_custom_attribute_data(asset, asset.Children) + usd_objects = [] for children in asset.Children: children.name = f"{namespace}:{children.name}" - children.pos = transform_data[ - f"{children.name}.transform"] - children.scale = transform_data[ - f"{children.name}.scale"] - - asset.name = sub_node_name + usd_objects.append(children) + if children in node_list: + children.pos = transform_data[ + f"{children.name}.transform"] or children.pos + children.scale = transform_data[ + f"{children.name}.scale"] or children.scale + asset.name = f"{namespace}:{asset.name}" + usd_objects.append(asset) + update_custom_attribute_data(node, usd_objects) with maintained_selection(): rt.Select(node) @@ -108,7 +107,5 @@ class ModelUSDLoader(load.LoaderPlugin): self.update(container, representation) def remove(self, container): - from pymxs import runtime as rt - node = rt.GetNodeByName(container["instance_node"]) rt.Delete(node) diff --git a/openpype/hosts/max/plugins/load/load_pointcache.py b/openpype/hosts/max/plugins/load/load_pointcache.py index 070dea88d4..995e56ca37 100644 --- a/openpype/hosts/max/plugins/load/load_pointcache.py +++ b/openpype/hosts/max/plugins/load/load_pointcache.py @@ -10,8 +10,7 @@ from openpype.hosts.max.api import lib, maintained_selection from openpype.hosts.max.api.lib import unique_namespace from openpype.hosts.max.api.pipeline import ( containerise, - import_custom_attribute_data, - update_custom_attribute_data + get_previous_loaded_object ) @@ -24,7 +23,6 @@ class AbcLoader(load.LoaderPlugin): order = -10 icon = "code-fork" color = "orange" - postfix = "param" def load(self, context, name=None, namespace=None, data=None): from pymxs import runtime as rt @@ -55,8 +53,6 @@ class AbcLoader(load.LoaderPlugin): abc_container = abc_containers.pop() selections = rt.GetCurrentSelection() - import_custom_attribute_data( - abc_container, abc_container.Children) for abc in selections: for cam_shape in abc.Children: cam_shape.playbackType = 2 @@ -65,15 +61,17 @@ class AbcLoader(load.LoaderPlugin): name + "_", suffix="_", ) - + abc_objects = [] for abc_object in abc_container.Children: abc_object.name = f"{namespace}:{abc_object.name}" + abc_objects.append(abc_object) # rename the abc container with namespace - abc_container_name = f"{namespace}:{name}_{self.postfix}" + abc_container_name = f"{namespace}:{name}" abc_container.name = abc_container_name + abc_objects.append(abc_container) return containerise( - name, [abc_container], context, + name, abc_objects, context, namespace, loader=self.__class__.__name__ ) @@ -82,20 +80,19 @@ class AbcLoader(load.LoaderPlugin): path = get_representation_path(representation) node = rt.GetNodeByName(container["instance_node"]) - + abc_container = [n for n in get_previous_loaded_object(node) + if rt.ClassOf(n) == rt.AlembicContainer] with maintained_selection(): - rt.Select(node.Children) + rt.Select(abc_container) for alembic in rt.Selection: abc = rt.GetNodeByName(alembic.name) - update_custom_attribute_data(abc, abc.Children) rt.Select(abc.Children) for abc_con in abc.Children: abc_con.source = path rt.Select(abc_con.Children) for abc_obj in abc_con.Children: abc_obj.source = path - lib.imprint( container["instance_node"], {"representation": str(representation["_id"])}, diff --git a/openpype/hosts/max/plugins/load/load_pointcloud.py b/openpype/hosts/max/plugins/load/load_pointcloud.py index c4c4cfbc6c..2309d3aebf 100644 --- a/openpype/hosts/max/plugins/load/load_pointcloud.py +++ b/openpype/hosts/max/plugins/load/load_pointcloud.py @@ -2,11 +2,11 @@ import os from openpype.hosts.max.api import lib, maintained_selection from openpype.hosts.max.api.lib import ( - unique_namespace, get_namespace + unique_namespace ) from openpype.hosts.max.api.pipeline import ( containerise, - import_custom_attribute_data, + get_previous_loaded_object, update_custom_attribute_data ) from openpype.pipeline import get_representation_path, load @@ -34,14 +34,10 @@ class PointCloudLoader(load.LoaderPlugin): name + "_", suffix="_", ) - prt_container = rt.Container( - name=f"{namespace}:{name}_{self.postfix}") - import_custom_attribute_data(prt_container, [obj]) - obj.Parent = prt_container obj.name = f"{namespace}:{obj.name}" return containerise( - name, [prt_container], context, + name, [obj], context, namespace, loader=self.__class__.__name__) def update(self, container, representation): @@ -50,14 +46,12 @@ class PointCloudLoader(load.LoaderPlugin): path = get_representation_path(representation) node = rt.GetNodeByName(container["instance_node"]) - namespace, name = get_namespace(container["instance_node"]) - sub_node_name = f"{namespace}:{name}_{self.postfix}" - inst_container = rt.getNodeByName(sub_node_name) + node_list = get_previous_loaded_object(node) update_custom_attribute_data( - inst_container, inst_container.Children) + node, node_list) with maintained_selection(): - rt.Select(node.Children) - for prt in inst_container.Children: + rt.Select(node_list) + for prt in rt.Selection: prt.filename = path lib.imprint(container["instance_node"], { "representation": str(representation["_id"]) diff --git a/openpype/hosts/max/plugins/load/load_redshift_proxy.py b/openpype/hosts/max/plugins/load/load_redshift_proxy.py index f7dd95962b..36bc7ac9e2 100644 --- a/openpype/hosts/max/plugins/load/load_redshift_proxy.py +++ b/openpype/hosts/max/plugins/load/load_redshift_proxy.py @@ -7,12 +7,12 @@ from openpype.pipeline import ( ) from openpype.hosts.max.api.pipeline import ( containerise, - import_custom_attribute_data, - update_custom_attribute_data + update_custom_attribute_data, + get_previous_loaded_object ) from openpype.hosts.max.api import lib from openpype.hosts.max.api.lib import ( - unique_namespace, get_namespace + unique_namespace ) @@ -25,7 +25,6 @@ class RedshiftProxyLoader(load.LoaderPlugin): order = -9 icon = "code-fork" color = "white" - postfix = "param" def load(self, context, name=None, namespace=None, data=None): from pymxs import runtime as rt @@ -42,27 +41,22 @@ class RedshiftProxyLoader(load.LoaderPlugin): name + "_", suffix="_", ) - container = rt.Container( - name=f"{namespace}:{name}_{self.postfix}") - rs_proxy.Parent = container rs_proxy.name = f"{namespace}:{rs_proxy.name}" - import_custom_attribute_data(container, [rs_proxy]) return containerise( - name, [container], context, + name, [rs_proxy], context, namespace, loader=self.__class__.__name__) def update(self, container, representation): from pymxs import runtime as rt path = get_representation_path(representation) - namespace, name = get_namespace(container["instance_node"]) - sub_node_name = f"{namespace}:{name}_{self.postfix}" - inst_container = rt.getNodeByName(sub_node_name) - + node = rt.getNodeByName(container["instance_node"]) + node_list = get_previous_loaded_object(node) + rt.Select(node_list) update_custom_attribute_data( - inst_container, inst_container.Children) - for proxy in inst_container.Children: + node, rt.Selection) + for proxy in rt.Selection: proxy.file = path lib.imprint(container["instance_node"], { From 78ec30cb392bd3fbe686101329089d63da797e86 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 13 Sep 2023 18:21:17 +0800 Subject: [PATCH 07/13] hound --- openpype/hosts/max/api/pipeline.py | 4 ++-- openpype/hosts/max/plugins/load/load_camera_fbx.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/max/api/pipeline.py b/openpype/hosts/max/api/pipeline.py index 6c40acc56b..86a0a99ca9 100644 --- a/openpype/hosts/max/api/pipeline.py +++ b/openpype/hosts/max/api/pipeline.py @@ -166,8 +166,6 @@ def containerise(name: str, nodes: list, context, } container_name = f"{namespace}:{name}{suffix}" container = rt.container(name=container_name) - #for node in nodes: - # node.Parent = container import_custom_attribute_data(container, nodes) if not lib.imprint(container_name, data): print(f"imprinting of {container_name} failed.") @@ -211,6 +209,7 @@ def import_custom_attribute_data(container: str, selections: list): container.modifiers[0].openPypeData, "sel_list", sel_list) + def update_custom_attribute_data(container: str, selections: list): """Updating the Openpype/AYON custom parameter built by the creator @@ -223,6 +222,7 @@ def update_custom_attribute_data(container: str, selections: list): rt.deleteModifier(container, container.modifiers[0]) import_custom_attribute_data(container, selections) + def get_previous_loaded_object(container: str): """Get previous loaded_object through the OP data diff --git a/openpype/hosts/max/plugins/load/load_camera_fbx.py b/openpype/hosts/max/plugins/load/load_camera_fbx.py index 39bbf79d0f..d28364d5c2 100644 --- a/openpype/hosts/max/plugins/load/load_camera_fbx.py +++ b/openpype/hosts/max/plugins/load/load_camera_fbx.py @@ -81,7 +81,7 @@ class FbxLoader(load.LoaderPlugin): fbx_object.pos = transform_data[ f"{fbx_object.name}.transform"] or fbx_object.pos fbx_object.scale = transform_data[ - f"{fbx_object.name}.scale"] or fbx_object.scale + f"{fbx_object.name}.scale"] or fbx_object.scale with maintained_selection(): rt.Select(node) From bdaeb3c92f3ba5c2744ce69fa3aadd3135f33699 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 13 Sep 2023 19:08:09 +0800 Subject: [PATCH 08/13] add loadError for loaders which uses external plugins --- openpype/hosts/max/api/lib.py | 16 ++++++++++++++++ .../hosts/max/plugins/load/load_model_usd.py | 8 ++++++-- .../hosts/max/plugins/load/load_pointcloud.py | 4 ++-- .../max/plugins/load/load_redshift_proxy.py | 8 ++++++-- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/max/api/lib.py b/openpype/hosts/max/api/lib.py index 8287341456..4a150067e1 100644 --- a/openpype/hosts/max/api/lib.py +++ b/openpype/hosts/max/api/lib.py @@ -407,3 +407,19 @@ def object_transform_set(container_children): name = f"{node.name}.scale" transform_set[name] = node.scale return transform_set + + +def get_plugins() -> list: + """Get all loaded plugins in 3dsMax + + Returns: + plugin_info_list: a list of loaded plugins + """ + manager = rt.PluginManager + count = manager.pluginDllCount + plugin_info_list = [] + for p in range(1, count + 1): + plugin_info = manager.pluginDllName(p) + plugin_info_list.append(plugin_info) + + return plugin_info_list diff --git a/openpype/hosts/max/plugins/load/load_model_usd.py b/openpype/hosts/max/plugins/load/load_model_usd.py index 09566c2e78..67d0e75259 100644 --- a/openpype/hosts/max/plugins/load/load_model_usd.py +++ b/openpype/hosts/max/plugins/load/load_model_usd.py @@ -1,12 +1,13 @@ import os from pymxs import runtime as rt - +from openpype.pipeline.load import LoadError from openpype.hosts.max.api import lib from openpype.hosts.max.api.lib import ( unique_namespace, get_namespace, - object_transform_set + object_transform_set, + get_plugins ) from openpype.hosts.max.api.lib import maintained_selection from openpype.hosts.max.api.pipeline import ( @@ -29,6 +30,9 @@ class ModelUSDLoader(load.LoaderPlugin): def load(self, context, name=None, namespace=None, data=None): # asset_filepath + plugin_info = get_plugins() + if "usdimport.dli" not in plugin_info: + raise LoadError("No USDImporter loaded/installed in Max..") filepath = os.path.normpath(self.filepath_from_context(context)) import_options = rt.USDImporter.CreateOptions() base_filename = os.path.basename(filepath) diff --git a/openpype/hosts/max/plugins/load/load_pointcloud.py b/openpype/hosts/max/plugins/load/load_pointcloud.py index 2309d3aebf..e0317a2e22 100644 --- a/openpype/hosts/max/plugins/load/load_pointcloud.py +++ b/openpype/hosts/max/plugins/load/load_pointcloud.py @@ -2,7 +2,8 @@ import os from openpype.hosts.max.api import lib, maintained_selection from openpype.hosts.max.api.lib import ( - unique_namespace + unique_namespace, + ) from openpype.hosts.max.api.pipeline import ( containerise, @@ -25,7 +26,6 @@ class PointCloudLoader(load.LoaderPlugin): def load(self, context, name=None, namespace=None, data=None): """load point cloud by tyCache""" from pymxs import runtime as rt - filepath = os.path.normpath(self.filepath_from_context(context)) obj = rt.tyCache() obj.filename = filepath diff --git a/openpype/hosts/max/plugins/load/load_redshift_proxy.py b/openpype/hosts/max/plugins/load/load_redshift_proxy.py index 36bc7ac9e2..daf6d3e169 100644 --- a/openpype/hosts/max/plugins/load/load_redshift_proxy.py +++ b/openpype/hosts/max/plugins/load/load_redshift_proxy.py @@ -5,6 +5,7 @@ from openpype.pipeline import ( load, get_representation_path ) +from openpype.pipeline.load import LoadError from openpype.hosts.max.api.pipeline import ( containerise, update_custom_attribute_data, @@ -12,7 +13,8 @@ from openpype.hosts.max.api.pipeline import ( ) from openpype.hosts.max.api import lib from openpype.hosts.max.api.lib import ( - unique_namespace + unique_namespace, + get_plugins ) @@ -28,7 +30,9 @@ class RedshiftProxyLoader(load.LoaderPlugin): def load(self, context, name=None, namespace=None, data=None): from pymxs import runtime as rt - + plugin_info = get_plugins() + if "redshift4max.dlr" not in plugin_info: + raise LoadError("Redshift not loaded/installed in Max..") filepath = self.filepath_from_context(context) rs_proxy = rt.RedshiftProxy() rs_proxy.file = filepath From 8c890641ad9bb8a6f30f82fb2b668e0a6c05281d Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 13 Sep 2023 21:18:30 +0800 Subject: [PATCH 09/13] fixing the issue of duplciated contents during switching assets --- openpype/hosts/max/plugins/load/load_camera_fbx.py | 4 ++-- openpype/hosts/max/plugins/load/load_max_scene.py | 7 +++---- openpype/hosts/max/plugins/load/load_model_fbx.py | 4 ++-- openpype/hosts/max/plugins/load/load_model_obj.py | 4 ++-- openpype/hosts/max/plugins/load/load_model_usd.py | 4 ++-- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/openpype/hosts/max/plugins/load/load_camera_fbx.py b/openpype/hosts/max/plugins/load/load_camera_fbx.py index d28364d5c2..156e8dcaf6 100644 --- a/openpype/hosts/max/plugins/load/load_camera_fbx.py +++ b/openpype/hosts/max/plugins/load/load_camera_fbx.py @@ -79,9 +79,9 @@ class FbxLoader(load.LoaderPlugin): fbx_object.name = f"{namespace}:{fbx_object.name}" if fbx_object in node_list: fbx_object.pos = transform_data[ - f"{fbx_object.name}.transform"] or fbx_object.pos + f"{fbx_object.name}.transform"] or 0 fbx_object.scale = transform_data[ - f"{fbx_object.name}.scale"] or fbx_object.scale + f"{fbx_object.name}.scale"] or 0 with maintained_selection(): rt.Select(node) diff --git a/openpype/hosts/max/plugins/load/load_max_scene.py b/openpype/hosts/max/plugins/load/load_max_scene.py index 86b7637c90..b7ce5bfe39 100644 --- a/openpype/hosts/max/plugins/load/load_max_scene.py +++ b/openpype/hosts/max/plugins/load/load_max_scene.py @@ -60,8 +60,7 @@ class MaxSceneLoader(load.LoaderPlugin): # delete old duplicate # use the modifier OP data to delete the data node_list = get_previous_loaded_object(node) - rt.Select(node_list) - prev_max_objects = rt.GetCurrentSelection() + prev_max_objects = rt.getLastMergedNodes() transform_data = object_transform_set(prev_max_objects) for prev_max_obj in prev_max_objects: if rt.isValidNode(prev_max_obj): # noqa @@ -77,9 +76,9 @@ class MaxSceneLoader(load.LoaderPlugin): max_obj.name = f"{namespace}:{obj_name}" if max_obj in node_list: max_obj.pos = transform_data[ - f"{max_obj.name}.transform"] or max_obj.pos + f"{max_obj.name}.transform"] or 0 max_obj.scale = transform_data[ - f"{max_obj.name}.scale"] or max_obj.scale + f"{max_obj.name}.scale"] or 0 lib.imprint(container["instance_node"], { "representation": str(representation["_id"]) }) diff --git a/openpype/hosts/max/plugins/load/load_model_fbx.py b/openpype/hosts/max/plugins/load/load_model_fbx.py index a8f6ea90d6..bea4d28fb7 100644 --- a/openpype/hosts/max/plugins/load/load_model_fbx.py +++ b/openpype/hosts/max/plugins/load/load_model_fbx.py @@ -73,9 +73,9 @@ class FbxModelLoader(load.LoaderPlugin): fbx_object.name = f"{namespace}:{fbx_object.name}" if fbx_object in node_list: fbx_object.pos = transform_data[ - f"{fbx_object.name}.transform"] or fbx_object.pos + f"{fbx_object.name}.transform"] or 0 fbx_object.scale = transform_data[ - f"{fbx_object.name}.scale"] or fbx_object.scale + f"{fbx_object.name}.scale"] or 0 with maintained_selection(): rt.Select(node) diff --git a/openpype/hosts/max/plugins/load/load_model_obj.py b/openpype/hosts/max/plugins/load/load_model_obj.py index 421bd34e62..ca970fb9d7 100644 --- a/openpype/hosts/max/plugins/load/load_model_obj.py +++ b/openpype/hosts/max/plugins/load/load_model_obj.py @@ -68,9 +68,9 @@ class ObjLoader(load.LoaderPlugin): selection.name = f"{namespace}:{selection.name}" if selection in node_list: selection.pos = transform_data[ - f"{selection.name}.transform"] or selection.pos + f"{selection.name}.transform"] or 0 selection.scale = transform_data[ - f"{selection.name}.scale"] or selection.scale + f"{selection.name}.scale"] or 0 update_custom_attribute_data(node, selections) with maintained_selection(): rt.Select(node) diff --git a/openpype/hosts/max/plugins/load/load_model_usd.py b/openpype/hosts/max/plugins/load/load_model_usd.py index 67d0e75259..6476f65a04 100644 --- a/openpype/hosts/max/plugins/load/load_model_usd.py +++ b/openpype/hosts/max/plugins/load/load_model_usd.py @@ -93,9 +93,9 @@ class ModelUSDLoader(load.LoaderPlugin): usd_objects.append(children) if children in node_list: children.pos = transform_data[ - f"{children.name}.transform"] or children.pos + f"{children.name}.transform"] or 0 children.scale = transform_data[ - f"{children.name}.scale"] or children.scale + f"{children.name}.scale"] or 0 asset.name = f"{namespace}:{asset.name}" usd_objects.append(asset) From 70bab9fdb8e673350e76e2e7fc18e967b86c6e8e Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 13 Sep 2023 21:59:57 +0800 Subject: [PATCH 10/13] fixing the issue of duplciated contents during switching assets --- openpype/hosts/max/plugins/load/load_camera_fbx.py | 5 ++++- openpype/hosts/max/plugins/load/load_model_fbx.py | 4 +++- openpype/hosts/max/plugins/load/load_model_obj.py | 4 +++- openpype/hosts/max/plugins/load/load_model_usd.py | 4 +++- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/max/plugins/load/load_camera_fbx.py b/openpype/hosts/max/plugins/load/load_camera_fbx.py index 156e8dcaf6..5e4623fe4c 100644 --- a/openpype/hosts/max/plugins/load/load_camera_fbx.py +++ b/openpype/hosts/max/plugins/load/load_camera_fbx.py @@ -73,7 +73,10 @@ class FbxLoader(load.LoaderPlugin): rt.FBXImporterSetParam("Preserveinstances", True) rt.ImportFile( path, rt.name("noPrompt"), using=rt.FBXIMP) - current_fbx_objects = rt.GetCurrentSelection() + current_fbx_objects = [sel for sel in rt.GetCurrentSelection() + if sel != rt.Container + and sel.name == node_name] + update_custom_attribute_data(node, current_fbx_objects) for fbx_object in current_fbx_objects: fbx_object.name = f"{namespace}:{fbx_object.name}" diff --git a/openpype/hosts/max/plugins/load/load_model_fbx.py b/openpype/hosts/max/plugins/load/load_model_fbx.py index bea4d28fb7..9542eaa74e 100644 --- a/openpype/hosts/max/plugins/load/load_model_fbx.py +++ b/openpype/hosts/max/plugins/load/load_model_fbx.py @@ -56,7 +56,9 @@ class FbxModelLoader(load.LoaderPlugin): node_list = get_previous_loaded_object(node) rt.Select(node_list) - prev_fbx_objects = rt.GetCurrentSelection() + prev_fbx_objects = [sel for sel in rt.GetCurrentSelection() + if sel != rt.Container + and sel.name == node_name] transform_data = object_transform_set(prev_fbx_objects) for prev_fbx_obj in prev_fbx_objects: if rt.isValidNode(prev_fbx_obj): diff --git a/openpype/hosts/max/plugins/load/load_model_obj.py b/openpype/hosts/max/plugins/load/load_model_obj.py index ca970fb9d7..38ba5e3e8f 100644 --- a/openpype/hosts/max/plugins/load/load_model_obj.py +++ b/openpype/hosts/max/plugins/load/load_model_obj.py @@ -55,7 +55,9 @@ class ObjLoader(load.LoaderPlugin): namespace, _ = get_namespace(node_name) node_list = get_previous_loaded_object(node) rt.Select(node_list) - previous_objects = rt.GetCurrentSelection() + previous_objects = [sel for sel in rt.GetCurrentSelection() + if sel != rt.Container + and sel.name == node_name] transform_data = object_transform_set(previous_objects) for prev_obj in previous_objects: if rt.isValidNode(prev_obj): diff --git a/openpype/hosts/max/plugins/load/load_model_usd.py b/openpype/hosts/max/plugins/load/load_model_usd.py index 6476f65a04..cabcdaa6b5 100644 --- a/openpype/hosts/max/plugins/load/load_model_usd.py +++ b/openpype/hosts/max/plugins/load/load_model_usd.py @@ -71,7 +71,9 @@ class ModelUSDLoader(load.LoaderPlugin): namespace, name = get_namespace(node_name) node_list = get_previous_loaded_object(node) rt.Select(node_list) - prev_objects = rt.GetCurrentSelection() + prev_objects = [sel for sel in rt.GetCurrentSelection() + if sel != rt.Container + and sel.name == node_name] transform_data = object_transform_set(prev_objects) for n in prev_objects: rt.Delete(n) From c53abb50f07c5e7e1df185425e034f744d2314a8 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 13 Sep 2023 22:06:11 +0800 Subject: [PATCH 11/13] fixing the issue of duplciated contents during switching assets --- openpype/hosts/max/plugins/load/load_camera_fbx.py | 2 +- openpype/hosts/max/plugins/load/load_model_fbx.py | 2 +- openpype/hosts/max/plugins/load/load_model_usd.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/max/plugins/load/load_camera_fbx.py b/openpype/hosts/max/plugins/load/load_camera_fbx.py index 5e4623fe4c..1f891e19b3 100644 --- a/openpype/hosts/max/plugins/load/load_camera_fbx.py +++ b/openpype/hosts/max/plugins/load/load_camera_fbx.py @@ -75,7 +75,7 @@ class FbxLoader(load.LoaderPlugin): path, rt.name("noPrompt"), using=rt.FBXIMP) current_fbx_objects = [sel for sel in rt.GetCurrentSelection() if sel != rt.Container - and sel.name == node_name] + and sel.name != node_name] update_custom_attribute_data(node, current_fbx_objects) for fbx_object in current_fbx_objects: diff --git a/openpype/hosts/max/plugins/load/load_model_fbx.py b/openpype/hosts/max/plugins/load/load_model_fbx.py index 9542eaa74e..cdc5667d78 100644 --- a/openpype/hosts/max/plugins/load/load_model_fbx.py +++ b/openpype/hosts/max/plugins/load/load_model_fbx.py @@ -58,7 +58,7 @@ class FbxModelLoader(load.LoaderPlugin): rt.Select(node_list) prev_fbx_objects = [sel for sel in rt.GetCurrentSelection() if sel != rt.Container - and sel.name == node_name] + and sel.name != node_name] transform_data = object_transform_set(prev_fbx_objects) for prev_fbx_obj in prev_fbx_objects: if rt.isValidNode(prev_fbx_obj): diff --git a/openpype/hosts/max/plugins/load/load_model_usd.py b/openpype/hosts/max/plugins/load/load_model_usd.py index cabcdaa6b5..38233cfd62 100644 --- a/openpype/hosts/max/plugins/load/load_model_usd.py +++ b/openpype/hosts/max/plugins/load/load_model_usd.py @@ -73,7 +73,7 @@ class ModelUSDLoader(load.LoaderPlugin): rt.Select(node_list) prev_objects = [sel for sel in rt.GetCurrentSelection() if sel != rt.Container - and sel.name == node_name] + and sel.name != node_name] transform_data = object_transform_set(prev_objects) for n in prev_objects: rt.Delete(n) From 559021b5f6d42d644ed0efde7ae09ccba2399c6f Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 14 Sep 2023 16:27:49 +0800 Subject: [PATCH 12/13] fix the bug of the 3dsmax OP data not being collected during switching version --- .../hosts/max/plugins/load/load_camera_fbx.py | 18 ++++++------- .../hosts/max/plugins/load/load_max_scene.py | 25 ++++++++++++------- .../hosts/max/plugins/load/load_model_fbx.py | 17 +++++++------ .../hosts/max/plugins/load/load_model_obj.py | 10 +++----- .../hosts/max/plugins/load/load_model_usd.py | 6 ++--- 5 files changed, 39 insertions(+), 37 deletions(-) diff --git a/openpype/hosts/max/plugins/load/load_camera_fbx.py b/openpype/hosts/max/plugins/load/load_camera_fbx.py index 1f891e19b3..ce1427a980 100644 --- a/openpype/hosts/max/plugins/load/load_camera_fbx.py +++ b/openpype/hosts/max/plugins/load/load_camera_fbx.py @@ -73,22 +73,18 @@ class FbxLoader(load.LoaderPlugin): rt.FBXImporterSetParam("Preserveinstances", True) rt.ImportFile( path, rt.name("noPrompt"), using=rt.FBXIMP) - current_fbx_objects = [sel for sel in rt.GetCurrentSelection() - if sel != rt.Container - and sel.name != node_name] - - update_custom_attribute_data(node, current_fbx_objects) + current_fbx_objects = rt.GetCurrentSelection() + fbx_objects = [] for fbx_object in current_fbx_objects: fbx_object.name = f"{namespace}:{fbx_object.name}" - if fbx_object in node_list: - fbx_object.pos = transform_data[ - f"{fbx_object.name}.transform"] or 0 + fbx_objects.append(fbx_object) + fbx_transform = f"{fbx_object.name}.transform" + if fbx_transform in transform_data.keys(): + fbx_object.pos = transform_data[fbx_transform] or 0 fbx_object.scale = transform_data[ f"{fbx_object.name}.scale"] or 0 - with maintained_selection(): - rt.Select(node) - + update_custom_attribute_data(node, fbx_objects) lib.imprint(container["instance_node"], { "representation": str(representation["_id"]) }) diff --git a/openpype/hosts/max/plugins/load/load_max_scene.py b/openpype/hosts/max/plugins/load/load_max_scene.py index b7ce5bfe39..4b66dbff6f 100644 --- a/openpype/hosts/max/plugins/load/load_max_scene.py +++ b/openpype/hosts/max/plugins/load/load_max_scene.py @@ -43,7 +43,6 @@ class MaxSceneLoader(load.LoaderPlugin): for max_obj, obj_name in zip(max_objects, max_object_names): max_obj.name = f"{namespace}:{obj_name}" max_container.append(rt.getNodeByName(max_obj.name)) - return containerise( name, max_container, context, namespace, loader=self.__class__.__name__) @@ -53,32 +52,40 @@ class MaxSceneLoader(load.LoaderPlugin): path = get_representation_path(representation) node_name = container["instance_node"] - + print(node_name) node = rt.getNodeByName(node_name) namespace, _ = get_namespace(node_name) # delete the old container with attribute # delete old duplicate # use the modifier OP data to delete the data node_list = get_previous_loaded_object(node) - prev_max_objects = rt.getLastMergedNodes() + rt.select(node_list) + prev_max_objects = rt.GetCurrentSelection() + print(f"{node_list}") transform_data = object_transform_set(prev_max_objects) + for prev_max_obj in prev_max_objects: if rt.isValidNode(prev_max_obj): # noqa rt.Delete(prev_max_obj) - rt.MergeMaxFile(path, rt.Name("deleteOldDups")) + rt.MergeMaxFile(path, quiet=True) current_max_objects = rt.getLastMergedNodes() + current_max_object_names = [obj.name for obj in current_max_objects] - update_custom_attribute_data(node, current_max_objects) + + max_objects = [] for max_obj, obj_name in zip(current_max_objects, - current_max_object_names): + current_max_object_names): max_obj.name = f"{namespace}:{obj_name}" - if max_obj in node_list: - max_obj.pos = transform_data[ - f"{max_obj.name}.transform"] or 0 + max_objects.append(max_obj) + max_transform = f"{max_obj.name}.transform" + if max_transform in transform_data.keys(): + max_obj.pos = transform_data[max_transform] or 0 max_obj.scale = transform_data[ f"{max_obj.name}.scale"] or 0 + + update_custom_attribute_data(node, max_objects) lib.imprint(container["instance_node"], { "representation": str(representation["_id"]) }) diff --git a/openpype/hosts/max/plugins/load/load_model_fbx.py b/openpype/hosts/max/plugins/load/load_model_fbx.py index cdc5667d78..71fc382eed 100644 --- a/openpype/hosts/max/plugins/load/load_model_fbx.py +++ b/openpype/hosts/max/plugins/load/load_model_fbx.py @@ -52,13 +52,13 @@ class FbxModelLoader(load.LoaderPlugin): path = get_representation_path(representation) node_name = container["instance_node"] node = rt.getNodeByName(node_name) + if not node: + rt.Container(name=node_name) namespace, _ = get_namespace(node_name) node_list = get_previous_loaded_object(node) rt.Select(node_list) - prev_fbx_objects = [sel for sel in rt.GetCurrentSelection() - if sel != rt.Container - and sel.name != node_name] + prev_fbx_objects = rt.GetCurrentSelection() transform_data = object_transform_set(prev_fbx_objects) for prev_fbx_obj in prev_fbx_objects: if rt.isValidNode(prev_fbx_obj): @@ -70,18 +70,19 @@ class FbxModelLoader(load.LoaderPlugin): rt.FBXImporterSetParam("Preserveinstances", True) rt.importFile(path, rt.name("noPrompt"), using=rt.FBXIMP) current_fbx_objects = rt.GetCurrentSelection() - update_custom_attribute_data(node, current_fbx_objects) + fbx_objects = [] for fbx_object in current_fbx_objects: fbx_object.name = f"{namespace}:{fbx_object.name}" - if fbx_object in node_list: - fbx_object.pos = transform_data[ - f"{fbx_object.name}.transform"] or 0 + fbx_objects.append(fbx_object) + fbx_transform = f"{fbx_object.name}.transform" + if fbx_transform in transform_data.keys(): + fbx_object.pos = transform_data[fbx_transform] or 0 fbx_object.scale = transform_data[ f"{fbx_object.name}.scale"] or 0 with maintained_selection(): rt.Select(node) - + update_custom_attribute_data(node, fbx_objects) lib.imprint(container["instance_node"], { "representation": str(representation["_id"]) }) diff --git a/openpype/hosts/max/plugins/load/load_model_obj.py b/openpype/hosts/max/plugins/load/load_model_obj.py index 38ba5e3e8f..aedb288a2d 100644 --- a/openpype/hosts/max/plugins/load/load_model_obj.py +++ b/openpype/hosts/max/plugins/load/load_model_obj.py @@ -55,9 +55,7 @@ class ObjLoader(load.LoaderPlugin): namespace, _ = get_namespace(node_name) node_list = get_previous_loaded_object(node) rt.Select(node_list) - previous_objects = [sel for sel in rt.GetCurrentSelection() - if sel != rt.Container - and sel.name == node_name] + previous_objects = rt.GetCurrentSelection() transform_data = object_transform_set(previous_objects) for prev_obj in previous_objects: if rt.isValidNode(prev_obj): @@ -68,9 +66,9 @@ class ObjLoader(load.LoaderPlugin): selections = rt.GetCurrentSelection() for selection in selections: selection.name = f"{namespace}:{selection.name}" - if selection in node_list: - selection.pos = transform_data[ - f"{selection.name}.transform"] or 0 + selection_transform = f"{selection.name}.transform" + if selection_transform in transform_data.keys(): + selection.pos = transform_data[selection_transform] or 0 selection.scale = transform_data[ f"{selection.name}.scale"] or 0 update_custom_attribute_data(node, selections) diff --git a/openpype/hosts/max/plugins/load/load_model_usd.py b/openpype/hosts/max/plugins/load/load_model_usd.py index 38233cfd62..bce4bd4a9a 100644 --- a/openpype/hosts/max/plugins/load/load_model_usd.py +++ b/openpype/hosts/max/plugins/load/load_model_usd.py @@ -93,9 +93,9 @@ class ModelUSDLoader(load.LoaderPlugin): for children in asset.Children: children.name = f"{namespace}:{children.name}" usd_objects.append(children) - if children in node_list: - children.pos = transform_data[ - f"{children.name}.transform"] or 0 + children_transform = f"{children.name}.transform" + if children_transform in transform_data.keys(): + children.pos = transform_data[children_transform] or 0 children.scale = transform_data[ f"{children.name}.scale"] or 0 From cad715ad0182cbfaa2093b7217723170af293887 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 14 Sep 2023 16:32:04 +0800 Subject: [PATCH 13/13] remove print & hound --- openpype/hosts/max/plugins/load/load_max_scene.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/hosts/max/plugins/load/load_max_scene.py b/openpype/hosts/max/plugins/load/load_max_scene.py index 4b66dbff6f..0b5f0a2858 100644 --- a/openpype/hosts/max/plugins/load/load_max_scene.py +++ b/openpype/hosts/max/plugins/load/load_max_scene.py @@ -52,7 +52,6 @@ class MaxSceneLoader(load.LoaderPlugin): path = get_representation_path(representation) node_name = container["instance_node"] - print(node_name) node = rt.getNodeByName(node_name) namespace, _ = get_namespace(node_name) # delete the old container with attribute @@ -61,7 +60,6 @@ class MaxSceneLoader(load.LoaderPlugin): node_list = get_previous_loaded_object(node) rt.select(node_list) prev_max_objects = rt.GetCurrentSelection() - print(f"{node_list}") transform_data = object_transform_set(prev_max_objects) for prev_max_obj in prev_max_objects: @@ -76,7 +74,7 @@ class MaxSceneLoader(load.LoaderPlugin): max_objects = [] for max_obj, obj_name in zip(current_max_objects, - current_max_object_names): + current_max_object_names): max_obj.name = f"{namespace}:{obj_name}" max_objects.append(max_obj) max_transform = f"{max_obj.name}.transform"