ARTv2

Latest Revision:

Source code for artv2_rig_modules.rig_module

# -*- coding: utf-8 -*-
"""
The rig_module provides the base class, ART_Component, from which all rig modules are derived.

When creating a new rig module, here is a list of common attributes and functions you will want or need to override.

    +------------+------------------------+----------------------------------------------------------------------------+
    | Type       | Name                   | Description                                                                |
    +============+========================+============================================================================+
    | attribute  | nice_name              | The string nice name of the module (as it will appear in UIs)              |
    +------------+------------------------+----------------------------------------------------------------------------+
    | attribute  | base_name              | The string base name of the module. This is a simple string used to        |
    |            |                        | identify the module type and append onto nodes created by the module.      |
    |            |                        | For example, on a leg module, the base_name is simply: "leg"               |
    +------------+------------------------+----------------------------------------------------------------------------+
    | attribute  | has_sides              | Boolean for whether or not the module supports different sides, like a leg |
    |            |                        | or arm do.                                                                 |
    +------------+------------------------+----------------------------------------------------------------------------+
    | attribute  | joint_mover_file       | The relative path from the ARTv2 directory to the joint mover file of the  |
    |            |                        | module. For example, self.joint_mover_file =                               |
    |            |                        | "resources/rigging_guides/root.ma"                                         |
    +------------+------------------------+----------------------------------------------------------------------------+
    | function   | _add_metadata          | This method adds attributes you want to keep track of that are unique to   |
    |            |                        | your module. Make sure that you still call on the base class's             |
    |            |                        | _add_metadata method to setup the required attributes.                     |
    +------------+------------------------+----------------------------------------------------------------------------+

"""
import inspect
import os
from abc import abstractmethod, ABCMeta

import maya.cmds as cmds
import pymel.core as pm

import artv2_utilities.error_utilities as errors
import artv2_utilities.general_utilities as utils
import artv2_utilities.rig_module_utilities as module_utils
from joint_mover import JointMover

reload(module_utils)
reload(utils)


# noinspection PyPep8Naming
[docs]class ART_Component(object): """ Base class for defining a rig module in ARTv2. All rig modules should inherit from this class. """ __metaclass__ = ABCMeta nice_name = "" base_name = None has_sides = False up = cmds.upAxis(q=True, ax=True) joint_mover_file = "replace_me_with_valid_path.ma" @abstractmethod def __init__(self, prefix="", suffix="", network_node=None): prefix = module_utils.validate_prefix(network_node, prefix) suffix = module_utils.validate_suffix(network_node, suffix) if network_node is None: self._unique_name = prefix + self.base_name + suffix self._create_component(prefix, suffix) self.joint_mover = JointMover(self.joint_mover_file, self.network_node) self.joint_mover.add_joint_mover() else: if cmds.objExists(network_node): prefix = cmds.getAttr(network_node + ".prefix") suffix = cmds.getAttr(network_node + ".suffix") self._unique_name = prefix + self.base_name + suffix self.joint_mover = JointMover(self.joint_mover_file, network_node) self.prefix = prefix self.suffix = suffix # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def _create_component(self, prefix, suffix): """ Method for adding the module to the Maya scene. Calls on various functions to accomplish. """ character_node = module_utils.get_rig_asset_node() network_node = self._create_network_node() self._add_metadata(network_node, prefix, suffix) cmds.connectAttr(character_node + ".rigModules", network_node + ".asset") # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @abstractmethod def _add_metadata(self, network_node, prefix, suffix): """ Method for adding metadata attributes to the network node that are important for the module. The ones created by the base class are necessary for all modules. :param (str) network_node: module's network node name to add attributes to. :param (str) prefix: the module's (optional) prefix. :param (str) suffix: the module's (optional) suffix. """ cmds.lockNode(network_node, lock=False) cmds.addAttr(network_node, ln="asset", at="message") cmds.addAttr(network_node, ln="modulePath", dt="string", keyable=False) module_path = os.path.splitext(inspect.getfile(self.__class__).split("artv2_source")[1])[0] module_path = module_path.replace("\\", ".") module_path = module_path.partition(".")[2] cmds.setAttr(network_node + ".modulePath", module_path, type="string", lock=True) cmds.addAttr(network_node, ln="className", dt="string", keyable=False) cmds.setAttr(network_node + ".className", self.__class__.__name__, type="string", lock=True) cmds.addAttr(network_node, ln="moduleName", dt="string", keyable=False) cmds.setAttr(network_node + ".moduleName", self._unique_name, type="string", lock=True) cmds.addAttr(network_node, ln="baseName", dt="string", keyable=False) cmds.setAttr(network_node + ".baseName", self.base_name, type="string", lock=True) cmds.addAttr(network_node, ln="prefix", dt="string", keyable=False) cmds.setAttr(network_node + ".prefix", prefix, type="string", lock=True) cmds.addAttr(network_node, ln="suffix", dt="string", keyable=False) cmds.setAttr(network_node + ".suffix", suffix, type="string", lock=True) cmds.addAttr(network_node, ln="parentModuleBone", dt="string", keyable=False) cmds.addAttr(network_node, ln="mirrorModule", dt="string", keyable=False) cmds.addAttr(network_node, ln="pinned", at="bool", keyable=False) cmds.setAttr(network_node + ".pinned", False, lock=True) cmds.addAttr(network_node, ln="global_movers", at="message") cmds.addAttr(network_node, ln="offset_movers", at="message") cmds.addAttr(network_node, ln="geo_movers", at="message") cmds.addAttr(network_node, ln="lra_movers", at="message") cmds.addAttr(network_node, ln="mover_grp", at="message") cmds.lockNode(network_node, lock=True) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def _create_network_node(self): existing_nodes = module_utils.return_all_components() for node in existing_nodes: if cmds.getAttr(node + ".moduleName") == self._unique_name: errors.raise_error("This module instance has already been created! Aborting.") return network_node = cmds.shadingNode("network", name=self._unique_name + "_metadata", asUtility=True) cmds.lockNode(network_node, lock=True) return network_node # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @property def parent(self): """ This property holds the joint name of the parent of this module. """ return cmds.getAttr(self.network_node + ".parentModuleBone") @parent.setter def parent(self, new_parent): all_joints = module_utils.get_all_created_joints() if new_parent in all_joints: utils.set_attribute(self.network_node, "parentModuleBone", new_parent, "string") self.joint_mover.set_mover_parent(new_parent) else: errors.raise_error("Invalid parent: {0}! No module creates such a joint.".format(new_parent)) return # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @property def prefix(self): return cmds.getAttr(self.network_node + ".prefix") @prefix.setter def prefix(self, new_prefix): valid_prefix = module_utils.validate_prefix(self.network_node, new_prefix) if valid_prefix is not False: old_prefix = self.prefix suffix = self.suffix utils.set_attribute(self.network_node, "prefix", valid_prefix, "string") utils.set_attribute(self.network_node, "moduleName", valid_prefix + self.base_name + suffix, "string") self._unique_name = valid_prefix + self.base_name + suffix pynode = pm.PyNode(self.network_node) utils.rename_object(pynode, self._unique_name + "_metadata") self.joint_mover.metanode = self._unique_name + "_metadata" self.joint_mover.rename_movers(old_prefix, self.suffix) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @property def suffix(self): return cmds.getAttr(self.network_node + ".suffix") @suffix.setter def suffix(self, new_suffix): valid_suffix = module_utils.validate_suffix(self.network_node, new_suffix) if valid_suffix is not False: old_suffix = self.suffix prefix = self.prefix utils.set_attribute(self.network_node, "suffix", valid_suffix, "string") utils.set_attribute(self.network_node, "moduleName", prefix + self.base_name + valid_suffix, "string") self._unique_name = prefix + self.base_name + valid_suffix pynode = pm.PyNode(self.network_node) utils.rename_object(pynode, self._unique_name + "_metadata") self.joint_mover.metanode = self._unique_name + "_metadata" self.joint_mover.rename_movers(self.prefix, old_suffix) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @property def network_node(self): """ This property holds the network node that contains this module's metadata. """ return_node = None rig_modules = module_utils.return_all_components() for module in rig_modules: if cmds.getAttr(module + ".moduleName") == self._unique_name: return_node = module break if return_node is None: errors.raise_error("ART_Component.network_node: No network node found.") return return return_node