From 8468dbce679cc5dfee58e99e4015bb812f47080d Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Fri, 6 Jan 2023 05:04:53 +0100 Subject: [PATCH] Implement managing for Load Mesh (draft implementation) --- .../hosts/substancepainter/api/pipeline.py | 47 +++++++++++- .../plugins/load/load_mesh.py | 71 ++++++++++++++----- 2 files changed, 97 insertions(+), 21 deletions(-) diff --git a/openpype/hosts/substancepainter/api/pipeline.py b/openpype/hosts/substancepainter/api/pipeline.py index 31c87f079d..4d49fa83d7 100644 --- a/openpype/hosts/substancepainter/api/pipeline.py +++ b/openpype/hosts/substancepainter/api/pipeline.py @@ -123,7 +123,16 @@ class SubstanceHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost): return filepath def get_containers(self): - return [] + + if not substance_painter.project.is_open(): + return + + metadata = substance_painter.project.Metadata("OpenPype") + containers = metadata.get("containers") + if containers: + for key, container in containers.items(): + container["objectName"] = key + yield container @staticmethod def create_context_node(): @@ -231,4 +240,38 @@ def on_open(): dialog.setMessage("There are outdated containers in " "your Substance scene.") dialog.on_clicked.connect(_on_show_inventory) - dialog.show() \ No newline at end of file + dialog.show() + + +def imprint_container(container, + name, + namespace, + context, + loader): + """Imprint a loaded container with metadata. + + Containerisation enables a tracking of version, author and origin + for loaded assets. + + Arguments: + container (dict): The (substance metadata) dictionary to imprint into. + name (str): Name of resulting assembly + namespace (str): Namespace under which to host container + context (dict): Asset information + loader (load.LoaderPlugin): loader instance used to produce container. + + Returns: + None + + """ + + data = [ + ("schema", "openpype:container-2.0"), + ("id", AVALON_CONTAINER_ID), + ("name", str(name)), + ("namespace", str(namespace) if namespace else None), + ("loader", str(loader.__class__.__name__)), + ("representation", str(context["representation"]["_id"])), + ] + for key, value in data: + container[key] = value diff --git a/openpype/hosts/substancepainter/plugins/load/load_mesh.py b/openpype/hosts/substancepainter/plugins/load/load_mesh.py index 7cc5e35912..519ed3ad4e 100644 --- a/openpype/hosts/substancepainter/plugins/load/load_mesh.py +++ b/openpype/hosts/substancepainter/plugins/load/load_mesh.py @@ -2,12 +2,27 @@ from openpype.pipeline import ( load, get_representation_path, ) -from openpype.pipeline import legacy_io +from openpype.hosts.substancepainter.api.pipeline import imprint_container import substance_painter.project import qargparse +def set_container(key, container): + metadata = substance_painter.project.Metadata("OpenPype") + containers = metadata.get("containers") or {} + containers[key] = container + metadata.set("containers", containers) + + +def remove_container(key): + metadata = substance_painter.project.Metadata("OpenPype") + containers = metadata.get("containers") + if containers: + containers.pop(key, None) + metadata.set("containers", containers) + + class SubstanceLoadProjectMesh(load.LoaderPlugin): """Load mesh for project""" @@ -33,6 +48,8 @@ class SubstanceLoadProjectMesh(load.LoaderPlugin): ) ] + container_key = "ProjectMesh" + def load(self, context, name, namespace, data): if not substance_painter.project.is_open(): @@ -49,25 +66,34 @@ class SubstanceLoadProjectMesh(load.LoaderPlugin): mesh_file_path=self.fname, settings=settings ) - return - # Reload the mesh - settings = substance_painter.project.MeshReloadingSettings( - import_cameras=data.get("import_cameras", True), - preserve_strokes=data.get("preserve_strokes", True) - ) + else: + # Reload the mesh + settings = substance_painter.project.MeshReloadingSettings( + import_cameras=data.get("import_cameras", True), + preserve_strokes=data.get("preserve_strokes", True) + ) - def on_mesh_reload(status: substance_painter.project.ReloadMeshStatus): - if status == substance_painter.project.ReloadMeshStatus.SUCCESS: - print("Reload succeeded") - else: - raise RuntimeError("Reload of mesh failed") + def on_mesh_reload(status: substance_painter.project.ReloadMeshStatus): # noqa + if status == substance_painter.project.ReloadMeshStatus.SUCCESS: # noqa + print("Reload succeeded") + else: + raise RuntimeError("Reload of mesh failed") - path = self.fname - substance_painter.project.reload_mesh(path, settings, on_mesh_reload) + path = self.fname + substance_painter.project.reload_mesh(path, + settings, + on_mesh_reload) - # TODO: Register with the project so host.get_containers() can return - # the loaded content in manager + # Store container + container = {} + imprint_container(container, + name=self.container_key, + namespace=self.container_key, + context=context, + loader=self) + container["options"] = data + set_container(self.container_key, container) def switch(self, container, representation): self.update(container, representation) @@ -78,9 +104,10 @@ class SubstanceLoadProjectMesh(load.LoaderPlugin): # Reload the mesh # TODO: Re-use settings from first load? + container_options = container.get("options", {}) settings = substance_painter.project.MeshReloadingSettings( - import_cameras=True, - preserve_strokes=True + import_cameras=container_options.get("import_cameras", True), + preserve_strokes=container_options.get("preserve_strokes", True) ) def on_mesh_reload(status: substance_painter.project.ReloadMeshStatus): @@ -91,8 +118,14 @@ class SubstanceLoadProjectMesh(load.LoaderPlugin): substance_painter.project.reload_mesh(path, settings, on_mesh_reload) + # Update container representation + container["representation"] = str(representation["_id"]) + set_container(self.container_key, container) + def remove(self, container): # Remove OpenPype related settings about what model was loaded # or close the project? - pass + # TODO: This is likely best 'hidden' away to the user because + # this will leave the project's mesh unmanaged. + remove_container(self.container_key)