Example #1
0
    def __create_pivots(self, ik_control, pivots):
        """
        """
        hierarchy = {
            "ball_pivot": {
                "heel_pivot_ctrl": {
                    "out_pivot": {
                        "in_pivot": {
                            "toe_pivot_ctrl": {
                                "toe_ctrl": None,
                                "heel_ctrl": None
                            }
                        }
                    }
                }
            }
        }
        hierarchy = common.RigHierarchy(
            hierarchy,
            prefix="{}_".format(self.name),
            suffix="",
            lock_and_hide=["s", "v"],
        )
        hierarchy.create()
        cmds.parent(hierarchy.ball_pivot, ik_control)
        for driver, driven in [
            [self.ball_joint, hierarchy.ball_pivot],
            [self.two_bone_ik.end_joint, hierarchy.heel_pivot_ctrl],
            [self.ball_joint, hierarchy.out_pivot],
            [self.ball_joint, hierarchy.in_pivot],
            [self.toe_joint, hierarchy.toe_pivot_ctrl],
            [self.ball_joint, hierarchy.toe_ctrl],
            [self.ball_joint, hierarchy.heel_ctrl],
        ]:
            if driver and driven:
                common.snap_to_position(driven, driver)
        for node, position in pivots.items():
            node = getattr(hierarchy, node, None)
            if not node:
                continue
            children = cmds.listRelatives(node, children=True, path=True)
            if children:
                cmds.parent(children, world=True)
            cmds.xform(node, ws=True, t=position)
            if children:
                cmds.parent(children, node)

        hierarchy.parent_to_heel_ctrl(self.ik_handle_ball)
        if self.ik_handle_toe:
            hierarchy.parent_to_toe_ctrl(self.ik_handle_toe)
        for node in hierarchy:
            common.lock_and_hide(node, "t")

        cmds.setAttr("{}.rotateOrder".format(hierarchy.heel_ctrl), 2)  # zxy

        self.hierarchy = hierarchy
Example #2
0
    def __create_ik(self, ik_control, pole_vector, soft_ik_parent,
                    global_scale_attr, scale_stretch):
        self.ik_handle = cmds.ikHandle(
            name="{}_ikh".format(self.name),
            solver="ikRPsolver",
            startJoint=self.start_joint,
            endEffector=self.end_joint,
        )[0]

        cmds.setAttr("{}.v".format(self.ik_handle), 0)

        # Drive visibility
        ik_vis = dge("1.0 - ikFk", ikFk="{}.ikFk".format(self.config_control))
        for node in [ik_control, pole_vector]:
            vis = "{}.v".format(node)
            locked = cmds.getAttr(vis, lock=True)
            cmds.setAttr(vis, lock=False)
            cmds.connectAttr(ik_vis, "{}.v".format(node))
            if locked:
                cmds.setAttr(vis, lock=True)

        dge(
            "ikBlend = 1.0 - ikFk",
            ikBlend="{}.ikBlend".format(self.ik_handle),
            ikFk="{}.ikFk".format(self.config_control),
        )

        self.soft_ik = cmds.createNode("transform",
                                       name="{}_soft_ik".format(self.name))
        common.snap_to_position(self.soft_ik, self.end_joint)
        cmds.parent(self.ik_handle, self.soft_ik)
        cmds.parent(self.soft_ik, soft_ik_parent)

        self.__create_stretch(ik_control, global_scale_attr, scale_stretch)
        cmds.parent(self.end_loc, soft_ik_parent)

        cmds.poleVectorConstraint(pole_vector, self.ik_handle)
Example #3
0
    def __create_stretch(self,
                         ik_control,
                         global_scale_attr=None,
                         scale_stretch=True):
        """Create the stretchy soft ik setup.

        :param ik_control: Name of the node to use as the ik control.
        :param global_scale_attr: Optional attribute containing global scale value.
        :param scale_stretch: True to stretch with scale, False to use translate.
        """
        for attr in ["stretch", "softIk"]:
            cmds.addAttr(
                ik_control,
                ln=attr,
                minValue=0.0,
                maxValue=1.0,
                defaultValue=0.0,
                keyable=True,
            )

        # Locator for start distance measurement
        self.start_loc = cmds.spaceLocator(
            name="{}_stretch_start".format(self.name))[0]
        parent = cmds.listRelatives(self.start_joint, parent=True, path=True)
        if parent:
            cmds.connectAttr(
                "{}.worldMatrix[0]".format(parent[0]),
                "{}.offsetParentMatrix".format(self.start_loc),
            )
        common.snap_to_position(self.start_loc, self.start_joint)

        # Locator for end distance measurement
        self.end_loc = cmds.spaceLocator(
            name="{}_stretch_end".format(self.name))[0]
        cmds.setAttr("{}.v".format(self.end_loc), 0)
        common.snap_to_position(self.end_loc, self.end_joint)

        rest_length = shortcuts.distance(self.start_joint, self.mid_joint)
        rest_length += shortcuts.distance(self.mid_joint, self.end_joint)

        length_ratio = dge(
            "distance(start, end) / (restLength * globalScale)",
            container="{}_percent_from_rest".format(self.name),
            start=self.start_loc,
            end=self.end_loc,
            restLength=rest_length,
            globalScale=global_scale_attr or 1.0,
        )

        # Prevent divide by 0
        softik = dge("max(x, 0.001)", x="{}.softIk".format(ik_control))

        # We need to adjust offset the ik handle and scale the joints to create the soft
        # effect
        # See this graph to see the the softIk and scale values plotted
        # https://www.desmos.com/calculator/csi40rsztl
        # x = length_ratio
        # f(x) = softik_scale
        # c(x) = Scale x of the joints
        # s = softIk attribute
        # t = stretch attribute
        softik_scale = dge(
            "x > (1.0 - softIk)"
            "? (1.0 - softIk) + softIk * (1.0 - exp(-(x - (1.0 - softIk)) / softIk)) "
            ": x",
            container="{}_softik".format(self.name),
            x=length_ratio,
            softIk=softik,
        )

        compose_matrix = cmds.createNode("composeMatrix")

        # Set the effector position
        dge(
            "tx = restLength * lerp(softIk, lengthRatio, stretch)",
            container="{}_effector_position".format(self.name),
            tx="{}.inputTranslate.inputTranslateX".format(compose_matrix),
            restLength=rest_length,
            lengthRatio=length_ratio,
            softIk=softik_scale,
            stretch="{}.stretch".format(ik_control),
        )

        # Drive the joint scale for stretch
        scale = dge(
            "lerp(1, lengthRatio / softIk, stretch)",
            container="{}_stretch_scale".format(self.name),
            lengthRatio=length_ratio,
            softIk=softik_scale,
            stretch="{}.stretch".format(ik_control),
        )
        if scale_stretch:
            for node in [self.start_joint, self.mid_joint]:
                cmds.connectAttr(scale, "{}.sx".format(node))
                inverse_scale = dge("1/sx", sx="{}.sx".format(node))
                cmds.connectAttr(inverse_scale, "{}.sy".format(node))
                cmds.connectAttr(inverse_scale, "{}.sz".format(node))
        else:
            for node in [self.mid_joint, self.end_joint]:
                tx = cmds.getAttr("{}.tx".format(node))
                dge("x = {} * s".format(tx), x="{}.tx".format(node), s=scale)

        # Drive the soft ik transform
        aim = cmds.createNode("aimMatrix")
        cmds.connectAttr("{}.worldMatrix[0]".format(self.start_loc),
                         "{}.inputMatrix".format(aim))
        cmds.connectAttr(
            "{}.worldMatrix[0]".format(self.end_loc),
            "{}.primary.primaryTargetMatrix".format(aim),
        )
        mult = cmds.createNode("multMatrix")
        cmds.connectAttr("{}.outputMatrix".format(compose_matrix),
                         "{}.matrixIn[0]".format(mult))
        cmds.connectAttr("{}.outputMatrix".format(aim),
                         "{}.matrixIn[1]".format(mult))
        parent = cmds.listRelatives(self.soft_ik, parent=True, path=True)[0]
        if parent:
            cmds.connectAttr("{}.worldInverseMatrix[0]".format(parent),
                             "{}.matrixIn[2]".format(mult))
        pick = cmds.createNode("pickMatrix")
        cmds.connectAttr("{}.matrixSum".format(mult),
                         "{}.inputMatrix".format(pick))
        for attr in ["Scale", "Shear", "Rotate"]:
            cmds.setAttr("{}.use{}".format(pick, attr), 0)
        cmds.connectAttr("{}.outputMatrix".format(pick),
                         "{}.offsetParentMatrix".format(self.soft_ik))
        cmds.setAttr("{}.t".format(self.soft_ik), 0, 0, 0)
Example #4
0
File: leg.py Project: mmallmann/cmt
    def __create_pivots(self, ik_control, pivots):
        """
        """
        hierarchy = {
            "soft_ik": {
                "ball_pivot": {
                    "heel_pivot": {
                        "out_pivot": {
                            "in_pivot": {
                                "toe_pivot": {
                                    "toe_lift": None,
                                    "heel_raise": {
                                        "pole_vector_rotate": {
                                            "pole_vector": None
                                        }
                                    },
                                }
                            }
                        }
                    }
                }
            }
        }
        hierarchy = common.RigHierarchy(
            hierarchy,
            prefix="{}_".format(self.name),
            suffix="",
            lock_and_hide=["s", "v"],
        )
        hierarchy.create()
        cmds.parent(hierarchy.soft_ik, ik_control)
        for driver, driven in [
            [self.ankle_joint, hierarchy.soft_ik],
            [self.ball_joint, hierarchy.ball_pivot],
            [self.ankle_joint, hierarchy.heel_pivot],
            [self.ball_joint, hierarchy.out_pivot],
            [self.ball_joint, hierarchy.in_pivot],
            [self.toe_joint, hierarchy.toe_pivot],
            [self.ball_joint, hierarchy.toe_lift],
            [self.ball_joint, hierarchy.heel_raise],
            [self.ankle_joint, hierarchy.pole_vector_rotate],
        ]:
            common.snap_to_position(driven, driver)
        for node, position in pivots.items():
            node = getattr(hierarchy, node)
            if not node:
                continue
            children = cmds.listRelatives(node, children=True, path=True)
            if children:
                cmds.parent(children, world=True)
            cmds.xform(node, ws=True, t=position)
            if children:
                cmds.parent(children, node)

        hierarchy.parent_to_toe_lift(self.ik_handle_ball)
        hierarchy.parent_to_toe_lift(self.ik_handle_toe)
        hierarchy.parent_to_heel_raise(self.ik_handle_leg)

        cmds.poleVectorConstraint(hierarchy.pole_vector, self.ik_handle_leg)
        cmds.xform(hierarchy.pole_vector, ws=True, r=True, t=(50, 0, 0))
        cmds.setAttr("{}.twist".format(self.ik_handle_leg), 90)

        self.hierarchy = hierarchy
Example #5
0
File: leg.py Project: mmallmann/cmt
    def __create_stretch(self, ik_control, global_scale_attr=None):
        cmds.addAttr(
            ik_control,
            ln="stretch",
            minValue=0.0,
            maxValue=1.0,
            defaultValue=1.0,
            keyable=True,
        )
        # Locator for start distance measurement
        self.start_loc = cmds.spaceLocator(
            name="{}_stretch_start".format(self.name))[0]
        common.snap_to_position(self.start_loc, self.up_leg_joint)
        parent = cmds.listRelatives(self.up_leg_joint, parent=True, path=True)
        if parent:
            cmds.parentConstraint(parent[0], self.start_loc, mo=True)
            cmds.scaleConstraint(parent[0], self.start_loc)
        start_loc = cmds.listRelatives(self.start_loc,
                                       children=True,
                                       shapes=True)[0]

        # Locator for end distance measurement
        self.end_loc = cmds.spaceLocator(
            name="{}_stretch_end".format(self.name))[0]
        cmds.setAttr("{}.v".format(self.end_loc), 0)
        common.snap_to_position(self.end_loc, self.ankle_joint)
        cmds.parent(self.end_loc, ik_control)
        end_loc = cmds.listRelatives(self.end_loc, children=True,
                                     shapes=True)[0]

        distance_between = cmds.createNode("distanceBetween",
                                           name="{}_distance".format(
                                               self.name))
        cmds.connectAttr("{}.worldPosition".format(start_loc),
                         "{}.point1".format(distance_between))
        cmds.connectAttr("{}.worldPosition".format(end_loc),
                         "{}.point2".format(distance_between))
        mdn = cmds.createNode("multiplyDivide",
                              name="{}_stretch_scale".format(self.name))
        rest_length = shortcuts.distance(self.up_leg_joint, self.knee_joint)
        rest_length += shortcuts.distance(self.knee_joint, self.ankle_joint)
        cmds.setAttr("{}.operation".format(mdn), 2)  # divide
        cmds.connectAttr("{}.distance".format(distance_between),
                         "{}.input1X".format(mdn))

        if global_scale_attr:
            global_scale = cmds.createNode("multDoubleLinear",
                                           name="{}_global_scale".format(
                                               self.name))
            cmds.setAttr("{}.input1".format(global_scale), rest_length)
            cmds.connectAttr(global_scale_attr,
                             "{}.input2".format(global_scale))
            cmds.connectAttr("{}.output".format(global_scale),
                             "{}.input2X".format(mdn))
        else:
            cmds.setAttr("{}.input2X".format(mdn), rest_length)
        self.percent_rest_distance = "{}.outputX".format(mdn)

        softik_percentage = self.__create_soft_ik(ik_control)

        # Create the locators used to calculate the actual position we want the ik to
        # be placed
        loc = cmds.spaceLocator(name="{}_softik_aim".format(self.name))[0]
        offset_loc = cmds.spaceLocator(
            name="{}_softik_goal".format(self.name))[0]
        cmds.parent(offset_loc, loc)
        cmds.parent(loc, self.start_loc)
        common.snap_to_position(loc, self.start_loc)
        cmds.aimConstraint(self.end_loc, loc, worldUpType="none")

        # Calculate length for the target position to allow stretch with soft ik
        # rest_length = rest_length * min(1, percent_rest) * stretch)

        # min(1, percent_rest)
        clamp = cmds.createNode("clamp",
                                name="{}_stretch_clamp".format(self.name))
        cmds.setAttr("{}.minR".format(clamp), 1)
        cmds.setAttr("{}.maxR".format(clamp), 100)
        cmds.connectAttr(self.percent_rest_distance, "{}.inputR".format(clamp))
        stretch_percent = "{}.outputR".format(clamp)

        # min(1, percent_rest) * stretch
        enable_stretch = cmds.createNode("blendTwoAttr",
                                         name="{}_stretch_enable".format(
                                             self.name))
        cmds.setAttr("{}.input[0]".format(enable_stretch), 1)
        cmds.connectAttr(stretch_percent, "{}.input[1]".format(enable_stretch))
        cmds.connectAttr(
            "{}.stretch".format(ik_control),
            "{}.attributesBlender".format(enable_stretch),
        )
        stretch_factor = "{}.output".format(enable_stretch)

        # rest_length * min(1, percent_rest) * stretch
        mdl = cmds.createNode("multDoubleLinear",
                              name="{}_stretch_target_length".format(
                                  self.name))
        cmds.setAttr("{}.input1".format(mdl), rest_length)
        cmds.connectAttr(stretch_factor, "{}.input2".format(mdl))

        target_rest_length = "{}.output".format(mdl)

        # Now the final position will be the percentage of the rest length calculated
        # from soft ik
        mdl = cmds.createNode("multDoubleLinear")
        cmds.connectAttr(softik_percentage, "{}.input1".format(mdl))
        cmds.connectAttr(target_rest_length, "{}.input2".format(mdl))
        cmds.connectAttr("{}.output".format(mdl), "{}.tx".format(offset_loc))
        cmds.pointConstraint(offset_loc, self.hierarchy.soft_ik)

        # Inverse scale for volume preservation
        inverse_scale = cmds.createNode("multiplyDivide",
                                        name="{}_inverse_scale".format(
                                            self.name))
        cmds.setAttr("{}.operation".format(inverse_scale), 2)  # divide
        cmds.setAttr("{}.input1X".format(inverse_scale), 1)
        cmds.connectAttr(stretch_factor, "{}.input2X".format(inverse_scale))
        for node in [self.up_leg_joint, self.knee_joint]:
            cmds.connectAttr(stretch_factor, "{}.sx".format(node))
            cmds.connectAttr("{}.outputX".format(inverse_scale),
                             "{}.sy".format(node))
            cmds.connectAttr("{}.outputX".format(inverse_scale),
                             "{}.sz".format(node))