From 115a85f3914febd5825267e7dd1bd97139fa6f3d Mon Sep 17 00:00:00 2001 From: aardschok Date: Tue, 25 Jul 2017 13:39:05 +0200 Subject: [PATCH] extended load_look, improved load_animation namespace --- colorbleed/plugins/maya/load/load_look.py | 160 ++++++++++++++++++++-- colorbleed/plugins/maya/load/load_rig.py | 22 ++- 2 files changed, 159 insertions(+), 23 deletions(-) diff --git a/colorbleed/plugins/maya/load/load_look.py b/colorbleed/plugins/maya/load/load_look.py index 411f2fbed5..c73e2b73a8 100644 --- a/colorbleed/plugins/maya/load/load_look.py +++ b/colorbleed/plugins/maya/load/load_look.py @@ -2,7 +2,7 @@ import os import json from maya import cmds -from avalon import api +from avalon import api, maya class LookLoader(api.Loader): @@ -17,7 +17,25 @@ class LookLoader(api.Loader): color = "orange" def process(self, name, namespace, context, data): - from avalon import maya + """ + Load and try to ssign Lookdev to nodes based on relationship data + Args: + name: + namespace: + context: + data: + + Returns: + + """ + + # improve readability of the namespace + assetname = context["asset"]["name"] + ns_assetname = "{}_".format(assetname) + + namespace = maya.unique_namespace(ns_assetname, + format="%03d", + suffix="_look") try: existing_reference = cmds.file(self.fname, query=True, @@ -28,20 +46,16 @@ class LookLoader(api.Loader): self.log.info("Loading lookdev for the first time..") with maya.maintained_selection(): - nodes = cmds.file( - self.fname, - namespace=namespace, - reference=True, - returnNewNodes=True - ) + nodes = cmds.file(self.fname, + namespace=namespace, + reference=True, + returnNewNodes=True) else: self.log.info("Reusing existing lookdev..") nodes = cmds.referenceQuery(existing_reference, nodes=True) - namespace = nodes[0].split(":", 1)[0] # Assign shaders self.fname = self.fname.rsplit(".", 1)[0] + ".json" - if not os.path.isfile(self.fname): self.log.warning("Look development asset " "has no relationship data.") @@ -50,6 +64,130 @@ class LookLoader(api.Loader): with open(self.fname) as f: relationships = json.load(f) - maya.apply_shaders(relationships, namespace) + # Get all nodes which belong to a matching name space + # Currently this is the safest way to get all the nodes + namespace_nodes = self.get_namespace_nodes(assetname) + self.apply_shaders(relationships, nodes, namespace_nodes) self[:] = nodes + + def apply_shaders(self, relationships, nodes, namespace_nodes): + """Apply all shaders to the nodes based on the relationship data + + Args: + relationships (dict): shader to node relationships + nodes (list): shader network nodes + namespace_nodes (list): nodes from linked to namespace + + Returns: + None + """ + + # attributes = relationships.get("attributes", []) + sets = relationships.get("sets", []) + + shading_engines = cmds.ls(nodes, type="shadingEngine", long=True) + assert len(shading_engines) > 0, ("Error in retrieving shading engine " + "from reference") + + # get all nodes which we need to link + for set in sets: + # collect all unique IDs of the set members + uuid = set["uuid"] + member_uuids = [member["uuid"] for member in set["members"]] + filtered_nodes = self.get_matching_nodes(namespace_nodes, + member_uuids) + shading_engine = self.get_matching_nodes(shading_engines, + [uuid]) + + assert len(shading_engine) == 1, ("Could not find the correct " + "shading engine with cbId " + "'{}'".format(uuid)) + + cmds.sets(filtered_nodes, forceElement=shading_engine[0]) + + def get_matching_nodes(self, nodes, uuids): + """Filter all nodes which match the UUIDs + + Args: + nodes (list): collection of nodes to check + uuids (list): a list of UUIDs which are linked to the shader + + Returns: + list: matching nodes + """ + + filtered_nodes = [] + for node in nodes: + if node is None: + continue + + if not cmds.attributeQuery("cbId", node=node, exists=True): + continue + + # Deformed shaped + attr = "{}.cbId".format(node) + attribute_value = cmds.getAttr(attr) + + if attribute_value not in uuids: + continue + + filtered_nodes.append(node) + + return filtered_nodes + + def get_namespace_nodes(self, assetname): + """ + Get all nodes of namespace `asset_*` and check if they have a shader + assigned, if not add to list + Args: + context (dict): current context of asset + + Returns: + list + + """ + + # types = ["transform", "mesh"] + list_nodes = [] + + namespaces = cmds.namespaceInfo(listOnlyNamespaces=True) + + # remove basic namespaces + namespaces.remove("UI") + namespaces.remove("shared") + + for ns in namespaces: + if not ns.startswith(assetname): + continue + # get reference nodes + ns_nodes = cmds.namespaceInfo(ns, listOnlyDependencyNodes=True) + # TODO: might need to extend the types + # check if any nodes are connected to something else than lambert1 + list_nodes = cmds.ls(ns_nodes, long=True) + unassigned_nodes = [self.has_default_shader(n) for n in list_nodes] + nodes = [n for n in unassigned_nodes if n is not None] + + list_nodes.extend(nodes) + + return set(list_nodes) + + def has_default_shader(self, node): + """Check if the nodes have `initialShadingGroup` shader assigned + + Args: + node (str): node to check + + Returns: + str + """ + + shaders = cmds.listConnections(node, type="shadingEngine") or [] + if "initialShadingGroup" in shaders: + # return transform node + transform = cmds.listRelatives(node, parent=True, type="transform", + fullPath=True) + if not transform: + return [] + + return transform[0] diff --git a/colorbleed/plugins/maya/load/load_rig.py b/colorbleed/plugins/maya/load/load_rig.py index 0138f56b76..5604ec22c5 100644 --- a/colorbleed/plugins/maya/load/load_rig.py +++ b/colorbleed/plugins/maya/load/load_rig.py @@ -2,7 +2,7 @@ import os from maya import cmds -from avalon import api +from avalon import api, maya class RigLoader(api.Loader): @@ -21,7 +21,9 @@ class RigLoader(api.Loader): color = "orange" def process(self, name, namespace, context, data): - print("debug : {}\n{}\n".format(name, namespace)) + + assetname = "{}_".format(context["asset"]["name"]) + unique_namespace = maya.unique_namespace(assetname, format="%03d") nodes = cmds.file(self.fname, namespace=namespace, reference=True, @@ -31,9 +33,8 @@ class RigLoader(api.Loader): # Store for post-process self[:] = nodes - if data.get("post_process", True): - self._post_process(name, namespace, context, data) + self._post_process(name, unique_namespace, context, data) def _post_process(self, name, namespace, context, data): from avalon import maya @@ -43,12 +44,10 @@ class RigLoader(api.Loader): # elsewhere, such as in the Integrator plug-in, # without duplication. - output = next( - (node for node in self - if node.endswith("out_SET")), None) - controls = next( - (node for node in self - if node.endswith("controls_SET")), None) + output = next((node for node in self if + node.endswith("out_SET")), None) + controls = next((node for node in self if + node.endswith("controls_SET")), None) assert output, "No out_SET in rig, this is a bug." assert controls, "No controls_SET in rig, this is a bug." @@ -68,9 +67,8 @@ class RigLoader(api.Loader): # TODO(marcus): Hardcoding the family here, better separate this. dependencies = [context["representation"]["_id"]] dependencies = " ".join(str(d) for d in dependencies) - unique_name = maya.unique_name(asset_name, suffix="_SET") - maya.create(name=unique_name, + maya.create(name=namespace, asset=asset, family="colorbleed.animation", options={"useSelection": True},