def process(self, instance): variant = instance.data["subset"][len("animation"):].lower() members = instance[:] # Re-Create instances context = instance.context context.remove(instance) source_data = instance.data ANIM_SET = "ControlSet" out_cache = dict() if variant == "default": # Collect animatable nodes from ControlSet of loaded subset out_sets = list() for node in cmds.ls(members, type="transform", long=True): try: container = pipeline.get_container_from_group(node) except AssertionError: continue sets = cmds.ls(cmds.sets(container, query=True), type="objectSet") out_sets += [s for s in sets if s.endswith(ANIM_SET)] for node in out_sets: name = node.rsplit(":", 1)[-1][:-len(ANIM_SET)] or "Default" self.log.info(name) namespace = lib.get_ns(node) animatables = cmds.ls(cmds.sets(node, query=True), long=True) out_cache[namespace] = (name, animatables) else: # Collect animatable nodes from instance member for node in cmds.ls(members, type="transform", long=True): namespace = lib.get_ns(node) try: # Must be containerized pipeline.get_container_from_namespace(namespace) except RuntimeError: continue if namespace not in out_cache: out_cache[namespace] = (variant, list()) out_cache[namespace][1].append(node) for namespace, (name, animatables) in out_cache.items(): instance = context.create_instance(namespace or name) container = pipeline.get_container_from_namespace(namespace) asset_id = cmds.getAttr(container + ".assetId") namespace = namespace[1:] # Remove root ":" instance.data.update(source_data) instance.data["subset"] = ".".join(["animation", namespace, name]) instance[:] = animatables instance.data["outAnim"] = animatables instance.data["animatedNamespace"] = namespace instance.data["animatedAssetId"] = asset_id # (NOTE) Although we put those animatable nodes to validate # AvalonUUID existence, but currently AvalonUUID is # not needed on load. instance.data["requireAvalonUUID"] = animatables
def process_import(self, context, name, namespace, group, options): from maya import cmds, mel from reveries import plugins representation = context["representation"] asset_id = representation["data"]["animatedAssetId"] selected = cmds.ls(selection=True, long=True) # Collect namespace from selected nodes namespaces = defaultdict(set) for node in selected: ns = lib.get_ns(node) if ns == ":": continue namespaces[ns].add(node) for ns, nodes in namespaces.items(): try: container = pipeline.get_container_from_namespace(ns) except RuntimeError: continue if asset_id != cmds.getAttr(container + ".assetId"): confirm = plugins.message_box_warning( "Warning", "Applying animation to different asset, are you sure ?", optional=True, ) if not confirm: raise Exception("Operation canceled.") target_ns = ns members = nodes break else: raise Exception("No matched asset found.") cmds.loadPlugin("animImportExport", quiet=True) entry_path = self.file_path(representation).replace("\\", "/") sele_path = entry_path.rsplit("anim", 1)[0] + "mel" sele_path = os.path.expandvars(sele_path) with capsule.maintained_selection(): # Select nodes with order with contextlib.nested(capsule.namespaced(target_ns, new=False), capsule.relative_namespaced()): self._selection_patch(sele_path) mel.eval("source \"%s\"" % sele_path) targets = cmds.ls(selection=True, long=True) nodes = cmds.file(entry_path, force=True, type="animImport", i=True, importTimeRange="keep", ignoreVersion=True, returnNewNodes=True, options=("targetTime=4;" "option=replace;" "connect=0")) # Apply namespace by ourselves, since animImport does not # take -namespace flag namespaced_nodes = list() for node in nodes: node = cmds.rename(node, namespace + ":" + node) namespaced_nodes.append(node) # Delete not connected targets = set(targets) connected = list() for node in namespaced_nodes: future = cmds.listHistory(node, future=True) future = set(cmds.ls(future, long=True)) if targets.intersection(future): connected.append(node) else: cmds.delete(node) if not connected: raise Exception("No animation been applied.") self[:] = connected # Remove assigned from selection unprocessed = list(set(selected) - members) cmds.select(unprocessed, replace=True, noExpand=True)
def process(self, instance): import maya.cmds as cmds from reveries.maya import lib, pipeline variant = instance.data["subset"][len("animation"):].lower() members = instance[:] # Re-Create instances context = instance.context context.remove(instance) source_data = instance.data ANIM_SET = "ControlSet" out_cache = dict() if variant == "default": # Collect animatable nodes from ControlSet of loaded subset out_sets = list() for node in cmds.ls(members, type="transform"): try: # Must be containerized subset group node pipeline.get_container_from_group(node) except AssertionError: continue namespace = lib.get_ns(node) out_sets += cmds.ls("%s:*%s" % (namespace, ANIM_SET), sets=True) for node in out_sets: name = node.rsplit(":", 1)[-1][:-len(ANIM_SET)] or "Default" namespace = lib.get_ns(node) animatables = cmds.ls(cmds.sets(node, query=True), type="transform") key = (namespace, name) self.log.info("%s, %s" % key) if not animatables: self.log.warning("No animatable (e.g. controllers) been " "found in '%s', skipping.." % node) continue out_cache[key] = animatables else: # Collect animatable nodes from instance member for node in cmds.ls(members, type="transform"): namespace = lib.get_ns(node) try: # Must be containerized pipeline.get_container_from_namespace(namespace) except RuntimeError: continue key = (namespace, variant) if key not in out_cache: self.log.info("%s, %s" % key) out_cache[key] = list() out_cache[key].append(node) for (namespace, name), animatables in sorted(out_cache.items()): container = pipeline.get_container_from_namespace(namespace) asset_id = cmds.getAttr(container + ".assetId") fixed_namespace = namespace[1:] # Remove root ":" # For filesystem, remove other ":" if the namespace is nested fixed_namespace = fixed_namespace.replace(":", "._.") subset = ".".join(["animation", fixed_namespace, name]) instance = context.create_instance(subset) instance.data.update(source_data) instance.data["subset"] = subset instance[:] = animatables instance.data["outAnim"] = animatables instance.data["animatedNamespace"] = namespace instance.data["animatedAssetId"] = asset_id # (NOTE) Although we put those animatable nodes to validate # AvalonUUID existence, but currently AvalonUUID is # not needed on load. instance.data["requireAvalonUUID"] = animatables