def create_interface(self):
        super(ModelInteractiveCtrl, self).create_interface()

        # The values will be computed when attach_ctrl will be called
        libAttr.addAttr_separator(
            self.grp_rig,
            "ctrlCalibration"
        )
        self.attr_sensitivity_tx = libAttr.addAttr(
            self.grp_rig,
            longName=self._ATTR_NAME_SENSITIVITY_TX,
            defaultValue=1.0
        )
        self.attr_sensitivity_ty = libAttr.addAttr(
            self.grp_rig,
            longName=self._ATTR_NAME_SENSITIVITY_TY,
            defaultValue=1.0
        )
        self.attr_sensitivity_tz = libAttr.addAttr(
            self.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)
Пример #2
0
    def create_interface(self):
        super(CtrlModelCalibratable, self).create_interface()

        # Add sensitivity attributes on the ctrl.
        # The values will be adjusted on calibration.
        libAttr.addAttr_separator(
            self.grp_rig,
            "ctrlCalibration"
        )
        self.attr_sensitivity_tx = libAttr.addAttr(
            self.grp_rig,
            longName=self._ATTR_NAME_SENSITIVITY_TX,
            defaultValue=1.0
        )
        self.attr_sensitivity_ty = libAttr.addAttr(
            self.grp_rig,
            longName=self._ATTR_NAME_SENSITIVITY_TY,
            defaultValue=1.0
        )
        self.attr_sensitivity_tz = libAttr.addAttr(
            self.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)
Пример #3
0
    def post_buid_module(self, module):
        super(RigSqueeze, self).post_buid_module(module)

        #
        # Connect all IK/FK attributes
        # TODO: Ensure all attributes are correctly transfered
        #
        if isinstance(module, rigLimb.Limb):
            # Inverse IK/FK state.
            # At Squeeze, 0 is IK and 1 is FK, strange.
            module.STATE_IK = 0.0
            module.STATE_FK = 1.0

            pymel.delete(module.ctrl_attrs)
            module.ctrl_attrs = None

            # Resolve name
            # TODO: Handle name conflict
            nomenclature_anm = module.get_nomenclature_anm(self)
            nomenclature_attr = self.nomenclature(tokens=[module.__class__.__name__], side=nomenclature_anm.side)
            attr_src_name = nomenclature_attr.resolve()
            attr_dst = module.grp_rig.attr(module.kAttrName_State)

            if not self.grp_anm.hasAttr(self.GROUP_NAME_IKFK, checkShape=False):
                libAttr.addAttr_separator(self.grp_anm, self.GROUP_NAME_IKFK)

            attr_src = None
            if not self.grp_anm.hasAttr(attr_src_name, checkShape=False):
                attr_src = libAttr.addAttr(self.grp_anm, longName=attr_src_name, at='short', k=True,
                              hasMinValue=True, hasMaxValue=True, minValue=0, maxValue=1, defaultValue=0)
            else:
                attr_src = self.grp_anm.attr(attr_src_name)

            # Note that at Squeeze, 0 is for IK and 1 is for FK so we'll need to reverse it.
            attr_src_inv = libRigging.create_utility_node('reverse', inputX=attr_src).outputX

            pymel.connectAttr(attr_src_inv, attr_dst)

        #
        # Set ctrls colors
        #
        color_by_side = {
            self.nomenclature.SIDE_L: 13,  # Red
            self.nomenclature.SIDE_R: 6  # Blue
        }
        epsilon = 0.1
        if module.grp_anm:
            nomenclature_anm = module.get_nomenclature_anm(self)
            for ctrl in module.get_ctrls(recursive=True):
                nomenclature_ctrl = nomenclature_anm.rebuild(ctrl.name())
                side = nomenclature_ctrl.side
                color = color_by_side.get(side, None)
                if color:
                    ctrl.drawOverride.overrideEnabled.set(1)
                    ctrl.drawOverride.overrideColor.set(color)
Пример #4
0
 def add_avars(self, attr_holder):
     """
     Create the network that contain all our avars.
     For ease of use, the avars are exposed on the grp_rig, however to protect the connection from Maya
     when unbuilding they are really existing in an external network node.
     """
     # Define macro avars
     libAttr.addAttr_separator(attr_holder, 'avars')
     self.attr_ud = self.add_avar(attr_holder, self.AVAR_NAME_UD)
     self.attr_lr = self.add_avar(attr_holder, self.AVAR_NAME_LR)
     self.attr_fb = self.add_avar(attr_holder, self.AVAR_NAME_FB)
     self.attr_yw = self.add_avar(attr_holder, self.AVAR_NAME_YAW)
     self.attr_pt = self.add_avar(attr_holder, self.AVAR_NAME_PITCH)
     self.attr_rl = self.add_avar(attr_holder, self.AVAR_NAME_ROLL)
Пример #5
0
 def add_avars(self, attr_holder):
     """
     Create the network that contain all our avars.
     For ease of use, the avars are exposed on the grp_rig, however to protect the connection from Maya
     when unbuilding they are really existing in an external network node.
     """
     # Define macro avars
     libAttr.addAttr_separator(attr_holder, 'avars')
     self.attr_ud = self.add_avar(attr_holder, self.AVAR_NAME_UD)
     self.attr_lr = self.add_avar(attr_holder, self.AVAR_NAME_LR)
     self.attr_fb = self.add_avar(attr_holder, self.AVAR_NAME_FB)
     self.attr_yw = self.add_avar(attr_holder, self.AVAR_NAME_YAW)
     self.attr_pt = self.add_avar(attr_holder, self.AVAR_NAME_PITCH)
     self.attr_rl = self.add_avar(attr_holder, self.AVAR_NAME_ROLL)
Пример #6
0
    def create_stacks(self):
        super(FaceLipsAvar, self).create_stacks()

        nomenclature_rig = self.get_nomenclature_rig()
        jnt_jaw = self.get_jaw_jnt()
        jaw_module = self.get_jaw_module()

        #
        # Create additional attributes to control the jaw layer
        #

        libAttr.addAttr_separator(self.grp_rig, 'jawLayer')
        self._attr_inn_jaw_ratio_default = libAttr.addAttr(
            self.grp_rig,
            'jawRatioDefault',
            defaultValue=0.5,
            hasMinValue=True,
            hasMaxValue=True,
            minValue=0,
            maxValue=1,
            k=True
        )
        self._attr_bypass_splitter = libAttr.addAttr(
            self.grp_rig,
            'jawSplitterBypass',
            defaultValue=0.0,
            hasMinValue=True,
            hasMaxValue=True,
            minValue=0,
            maxValue=1,
            k=True
        )

        # self._target_jaw_bindpose = self._parent_module._ref_jaw_predeform
        # self._attr_jaw_pitch = self._parent_module._attr_jaw_pt
        
        # Variable shared with the AvarInflModel
        self._attr_jaw_bind_tm = self._parent_module._ref_jaw_predeform.matrix
        self._attr_jaw_pitch = self._parent_module._attr_jaw_pt
Пример #7
0
    def pre_build(self):
        super(RigSqueeze, self).pre_build(create_master_grp=False)
        
        #
        # Create specific group related to squeeze rig convention
        #
        all_geos = libPymel.ls_root_geos()

        # Build All_Grp
        self.grp_master = self.build_grp(classRig.RigGrp, self.grp_master, self.nomenclature.root_all_name)
        self.grp_model = self.build_grp(classRig.RigGrp, self.grp_model, self.nomenclature.root_model_name)
        self.grp_proxy = self.build_grp(classRig.RigGrp, self.grp_proxy, self.nomenclature.root_proxy_name)
        self.grp_fx = self.build_grp(classRig.RigGrp, self.grp_fx, self.nomenclature.root_fx_name)

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

        # Lock and hide all attributes we don't want the animator to play with
        libAttr.lock_hide_trs(self.grp_master)
        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)
Пример #8
0
    def build(self, constraint=True, constraint_handle=True, setup_softik=True, **kwargs):
        """
        :param constraint: Bool to tell if we will constraint the chain bone on the ikchain
        :param constraint_handle: Bool to tell if we will contraint the handle on the ik ctrl
        :param setup_softik: Bool to tell if we setup the soft ik system
        :param kwargs: More kwargs passed to the superclass
        :return: Nothing
        """
        # Build the softik node after the setup for the quadruped
        super(LegIkQuad, self).build(constraint=False, constraint_handle=False, setup_softik=False, **kwargs)
        nomenclature_rig = self.get_nomenclature_rig()

        quad_swivel_pos = self.calc_swivel_pos(start_index=1, end_index=3)
        heel_idx = self.iCtrlIndex - 1

        # Create a second ik chain for the quadruped setup
        self._chain_quad_ik = self.chain.duplicate()
        for i, oIk in enumerate(self._chain_quad_ik):
            oIk.rename(nomenclature_rig.resolve('QuadChain{0:02}'.format(i)))
            # Constraint the bones after the iCtrlIdx to the first ik chain to make the foot roll work correctly
            if i > self.iCtrlIndex:
                pymel.parentConstraint(self._chain_ik[i], self._chain_quad_ik[i])

        self._chain_quad_ik[0].setParent(self._chain_ik[0])

        obj_e = self._chain_quad_ik[self.iCtrlIndex]

        # We need a second ik solver for the quad chain
        ik_solver_quad_name = nomenclature_rig.resolve('quadIkHandle')
        ik_effector_quad_name = nomenclature_rig.resolve('quadIkEffector')
        self._ik_handle_quad, _ik_effector = pymel.ikHandle(startJoint=self._chain_quad_ik[1],
                                                            endEffector=obj_e,
                                                            solver='ikRPsolver')
        self._ik_handle_quad.rename(ik_solver_quad_name)
        _ik_effector.rename(ik_effector_quad_name)
        self._ik_handle_quad.setParent(self._ik_handle)

        #
        # Create softIk node and connect user accessible attributes to it.
        #
        if setup_softik:
            self.setup_softik([self._ik_handle, self._ik_handle_quad], self._chain_quad_ik)

        # Create another swivel handle node for the quad chain setup
        self.ctrl_swivel_quad = self.setup_swivel_ctrl(self.ctrl_swivel_quad, self._chain_quad_ik[heel_idx],
                                                       quad_swivel_pos, self._ik_handle_quad, name='swivelQuad', mirror_setup=False)
        self.quad_swivel_distance = self.chain_length  # Used in ik/fk switch
        # Set by default the space to calf
        if self.ctrl_swivel_quad.space:
            enum = self.ctrl_swivel_quad.space.getEnums()
            calf_idx = enum.get('Calf', None)
            if calf_idx:
                self.ctrl_swivel_quad.space.set(calf_idx)

        attr_holder = self.ctrl_ik
        libAttr.addAttr_separator(attr_holder, 'Quadruped', niceName='Quadruped')
        attr_pitch = libAttr.addAttr(attr_holder, longName='pitch', k=True)
        pymel.connectAttr(attr_pitch, self._chain_quad_ik[0].rotateZ)

        pymel.orientConstraint(self.ctrl_ik, obj_e, maintainOffset=True)

        if constraint:
            for source, target in zip(self._chain_quad_ik, self.chain):
                pymel.parentConstraint(source, target)
    def build(self, avar, ref=None, ref_tm=None, grp_rig=None, obj_mesh=None, u_coord=None, v_coord=None,
              flip_lr=False, follow_mesh=True, ctrl_tm=None, ctrl_size=1.0, parent_pos=None,
              parent_rot=None, parent_scl=None, constraint=False, cancel_t=True, cancel_r=True, attr_bind_tm=None,
              **kwargs):
        # todo: get rid of the u_coods, v_coods etc, we should rely on the bind
        super(ModelCtrlLinear, self).build(avar, ctrl_size=ctrl_size, **kwargs)

        nomenclature_rig = self.get_nomenclature_rig()

        #
        # Resolve necessary informations
        #

        # Resolve which object will the InteractiveCtrl track.
        # If we don't want to follow a particular geometry, we'll use the end of the stack.
        # Otherwise the influence will be used (to also resolve the geometry).
        # todo: it could be better to resolve the geometry ourself
        if ref is None:
            ref = self.jnt

        # Resolve the ctrl default tm
        if ctrl_tm is None:
            ctrl_tm = self.get_default_tm_ctrl()
        if ctrl_tm is None:
            raise Exception("Cannot resolve ctrl transformation matrix!")

        # By default, we expect the rigger to mirror the face joints using the 'behavior' mode.
        if flip_lr:
            ctrl_tm = pymel.datatypes.Matrix(
                1.0, 0.0, 0.0, 0.0,
                0.0, -1.0, 0.0, 0.0,
                0.0, 0.0, -1.0, 0.0,
                0.0, 0.0, 0.0, 1.0) * ctrl_tm

        self._grp_bind_ctrl = pymel.createNode(
            'transform',
            name=nomenclature_rig.resolve('ctrlBindTm'),
            parent=self.grp_rig,
        )
        self._grp_bind_ctrl.setMatrix(ctrl_tm)

        # Resolve the influence bind tm
        # Create an offset node to easily change it.
        self._grp_bind_infl = pymel.createNode('transform', name=nomenclature_rig.resolve('bind'), parent=self.grp_rig)
        if attr_bind_tm:
            util_decompose_bind = libRigging.create_utility_node(
                'decomposeMatrix',
                inputMatrix=attr_bind_tm,
            )
            pymel.connectAttr(util_decompose_bind.outputTranslate, self._grp_bind_infl.translate)
            pymel.connectAttr(util_decompose_bind.outputRotate, self._grp_bind_infl.rotate)
            pymel.connectAttr(util_decompose_bind.outputScale, self._grp_bind_infl.scale)
        else:  # todo: deprecate this?
            self._grp_bind_infl.setTranslation(ctrl_tm.translate)

        # Create a follicle, this will be used for calibration purpose.
        # If this affect performance we can create it only when necessary, however being able to
        # see it help with debugging.
        follicle_transform, follicle_shape = self._create_follicle(
            ctrl_tm,
            ref,
            obj_mesh=obj_mesh,
            u_coord=u_coord,
            v_coord=v_coord,
        )
        self.follicle = follicle_transform

        #
        # Add calibration-related attribute
        #

        # The values will be computed when attach_ctrl will be called
        libAttr.addAttr_separator(
            self.grp_rig,
            "ctrlCalibration"
        )
        self.attr_sensitivity_tx = libAttr.addAttr(
            self.grp_rig,
            longName=self._ATTR_NAME_SENSITIVITY_TX,
            defaultValue=1.0
        )
        self.attr_sensitivity_ty = libAttr.addAttr(
            self.grp_rig,
            longName=self._ATTR_NAME_SENSITIVITY_TY,
            defaultValue=1.0
        )
        self.attr_sensitivity_tz = libAttr.addAttr(
            self.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)

        # Hack: Since there's scaling on the ctrl so the left and right side ctrl channels matches, we need to flip the ctrl shapes.
        if flip_lr:
            self.ctrl.scaleX.set(-1)
            libPymel.makeIdentity_safe(self.ctrl, rotate=True, scale=True, apply=True)

        grp_output = pymel.createNode(
            'transform',
            name=nomenclature_rig.resolve('output'),
            parent=self.grp_rig
        )

        attr_output_tm = libRigging.create_utility_node(
            'multMatrix',
            matrixIn=(
                self._grp_bind_ctrl.matrix,
                self._attr_inn_parent_tm,
                self.rig.grp_anm.worldInverseMatrix
            )
        ).matrixSum
        libRigging.connect_matrix_to_node(attr_output_tm, grp_output)

        # 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

        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

        # Connect any additionel scale source.
        if parent_scl:
            u = libRigging.create_utility_node(
                'multiplyDivide',
                name=nomenclature_rig.resolve('getAbsoluteCtrlOffsetScale'),
                input1X=attr_ctrl_offset_sx_inn,
                input1Y=attr_ctrl_offset_sy_inn,
                input1Z=attr_ctrl_offset_sz_inn,
                input2X=parent_scl.scaleX,
                input2Y=parent_scl.scaleY,
                input2Z=parent_scl.scaleZ
            )
            attr_ctrl_offset_sx_inn, attr_ctrl_offset_sy_inn, attr_ctrl_offset_sz_inn = u.outputX, u.outputY, u.outputZ

        # Ensure the scaling of the parent is taken in account.
        attr_calibration_scale_tm = libRigging.create_utility_node(
            'composeMatrix',
            name=nomenclature_rig.resolve('composeCalibrationScaleTm'),
            inputScaleX=attr_ctrl_offset_sx_inn,
            inputScaleY=attr_ctrl_offset_sy_inn,
            inputScaleZ=attr_ctrl_offset_sz_inn,
        ).outputMatrix
        attr_ctrl_offset_scale_tm = libRigging.create_utility_node(
            'multMatrix',
            name=nomenclature_rig.resolve('getCtrlOffsetScaleTm'),
            matrixIn=(
                attr_calibration_scale_tm,
                self._attr_inn_parent_tm,
                self.rig.grp_anm.worldInverseMatrix,
            )
        ).matrixSum
        attr_ctrl_offset_scale = libRigging.create_utility_node(
            'decomposeMatrix',
            inputMatrix=attr_ctrl_offset_scale_tm
        ).outputScale

        # Flip the x axis if we are on the right side of the face.
        # We need to do it as the last step since this will result in a right-handed matrix
        # which will be canceled out if we feed it into multMatrix or other maya nodes.
        if flip_lr:
            attr_ctrl_offset_scale = libRigging.create_utility_node(
                'multiplyDivide',
                input1=attr_ctrl_offset_scale,
                input2X=-1.0,
                input2Y=1.0,
                input2Z=1.0,
            ).output
        pymel.connectAttr(attr_ctrl_offset_scale, self.ctrl.offset.scale)

        # Apply sensibility on the ctrl shape
        ctrl_shape = self.ctrl.node.getShape()
        tmp = pymel.duplicate(self.ctrl.node.getShape())[0]
        ctrl_shape_orig = tmp.getShape()
        ctrl_shape_orig.setParent(self.ctrl.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.ctrl.node.rotateX,
            inputRotateY=self.ctrl.node.rotateY,
            inputRotateZ=self.ctrl.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)

        pymel.connectAttr(grp_output.translate, self.ctrl.offset.translate)
        pymel.connectAttr(grp_output.rotate, self.ctrl.offset.rotate)

        if constraint and self.jnt:
            pymel.parentConstraint(self.ctrl.node, self.jnt, maintainOffset=True)
Пример #10
0
    def build(self,
              constraint=True,
              constraint_handle=True,
              setup_softik=True,
              **kwargs):
        """
        :param constraint: Bool to tell if we will constraint the chain bone on the ikchain
        :param constraint_handle: Bool to tell if we will contraint the handle on the ik ctrl
        :param setup_softik: Bool to tell if we setup the soft ik system
        :param kwargs: More kwargs passed to the superclass
        :return: Nothing
        """
        # Build the softik node after the setup for the quadruped
        super(LegIkQuad, self).build(constraint=False,
                                     constraint_handle=False,
                                     setup_softik=False,
                                     **kwargs)
        nomenclature_rig = self.get_nomenclature_rig()

        quad_swivel_pos = self.calc_swivel_pos(start_index=1, end_index=3)
        heel_idx = self.iCtrlIndex - 1

        # Create a second ik chain for the quadruped setup
        self._chain_quad_ik = self.chain.duplicate()
        for i, oIk in enumerate(self._chain_quad_ik):
            oIk.rename(nomenclature_rig.resolve('QuadChain{0:02}'.format(i)))
            # Constraint the bones after the iCtrlIdx to the first ik chain to make the foot roll work correctly
            if i > self.iCtrlIndex:
                pymel.parentConstraint(self._chain_ik[i],
                                       self._chain_quad_ik[i])

        self._chain_quad_ik[0].setParent(self._chain_ik[0])

        obj_e = self._chain_quad_ik[self.iCtrlIndex]

        # We need a second ik solver for the quad chain
        ik_solver_quad_name = nomenclature_rig.resolve('quadIkHandle')
        ik_effector_quad_name = nomenclature_rig.resolve('quadIkEffector')
        self._ik_handle_quad, _ik_effector = pymel.ikHandle(
            startJoint=self._chain_quad_ik[1],
            endEffector=obj_e,
            solver='ikRPsolver')
        self._ik_handle_quad.rename(ik_solver_quad_name)
        _ik_effector.rename(ik_effector_quad_name)
        self._ik_handle_quad.setParent(self._ik_handle)

        #
        # Create softIk node and connect user accessible attributes to it.
        #
        if setup_softik:
            self.setup_softik([self._ik_handle, self._ik_handle_quad],
                              self._chain_quad_ik)

        # Create another swivel handle node for the quad chain setup
        self.ctrl_swivel_quad = self.setup_swivel_ctrl(
            self.ctrl_swivel_quad,
            self._chain_quad_ik[heel_idx],
            quad_swivel_pos,
            self._ik_handle_quad,
            name='swivelQuad',
            mirror_setup=False)
        self.quad_swivel_distance = self.chain_length  # Used in ik/fk switch
        # Set by default the space to calf
        if self.ctrl_swivel_quad.space:
            enum = self.ctrl_swivel_quad.space.getEnums()
            calf_idx = enum.get('Calf', None)
            if calf_idx:
                self.ctrl_swivel_quad.space.set(calf_idx)

        attr_holder = self.ctrl_ik
        libAttr.addAttr_separator(attr_holder,
                                  'Quadruped',
                                  niceName='Quadruped')
        attr_pitch = libAttr.addAttr(attr_holder, longName='pitch', k=True)
        pymel.connectAttr(attr_pitch, self._chain_quad_ik[0].rotateZ)

        pymel.orientConstraint(self.ctrl_ik, obj_e, maintainOffset=True)

        if constraint:
            for source, target in zip(self._chain_quad_ik, self.chain):
                pymel.parentConstraint(source, target)
Пример #11
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)
Пример #12
0
    def build_stack(self, stack, **kwargs):
        nomenclature_rig = self.get_nomenclature_rig()
        jnt_head = self.rig.get_head_jnt()
        jnt_jaw = self.rig.get_jaw_jnt()

        #
        # Create additional attributes to control the jaw layer
        #

        libAttr.addAttr_separator(self.grp_rig, 'jawLayer')
        self._attr_inn_jaw_ratio_default = libAttr.addAttr(self.grp_rig,
                                                           'jawRatioDefault',
                                                           defaultValue=0.5,
                                                           hasMinValue=True,
                                                           hasMaxValue=True,
                                                           minValue=0,
                                                           maxValue=1,
                                                           k=True)
        self._attr_bypass_splitter = libAttr.addAttr(self.grp_rig,
                                                     'jawSplitterBypass',
                                                     defaultValue=0.0,
                                                     hasMinValue=True,
                                                     hasMaxValue=True,
                                                     minValue=0,
                                                     maxValue=1,
                                                     k=True)

        #
        # Create reference objects used for calculations.
        #

        # Create a reference node that follow the head
        self._target_head = pymel.createNode(
            'transform',
            name=nomenclature_rig.resolve('innHead'),
            parent=self.grp_rig)
        self._target_head.setTranslation(
            jnt_head.getTranslation(space='world'))
        pymel.parentConstraint(jnt_head,
                               self._target_head,
                               maintainOffset=True)
        pymel.scaleConstraint(jnt_head, self._target_head, maintainOffset=True)

        # Create a reference node that follow the jaw initial position
        jaw_pos = jnt_jaw.getTranslation(space='world')
        self._target_jaw_bindpose = pymel.createNode(
            'transform',
            name=nomenclature_rig.resolve('innJawBindPose'),
            parent=self.grp_rig)
        self._target_jaw_bindpose.setTranslation(jaw_pos)

        # Create a reference node that follow the jaw
        self._target_jaw = pymel.createNode(
            'transform',
            name=nomenclature_rig.resolve('innJaw'),
            parent=self._target_jaw_bindpose)
        self._target_jaw.t.set(0, 0, 0)
        pymel.parentConstraint(jnt_jaw, self._target_jaw, maintainOffset=True)
        pymel.scaleConstraint(jnt_jaw, self._target_jaw, maintainOffset=True)

        # Create a node that contain the out jaw influence.
        # Note that the out jaw influence can be modified by the splitter node.
        grp_parent_pos = self._grp_parent.getTranslation(
            space='world')  # grp_offset is always in world coordinates
        self._jaw_ref = pymel.createNode(
            'transform',
            name=nomenclature_rig.resolve('outJawInfluence'),
            parent=self.grp_rig)
        self._jaw_ref.t.set(grp_parent_pos)
        pymel.parentConstraint(self._target_jaw,
                               self._jaw_ref,
                               maintainOffset=True)

        # Extract jaw influence
        attr_delta_tm = libRigging.create_utility_node(
            'multMatrix',
            matrixIn=[
                self._jaw_ref.worldMatrix, self._grp_parent.worldInverseMatrix
            ]).matrixSum

        util_extract_jaw = libRigging.create_utility_node(
            'decomposeMatrix',
            name=nomenclature_rig.resolve('getJawRotation'),
            inputMatrix=attr_delta_tm)

        super(FaceLipsAvar, self).build_stack(stack, **kwargs)

        #
        # Create jaw influence layer
        # Create a reference object to extract the jaw displacement.
        #

        # Add the jaw influence as a new stack layer.
        layer_jaw_r = stack.prepend_layer(name='jawRotate')
        layer_jaw_t = stack.prepend_layer(name='jawTranslate')

        pymel.connectAttr(util_extract_jaw.outputTranslate, layer_jaw_t.t)
        pymel.connectAttr(util_extract_jaw.outputRotate, layer_jaw_r.r)
Пример #13
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)
Пример #14
0
    def pre_build(self, create_grp_anm=True, create_display_layers=True, **kwargs):
        super(RigSqueeze, self).pre_build(create_grp_anm=create_grp_anm, create_master_grp=False,
                                          create_display_layers=create_display_layers, **kwargs)

        if create_grp_anm:
            grp_anim_size = CtrlMaster._get_recommended_radius(self)
            self.grp_anm_master = self.build_grp(
                CtrlMaster,
                self.grp_anm_master,
                self.nomenclature.root_anm_master_name,
                size=grp_anim_size
            )

        if create_display_layers:
            pymel.editDisplayLayerMembers(self.layer_anm, self.grp_anm_master, noRecurse=True)

        #
        # Create specific group related to squeeze rig convention
        #
        all_geos = libPymel.ls_root_geos()

        # Build All_Grp
        self.grp_master = self.build_grp(classRig.RigGrp, self.grp_master, self.nomenclature.root_all_name)
        self.grp_model = self.build_grp(classRig.RigGrp, self.grp_model, self.nomenclature.root_model_name)
        self.grp_proxy = self.build_grp(classRig.RigGrp, self.grp_proxy, self.nomenclature.root_proxy_name)
        self.grp_fx = self.build_grp(classRig.RigGrp, self.grp_fx, self.nomenclature.root_fx_name)

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

        # Lock and hide all attributes we don't want the animator to play with
        libAttr.lock_hide_trs(self.grp_master)
        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 while preserving existing connections.
        #
        if not self.grp_anm.hasAttr(self.GROUP_NAME_DISPLAY, checkShape=False):
            libAttr.addAttr_separator(self.grp_anm, self.GROUP_NAME_DISPLAY)

        attr_display_mesh_output_attrs = {self.grp_geo.visibility}
        attr_display_proxy_output_attrs = {self.grp_proxy.visibility}
        # attr_display_ctrl_output_attrs = set(
        #     [children.visibility for children in self.grp_anm.getChildren(type='transform')]
        # )

        # In the past, the displayMesh attribute was a boolean and the displayProxy was also a boolean.
        # Now we use an enum. This mean that we need to remap.
        if self.grp_anm.hasAttr(self.ATTR_NAME_DISPLAY_MESH):
            attr_display_mesh = self.grp_anm.attr(self.ATTR_NAME_DISPLAY_MESH)
            if attr_display_mesh.type() == 'short':
                for attr_dst in attr_display_mesh.outputs(plugs=True):
                    attr_display_mesh_output_attrs.add(attr_dst)
                    pymel.disconnectAttr(attr_display_mesh, attr_dst)

        if self.grp_anm.hasAttr(self.ATTR_NAME_DISPLAY_PROXY):
            attr_display_proxy = self.grp_anm.attr(self.ATTR_NAME_DISPLAY_PROXY)
            for attr_dst in attr_display_proxy.outputs(plugs=True):
                attr_display_proxy_output_attrs.add(attr_dst)
                pymel.disconnectAttr(attr_display_proxy, attr_dst)
            attr_display_proxy.delete()

        # Create DisplayMesh attribute
        attr_display_mesh = self._init_attr_display_mesh()

        # Create DisplayCtrl attribute
        attr_display_ctrl = self._init_attr_display_ctrl()

        # Connect DisplayMesh attribute
        for attr_dst in attr_display_mesh_output_attrs:
            if not libAttr.is_connected_to(attr_display_mesh, attr_dst, max_depth=3):
                self.debug("Connecting {} to {}".format(attr_display_mesh, attr_dst))
                attr_proxy_display_inn = libRigging.create_utility_node(
                    'condition',
                    firstTerm=attr_display_mesh,
                    secondTerm=0,
                    colorIfTrueR=True,
                    colorIfFalseR=False
                ).outColorR
                pymel.connectAttr(attr_proxy_display_inn, attr_dst, force=True)

        for attr_dst in attr_display_proxy_output_attrs:
            if not libAttr.is_connected_to(attr_display_mesh, attr_dst, max_depth=3):
                self.debug("Connecting {} to {}".format(attr_display_mesh, attr_dst))
                # attr_proxy_display_inn = libRigging.create_utility_node(
                #     'condition',
                #     firstTerm=attr_display_mesh,
                #     secondTerm=0,
                #     colorIfTrueR=True,
                #     colorIfFalseR=False
                # ).outColorR
                pymel.connectAttr(attr_display_mesh, attr_dst, force=True)
Пример #15
0
    def build(self, constraint=True, constraint_handle=True, setup_softik=True, **kwargs):
        """
        :param constraint: Bool to tell if we will constraint the chain bone on the ikchain
        :param constraint_handle: Bool to tell if we will contraint the handle on the ik ctrl
        :param setup_softik: Bool to tell if we setup the soft ik system
        :param kwargs: More kwargs passed to the superclass
        :return: Nothing
        """
        # Build the softik node after the setup for the quadruped
        super(LegIkQuad, self).build(constraint=False, constraint_handle=False, setup_softik=False, **kwargs)
        nomenclature_rig = self.get_nomenclature_rig()

        quad_swivel_pos = self.calc_swivel_pos(start_index=1, end_index=3)
        heel_idx = self.iCtrlIndex - 1

        # Hack: Re-parent ehe ik chain as a workaround for the spring ik solver bug.
        # Otherwise the current parent (which is constrained) will trigger and old sprint ik solver bug
        # that will result in double rotation.
        # src: http://forums.cgsociety.org/showthread.php?t=936724
        ik_chain_start = self._chain_ik[0]
        ik_chain_start.setParent(self.grp_rig)
        pymel.parentConstraint(self._ikChainGrp, ik_chain_start, maintainOffset=True, skipRotate=['x', 'y', 'z'])

        # Create a second ik chain for the quadruped setup
        self._chain_quad_ik = self.chain.duplicate()
        for i, oIk in enumerate(self._chain_quad_ik):
            oIk.rename(nomenclature_rig.resolve('QuadChain{0:02}'.format(i)))

            # Constraint the bones after the iCtrlIdx to the first ik chain to make the foot roll work correctly
            if i > self.iCtrlIndex:
                pymel.parentConstraint(self._chain_ik[i], self._chain_quad_ik[i])
        self._chain_quad_ik[0].setParent(self._chain_ik[0])

        # Hack: Since we are using direct connection on the first joint of the quad_ik chain,
        # there might be situation where Maya will give an initial rotation of (180, 180, 180) instead of (0, 0, 0).
        # To prevent this we'll manually make sure that the rotation is zeroed out.
        self._chain_quad_ik[0].r.set(0, 0, 0)

        obj_e_ik = self._chain_ik[self.iCtrlIndex]
        obj_e_quadik = self._chain_quad_ik[self.iCtrlIndex]

        # We need a second ik solver for the quad chain
        ik_solver_quad_name = nomenclature_rig.resolve('quadIkHandle')
        ik_effector_quad_name = nomenclature_rig.resolve('quadIkEffector')
        self._ik_handle_quad, _ik_effector = pymel.ikHandle(startJoint=self._chain_quad_ik[1],
                                                            endEffector=obj_e_quadik,
                                                            solver='ikRPsolver')
        self._ik_handle_quad.rename(ik_solver_quad_name)
        _ik_effector.rename(ik_effector_quad_name)
        self._ik_handle_quad.setParent(self._ik_handle)

        #
        # Create softIk node and connect user accessible attributes to it.
        #
        if setup_softik:
            self.setup_softik([self._ik_handle, self._ik_handle_quad], [self._chain_ik, self._chain_quad_ik])

        # Create another swivel handle node for the quad chain setup
        self.ctrl_swivel_quad = self.setup_swivel_ctrl(self.ctrl_swivel_quad, self._chain_quad_ik[heel_idx],
                                                       quad_swivel_pos, self._ik_handle_quad, name='swivelQuad',
                                                       mirror_setup=False, adjust_ik_handle_twist=False)

        # self.quad_swivel_distance = self.chain_length  # Used in ik/fk switch
        # Set by default the space to calf
        if self.ctrl_swivel_quad.space:
            enum = self.ctrl_swivel_quad.space.getEnums()
            calf_idx = enum.get('Calf', None)
            if calf_idx:
                self.ctrl_swivel_quad.space.set(calf_idx)

        # Expose 'pitch' Quadruped-specific attribute.
        attr_holder = self.ctrl_ik
        libAttr.addAttr_separator(attr_holder, 'Quadruped', niceName='Quadruped')
        attr_pitch = libAttr.addAttr(attr_holder, longName='pitch', k=True)
        pymel.connectAttr(attr_pitch, self._chain_quad_ik[0].rotateZ)

        pymel.orientConstraint(obj_e_ik, obj_e_quadik, maintainOffset=True)

        if constraint:
            for source, target in zip(self._chain_quad_ik, self.chain):
                # Note that maintainOffset should not be necessary, however in some rare case even after all the
                # adjustments we do, the rotation of the influence might be flipped for no particular reasons.
                # (see Task #70938).
                pymel.parentConstraint(source, target, maintainOffset=True)
Пример #16
0
    def build(self, attr_holder=None, constraint_handle=False, setup_softik=True, **kwargs):
        """
        Build the LegIk system
        :param attr_holder: The attribute holder object for all the footroll params
        :param kwargs: More kwargs pass to the superclass
        :return: Nothing
        """
        # Compute ctrl_ik orientation
        # Hack: Bypass pymel bug (see https://github.com/LumaPictures/pymel/issues/355)
        ctrl_ik_orientation = pymel.datatypes.TransformationMatrix(self._get_reference_plane()).rotate

        super(LegIk, self).build(ctrl_ik_orientation=ctrl_ik_orientation, constraint_handle=constraint_handle, setup_softik=setup_softik, **kwargs)

        nomenclature_rig = self.get_nomenclature_rig()

        jnts = self._chain_ik[self.iCtrlIndex:]
        num_jnts = len(jnts)
        if num_jnts == 4:
            jnt_foot, jnt_heel, jnt_toes, jnt_tip = jnts
        elif num_jnts == 3:
            jnt_foot, jnt_toes, jnt_tip = jnts
            jnt_heel = None
        else:
            raise Exception("Unexpected number of joints after the limb. Expected 3 or 4, got {0}".format(num_jnts))

        # Create FootRoll (chain?)
        pos_foot = pymel.datatypes.Point(jnt_foot.getTranslation(space='world'))
        pos_heel = pymel.datatypes.Point(jnt_heel.getTranslation(space='world')) if jnt_heel else None
        pos_toes = pymel.datatypes.Point(jnt_toes.getTranslation(space='world'))
        pos_tip = pymel.datatypes.Point(jnt_tip.getTranslation(space='world'))

        # Resolve pivot locations
        tm_ref = self._get_reference_plane()
        tm_ref_dir = pymel.datatypes.Matrix(  # Used to compute raycast directions
            tm_ref.a00, tm_ref.a01, tm_ref.a02, tm_ref.a03,
            tm_ref.a10, tm_ref.a11, tm_ref.a12, tm_ref.a13,
            tm_ref.a20, tm_ref.a21, tm_ref.a22, tm_ref.a23,
            0, 0, 0, 1
        )

        #
        # Resolve pivot positions
        #
        geometries = self.rig.get_meshes()

        # Resolve pivot inn
        if self.pivot_foot_inn_pos:
            pos_pivot_inn = pymel.datatypes.Point(self.pivot_foot_inn_pos) * tm_ref
        else:
            pos_pivot_inn = self._get_recommended_pivot_bank(geometries, tm_ref, tm_ref_dir, pos_toes, direction=-1)

        # Resolve pivot bank out
        if self.pivot_foot_out_pos:
            pos_pivot_out = pymel.datatypes.Point(self.pivot_foot_out_pos) * tm_ref
        else:
            pos_pivot_out = self._get_recommended_pivot_bank(geometries, tm_ref, tm_ref_dir, pos_toes, direction=1)

        # Resolve pivot Back
        if self.pivot_foot_back_pos:
            pos_pivot_back = pymel.datatypes.Point(self.pivot_foot_back_pos) * tm_ref
        else:
            pos_pivot_back = self._get_recommended_pivot_back(geometries, tm_ref, tm_ref_dir, pos_toes)

        # Set pivot Front
        if self.pivot_foot_front_pos:
            pos_pivot_front = pymel.datatypes.Point(self.pivot_foot_front_pos) * tm_ref
        else:
            pos_pivot_front = self._get_recommended_pivot_front(geometries, tm_ref, tm_ref_dir, pos_toes, pos_tip)

        # Set pivot Ankle
        if self.pivot_toes_ankle_pos:
            pos_pivot_ankle = pymel.datatypes.Point(self.pivot_toes_ankle_pos) * tm_ref
        else:
            pos_pivot_ankle = pos_toes

        # Set pivot Heel floor
        if self.pivot_toes_heel_pos:
            pos_pivot_heel = pymel.datatypes.Point(self.pivot_toes_heel_pos) * tm_ref
        else:
            if jnt_heel:
                pos_pivot_heel = pos_heel
            else:
                pos_pivot_heel = pymel.datatypes.Point(pos_foot)
                pos_pivot_heel.y = 0


        #
        # Build Setup
        #

        root_footRoll = pymel.createNode('transform', name=nomenclature_rig.resolve('footRoll'))

        # Align all pivots to the reference plane
        root_footRoll.setMatrix(tm_ref)

        # Create pivots hierarchy
        self.pivot_toes_heel = pymel.spaceLocator(name=nomenclature_rig.resolve('pivotToesHeel'))
        self.pivot_toes_ankle = pymel.spaceLocator(name=nomenclature_rig.resolve('pivotToesAnkle'))
        self.pivot_foot_ankle = pymel.spaceLocator(name=nomenclature_rig.resolve('pivotFootAnkle'))
        self.pivot_foot_front = pymel.spaceLocator(name=nomenclature_rig.resolve('pivotFootFront'))
        self.pivot_foot_back = pymel.spaceLocator(name=nomenclature_rig.resolve('pivotFootBack'))
        self.pivot_foot_inn = pymel.spaceLocator(name=nomenclature_rig.resolve('pivotFootBankInn'))
        self.pivot_foot_out = pymel.spaceLocator(name=nomenclature_rig.resolve('pivotFootBankOut'))
        self.pivot_foot_heel = pymel.spaceLocator(name=nomenclature_rig.resolve('pivotFootHeel'))
        self.pivot_foot_toes_fk = pymel.spaceLocator(name=nomenclature_rig.resolve('pivotToesFkRoll'))

        chain_footroll = [
            root_footRoll,
            self.pivot_foot_ankle,
            self.pivot_foot_inn,
            self.pivot_foot_out,
            self.pivot_foot_back,
            self.pivot_foot_heel,
            self.pivot_foot_front,
            self.pivot_toes_ankle,
            self.pivot_toes_heel
        ]
        libRigging.create_hyerarchy(chain_footroll)
        chain_footroll[0].setParent(self.grp_rig)
        self.pivot_foot_toes_fk.setParent(self.pivot_foot_heel)

        self.pivot_foot_ankle.setTranslation(pos_pivot_ankle, space='world')
        self.pivot_foot_inn.setTranslation(pos_pivot_inn, space='world')
        self.pivot_foot_out.setTranslation(pos_pivot_out, space='world')
        self.pivot_foot_back.setTranslation(pos_pivot_back, space='world')
        self.pivot_foot_heel.setTranslation(pos_pivot_heel, space='world')
        self.pivot_foot_front.setTranslation(pos_pivot_front, space='world')
        self.pivot_toes_ankle.setTranslation(pos_pivot_ankle, space='world')
        self.pivot_foot_toes_fk.setTranslation(pos_pivot_ankle, space='world')
        self.pivot_toes_heel.setTranslation(pos_pivot_heel, space='world')

        # Create attributes
        attr_holder = self.ctrl_ik
        libAttr.addAttr_separator(attr_holder, 'footRoll', niceName='Foot Roll')
        attr_inn_roll_auto = libAttr.addAttr(attr_holder, longName='rollAuto', k=True)
        attr_inn_roll_auto_threshold = libAttr.addAttr(attr_holder, longName='rollAutoThreshold', k=True, defaultValue=25)
        attr_inn_bank = libAttr.addAttr(attr_holder, longName='bank', k=True)
        attr_inn_ankle_rotz   = libAttr.addAttr(attr_holder, longName=self.ANKLE_ROTZ_LONGNAME, niceName=self.ANKLE_ROTZ_NICENAME, k=True, hasMinValue=True, hasMaxValue=True, minValue=-90, maxValue=90)
        attr_inn_back_rotx   = libAttr.addAttr(attr_holder, longName=self.BACK_ROTX_LONGNAME, niceName=self.BACK_ROTX_NICENAME, k=True, hasMinValue=True, hasMaxValue=True, minValue=-90, maxValue=0)
        attr_inn_ankle_rotx  = libAttr.addAttr(attr_holder, longName=self.ANKLE_ROTX_LONGNAME, niceName=self.ANKLE_ROTX_NICENAME, k=True, hasMinValue=True, hasMaxValue=True, minValue=0, maxValue=90)
        attr_inn_front_rotx  = libAttr.addAttr(attr_holder, longName=self.FRONT_ROTX_LONGNAME, niceName=self.FRONT_ROTX_NICENAME, k=True, hasMinValue=True, hasMaxValue=True, minValue=0, maxValue=90)
        attr_inn_back_roty  = libAttr.addAttr(attr_holder, longName=self.BACK_ROTY_LONGNAME, niceName=self.BACK_ROTY_NICENAME, k=True, hasMinValue=True, hasMaxValue=True, minValue=-90, maxValue=90)
        attr_inn_heel_roty  = libAttr.addAttr(attr_holder, longName=self.HEEL_ROTY_LONGNAME, niceName=self.HEEL_ROTY_NICENAME, k=True, hasMinValue=True, hasMaxValue=True, minValue=-90, maxValue=90)
        attr_inn_toes_roty = libAttr.addAttr(attr_holder, longName=self.TOES_ROTY_LONGNAME, niceName=self.TOES_ROTY_NICENAME, k=True, hasMinValue=True, hasMaxValue=True, minValue=-90, maxValue=90)
        attr_inn_front_roty = libAttr.addAttr(attr_holder, longName=self.FRONT_ROTY_LONGNAME, niceName=self.FRONT_ROTY_NICENAME, k=True, hasMinValue=True, hasMaxValue=True, minValue=-90, maxValue=90)
        attr_inn_toes_fk_rotx = libAttr.addAttr(attr_holder, longName=self.TOESFK_ROTX_LONGNAME, niceName=self.TOESFK_ROTX_NICENAME, k=True, hasMinValue=True, hasMaxValue=True, minValue=-90, maxValue=90)

        attr_roll_auto_pos = libRigging.create_utility_node('condition', operation=2, firstTerm=attr_inn_roll_auto,
                                                            secondTerm=0,
                                                            colorIfTrueR=attr_inn_roll_auto,
                                                            colorIfFalseR=0.0).outColorR  # Greater

        attr_roll_auto_f = libRigging.create_utility_node('condition', operation=2,
                                                          firstTerm=attr_inn_roll_auto,
                                                          secondTerm=attr_inn_roll_auto_threshold,
                                                          colorIfFalseR=0,
                                                          colorIfTrueR=(
                                                              libRigging.create_utility_node('plusMinusAverage',
                                                                                             operation=2,
                                                                                             input1D=[
                                                                                                 attr_inn_roll_auto,
                                                                                                 attr_inn_roll_auto_threshold]).output1D)
                                                          ).outColorR  # Substract
        attr_roll_auto_b = libRigging.create_utility_node('condition', operation=2, firstTerm=attr_inn_roll_auto,
                                                          secondTerm=0.0,
                                                          colorIfTrueR=0, colorIfFalseR=attr_inn_roll_auto
                                                          ).outColorR  # Greater

        attr_roll_m = libRigging.create_utility_node('addDoubleLinear', input1=attr_roll_auto_pos,
                                                     input2=attr_inn_ankle_rotx).output
        attr_roll_f = libRigging.create_utility_node('addDoubleLinear', input1=attr_roll_auto_f,
                                                     input2=attr_inn_front_rotx).output
        attr_roll_b = libRigging.create_utility_node('addDoubleLinear', input1=attr_roll_auto_b,
                                                     input2=attr_inn_back_rotx).output

        attr_bank_inn = libRigging.create_utility_node('condition', operation=2,
                                                       firstTerm=attr_inn_bank, secondTerm=0,
                                                       colorIfTrueR=attr_inn_bank,
                                                       colorIfFalseR=0.0
                                                       ).outColorR  # Greater

        attr_bank_out = libRigging.create_utility_node('condition', operation=4,
                                                       firstTerm=attr_inn_bank, secondTerm=0,
                                                       colorIfTrueR=attr_inn_bank,
                                                       colorIfFalseR=0.0).outColorR  # Less

        pymel.connectAttr(attr_roll_m, self.pivot_toes_ankle.rotateX)
        pymel.connectAttr(attr_roll_f, self.pivot_foot_front.rotateX)
        pymel.connectAttr(attr_roll_b, self.pivot_foot_back.rotateX)
        pymel.connectAttr(attr_bank_inn, self.pivot_foot_inn.rotateZ)
        pymel.connectAttr(attr_bank_out, self.pivot_foot_out.rotateZ)
        pymel.connectAttr(attr_inn_heel_roty, self.pivot_foot_heel.rotateY)
        pymel.connectAttr(attr_inn_front_roty, self.pivot_foot_front.rotateY)
        pymel.connectAttr(attr_inn_back_roty, self.pivot_foot_back.rotateY)
        pymel.connectAttr(attr_inn_ankle_rotz, self.pivot_toes_heel.rotateZ)
        pymel.connectAttr(attr_inn_toes_roty, self.pivot_foot_ankle.rotateY)
        pymel.connectAttr(attr_inn_toes_fk_rotx, self.pivot_foot_toes_fk.rotateX)

        # Create ikHandles and parent them
        # Note that we are directly parenting them so the 'Preserve Child Transform' of the translate tool still work.
        if jnt_heel:
            ikHandle_foot, ikEffector_foot = pymel.ikHandle(startJoint=jnt_foot, endEffector=jnt_heel, solver='ikSCsolver')
        else:
            ikHandle_foot, ikEffector_foot = pymel.ikHandle(startJoint=jnt_foot, endEffector=jnt_toes, solver='ikSCsolver')
        ikHandle_foot.rename(nomenclature_rig.resolve('ikHandle', 'foot'))
        ikHandle_foot.setParent(self.grp_rig)
        ikHandle_foot.setParent(self.pivot_toes_heel)
        if jnt_heel:
            ikHandle_heel, ikEffector_foot = pymel.ikHandle(startJoint=jnt_heel, endEffector=jnt_toes, solver='ikSCsolver')
            ikHandle_heel.rename(nomenclature_rig.resolve('ikHandle', 'heel'))
            ikHandle_heel.setParent(self.grp_rig)
            ikHandle_heel.setParent(self.pivot_foot_front)
        ikHandle_toes, ikEffector_toes = pymel.ikHandle(startJoint=jnt_toes, endEffector=jnt_tip, solver='ikSCsolver')
        ikHandle_toes.rename(nomenclature_rig.resolve('ikHandle', 'toes'))
        ikHandle_toes.setParent(self.grp_rig)
        ikHandle_toes.setParent(self.pivot_foot_toes_fk)

        # Hack: Re-constraint foot ikhandle
        # todo: cleaner!
        pymel.parentConstraint(self.ctrl_ik, root_footRoll, maintainOffset=True)

        # Connect the footroll to the main ikHandle
        # Note that we also need to hijack the softik network.
        fn_can_delete = lambda x: isinstance(x, pymel.nodetypes.Constraint) and \
                                  not isinstance(x, pymel.nodetypes.PoleVectorConstraint)
        pymel.delete(filter(fn_can_delete, self._ik_handle_target.getChildren()))

        if jnt_heel:
            pymel.parentConstraint(self.pivot_toes_heel, self._ik_handle_target, maintainOffset=True)
        else:
            pymel.parentConstraint(self.pivot_toes_ankle, self._ik_handle_target, maintainOffset=True)


        '''
        # Constraint swivel to ctrl_ik
        pymel.parentConstraint(self.ctrl_ik, self.ctrl_swivel,
                               maintainOffset=True)  # TODO: Implement SpaceSwitch
        '''

        # Handle globalScale
        pymel.connectAttr(self.grp_rig.globalScale, root_footRoll.scaleX)
        pymel.connectAttr(self.grp_rig.globalScale, root_footRoll.scaleY)
        pymel.connectAttr(self.grp_rig.globalScale, root_footRoll.scaleZ)
Пример #17
0
    def build_stack(self, stack, **kwargs):
        nomenclature_rig = self.get_nomenclature_rig()
        jnt_head = self.rig.get_head_jnt()
        jnt_jaw = self.rig.get_jaw_jnt()

        #
        # Create additional attributes to control the jaw layer
        #

        libAttr.addAttr_separator(self.grp_rig, 'jawLayer')
        self._attr_inn_jaw_ratio_default = libAttr.addAttr(
            self.grp_rig,
            'jawRatioDefault',
            defaultValue=0.5,
            hasMinValue=True,
            hasMaxValue=True,
            minValue=0,
            maxValue=1,
            k=True
        )
        self._attr_bypass_splitter = libAttr.addAttr(
            self.grp_rig,
            'jawSplitterBypass',
            defaultValue=0.0,
            hasMinValue=True,
            hasMaxValue=True,
            minValue=0,
            maxValue=1,
            k=True
        )

        #
        # Create reference objects used for calculations.
        #

        # Create a reference node that follow the head
        self._target_head = pymel.createNode(
            'transform',
            name=nomenclature_rig.resolve('innHead'),
            parent=self.grp_rig
        )
        self._target_head.setTranslation(jnt_head.getTranslation(space='world'))
        pymel.parentConstraint(jnt_head, self._target_head, maintainOffset=True)
        pymel.scaleConstraint(jnt_head, self._target_head, maintainOffset=True)

        # Create a reference node that follow the jaw initial position
        jaw_pos = jnt_jaw.getTranslation(space='world')
        self._target_jaw_bindpose = pymel.createNode(
            'transform',
            name=nomenclature_rig.resolve('innJawBindPose'),
            parent=self.grp_rig
        )
        self._target_jaw_bindpose.setTranslation(jaw_pos)

        # Create a reference node that follow the jaw
        self._target_jaw = pymel.createNode(
            'transform',
            name=nomenclature_rig.resolve('innJaw'),
            parent=self._target_jaw_bindpose
        )
        self._target_jaw.t.set(0,0,0)
        pymel.parentConstraint(jnt_jaw, self._target_jaw, maintainOffset=True)
        pymel.scaleConstraint(jnt_jaw, self._target_jaw, maintainOffset=True)

        # Create a node that contain the out jaw influence.
        # Note that the out jaw influence can be modified by the splitter node.
        grp_parent_pos = self._grp_parent.getTranslation(space='world')  # grp_offset is always in world coordinates
        self._jaw_ref = pymel.createNode(
            'transform',
            name=nomenclature_rig.resolve('outJawInfluence'),
            parent=self.grp_rig
        )
        self._jaw_ref.t.set(grp_parent_pos)
        pymel.parentConstraint(self._target_jaw, self._jaw_ref, maintainOffset=True)

        # Extract jaw influence
        attr_delta_tm = libRigging.create_utility_node('multMatrix', matrixIn=[
            self._jaw_ref.worldMatrix,
            self._grp_parent.worldInverseMatrix
        ]).matrixSum

        util_extract_jaw = libRigging.create_utility_node(
            'decomposeMatrix',
            name=nomenclature_rig.resolve('getJawRotation'),
            inputMatrix=attr_delta_tm
        )

        super(FaceLipsAvar, self).build_stack(stack, **kwargs)

        #
        # Create jaw influence layer
        # Create a reference object to extract the jaw displacement.
        #

        # Add the jaw influence as a new stack layer.
        layer_jaw_r = stack.prepend_layer(name='jawRotate')
        layer_jaw_t = stack.prepend_layer(name='jawTranslate')

        pymel.connectAttr(util_extract_jaw.outputTranslate, layer_jaw_t.t)
        pymel.connectAttr(util_extract_jaw.outputRotate, layer_jaw_r.r)