Beispiel #1
0
    def _build_avar_macro(self, cls_ctrl, avar, constraint=False, **kwargs):
        """
        Factory method that create an avar that is not affiliated with any influence and is only used for connections.
        :param cls_ctrl: The class definition to use for the ctrl.
        :param avar: The Avar class instance to use.
        :param constraint: By default, a macro Avar don't affect it's influence (directly). This is False by default.
        :param kwargs: Any additional keyword arguments will be sent to the avar build method.
        :return:
        """
        if cls_ctrl:
            avar._CLS_CTRL = cls_ctrl  # Hack, find a more elegant way.
        self._build_avar(
            avar,
            callibrate_doritos=False,  # We'll callibrate ourself since we're connecting manually.
            constraint=constraint,
            **kwargs
        )

        if libPymel.is_valid_PyNode(avar.grp_anm):
            if self._grp_anm_avars_macro:
                avar.grp_anm.setParent(self._grp_anm_avars_macro)
            else:
                avar.grp_anm.setParent(self.grp_anm)

        if libPymel.is_valid_PyNode(avar.grp_rig):
            if self._grp_rig_avars_macro:
                avar.grp_rig.setParent(self._grp_rig_avars_macro)
            else:
                avar.grp_rig.setParent(self.grp_rig)  # todo: raise warning?

        return avar  #
Beispiel #2
0
    def _build_avar_macro(self, cls_ctrl, avar, constraint=False, **kwargs):
        """
        Factory method that create an avar that is not affiliated with any influence and is only used for connections.
        :param cls_ctrl: The class definition to use for the ctrl.
        :param avar: The Avar class instance to use.
        :param constraint: By default, a macro Avar don't affect it's influence (directly). This is False by default.
        :param kwargs: Any additional keyword arguments will be sent to the avar build method.
        :return:
        """
        if cls_ctrl:
            avar._CLS_CTRL = cls_ctrl  # Hack, find a more elegant way.
        self._build_avar(
            avar,
            callibrate_doritos=
            False,  # We'll callibrate ourself since we're connecting manually.
            constraint=constraint,
            **kwargs)

        if libPymel.is_valid_PyNode(avar.grp_anm):
            if self._grp_anm_avars_macro:
                avar.grp_anm.setParent(self._grp_anm_avars_macro)
            else:
                avar.grp_anm.setParent(self.grp_anm)

        if libPymel.is_valid_PyNode(avar.grp_rig):
            if self._grp_rig_avars_macro:
                avar.grp_rig.setParent(self._grp_rig_avars_macro)
            else:
                avar.grp_rig.setParent(self.grp_rig)  # todo: raise warning?

        return avar  #
    def unbuild(self, disconnect_attr=True):
        """
        Call unbuild on each individual ctrls
        This allow the rig to save his ctrls appearance (shapes) and animation (animCurves).
        Note that this happen first so the rig can return to it's bind pose before anything else is done.
        :param disconnect_attr: Tell the unbuild if we want to disconnect the input translate, rotate, scale
        """
        self.info("Un-building")

        # Ensure that there's no more connections in the input chain
        if disconnect_attr:
            self._disconnect_inputs()

        # Delete the ctrls in reverse hyerarchy order.
        ctrls = self.get_ctrls()
        ctrls = filter(libPymel.is_valid_PyNode, ctrls)
        ctrls = reversed(sorted(ctrls, key=libPymel.get_num_parents))
        for ctrl in ctrls:
            ctrl.unbuild()

        if self.grp_anm is not None and libPymel.is_valid_PyNode(self.grp_anm):
            pymel.delete(self.grp_anm)
            self.grp_anm = None
        if self.grp_rig is not None and libPymel.is_valid_PyNode(self.grp_rig):
            pymel.delete(self.grp_rig)
            self.grp_rig = None

        self.globalScale = None

        # Reset any cached properties
        # todo: ensure it's the best way
        if '_cache' in self.__dict__:
            self.__dict__.pop('_cache')
Beispiel #4
0
 def parent(self):
     if not self.chain_jnt:
         return None
     first_input = next(iter(self.chain_jnt), None)
     if libPymel.is_valid_PyNode(first_input):
         return first_input.getParent()
     return None
Beispiel #5
0
    def unbuild(self, keep_shapes=True, *args, **kwargs):
        """
        Delete ctrl setup, but store the animation and the shapes.
        """
        if not libPymel.is_valid_PyNode(self.node):
            raise Exception("Can't hold ctrl attribute! Some information may be lost... {0}".format(self.node))
        else:
            self.hold_attrs_all()
            self.hold_shapes()
            super(BaseCtrl, self).unbuild(*args, **kwargs)

        # Delete offset node if necessary.
        # Note that we delete the offset node AFTER deleting the original node.
        if libPymel.is_valid_PyNode(self.offset):
            pymel.delete(self.offset)
            self.offset = None
Beispiel #6
0
 def prebuild(self):
     # Ensure we got a root joint
     # If needed, parent orphan joints to this one
     all_root_jnts = libPymel.ls_root_jnts()
     if not libPymel.is_valid_PyNode(self.grp_jnts):
         self.grp_jnts = pymel.createNode('joint', name='jnts')
     all_root_jnts.setParent(self.grp_jnts)
 def parent(self):
     # TODO: We might want to search for specifically a joint in case the influence have intermediate objects.
     if not self.chain_jnt:
         return None
     first_input = next(iter(self.chain_jnt), None)
     if libPymel.is_valid_PyNode(first_input):
         return first_input.getParent()
     return None
Beispiel #8
0
    def _build_avar_micro(self, cls_ctrl, avar, **kwargs):
        if cls_ctrl:
            avar._CLS_CTRL = cls_ctrl  # Hack, find a more elegant way.

        self._build_avar(avar, **kwargs)

        if libPymel.is_valid_PyNode(avar.grp_anm):
            if self._grp_anm_avars_micro:
                avar.grp_anm.setParent(self._grp_anm_avars_micro)
            else:
                avar.grp_anm.setParent(self.grp_anm)

        if libPymel.is_valid_PyNode(avar.grp_rig):
            if self._grp_rig_avars_micro:
                avar.grp_rig.setParent(self._grp_rig_avars_micro)
            else:
                avar.grp_rig.setParent(self.grp_rig)  # todo: raise warning?
Beispiel #9
0
    def _build_avar_micro(self, cls_ctrl, avar, **kwargs):
        if cls_ctrl:
            avar._CLS_CTRL = cls_ctrl  # Hack, find a more elegant way.

        self._build_avar(avar, **kwargs)

        if libPymel.is_valid_PyNode(avar.grp_anm):
            if self._grp_anm_avars_micro:
                avar.grp_anm.setParent(self._grp_anm_avars_micro)
            else:
                avar.grp_anm.setParent(self.grp_anm)

        if libPymel.is_valid_PyNode(avar.grp_rig):
            if self._grp_rig_avars_micro:
                avar.grp_rig.setParent(self._grp_rig_avars_micro)
            else:
                avar.grp_rig.setParent(self.grp_rig)  # todo: raise warning?
Beispiel #10
0
 def parent(self):
     # TODO: We might want to search for specifically a joint in case the influence have intermediate objects.
     if not self.chain_jnt:
         return None
     first_input = next(iter(self.chain_jnt), None)
     if libPymel.is_valid_PyNode(first_input):
         return first_input.getParent()
     return None
Beispiel #11
0
    def unbuild(self, **kwargs):
        for child in self.children:
            child.unbuild(**kwargs)

        # Delete the rig group if it isnt used anymore
        if libPymel.is_valid_PyNode(self.grp_rigs) and len(self.grp_rigs.getChildren()) == 0:
            pymel.delete(self.grp_rigs)
            self.grp_rigs = None

        super(RigRoot, self).unbuild(**kwargs)
Beispiel #12
0
    def unbuild(self, keep_shapes=True, *args, **kwargs):
        """
        Delete ctrl setup, but store the animation, shapes and rotate order0.
        """
        if not libPymel.is_valid_PyNode(self.node):
            raise Exception(
                "Can't hold ctrl attribute! Some information may be lost... {0}"
                .format(self.node))
        else:
            self.rotateOrder = self.node.rotateOrder.get()
            self.hold_attrs_all()
            self.hold_shapes()
            super(BaseCtrl, self).unbuild(*args, **kwargs)

        # Delete offset node if necessary.
        # Note that we delete the offset node AFTER deleting the original node.
        if libPymel.is_valid_PyNode(self.offset):
            pymel.delete(self.offset)
            self.offset = None
Beispiel #13
0
    def unbuild(self, disconnect_attr=True):
        """
        Call unbuild on each individual ctrls
        This allow the rig to save his ctrls appearance (shapes) and animation (animCurves).
        Note that this happen first so the rig can return to it's bind pose before anything else is done.
        :param disconnect_attr: Tell the unbuild if we want to disconnect the input translate, rotate, scale
        """
        self.info("Un-building")

        # Ensure that there's no more connections in the input chain
        if disconnect_attr:
            for obj in self.input:
                if isinstance(obj, pymel.nodetypes.Transform):
                    libAttr.disconnectAttr(obj.tx)
                    libAttr.disconnectAttr(obj.ty)
                    libAttr.disconnectAttr(obj.tz)
                    libAttr.disconnectAttr(obj.rx)
                    libAttr.disconnectAttr(obj.ry)
                    libAttr.disconnectAttr(obj.rz)
                    libAttr.disconnectAttr(obj.sx)
                    libAttr.disconnectAttr(obj.sy)
                    libAttr.disconnectAttr(obj.sz)

        # Delete the ctrls in reverse hyerarchy order.
        ctrls = self.get_ctrls()
        ctrls = filter(libPymel.is_valid_PyNode, ctrls)
        ctrls = reversed(sorted(ctrls, key=libPymel.get_num_parents))
        for ctrl in ctrls:
            ctrl.unbuild()

        if self.grp_anm is not None and libPymel.is_valid_PyNode(self.grp_anm):
            pymel.delete(self.grp_anm)
            self.grp_anm = None
        if self.grp_rig is not None and libPymel.is_valid_PyNode(self.grp_rig):
            pymel.delete(self.grp_rig)
            self.grp_rig = None

        self.globalScale = None

        # Reset any cached properties
        # todo: ensure it's the best way
        if '_cache' in self.__dict__:
            self.__dict__.pop('_cache')
Beispiel #14
0
    def post_build_module(self, module):
        # Raise warnings if a module leave junk in the scene.
        if module.grp_anm and not module.grp_anm.getChildren():
            cmds.warning(
                "Found empty group {0}, please cleanup module {1}.".format(
                    module.grp_anm.longName(), module))
            pymel.delete(module.grp_anm)
        if module.grp_rig and not module.grp_rig.getChildren():
            cmds.warning(
                "Found empty group {0}, please cleanup module {1}.".format(
                    module.grp_rig.longName(), module))
            pymel.delete(module.grp_rig)

        # Prevent animators from accidentaly moving offset nodes
        # TODO: Lock more?
        for ctrl in module.get_ctrls():
            if libPymel.is_valid_PyNode(ctrl) and hasattr(
                    ctrl, 'offset') and ctrl.offset:
                ctrl.offset.t.lock()
                ctrl.offset.r.lock()
                ctrl.offset.s.lock()

        # Parent modules grp_anm to main grp_anm
        if libPymel.is_valid_PyNode(
                module.grp_anm) and libPymel.is_valid_PyNode(self.grp_anm):
            module.grp_anm.setParent(self.grp_anm)

        # Constraint modules grp_rig to main grp_rig
        if libPymel.is_valid_PyNode(
                module.grp_rig) and libPymel.is_valid_PyNode(self.grp_rig):
            module.grp_rig.setParent(self.grp_rig)

        # Connect globalScale attribute to each modules globalScale.
        if module.globalScale:
            pymel.connectAttr(self.grp_anm.globalScale,
                              module.globalScale,
                              force=True)

        # Apply ctrl color if needed
        if self._color_ctrl:
            self.color_module_ctrl(module)
Beispiel #15
0
 def _clean_invalid_pynodes(self):
     fnCanDelete = lambda x: (isinstance(x, (pymel.PyNode, pymel.Attribute))
                              and not libPymel.is_valid_PyNode(x))
     for key, val in self.__dict__.iteritems():
         if fnCanDelete(val):
             setattr(self, key, None)
         elif isinstance(val, (list, set, tuple)):
             for i in reversed(range(len(val))):
                 if fnCanDelete(val[i]):
                     val.pop(i)
             if len(val) == 0:
                 setattr(self, key, None)
Beispiel #16
0
 def _is_potential_influence(self, jnt):
     """
     Take a potential influence and validate that it is not blacklisted.
     Currently any influence under the rig group is automatically ignored.
     :param mesh: A pymel.PyNode representing an influence object.
     :return: True if the object is a good deformable candidate.
     """
     # Ignore any joint in the rig group (like joint used with ikHandles)
     if libPymel.is_valid_PyNode(self.grp_rig):
         if libPymel.is_child_of(jnt, self.grp_rig.node):
             return False
     return True
Beispiel #17
0
    def post_build_module(self, module):
        """
        Additional changes on the different module built for the rig

        :param module: The built module on which we want to do additional changes
        """
        super(RigUnreal, self).post_build_module(module)

        # Allow animators to change the rotate order if needed
        for ctrl in module.get_ctrls():
            if libPymel.is_valid_PyNode(ctrl):
                ctrl.node.rotateOrder.setKeyable(True)
Beispiel #18
0
    def post_build_module(self, module):
        # Raise warnings if a module leave junk in the scene.
        if module.grp_anm and not module.grp_anm.getChildren():
            cmds.warning("Found empty group {0}, please cleanup module {1}.".format(
                module.grp_anm.longName(), module
            ))
            pymel.delete(module.grp_anm)
        if module.grp_rig and not module.grp_rig.getChildren():
            cmds.warning("Found empty group {0}, please cleanup module {1}.".format(
                module.grp_rig.longName(), module
            ))
            pymel.delete(module.grp_rig)

        # Prevent animators from accidentaly moving offset nodes
        # TODO: Lock more?
        for ctrl in module.get_ctrls():
            if libPymel.is_valid_PyNode(ctrl) and hasattr(ctrl, 'offset') and ctrl.offset:
                ctrl.offset.t.lock()
                ctrl.offset.r.lock()
                ctrl.offset.s.lock()

        # Parent modules grp_anm to main grp_anm
        if libPymel.is_valid_PyNode(module.grp_anm) and libPymel.is_valid_PyNode(self.grp_anm):
            module.grp_anm.setParent(self.grp_anm)

        # Constraint modules grp_rig to main grp_rig
        if libPymel.is_valid_PyNode(module.grp_rig) and libPymel.is_valid_PyNode(self.grp_rig):
            module.grp_rig.setParent(self.grp_rig)

        # Connect globalScale attribute to each modules globalScale.
        if module.globalScale:
            pymel.connectAttr(self.grp_anm.globalScale, module.globalScale, force=True)

        # Apply ctrl color if needed
        if self._color_ctrl:
            self.color_module_ctrl(module)

        # Store the version of omtk used to generate the rig.
        module.version = api.get_version()
Beispiel #19
0
 def fetch_avars(self):
     """
     If a previously created network have be created holding avars connection,
     we'll transfert thoses connections back to the grp_rig node.
     Note that the avars have to been added to the grp_rig before..
     """
     if libPymel.is_valid_PyNode(self.avar_network):
         for attr_name in pymel.listAttr(self.avar_network, userDefined=True):
             attr_src = self.avar_network.attr(attr_name)
             attr_dst = self.grp_rig.attr(attr_name)
             libAttr.transfer_connections(attr_src, attr_dst)
         pymel.delete(self.avar_network)
         self.avar_network = None
Beispiel #20
0
 def fetch_avars(self):
     """
     If a previously created network have be created holding avars connection,
     we'll transfert thoses connections back to the grp_rig node.
     Note that the avars have to been added to the grp_rig before..
     """
     if libPymel.is_valid_PyNode(self.avar_network):
         for attr_name in pymel.listAttr(self.avar_network,
                                         userDefined=True):
             attr_src = self.avar_network.attr(attr_name)
             attr_dst = self.grp_rig.attr(attr_name)
             libAttr.transfer_connections(attr_src, attr_dst)
         pymel.delete(self.avar_network)
         self.avar_network = None
Beispiel #21
0
    def build(self, *args, **kwargs):
        super(RigCtrl, self).build(*args, **kwargs)
        if self._create_offset:
            self.offset = self.__createOffset__()

        self.fetch_attr_all()

        if libPymel.is_valid_PyNode(self.shape):
            libRigging.fetch_ctrl_shapes(self.shape, self.node)
            #pymel.delete(self.shape)
            self.shape = None

        #super(RigCtrl, self).build(*args, **kwargs)
        return self.node
Beispiel #22
0
    def unbuild(self, **kwargs):
        """
        :param kwargs: Potential parameters to pass recursively to the unbuild method of each module.
        :return: True if successful.
        """
        # Unbuild all children
        for child in self.modules:
            if child.is_built():
                child.unbuild(**kwargs)

        # Delete anm_grp
        if isinstance(self.grp_anm, CtrlRoot) and self.grp_anm.is_built():
            self.grp_anm.unbuild()

        # Delete the rig group if it isnt used anymore
        if libPymel.is_valid_PyNode(self.grp_rig) and len(self.grp_rig.getChildren()) == 0:
            pymel.delete(self.grp_rig)
            self.grp_rig = None

        # Delete the displayLayers
        if libPymel.is_valid_PyNode(self.layer_anm):
            pymel.delete(self.layer_anm)
            self.layer_anm = None
        if libPymel.is_valid_PyNode(self.layer_geo):
            pymel.delete(self.layer_geo)
            self.layer_geo = None
        if libPymel.is_valid_PyNode(self.layer_rig):
            pymel.delete(self.layer_rig)

        # Remove any references to missing pynodes
        #HACK --> Remove clean invalid PyNode
        self._clean_invalid_pynodes()
        if self.modules is None:
            self.modules = []

        return True
Beispiel #23
0
    def get_parent_obj(self):
        """
        :return: The object to act as the parent of the module if applicable.
        """
        if self.parent is None:
            return None

        module = self.rig.get_module_by_input(self.parent)
        if module:
            desired_parent = module.get_parent(self.parent)
            if desired_parent:
                self.debug("Will be parented to {0}, {1}".format(module, desired_parent))
                return desired_parent

        if libPymel.is_valid_PyNode(self.parent):
            self.debug("Can't recommend a parent. {0} is not in any known module.".format(self.parent))

        return self.parent
    def fetch_avars(self):
        """
        If a previously created network have be created holding avars connection,
        we'll transfert thoses connections back to the grp_rig node.
        Note that the avars have to been added to the grp_rig before..
        """
        if libPymel.is_valid_PyNode(self.avar_network):
            for attr_name in pymel.listAttr(self.avar_network, userDefined=True):
                attr_src = self.avar_network.attr(attr_name)
                if not self.grp_rig.hasAttr(attr_name):
                    self.warning("Can't fetch stored avar named {0}!".format(attr_name))
                    continue
                attr_dst = self.grp_rig.attr(attr_name)
                libAttr.transfer_connections(attr_src, attr_dst)

            # Ensure Maya don't delete our networks when removing the backup node...
            pymel.disconnectAttr(self.avar_network.message)
            pymel.delete(self.avar_network)
            self.avar_network = None
Beispiel #25
0
    def color_module_ctrl(self, module):
        #
        # Set ctrls colors
        #
        color_by_side = {
            self.nomenclature.SIDE_L: self.LEFT_CTRL_COLOR,  # Red
            self.nomenclature.SIDE_R: self.RIGHT_CTRL_COLOR  # Blue
        }

        epsilon = 0.1
        if module.grp_anm:
            nomenclature_anm = module.get_nomenclature_anm()
            for ctrl in module.get_ctrls():
                if libPymel.is_valid_PyNode(ctrl):
                    if not ctrl.drawOverride.overrideEnabled.get():
                        nomenclature_ctrl = nomenclature_anm.rebuild(ctrl.stripNamespace().nodeName())
                        side = nomenclature_ctrl.side
                        color = color_by_side.get(side, self.CENTER_CTRL_COLOR)
                        ctrl.drawOverride.overrideEnabled.set(1)
                        ctrl.drawOverride.overrideColor.set(color)
Beispiel #26
0
    def color_module_ctrl(self, module):
        #
        # Set ctrls colors
        #
        color_by_side = {
            self.nomenclature.SIDE_L: self.LEFT_CTRL_COLOR,  # Red
            self.nomenclature.SIDE_R: self.RIGHT_CTRL_COLOR  # Blue
        }

        epsilon = 0.1
        if module.grp_anm:
            nomenclature_anm = module.get_nomenclature_anm()
            for ctrl in module.get_ctrls():
                if libPymel.is_valid_PyNode(ctrl):
                    if not ctrl.drawOverride.overrideEnabled.get():
                        nomenclature_ctrl = nomenclature_anm.rebuild(
                            ctrl.name())
                        side = nomenclature_ctrl.side
                        color = color_by_side.get(side, self.CENTER_CTRL_COLOR)
                        ctrl.drawOverride.overrideEnabled.set(1)
                        ctrl.drawOverride.overrideColor.set(color)
Beispiel #27
0
    def _is_potential_deformable(self, mesh):
        """
        Take a potential deformable shape and validate that it is not blacklisted.
        Currently any deformable under the rig group is automatically ignored.
        :param mesh: A pymel.PyNode representing a deformable object.
        :return: True if the object is a good deformable candidate.
        """
        # Any intermediate shape is automatically discarded.
        if isinstance(mesh, pymel.nodetypes.Shape) and mesh.intermediateObject.get():
            return False

        # Ignore any mesh in the rig group (like mesh used for ribbons)
        if libPymel.is_valid_PyNode(self.grp_rig):
            if libPymel.is_child_of(mesh, self.grp_rig.node):
                return False

        # Any mesh that is used as an input in a module is used for rigging.
        # if mesh in self._get_all_input_shapes():
        #     return False

        return True
Beispiel #28
0
    def get_parent_obj(self):
        """
        :return: The object to act as the parent of the module if applicable.
        """
        if self.parent is None:
            return None

        module = self.rig.get_module_by_input(self.parent)
        if module:
            desired_parent = module.get_parent(self.parent)
            if desired_parent:
                self.debug("Will be parented to {0}, {1}".format(
                    module, desired_parent))
                return desired_parent

        if libPymel.is_valid_PyNode(self.parent):
            self.debug(
                "Can't recommend a parent. {0} is not in any known module.".
                format(self.parent))

        return self.parent
Beispiel #29
0
    def get_spaceswitch_targets(self, rig, module, jnt, add_world=True, world_name='World'):
        targets = []
        target_names = []

        # Resolve modules
        modules = set()
        while jnt:
            module = rig.get_module_by_input(jnt)
            if module:
                modules.add(module)
                #targets.update(module.get_pin_locations())
            jnt = jnt.getParent()

        for module in modules:
            for target, target_name in module.get_pin_locations():
                targets.append(target)
                target_names.append(target_name)

        if add_world and libPymel.is_valid_PyNode(rig.grp_jnt):
            targets.append(rig.grp_jnt)
            target_names.append(world_name)

        return targets, target_names
Beispiel #30
0
def export_network(_data, **kwargs):
    log.debug('CreateNetwork {0}'.format(_data))

    # We'll deal with two additional attributes, '_network' and '_uid'.
    # Thoses two attributes allow us to find the network from the value and vice-versa.
    # Note that since the '_uid' refer to the current python context, it's value could be erroned when calling import_network.
    # However the change of collisions are extremely improbable so checking the type of the python variable is sufficient.
    # Please feel free to provide a better design if any if possible.

    # Optimisation: Use existing network if already present in scene
    if hasattr(_data, '_network') and libPymel.is_valid_PyNode(_data._network):
        network = _data._network
    else:
        # Automaticly name network whenever possible
        if hasattr(_data, '__getNetworkName__') and _data.__getNetworkName__ is None: 
            networkName = _data.__class__.__name__
        else:
            networkName = _data.__getNetworkName__() if hasattr(_data, '__getNetworkName__') else _data.__class__.__name__
            _data._network = networkName
        network = pymel.createNode('network', name=networkName)

    # Ensure the network have the current python id stored
    if not network.hasAttr('_uid'):
        pymel.addAttr(network, longName='_uid', niceName='_uid', at='long') # todo: validate attributeType
    network._uid.set(id(_data))

    # Convert _pData to basic data dictionary (recursive for now)
    dicData = core._export_basicData(_data, _bRecursive=False, **kwargs)
    assert(isinstance(dicData, dict))

    fnNet = network.__apimfn__()
    for key, val in dicData.items():
        if val is not None:
            if key == '_class' or key[0] != '_': # Attributes starting with '_' are protected or private
                _addAttr(fnNet, key, val)

    return network
Beispiel #31
0
    def pre_build(self,
                  create_master_grp=False,
                  create_grp_jnt=True,
                  create_grp_anm=True,
                  create_grp_rig=True,
                  create_grp_geo=True,
                  create_display_layers=True,
                  create_grp_backup=False):
        # Hack: Invalidate any cache before building anything.
        # This ensure we always have fresh data.
        try:
            del self._cache
        except AttributeError:
            pass

        # Look for a root joint
        if create_grp_jnt:
            # For now, we will determine the root jnt by it's name used in each rig. Not the best solution,
            # but currently the safer since we want to support multiple deformation layer
            if not libPymel.is_valid_PyNode(self.grp_jnt):
                # self.grp_jnt = next(iter(libPymel.ls_root(type='joint')), None)
                if cmds.objExists(self.nomenclature.root_jnt_name):
                    self.grp_jnt = pymel.PyNode(
                        self.nomenclature.root_jnt_name)
                else:
                    self.warning(
                        "Could not find any root joint, master ctrl will not drive anything"
                    )
                    # self.grp_jnt = pymel.createNode('joint', name=self.nomenclature.root_jnt_name)

        # Ensure all joints have segmentScaleComprensate deactivated.
        # This allow us to scale adequately and support video game rigs.
        # If for any mean stretch and squash are necessary, implement
        # them on a new joint chains parented to the skeletton.
        # TODO: Move elsewere?
        all_jnts = libPymel.ls(type='joint')
        for jnt in all_jnts:
            jnt.segmentScaleCompensate.set(False)

        # Create the master grp
        if create_master_grp:
            self.grp_master = self.build_grp(
                RigGrp, self.grp_master,
                self.name + '_' + self.nomenclature.type_rig)

        # Create grp_anm
        if create_grp_anm:
            grp_anim_size = CtrlRoot._get_recommended_radius(self)
            self.grp_anm = self.build_grp(CtrlRoot,
                                          self.grp_anm,
                                          self.nomenclature.root_anm_name,
                                          size=grp_anim_size)

        # Create grp_rig
        if create_grp_rig:
            self.grp_rig = self.build_grp(RigGrp, self.grp_rig,
                                          self.nomenclature.root_rig_name)

        # Create grp_geo
        if create_grp_geo:
            all_geos = libPymel.ls_root_geos()
            self.grp_geo = self.build_grp(RigGrp, self.grp_geo,
                                          self.nomenclature.root_geo_name)
            #if all_geos:
            #    all_geos.setParent(self.grp_geo)

        if create_grp_backup:
            self.grp_backup = self.build_grp(
                RigGrp, self.grp_backup, self.nomenclature.root_backup_name)

        #Parent all grp on the master grp
        if self.grp_master:
            if self.grp_jnt:
                self.grp_jnt.setParent(self.grp_master.node)
            if self.grp_anm:
                self.grp_anm.setParent(self.grp_master.node)
            if self.grp_rig:
                self.grp_rig.setParent(self.grp_master.node)
            if self.grp_geo:
                self.grp_geo.setParent(self.grp_master.node)
            if self.grp_backup:
                self.grp_backup.setParent(self.grp_master.node)

        # Setup displayLayers
        if create_display_layers:
            if not pymel.objExists(self.nomenclature.layer_anm_name):
                self.layer_anm = pymel.createDisplayLayer(
                    name=self.nomenclature.layer_anm_name,
                    number=1,
                    empty=True)
                self.layer_anm.color.set(17)  # Yellow
            else:
                self.layer_anm = pymel.PyNode(self.nomenclature.layer_anm_name)
            pymel.editDisplayLayerMembers(self.layer_anm,
                                          self.grp_anm,
                                          noRecurse=True)

            if not pymel.objExists(self.nomenclature.layer_rig_name):
                self.layer_rig = pymel.createDisplayLayer(
                    name=self.nomenclature.layer_rig_name,
                    number=1,
                    empty=True)
                self.layer_rig.color.set(13)  # Red
                # self.layer_rig.visibility.set(0)  # Hidden
                self.layer_rig.displayType.set(2)  # Frozen
            else:
                self.layer_rig = pymel.PyNode(self.nomenclature.layer_rig_name)
            pymel.editDisplayLayerMembers(self.layer_rig,
                                          self.grp_rig,
                                          noRecurse=True)
            pymel.editDisplayLayerMembers(self.layer_rig,
                                          self.grp_jnt,
                                          noRecurse=True)

            if not pymel.objExists(self.nomenclature.layer_geo_name):
                self.layer_geo = pymel.createDisplayLayer(
                    name=self.nomenclature.layer_geo_name,
                    number=1,
                    empty=True)
                self.layer_geo.color.set(12)  # Green?
                self.layer_geo.displayType.set(2)  # Frozen
            else:
                self.layer_geo = pymel.PyNode(self.nomenclature.layer_geo_name)
            pymel.editDisplayLayerMembers(self.layer_geo,
                                          self.grp_geo,
                                          noRecurse=True)
Beispiel #32
0
    def build(self, _bOrientIkCtrl=True, *args, **kwargs):
        super(IK, self).build(*args, **kwargs)

        # Duplicate input chain (we don't want to move the hierarchy)
        # Todo: implement a duplicate method in omtk.libs.libPymel.PyNodeChain
        # Create ikChain and fkChain
        self._chain_ik = pymel.duplicate(self.input, renameChildren=True, parentOnly=True)
        for oInput, oIk, in zip(self.input, self._chain_ik):
            pNameMap = NameMap(oInput, _sType='rig')
            oIk.rename(pNameMap.Serialize('ik'))
        self._chain_ik[0].setParent(self._oParent) # Trick the IK system (temporary solution)

        oChainS = self._chain_ik[0]
        oChainE = self._chain_ik[self.iCtrlIndex]

        # Compute chain length
        self._chain_length = self._chain.length()

        # Compute swivel position
        p3SwivelPos = self.calc_swivel_pos()

        # Create ikChain
        grp_ikChain = pymel.createNode('transform', name=self._pNameMapRig.Serialize('ikChain'), parent=self.grp_rig)
        grp_ikChain.setMatrix(oChainS.getMatrix(worldSpace=True), worldSpace=True)
        oChainS.setParent(grp_ikChain)

        # Create ikEffector
        self._oIkHandle, oIkEffector = pymel.ikHandle(startJoint=oChainS, endEffector=oChainE, solver='ikRPsolver')
        self._oIkHandle.rename(self._pNameMapRig.Serialize('ikHandle'))
        self._oIkHandle.setParent(grp_ikChain)
        oIkEffector.rename(self._pNameMapRig.Serialize('ikEffector'))

        # Create ctrls
        if not isinstance(self.ctrlIK, CtrlIk): self.ctrlIK = CtrlIk()
        self.ctrlIK.build()
        #self.ctrlIK = CtrlIk(_create=True)
        self.ctrlIK.setParent(self.grp_anm)
        self.ctrlIK.rename(self._pNameMapAnm.Serialize('ik'))
        self.ctrlIK.offset.setTranslation(oChainE.getTranslation(space='world'), space='world')
        if _bOrientIkCtrl is True:
            self.ctrlIK.offset.setRotation(oChainE.getRotation(space='world'), space='world')

        if not isinstance(self.ctrl_swivel, CtrlIkSwivel): self.ctrl_swivel = CtrlIkSwivel()
        self.ctrl_swivel.build()
        #self.ctrl_swivel = CtrlIkSwivel(_oLineTarget=self.input[1], _create=True)
        self.ctrl_swivel.setParent(self.grp_anm)
        self.ctrl_swivel.rename(self._pNameMapAnm.Serialize('ikSwivel'))
        self.ctrl_swivel.offset.setTranslation(p3SwivelPos, space='world')
        self.ctrl_swivel.offset.setRotation(self.input[self.iCtrlIndex - 1].getRotation(space='world'), space='world')
        self.swivelDistance = self._chain_length # Used in ik/fk switch

        #
        # Create softIk node and connect user accessible attributes to it.
        #
        oAttHolder   = self.ctrlIK
        fnAddAttr    = functools.partial(libAttr.addAttr, hasMinValue=True, hasMaxValue=True)
        attInRatio   = fnAddAttr(oAttHolder, longName='SoftIkRatio', niceName='SoftIK', defaultValue=0, minValue=0, maxValue=.5, k=True)
        attInStretch = fnAddAttr(oAttHolder, longName='Stretch', niceName='Stretch', defaultValue=0, minValue=0, maxValue=1.0, k=True)

        rig_softIkNetwork = SoftIkNode()
        rig_softIkNetwork.build()
        pymel.connectAttr(attInRatio, rig_softIkNetwork.inRatio)
        pymel.connectAttr(attInStretch, rig_softIkNetwork.inStretch)
        pymel.connectAttr(grp_ikChain.worldMatrix, rig_softIkNetwork.inMatrixS)
        pymel.connectAttr(self.ctrlIK.worldMatrix, rig_softIkNetwork.inMatrixE)
        rig_softIkNetwork.inChainLength.set(self._chain_length)

        # Constraint effector
        attOutRatio = rig_softIkNetwork.outRatio
        attOutRatioInv = libRigging.CreateUtilityNode('reverse', inputX=rig_softIkNetwork.outRatio).outputX
        pymel.select(clear=True)
        pymel.select(self.ctrlIK, grp_ikChain, self._oIkHandle)
        constraint = pymel.pointConstraint()
        constraint.rename(constraint.name().replace('pointConstraint', 'softIkConstraint'))
        pymel.select(constraint)
        weight_inn, weight_out = constraint.getWeightAliasList()
        pymel.connectAttr(attOutRatio, weight_inn)
        pymel.connectAttr(attOutRatioInv, weight_out)

        # Constraint joints stretch
        attOutStretch = rig_softIkNetwork.outStretch
        num_jnts = len(self._chain_ik)
        for i in range(1, num_jnts):
            obj = self._chain_ik[i]
            pymel.connectAttr(
                libRigging.CreateUtilityNode('multiplyDivide',
                    input1X=attOutStretch,
                    input1Y=attOutStretch,
                    input1Z=attOutStretch,
                    input2=obj.t.get()).output,
                obj.t, force=True)

        # Connect rig -> anm
        pymel.orientConstraint(self.ctrlIK, oChainE, maintainOffset=True)
        pymel.poleVectorConstraint(self.ctrl_swivel, self._oIkHandle)

        # Connect to parent
        if libPymel.is_valid_PyNode(self.parent):
            pymel.parentConstraint(self.parent, grp_ikChain, maintainOffset=True)
        for source, target in zip(self._chain_ik, self._chain):
            pymel.parentConstraint(source, target)
Beispiel #33
0
 def is_built(self):
     return libPymel.is_valid_PyNode(self.node)
Beispiel #34
0
    def build(self,
              module,
              ref,
              ref_tm=None,
              grp_rig=None,
              obj_mesh=None,
              u_coord=None,
              v_coord=None,
              flip_lr=False,
              follow_mesh=True,
              **kwargs):
        """
        Create an Interactive controller that follow a geometry.
        :param module: ???
        :param ref:
        :param ref_tm:
        :param grp_rig:
        :param obj_mesh:
        :param u_coord:
        :param v_coord:
        :param kwargs:
        :return:
        """

        # HACK: Ensure flipped shapes are correctly restaured...
        # This is necessary since when holded, the scale of the ctrl is set to identity.
        # However ctrl from the right side have an inverted scale on the x axis. -_-
        if flip_lr and libPymel.is_valid_PyNode(self.shapes):
            self.shapes.sx.set(-1)
            pymel.makeIdentity(self.shapes,
                               rotate=True,
                               scale=True,
                               apply=True)

        # todo: Simplify the setup, too many nodes
        super(InteractiveCtrl, self).build(**kwargs)

        #nomenclature_anm = self.get_nomenclature_anm(parent)
        nomenclature_rig = module.rig.nomenclature(
            suffix=module.rig.nomenclature.type_rig)
        #nomenclature_rig = self.get_nomenclature_rig(parent)

        # TODO: Only use position instead of PyNode or Matrix?
        if ref_tm is None:
            ref_tm = ref.getMatrix(worldSpace=True)
        pos_ref = ref_tm.translate

        # Resolve u and v coordinates
        # todo: check if we really want to resolve the u and v ourself since it's now connected.
        if obj_mesh is None:
            # We'll scan all available geometries and use the one with the shortest distance.
            meshes = libRigging.get_affected_geometries(ref)
            meshes = list(set(meshes) & set(module.rig.get_meshes()))
            obj_mesh, _, out_u, out_v = libRigging.get_closest_point_on_shapes(
                meshes, pos_ref)
        else:
            _, out_u, out_v = libRigging.get_closest_point_on_shape(
                obj_mesh, pos_ref)

        if u_coord is None:
            u_coord = out_u
        if v_coord is None:
            v_coord = out_v

        if obj_mesh is None:
            raise Exception(
                "Can't find mesh affected by {0}. Skipping doritos ctrl setup."
            )

        if self.jnt:
            module.debug(
                'Creating doritos on {0} using {1} as reference'.format(
                    obj_mesh, self.jnt))
        else:
            module.debug('Creating doritos on {0}'.format(obj_mesh))

        # Initialize external stack
        # Normally this would be hidden from animators.
        stack_name = nomenclature_rig.resolve('doritosStack')
        stack = classNode.Node(self)
        stack.build(name=stack_name)
        stack.setTranslation(pos_ref)

        # Add sensibility attributes
        # The values will be computed when attach_ctrl will be called
        libAttr.addAttr_separator(module.grp_rig, "ctrlCalibration")
        self.attr_sensitivity_tx = libAttr.addAttr(
            module.grp_rig,
            longName=self._ATTR_NAME_SENSITIVITY_TX,
            defaultValue=1.0)
        self.attr_sensitivity_ty = libAttr.addAttr(
            module.grp_rig,
            longName=self._ATTR_NAME_SENSITIVITY_TY,
            defaultValue=1.0)
        self.attr_sensitivity_tz = libAttr.addAttr(
            module.grp_rig,
            longName=self._ATTR_NAME_SENSITIVITY_TZ,
            defaultValue=1.0)
        self.attr_sensitivity_tx.set(channelBox=True)
        self.attr_sensitivity_ty.set(channelBox=True)
        self.attr_sensitivity_tz.set(channelBox=True)

        # Note that to only check in the Z axis, we'll do a raycast first.
        # If we success this will become our reference position.
        '''
        pos = pos_ref
        pos.z = 999
        dir = pymel.datatypes.Point(0,0,-1)
        result = next(iter(libRigging.ray_cast(pos, dir, [obj_mesh])), None)
        if result:
            pos_ref = result
            ctrl_tm.translate = result
        '''

        # Create the layer_fol that will follow the geometry
        layer_fol_name = nomenclature_rig.resolve('doritosFol')
        layer_fol = stack.append_layer()
        layer_fol.rename(layer_fol_name)
        #layer_fol.setParent(self.grp_rig)

        # TODO: Validate that we don't need to inverse the rotation separately.
        fol_mesh = None
        if follow_mesh:
            fol_name = nomenclature_rig.resolve('doritosFollicle')
            fol_shape = libRigging.create_follicle2(obj_mesh,
                                                    u=u_coord,
                                                    v=v_coord)
            fol_mesh = fol_shape.getParent()
            self.follicle = fol_mesh
            fol_mesh.rename(fol_name)
            pymel.parentConstraint(fol_mesh, layer_fol, maintainOffset=True)
            fol_mesh.setParent(self.grp_rig)

            # HACK: Fix rotation issues.
            # The doritos setup can be hard to control when the rotation of the controller depend on the layer_fol since
            # any deformation can affect the normal of the faces.
            jnt_head = module.rig.get_head_jnt()
            if jnt_head:
                pymel.disconnectAttr(layer_fol.rx)
                pymel.disconnectAttr(layer_fol.ry)
                pymel.disconnectAttr(layer_fol.rz)
                pymel.orientConstraint(jnt_head,
                                       layer_fol,
                                       maintainOffset=True)
        else:
            self.follicle = layer_fol
            pymel.parentConstraint(ref, layer_fol, maintainOffset=True)

        #
        # Constraint a specic controller to the avar doritos stack.
        # Call this method after connecting the ctrl to the necessary avars.
        # The sensibility of the doritos will be automatically computed in this step if necessary.
        #

        # Create inverted attributes for sensibility
        util_sensitivity_inv = libRigging.create_utility_node(
            'multiplyDivide',
            operation=2,
            input1X=1.0,
            input1Y=1.0,
            input1Z=1.0,
            input2X=self.attr_sensitivity_tx,
            input2Y=self.attr_sensitivity_ty,
            input2Z=self.attr_sensitivity_tz)
        attr_sensibility_lr_inv = util_sensitivity_inv.outputX
        attr_sensibility_ud_inv = util_sensitivity_inv.outputY
        attr_sensibility_fb_inv = util_sensitivity_inv.outputZ

        # Add an inverse node that will counter animate the position of the ctrl.
        # TODO: Rename
        layer_doritos_name = nomenclature_rig.resolve('doritosInv')
        layer_doritos = pymel.createNode('transform', name=layer_doritos_name)
        layer_doritos.setParent(stack.node)

        # Create inverse attributes for the ctrl
        attr_ctrl_inv_t = libRigging.create_utility_node('multiplyDivide',
                                                         input1=self.node.t,
                                                         input2=[-1, -1,
                                                                 -1]).output
        attr_ctrl_inv_r = libRigging.create_utility_node('multiplyDivide',
                                                         input1=self.node.r,
                                                         input2=[-1, -1,
                                                                 -1]).output
        attr_ctrl_inv_t = libRigging.create_utility_node(
            'multiplyDivide',
            input1=attr_ctrl_inv_t,
            input2X=self.attr_sensitivity_tx,
            input2Y=self.attr_sensitivity_ty,
            input2Z=self.attr_sensitivity_tz).output

        if flip_lr:
            attr_doritos_tx = libRigging.create_utility_node(
                'multiplyDivide', input1X=attr_ctrl_inv_t.outputX,
                input2X=-1).outputX
        else:
            attr_doritos_tx = attr_ctrl_inv_t.outputX
        attr_doritos_ty = attr_ctrl_inv_t.outputY
        attr_doritos_tz = attr_ctrl_inv_t.outputZ

        pymel.connectAttr(attr_doritos_tx, layer_doritos.tx)
        pymel.connectAttr(attr_doritos_ty, layer_doritos.ty)
        pymel.connectAttr(attr_doritos_tz, layer_doritos.tz)
        pymel.connectAttr(attr_ctrl_inv_r, layer_doritos.r)

        # Apply scaling on the ctrl parent.
        # This is were the 'black magic' happen.
        if flip_lr:
            attr_ctrl_offset_sx_inn = libRigging.create_utility_node(
                'multiplyDivide', input1X=self.attr_sensitivity_tx,
                input2X=-1).outputX
        else:
            attr_ctrl_offset_sx_inn = self.attr_sensitivity_tx
        attr_ctrl_offset_sy_inn = self.attr_sensitivity_ty
        attr_ctrl_offset_sz_inn = self.attr_sensitivity_tz

        pymel.connectAttr(attr_ctrl_offset_sx_inn, self.offset.scaleX)
        pymel.connectAttr(attr_ctrl_offset_sy_inn, self.offset.scaleY)
        pymel.connectAttr(attr_ctrl_offset_sz_inn, self.offset.scaleZ)

        # Apply sensibility on the ctrl shape
        ctrl_shape = self.node.getShape()
        tmp = pymel.duplicate(self.node.getShape())[0]
        ctrl_shape_orig = tmp.getShape()
        ctrl_shape_orig.setParent(self.node, relative=True, shape=True)
        ctrl_shape_orig.rename('{0}Orig'.format(ctrl_shape.name()))
        pymel.delete(tmp)
        ctrl_shape_orig.intermediateObject.set(True)

        for cp in ctrl_shape.cp:
            cp.set(0, 0, 0)

        # Counter-scale the shape
        attr_adjustement_sx_inn = attr_sensibility_lr_inv
        attr_adjustement_sy_inn = attr_sensibility_ud_inv
        attr_adjustement_sz_inn = attr_sensibility_fb_inv
        attr_adjustement_scale = libRigging.create_utility_node(
            'composeMatrix',
            inputScaleX=attr_adjustement_sx_inn,
            inputScaleY=attr_adjustement_sy_inn,
            inputScaleZ=attr_adjustement_sz_inn).outputMatrix

        attr_adjustement_rot = libRigging.create_utility_node(
            'composeMatrix',
            inputRotateX=self.node.rotateX,
            inputRotateY=self.node.rotateY,
            inputRotateZ=self.node.rotateZ).outputMatrix

        attr_adjustement_rot_inv = libRigging.create_utility_node(
            'inverseMatrix', inputMatrix=attr_adjustement_rot).outputMatrix

        attr_adjustement_tm = libRigging.create_utility_node(
            'multMatrix',
            matrixIn=[
                attr_adjustement_rot, attr_adjustement_scale,
                attr_adjustement_rot_inv
            ]).matrixSum

        attr_transform_geometry = libRigging.create_utility_node(
            'transformGeometry',
            transform=attr_adjustement_tm,
            inputGeometry=ctrl_shape_orig.local).outputGeometry
        pymel.connectAttr(attr_transform_geometry,
                          ctrl_shape.create,
                          force=True)

        # Constraint ctrl
        pymel.parentConstraint(layer_doritos,
                               self.offset,
                               maintainOffset=False,
                               skipRotate=['x', 'y', 'z'])
        pymel.orientConstraint(layer_doritos.getParent(),
                               self.offset,
                               maintainOffset=True)

        # Clean dag junk
        if grp_rig:
            stack.setParent(grp_rig)
            if fol_mesh:
                fol_mesh.setParent(grp_rig)
Beispiel #35
0
    def get_spaceswitch_targets(self,
                                module,
                                jnt,
                                add_world=True,
                                add_root=True,
                                add_local=True,
                                root_name='Root',
                                world_name='World',
                                **kwargs):
        """
        Return the list of target used by the space switch of a controller. It will try get all module pin location it
        can find from it's jnt parameter
        :param module: The module on which we want to process space switch targets
        :param jnt: A list of joint that will be used to find associated modules to find space objects
        :param add_world: Is the world will be added as a space switch target of the ctrl
        :param add_root: Is the root will be added as a space switch target of the ctrl
        :param add_local: Is the local option will be used. Local will be the same than the first module target
        :param root_name: The name in the list of targets the root will take
        :param world_name: The name in the list of targets the world will take
        :param kwargs: Additional parameters
        :return: The targets obj, name and index of the found space switch target
        """

        targets = []
        targets.extend(self.targets)  # The target
        # Initialize the target name list with the same number of item than the targets keeped before
        target_names = []
        for i in range(0, len(targets)):
            target_names.append(None)
        indexes = []
        indexes.extend(self.targets_indexes)

        # Use the grp_rip node as the world target. It will always be the first target in the list
        if add_world and libPymel.is_valid_PyNode(module.rig.grp_rig):
            if module.rig.grp_rig not in targets:
                targets.append(module.rig.grp_rig)
                # World will always be -1
                indexes.append(
                    self.get_bestmatch_index(
                        module.rig.grp_rig,
                        constants.SpaceSwitchReservedIndex.world))
                target_names.append(world_name)
            else:
                idx = targets.index(module.rig.grp_rig)
                target_names[idx] = world_name

        # Add the master ctrl as a spaceswitch target
        if libPymel.is_valid_PyNode(module.rig.grp_anm):
            if module.rig.grp_anm not in targets:
                targets.append(module.rig.grp_anm)
                target_names.append(root_name)
                # The root will always be index 1, because we want to let local to be 0
                indexes.append(
                    self.get_bestmatch_index(
                        module.rig.grp_anm,
                        constants.SpaceSwitchReservedIndex.root))
            else:
                idx = targets.index(module.rig.grp_anm)
                target_names[idx] = root_name

        # Resolve modules targets
        first_module = True
        while jnt:
            m = module.rig.get_module_by_input(jnt)
            # We will not add as a target the first modules target found if we add the local space
            # The local space is an equivalent to not having any space activated so as if it follow it's parent which
            # would be the first module found
            if m and ((add_local and not first_module) or not add_local):
                target, target_name = m.get_pin_locations(jnt)
                if target:
                    if target not in targets:
                        targets.append(target)
                        target_names.append(target_name)
                        indexes.append(self.get_bestmatch_index(target))
                    else:
                        idx = targets.index(target)
                        target_names[idx] = target_name
            else:
                first_module = False
            jnt = jnt.getParent()

        # Final check to ensure that not target is None. If one None target is found, we need to remove it and let the
        # index in the space attribute to be free to fix manually
        for i, t in reversed(list(enumerate(targets))):
            if t is None:
                log.warning("Space switch index {0} target is None on {1}, "
                            "maybe a manual connection will be needed".format(
                                indexes[i], self.name))
                targets.pop(i)
                target_names.pop(i)
                indexes.pop(i)

        return targets, target_names, indexes
Beispiel #36
0
    def pre_build(self, create_master_grp=False, create_grp_jnt=True, create_grp_anm=True,
                  create_grp_rig=True, create_grp_geo=True, create_display_layers=True, create_grp_backup=False,
                  create_layer_jnt=False):
        # Hack: Invalidate any cache before building anything.
        # This ensure we always have fresh data.
        self._clear_cache()

        # Look for a root joint
        if create_grp_jnt:
            # For now, we will determine the root jnt by it's name used in each rig. Not the best solution,
            # but currently the safer since we want to support multiple deformation layer
            if not libPymel.is_valid_PyNode(self.grp_jnt):
                # self.grp_jnt = next(iter(libPymel.ls_root(type='joint')), None)
                if cmds.objExists(self.nomenclature.root_jnt_name):
                    self.grp_jnt = pymel.PyNode(self.nomenclature.root_jnt_name)
                else:
                    self.warning("Could not find any root joint, master ctrl will not drive anything")
                    # self.grp_jnt = pymel.createNode('joint', name=self.nomenclature.root_jnt_name)

        # Create the master grp
        if create_master_grp:
            self.grp_master = self.build_grp(RigGrp, self.grp_master, self.name + '_' + self.nomenclature.type_rig)

        # Create grp_anm
        if create_grp_anm:
            grp_anim_size = CtrlRoot._get_recommended_radius(self)
            self.grp_anm = self.build_grp(CtrlRoot, self.grp_anm, self.nomenclature.root_anm_name, size=grp_anim_size)

        # Create grp_rig
        if create_grp_rig:
            self.grp_rig = self.build_grp(RigGrp, self.grp_rig, self.nomenclature.root_rig_name)

        # Create grp_geo
        if create_grp_geo:
            all_geos = libPymel.ls_root_geos()
            self.grp_geo = self.build_grp(RigGrp, self.grp_geo, self.nomenclature.root_geo_name)
            # if all_geos:
            #    all_geos.setParent(self.grp_geo)

        if create_grp_backup:
            self.grp_backup = self.build_grp(RigGrp, self.grp_backup, self.nomenclature.root_backup_name)

        # Parent all grp on the master grp
        if self.grp_master:
            if self.grp_jnt:
                self.grp_jnt.setParent(self.grp_master.node)
            if self.grp_anm:
                self.grp_anm.setParent(self.grp_master.node)
            if self.grp_rig:
                self.grp_rig.setParent(self.grp_master.node)
            if self.grp_geo:
                self.grp_geo.setParent(self.grp_master.node)
            if self.grp_backup:
                self.grp_backup.setParent(self.grp_master.node)

        # Setup displayLayers
        if create_display_layers:
            if not pymel.objExists(self.nomenclature.layer_anm_name):
                self.layer_anm = pymel.createDisplayLayer(name=self.nomenclature.layer_anm_name, number=1, empty=True)
                self.layer_anm.color.set(17)  # Yellow
            else:
                self.layer_anm = pymel.PyNode(self.nomenclature.layer_anm_name)
            pymel.editDisplayLayerMembers(self.layer_anm, self.grp_anm, noRecurse=True)

            if not pymel.objExists(self.nomenclature.layer_rig_name):
                self.layer_rig = pymel.createDisplayLayer(name=self.nomenclature.layer_rig_name, number=1, empty=True)
                self.layer_rig.color.set(13)  # Red
                # self.layer_rig.visibility.set(0)  # Hidden
                self.layer_rig.displayType.set(2)  # Frozen
            else:
                self.layer_rig = pymel.PyNode(self.nomenclature.layer_rig_name)
            pymel.editDisplayLayerMembers(self.layer_rig, self.grp_rig, noRecurse=True)
            pymel.editDisplayLayerMembers(self.layer_rig, self.grp_jnt, noRecurse=True)

            if not pymel.objExists(self.nomenclature.layer_geo_name):
                self.layer_geo = pymel.createDisplayLayer(name=self.nomenclature.layer_geo_name, number=1, empty=True)
                self.layer_geo.color.set(12)  # Green?
                self.layer_geo.displayType.set(2)  # Frozen
            else:
                self.layer_geo = pymel.PyNode(self.nomenclature.layer_geo_name)
            pymel.editDisplayLayerMembers(self.layer_geo, self.grp_geo, noRecurse=True)

            if create_layer_jnt:
                if not pymel.objExists(self.nomenclature.layer_jnt_name):
                    self.layer_jnt = pymel.createDisplayLayer(name=self.nomenclature.layer_jnt_name, number=1,
                                                              empty=True)
                    self.layer_jnt.color.set(1)  # Black?
                    self.layer_jnt.visibility.set(0)  # Hidden
                    self.layer_jnt.displayType.set(2)  # Frozen
                else:
                    self.layer_jnt = pymel.PyNode(self.nomenclature.layer_jnt_name)
                pymel.editDisplayLayerMembers(self.layer_jnt, self.grp_jnt, noRecurse=True)
Beispiel #37
0
    def pre_build(self):
        super(RigSqueeze, self).pre_build(create_grp_jnt=False)
        
        #
        # Create specific group related to squeeze rig convention
        #
        if not libPymel.is_valid_PyNode(self.grp_all):
            if cmds.objExists(self.nomenclature.root_all_name):
                self.grp_all = pymel.PyNode(self.nomenclature.root_all_name)
            else:
                self.grp_all = pymel.createNode('transform', name=self.nomenclature.root_all_name)

        if not libPymel.is_valid_PyNode(self.grp_model):
            if cmds.objExists(self.nomenclature.root_model_name):
                self.grp_model = pymel.PyNode(self.nomenclature.root_model_name)
            else:
                self.grp_model = pymel.createNode('transform', name=self.nomenclature.root_model_name)

        if not libPymel.is_valid_PyNode(self.grp_proxy):
            if cmds.objExists(self.nomenclature.root_proxy_name):
                self.grp_proxy = pymel.PyNode(self.nomenclature.root_proxy_name)
            else:
                self.grp_proxy = pymel.createNode('transform', name=self.nomenclature.root_proxy_name)

        if not libPymel.is_valid_PyNode(self.grp_fx):
            if cmds.objExists(self.nomenclature.root_fx_name):
                self.grp_fx = pymel.PyNode(self.nomenclature.root_fx_name)
            else:
                self.grp_fx = pymel.createNode('transform', name=self.nomenclature.root_fx_name)

        #Parent all groups in the main grp_all
        pymel.parent(self.grp_anm, self.grp_all) #grp_anm is not a Node, but a Ctrl
        self.grp_rig.setParent(self.grp_all)
        self.grp_fx.setParent(self.grp_all)
        self.grp_model.setParent(self.grp_all)
        self.grp_proxy.setParent(self.grp_all)
        self.grp_geo.setParent(self.grp_all)
        '''
        if self.grp_jnt.getParent() is None:
            self.grp_jnt.setParent(self.grp_all)
        '''

        #Lock and hide all attributes we don't want the animator to play with
        libAttr.lock_hide_trs(self.grp_all)
        libAttr.lock_hide_trs(self.grp_rig)
        libAttr.lock_hide_trs(self.grp_fx)
        libAttr.lock_hide_trs(self.grp_model)
        libAttr.lock_hide_trs(self.grp_proxy)
        libAttr.lock_hide_trs(self.grp_geo)
        libAttr.hide_scale(self.grp_anm)

        #Hide some group
        #self.grp_jnt.visibility.set(False)
        self.grp_rig.visibility.set(False)
        self.grp_fx.visibility.set(False)
        self.grp_model.visibility.set(False)

        #
        # Add root ctrl attributes specific to squeeze
        #
        if not self.grp_anm.hasAttr(self.GROUP_NAME_DISPLAY, checkShape=False):
            libAttr.addAttr_separator(self.grp_anm, self.GROUP_NAME_DISPLAY)

        #Display Mesh
        if not self.grp_anm.hasAttr(self.ATTR_NAME_DISPLAY_MESH, checkShape=False):
            attr_displayMesh = libAttr.addAttr(self.grp_anm, longName=self.ATTR_NAME_DISPLAY_MESH, at='short', k=True,
                                               hasMinValue=True, hasMaxValue=True, minValue=0, maxValue=1, defaultValue=1)
        else:
            attr_displayMesh = self.grp_anm.attr(self.ATTR_NAME_DISPLAY_MESH)

        #Display Ctrl
        if not self.grp_anm.hasAttr(self.ATTR_NAME_DISPLAY_CTRL, checkShape=False):
            attr_displayCtrl = libAttr.addAttr(self.grp_anm, longName=self.ATTR_NAME_DISPLAY_CTRL, at='short', k=True,
                                               hasMinValue=True, hasMaxValue=True, minValue=0, maxValue=1, defaultValue=1)
        else:
            attr_displayCtrl = self.grp_anm.attr(self.ATTR_NAME_DISPLAY_CTRL)

        #Display Proxy
        if not self.grp_anm.hasAttr(self.ATTR_NAME_DISPLAY_PROXY, checkShape=False):
            attr_displayProxy = libAttr.addAttr(self.grp_anm, longName=self.ATTR_NAME_DISPLAY_PROXY, at='short', k=True,
                                               hasMinValue=True, hasMaxValue=True, minValue=0, maxValue=1, defaultValue=0)
        else:
            attr_displayProxy = self.grp_anm.attr(self.ATTR_NAME_DISPLAY_PROXY)

        pymel.connectAttr(attr_displayMesh, self.grp_geo.visibility, force=True)
        pymel.connectAttr(attr_displayProxy, self.grp_proxy.visibility, force=True)
        for child in self.grp_anm.getChildren():
            pymel.connectAttr(attr_displayCtrl, child.visibility, force=True)
Beispiel #38
0
 def _is_influence(self, jnt):
     # Ignore any joint in the rig group (like joint used with ikHandles)
     if libPymel.is_valid_PyNode(self.grp_rig):
         if libPymel.is_child_of(jnt, self.grp_rig.node):
             return False
     return True
Beispiel #39
0
def _createAttribute(_name, _val):
    if isinstance(_val, basestring):
        fn = OpenMaya.MFnTypedAttribute()
        fn.create(_name, _name, OpenMaya. MFnData.kString)
        return fn
    kType = type(_val)
    if issubclass(kType, bool):
        fn = OpenMaya.MFnNumericAttribute()
        fn.create(_name, _name, OpenMaya.MFnNumericData.kBoolean)
        return fn
    if issubclass(kType, int):
        fn = OpenMaya.MFnNumericAttribute()
        fn.create(_name, _name, OpenMaya.MFnNumericData.kInt)
        return fn
    if issubclass(kType, float):
        fn = OpenMaya.MFnNumericAttribute()
        fn.create(_name, _name, OpenMaya.MFnNumericData.kFloat)
        return fn
    if isinstance(_val, dict):
        fn = OpenMaya.MFnMessageAttribute()
        fn.create(_name, _name)
        return fn
    if isinstance(_val, list) or isinstance(type, tuple):
        if len(_val) < 1:
            pymel.warning("Can't create attribute {0}, empty array are unsuported".format(_name))
            return None
        # TODO: Throw error when the array have multiple types
        fn = _createAttribute(_name, _val[0])
        fn.setArray(True)
        return fn
    if isinstance(_val, pymel.datatypes.Matrix):
        fn = OpenMaya.MFnMatrixAttribute()
        fn.create(_name, _name)
        return fn
    if issubclass(kType, pymel.Attribute):
        if not libPymel.is_valid_PyNode(_val):
            log.warning("Can't serialize {0} attribute because of non-existent pymel Attribute!".format(_name))
            return None
        elif _val.type() == 'doubleAngle':
            fn = OpenMaya.MFnUnitAttribute()
            fn.create(_name, _name, OpenMaya.MFnUnitAttribute.kAngle)
            return fn
        elif _val.type() == 'time':
            fn = OpenMaya.MFnUnitAttribute()
            fn.create(_name, _name, OpenMaya.MFnUnitAttribute.kTime)
            return fn
        #elif _val.type() == '???':
        #    fn = OpenMaya.MFnUnitAttribute()
        #    fn.create(_name, _name, OpenMaya.MFnUnitAttribute.kDistance)
        #    return fn
        # If the attribute doesn't represent anything special, we'll check it's value to know what attribute type to create.
        else:
            return _createAttribute(_name, _val.get())
    if hasattr(_val, '__melobject__'): # TODO: Really usefull?
        fn = OpenMaya.MFnMessageAttribute()
        fn.create(_name, _name)
        return fn
    if hasattr(_val, '__dict__'):
        fn = OpenMaya.MFnMessageAttribute()
        fn.create(_name, _name)
        return fn
    pymel.error("Can't create MFnAttribute for {0} {1} {2}".format(_name, _val, kType))
Beispiel #40
0
    def unbuild(self):
        # hack: the ikEffector is parented to the bone chain and need to be deleted manually
        if libPymel.is_valid_PyNode(self.ikEffector):
            pymel.delete(self.ikEffector)

        super(SplineIK, self).unbuild()
Beispiel #41
0
 def _clean_invalid_pynodes(self):
     fnCanDelete = lambda x: (isinstance(x, (pymel.PyNode, pymel.Attribute)) and not libPymel.is_valid_PyNode(x))
     for key, val in self.__dict__.iteritems():
         if fnCanDelete(val):
             setattr(self, key, None)
         elif isinstance(val, (list, set, tuple)):
             for i in reversed(range(len(val))):
                 if fnCanDelete(val[i]):
                     val.pop(i)
             if len(val) == 0:
                 setattr(self, key, None)
Beispiel #42
0
 def can_fetch_shapes(self):
     return libPymel.is_valid_PyNode(self.shapes) and self.shapes.getShape()
Beispiel #43
0
    def get_spaceswitch_targets(self, module, jnt, add_world=True, add_root=True, add_local=True,
                                root_name='Root', world_name='World', **kwargs):
        """
        Return the list of target used by the space switch of a controller. It will try get all module pin location it
        can find from it's jnt parameter
        :param module: The module on which we want to process space switch targets
        :param jnt: A list of joint that will be used to find associated modules to find space objects
        :param add_world: Is the world will be added as a space switch target of the ctrl
        :param add_root: Is the root will be added as a space switch target of the ctrl
        :param add_local: Is the local option will be used. Local will be the same than the first module target
        :param root_name: The name in the list of targets the root will take
        :param world_name: The name in the list of targets the world will take
        :param kwargs: Additional parameters
        :return: The targets obj, name and index of the found space switch target
        """

        targets = []
        targets.extend(self.targets)  # The target
        # Initialize the target name list with the same number of item than the targets keeped before
        target_names = []
        for i in range(0, len(targets)):
            target_names.append(None)
        indexes = []
        indexes.extend(self.targets_indexes)

        # Use the grp_rip node as the world target. It will always be the first target in the list
        if add_world and libPymel.is_valid_PyNode(module.rig.grp_rig):
            if module.rig.grp_rig not in targets:
                targets.append(module.rig.grp_rig)
                # World will always be -1
                indexes.append(self.get_bestmatch_index(module.rig.grp_rig, constants.SpaceSwitchReservedIndex.world))
                target_names.append(world_name)
            else:
                idx = targets.index(module.rig.grp_rig)
                target_names[idx] = world_name

        # Add the master ctrl as a spaceswitch target
        if libPymel.is_valid_PyNode(module.rig.grp_anm):
            if module.rig.grp_anm not in targets:
                targets.append(module.rig.grp_anm)
                target_names.append(root_name)
                # The root will always be index 1, because we want to let local to be 0
                indexes.append(self.get_bestmatch_index(module.rig.grp_anm, constants.SpaceSwitchReservedIndex.root))
            else:
                idx = targets.index(module.rig.grp_anm)
                target_names[idx] = root_name

        # Resolve modules targets
        first_module = True
        while jnt:
            m = module.rig.get_module_by_input(jnt)
            # We will not add as a target the first modules target found if we add the local space
            # The local space is an equivalent to not having any space activated so as if it follow it's parent which
            # would be the first module found
            if m and ((add_local and not first_module) or not add_local):
                target, target_name = m.get_pin_locations(jnt)
                if target:
                    if target not in targets:
                        targets.append(target)
                        target_names.append(target_name)
                        indexes.append(self.get_bestmatch_index(target))
                    else:
                        idx = targets.index(target)
                        target_names[idx] = target_name
            else:
                first_module = False
            jnt = jnt.getParent()

        # Final check to ensure that not target is None. If one None target is found, we need to remove it and let the
        # index in the space attribute to be free to fix manually
        for i, t in reversed(list(enumerate(targets))):
            if t is None:
                log.warning("Space switch index {0} target is None on {1}, "
                            "maybe a manual connection will be needed".format(indexes[i], self.name))
                targets.pop(i)
                target_names.pop(i)
                indexes.pop(i)

        return targets, target_names, indexes
Beispiel #44
0
    def build(self, module, ref, ref_tm=None, grp_rig=None, obj_mesh=None, u_coord=None, v_coord=None, flip_lr=False, follow_mesh=True, **kwargs):
        """
        Create an Interactive controller that follow a geometry.
        :param module: ???
        :param ref:
        :param ref_tm:
        :param grp_rig:
        :param obj_mesh:
        :param u_coord:
        :param v_coord:
        :param kwargs:
        :return:
        """

        # HACK: Ensure flipped shapes are correctly restaured...
        # This is necessary since when holded, the scale of the ctrl is set to identity.
        # However ctrl from the right side have an inverted scale on the x axis. -_-
        if flip_lr and libPymel.is_valid_PyNode(self.shapes):
            self.shapes.sx.set(-1)
            pymel.makeIdentity(self.shapes, rotate=True, scale=True, apply=True)

        # todo: Simplify the setup, too many nodes
        super(InteractiveCtrl, self).build(**kwargs)

        #nomenclature_anm = self.get_nomenclature_anm(parent)
        nomenclature_rig = module.rig.nomenclature(suffix=module.rig.nomenclature.type_rig)
        #nomenclature_rig = self.get_nomenclature_rig(parent)

        # TODO: Only use position instead of PyNode or Matrix?
        if ref_tm is None:
            ref_tm = ref.getMatrix(worldSpace=True)
        pos_ref = ref_tm.translate

        # Resolve u and v coordinates
        # todo: check if we really want to resolve the u and v ourself since it's now connected.
        if obj_mesh is None:
            # We'll scan all available geometries and use the one with the shortest distance.
            meshes = libRigging.get_affected_geometries(ref)
            meshes = list(set(meshes) & set(module.rig.get_meshes()))
            obj_mesh, _, out_u, out_v = libRigging.get_closest_point_on_shapes(meshes, pos_ref)
        else:
            _, out_u, out_v = libRigging.get_closest_point_on_shape(obj_mesh, pos_ref)

        if u_coord is None:
            u_coord = out_u
        if v_coord is None:
            v_coord = out_v

        if obj_mesh is None:
            raise Exception("Can't find mesh affected by {0}. Skipping doritos ctrl setup.")

        if self.jnt:
            module.debug('Creating doritos on {0} using {1} as reference'.format(obj_mesh, self.jnt))
        else:
            module.debug('Creating doritos on {0}'.format(obj_mesh))


        # Initialize external stack
        # Normally this would be hidden from animators.
        stack_name = nomenclature_rig.resolve('doritosStack')
        stack = classNode.Node(self)
        stack.build(name=stack_name)
        stack.setTranslation(pos_ref)

        # Add sensibility attributes
        # The values will be computed when attach_ctrl will be called
        libAttr.addAttr_separator(
            module.grp_rig,
            "ctrlCalibration"
        )
        self.attr_sensitivity_tx = libAttr.addAttr(
            module.grp_rig,
            longName=self._ATTR_NAME_SENSITIVITY_TX,
            defaultValue=1.0
        )
        self.attr_sensitivity_ty = libAttr.addAttr(
            module.grp_rig,
            longName=self._ATTR_NAME_SENSITIVITY_TY,
            defaultValue=1.0
        )
        self.attr_sensitivity_tz = libAttr.addAttr(
            module.grp_rig,
            longName=self._ATTR_NAME_SENSITIVITY_TZ,
            defaultValue=1.0
        )
        self.attr_sensitivity_tx.set(channelBox=True)
        self.attr_sensitivity_ty.set(channelBox=True)
        self.attr_sensitivity_tz.set(channelBox=True)


        # Note that to only check in the Z axis, we'll do a raycast first.
        # If we success this will become our reference position.
        '''
        pos = pos_ref
        pos.z = 999
        dir = pymel.datatypes.Point(0,0,-1)
        result = next(iter(libRigging.ray_cast(pos, dir, [obj_mesh])), None)
        if result:
            pos_ref = result
            ctrl_tm.translate = result
        '''

        # Create the layer_fol that will follow the geometry
        layer_fol_name = nomenclature_rig.resolve('doritosFol')
        layer_fol = stack.append_layer()
        layer_fol.rename(layer_fol_name)
        #layer_fol.setParent(self.grp_rig)

        # TODO: Validate that we don't need to inverse the rotation separately.
        fol_mesh = None
        if follow_mesh:
            fol_name = nomenclature_rig.resolve('doritosFollicle')
            fol_shape = libRigging.create_follicle2(obj_mesh, u=u_coord, v=v_coord)
            fol_mesh = fol_shape.getParent()
            self.follicle = fol_mesh
            fol_mesh.rename(fol_name)
            pymel.parentConstraint(fol_mesh, layer_fol, maintainOffset=True)
            fol_mesh.setParent(self.grp_rig)

            # HACK: Fix rotation issues.
            # The doritos setup can be hard to control when the rotation of the controller depend on the layer_fol since
            # any deformation can affect the normal of the faces.
            jnt_head = module.rig.get_head_jnt()
            if jnt_head:
                pymel.disconnectAttr(layer_fol.rx)
                pymel.disconnectAttr(layer_fol.ry)
                pymel.disconnectAttr(layer_fol.rz)
                pymel.orientConstraint(jnt_head, layer_fol, maintainOffset=True)
        else:
            self.follicle = layer_fol
            pymel.parentConstraint(ref, layer_fol, maintainOffset=True)

        #
        # Constraint a specic controller to the avar doritos stack.
        # Call this method after connecting the ctrl to the necessary avars.
        # The sensibility of the doritos will be automatically computed in this step if necessary.
        #



        # Create inverted attributes for sensibility
        util_sensitivity_inv = libRigging.create_utility_node('multiplyDivide', operation=2,
                                                              input1X=1.0, input1Y=1.0, input1Z=1.0,
                                                              input2X=self.attr_sensitivity_tx,
                                                              input2Y=self.attr_sensitivity_ty,
                                                              input2Z=self.attr_sensitivity_tz
                                                              )
        attr_sensibility_lr_inv = util_sensitivity_inv.outputX
        attr_sensibility_ud_inv = util_sensitivity_inv.outputY
        attr_sensibility_fb_inv = util_sensitivity_inv.outputZ

        # Add an inverse node that will counter animate the position of the ctrl.
        # TODO: Rename
        layer_doritos_name = nomenclature_rig.resolve('doritosInv')
        layer_doritos = pymel.createNode('transform', name=layer_doritos_name)
        layer_doritos.setParent(stack.node)

        # Create inverse attributes for the ctrl
        attr_ctrl_inv_t = libRigging.create_utility_node('multiplyDivide', input1=self.node.t, input2=[-1, -1, -1]).output
        attr_ctrl_inv_r = libRigging.create_utility_node('multiplyDivide', input1=self.node.r, input2=[-1, -1, -1]).output
        attr_ctrl_inv_t = libRigging.create_utility_node('multiplyDivide',
                                                         input1=attr_ctrl_inv_t,
                                                         input2X=self.attr_sensitivity_tx,
                                                         input2Y=self.attr_sensitivity_ty,
                                                         input2Z=self.attr_sensitivity_tz
                                                         ).output

        if flip_lr:
            attr_doritos_tx = libRigging.create_utility_node('multiplyDivide',
                                                             input1X=attr_ctrl_inv_t.outputX,
                                                             input2X=-1
                                                             ).outputX
        else:
            attr_doritos_tx = attr_ctrl_inv_t.outputX
        attr_doritos_ty = attr_ctrl_inv_t.outputY
        attr_doritos_tz = attr_ctrl_inv_t.outputZ

        pymel.connectAttr(attr_doritos_tx, layer_doritos.tx)
        pymel.connectAttr(attr_doritos_ty, layer_doritos.ty)
        pymel.connectAttr(attr_doritos_tz, layer_doritos.tz)
        pymel.connectAttr(attr_ctrl_inv_r, layer_doritos.r)

        # Apply scaling on the ctrl parent.
        # This is were the 'black magic' happen.
        if flip_lr:
            attr_ctrl_offset_sx_inn = libRigging.create_utility_node('multiplyDivide',
                                                                     input1X=self.attr_sensitivity_tx,
                                                                     input2X=-1
                                                                     ).outputX
        else:
            attr_ctrl_offset_sx_inn = self.attr_sensitivity_tx
        attr_ctrl_offset_sy_inn = self.attr_sensitivity_ty
        attr_ctrl_offset_sz_inn = self.attr_sensitivity_tz

        pymel.connectAttr(attr_ctrl_offset_sx_inn, self.offset.scaleX)
        pymel.connectAttr(attr_ctrl_offset_sy_inn, self.offset.scaleY)
        pymel.connectAttr(attr_ctrl_offset_sz_inn, self.offset.scaleZ)

        # Apply sensibility on the ctrl shape
        ctrl_shape = self.node.getShape()
        tmp = pymel.duplicate(self.node.getShape())[0]
        ctrl_shape_orig = tmp.getShape()
        ctrl_shape_orig.setParent(self.node, relative=True, shape=True)
        ctrl_shape_orig.rename('{0}Orig'.format(ctrl_shape.name()))
        pymel.delete(tmp)
        ctrl_shape_orig.intermediateObject.set(True)

        for cp in ctrl_shape.cp:
            cp.set(0,0,0)

        # Counter-scale the shape
        attr_adjustement_sx_inn = attr_sensibility_lr_inv
        attr_adjustement_sy_inn = attr_sensibility_ud_inv
        attr_adjustement_sz_inn = attr_sensibility_fb_inv
        attr_adjustement_scale = libRigging.create_utility_node('composeMatrix',
                                                             inputScaleX=attr_adjustement_sx_inn,
                                                             inputScaleY=attr_adjustement_sy_inn,
                                                             inputScaleZ=attr_adjustement_sz_inn
                                                             ).outputMatrix

        attr_adjustement_rot = libRigging.create_utility_node('composeMatrix',
                                                              inputRotateX=self.node.rotateX,
                                                              inputRotateY=self.node.rotateY,
                                                              inputRotateZ=self.node.rotateZ
                                                              ).outputMatrix

        attr_adjustement_rot_inv = libRigging.create_utility_node('inverseMatrix', inputMatrix=attr_adjustement_rot).outputMatrix

        attr_adjustement_tm = libRigging.create_utility_node('multMatrix', matrixIn=[
            attr_adjustement_rot,
            attr_adjustement_scale,
            attr_adjustement_rot_inv
        ]).matrixSum

        attr_transform_geometry = libRigging.create_utility_node('transformGeometry', transform=attr_adjustement_tm,
                                                                 inputGeometry=ctrl_shape_orig.local).outputGeometry
        pymel.connectAttr(attr_transform_geometry, ctrl_shape.create, force=True)

        # Constraint ctrl
        pymel.parentConstraint(layer_doritos, self.offset, maintainOffset=False, skipRotate=['x', 'y', 'z'])
        pymel.orientConstraint(layer_doritos.getParent(), self.offset, maintainOffset=True)

        # Clean dag junk
        if grp_rig:
            stack.setParent(grp_rig)
            if fol_mesh:
                fol_mesh.setParent(grp_rig)
Beispiel #45
0
 def can_fetch_shapes(self):
     return libPymel.is_valid_PyNode(self.shapes) and self.shapes.getShape()
Beispiel #46
0
    def pre_build(self, create_master_grp=False, create_grp_jnt=True, create_grp_anm=True,
                  create_grp_rig=True, create_grp_geo=True, create_display_layers=True, create_grp_backup=False):
        # Hack: Invalidate any cache before building anything.
        # This ensure we always have fresh data.
        try:
            del self._cache
        except AttributeError:
            pass

        # Look for a root joint
        if create_grp_jnt:
            # For now, we will determine the root jnt by it's name used in each rig. Not the best solution,
            # but currently the safer since we want to support multiple deformation layer
            if not libPymel.is_valid_PyNode(self.grp_jnt):
                # self.grp_jnt = next(iter(libPymel.ls_root(type='joint')), None)
                if cmds.objExists(self.nomenclature.root_jnt_name):
                    self.grp_jnt = pymel.PyNode(self.nomenclature.root_jnt_name)
                else:
                    self.warning("Could not find any root joint, master ctrl will not drive anything")
                    # self.grp_jnt = pymel.createNode('joint', name=self.nomenclature.root_jnt_name)

        # Ensure all joints have segmentScaleComprensate deactivated.
        # This allow us to scale adequately and support video game rigs.
        # If for any mean stretch and squash are necessary, implement
        # them on a new joint chains parented to the skeletton.
        # TODO: Move elsewere?
        all_jnts = libPymel.ls(type='joint')
        for jnt in all_jnts:
            jnt.segmentScaleCompensate.set(False)

        # Create the master grp
        if create_master_grp:
            self.grp_master = self.build_grp(RigGrp, self.grp_master, self.name + '_' + self.nomenclature.type_rig)

        # Create grp_anm
        if create_grp_anm:
            grp_anim_size = CtrlRoot._get_recommended_radius(self)
            self.grp_anm = self.build_grp(CtrlRoot, self.grp_anm, self.nomenclature.root_anm_name, size=grp_anim_size)


        # Create grp_rig
        if create_grp_rig:
            self.grp_rig = self.build_grp(RigGrp, self.grp_rig, self.nomenclature.root_rig_name)

        # Create grp_geo
        if create_grp_geo:
            all_geos = libPymel.ls_root_geos()
            self.grp_geo = self.build_grp(RigGrp, self.grp_geo, self.nomenclature.root_geo_name)
            #if all_geos:
            #    all_geos.setParent(self.grp_geo)

        if create_grp_backup:
            self.grp_backup = self.build_grp(RigGrp, self.grp_backup, self.nomenclature.root_backup_name)

        #Parent all grp on the master grp
        if self.grp_master:
            if self.grp_jnt:
                self.grp_jnt.setParent(self.grp_master.node)
            if self.grp_anm:
                self.grp_anm.setParent(self.grp_master.node)
            if self.grp_rig:
                self.grp_rig.setParent(self.grp_master.node)
            if self.grp_geo:
                self.grp_geo.setParent(self.grp_master.node)
            if self.grp_backup:
                self.grp_backup.setParent(self.grp_master.node)

        # Setup displayLayers
        if create_display_layers:
            if not pymel.objExists(self.nomenclature.layer_anm_name):
                self.layer_anm = pymel.createDisplayLayer(name=self.nomenclature.layer_anm_name, number=1, empty=True)
                self.layer_anm.color.set(17)  # Yellow
            else:
                self.layer_anm = pymel.PyNode(self.nomenclature.layer_anm_name)
            pymel.editDisplayLayerMembers(self.layer_anm, self.grp_anm, noRecurse=True)

            if not pymel.objExists(self.nomenclature.layer_rig_name):
                self.layer_rig = pymel.createDisplayLayer(name=self.nomenclature.layer_rig_name, number=1, empty=True)
                self.layer_rig.color.set(13)  # Red
                # self.layer_rig.visibility.set(0)  # Hidden
                self.layer_rig.displayType.set(2)  # Frozen
            else:
                self.layer_rig = pymel.PyNode(self.nomenclature.layer_rig_name)
            pymel.editDisplayLayerMembers(self.layer_rig, self.grp_rig, noRecurse=True)
            pymel.editDisplayLayerMembers(self.layer_rig, self.grp_jnt, noRecurse=True)

            if not pymel.objExists(self.nomenclature.layer_geo_name):
                self.layer_geo = pymel.createDisplayLayer(name=self.nomenclature.layer_geo_name, number=1, empty=True)
                self.layer_geo.color.set(12)  # Green?
                self.layer_geo.displayType.set(2)  # Frozen
            else:
                self.layer_geo = pymel.PyNode(self.nomenclature.layer_geo_name)
            pymel.editDisplayLayerMembers(self.layer_geo, self.grp_geo, noRecurse=True)
Beispiel #47
0
    def unbuild(self, **kwargs):
        # hack: the ikEffector is parented to the bone chain and need to be deleted manually
        if libPymel.is_valid_PyNode(self.ikEffector):
            pymel.delete(self.ikEffector)

        super(SplineIK, self).unbuild(**kwargs)
Beispiel #48
0
 def is_built(self):
     return libPymel.is_valid_PyNode(self.node)