From 812f507a89ef5fa94812f960ea87a6ff970db57d Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 20 Feb 2019 17:17:01 +0100 Subject: [PATCH] add collector and loader for assembly --- pype/plugins/maya/load/load_assembly.py | 80 ++++++++++++++++ pype/plugins/maya/publish/collect_assembly.py | 94 +++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 pype/plugins/maya/load/load_assembly.py create mode 100644 pype/plugins/maya/publish/collect_assembly.py diff --git a/pype/plugins/maya/load/load_assembly.py b/pype/plugins/maya/load/load_assembly.py new file mode 100644 index 0000000000..4f72ff9e13 --- /dev/null +++ b/pype/plugins/maya/load/load_assembly.py @@ -0,0 +1,80 @@ +from avalon import api + + +class AssemblyLoader(api.Loader): + + families = ["assembly"] + representations = ["json"] + + label = "Load Set Dress" + order = -9 + icon = "code-fork" + color = "orange" + + def load(self, context, name, namespace, data): + + from avalon.maya.pipeline import containerise + from avalon.maya import lib + + asset = context['asset']['name'] + namespace = namespace or lib.unique_namespace( + asset + "_", + prefix="_" if asset[0].isdigit() else "", + suffix="_", + ) + + from pype import setdress_api + + containers = setdress_api.load_package(filepath=self.fname, + name=name, + namespace=namespace) + + self[:] = containers + + # Only containerize if any nodes were loaded by the Loader + nodes = self[:] + if not nodes: + return + + return containerise( + name=name, + namespace=namespace, + nodes=nodes, + context=context, + loader=self.__class__.__name__) + + def update(self, container, representation): + + from pype import setdress_api + return setdress_api.update_package(container, + representation) + + def remove(self, container): + """Remove all sub containers""" + + from avalon import api + from pype import setdress_api + import maya.cmds as cmds + + # Remove all members + member_containers = setdress_api.get_contained_containers(container) + for member_container in member_containers: + self.log.info("Removing container %s", + member_container['objectName']) + api.remove(member_container) + + # Remove alembic hierarchy reference + # TODO: Check whether removing all contained references is safe enough + members = cmds.sets(container['objectName'], query=True) or [] + references = cmds.ls(members, type="reference") + for reference in references: + self.log.info("Removing %s", reference) + fname = cmds.referenceQuery(reference, filename=True) + cmds.file(fname, removeReference=True) + + # Delete container and its contents + if cmds.objExists(container['objectName']): + members = cmds.sets(container['objectName'], query=True) or [] + cmds.delete([container['objectName']] + members) + + # TODO: Ensure namespace is gone diff --git a/pype/plugins/maya/publish/collect_assembly.py b/pype/plugins/maya/publish/collect_assembly.py new file mode 100644 index 0000000000..76274b1032 --- /dev/null +++ b/pype/plugins/maya/publish/collect_assembly.py @@ -0,0 +1,94 @@ +from collections import defaultdict +import pyblish.api + +from maya import cmds, mel +from avalon import maya as avalon +from pype.maya import lib + +# TODO : Publish of assembly: -unique namespace for all assets, VALIDATOR! + + +class CollectAssembly(pyblish.api.InstancePlugin): + """Collect all relevant assembly items + + Collected data: + + * File name + * Compatible loader + * Matrix per instance + * Namespace + + Note: GPU caches are currently not supported in the pipeline. There is no + logic yet which supports the swapping of GPU cache to renderable objects. + + """ + + order = pyblish.api.CollectorOrder + 0.49 + label = "Assemby" + families = ["assembly"] + + def process(self, instance): + + # Find containers + containers = avalon.ls() + + # Get all content from the instance + instance_lookup = set(cmds.ls(instance, type="transform", long=True)) + data = defaultdict(list) + self.log.info(instance_lookup) + + hierarchy_nodes = [] + for container in containers: + + self.log.info(container) + root = lib.get_container_transforms(container, root=True) + self.log.info(root) + if not root or root not in instance_lookup: + continue + + # Retrieve the hierarchy + parent = cmds.listRelatives(root, parent=True, fullPath=True)[0] + hierarchy_nodes.append(parent) + + # Temporary warning for GPU cache which are not supported yet + loader = container["loader"] + if loader == "GpuCacheLoader": + self.log.warning("GPU Cache Loader is currently not supported" + "in the pipeline, we will export it tho") + + # Gather info for new data entry + representation_id = container["representation"] + instance_data = {"loader": loader, + "parent": parent, + "namespace": container["namespace"]} + + # Check if matrix differs from default and store changes + matrix_data = self.get_matrix_data(root) + if matrix_data: + instance_data["matrix"] = matrix_data + + data[representation_id].append(instance_data) + + instance.data["scenedata"] = dict(data) + instance.data["hierarchy"] = list(set(hierarchy_nodes)) + + def get_file_rule(self, rule): + return mel.eval('workspace -query -fileRuleEntry "{}"'.format(rule)) + + def get_matrix_data(self, node): + """Get the matrix of all members when they are not default + + Each matrix which differs from the default will be stored in a + dictionary + + Args: + members (list): list of transform nmodes + Returns: + dict + """ + + matrix = cmds.xform(node, query=True, matrix=True) + if matrix == lib.DEFAULT_MATRIX: + return + + return matrix