示例#1
0
    def _create_joint_offset(self):
        euler_to_quat = maya.cmds.createNode(
            'eulerToQuat', name_utils.find_unique_name(self.description))
        quat_invert = maya.cmds.createNode(
            'quatInvert', name_utils.find_unique_name(self.description))
        quat_prod = maya.cmds.createNode(
            'quatProd', name_utils.find_unique_name(self.description))
        self._joint_orient_quat_to_euler = maya.cmds.createNode(
            'quatToEuler', name_utils.find_unique_name(self.description))

        maya.cmds.connectAttr('{}.jointOrient'.format(self._target),
                              '{}.inputRotate'.format(euler_to_quat))
        maya.cmds.connectAttr('{}.outputQuat'.format(euler_to_quat),
                              '{}.inputQuat'.format(quat_invert))
        maya.cmds.connectAttr(
            '{}.outputQuat'.format(self._node_decompose_matrix),
            '{}.input1Quat'.format(quat_prod))
        maya.cmds.connectAttr('{}.outputQuat'.format(quat_invert),
                              '{}.input2Quat'.format(quat_prod))
        maya.cmds.connectAttr(
            '{}.outputQuat'.format(quat_prod),
            '{}.inputQuat'.format(self._joint_orient_quat_to_euler))
        maya.cmds.connectAttr(
            '{}.outputRotate'.format(self._joint_orient_quat_to_euler),
            '{}.rotate'.format(self._target))
示例#2
0
def create_cluster(points,
                   name,
                   relative=False,
                   front_of_chain=True,
                   exclusive=False):
    """
    Creates a cluster on the given points
    :param points: list<str>, names of points to cluster
    :param name: str, name of the cluster
    :param relative: bool, sets whether or not cluster is created in relative mode. In this mode, only the
        transformations directly above the cluster are used by the cluster.
    :param front_of_chain: bool
    :param exclusive: bool, Whether or not cluster deformation set is put in a deform partition. If True, a vertex/CV
        only will be able to be deformed by one cluster.
    :return: list(str, str), [cluster, handle]
    """

    # NOTE: Bug detected in Maya 2019. If we pass exclusive argument, no matter if we pass True of False, exclusivity
    # will be enabled
    if exclusive:
        cluster, handle = maya.cmds.cluster(points,
                                            n=name_lib.find_unique_name(name),
                                            relative=relative,
                                            frontOfChain=front_of_chain,
                                            exclusive=True)
    else:
        cluster, handle = maya.cmds.cluster(points,
                                            n=name_lib.find_unique_name(name),
                                            relative=relative,
                                            frontOfChain=front_of_chain)
    return cluster, handle
示例#3
0
def create_hair_follicle(name=None, hair_system=None, uv=None):
    """
    Creates a new hair follicle
    :param name: str, name of the follicle
    :param hair_system: str, name of the hair system we want to connect follicle into
    :param uv: list(float, flaot), follicle uvs
    :return: list(str, str), [follicle name, follicle shape name]
    """

    name = 'follicle_{}'.format(name) if name else 'follicle'
    uv = python.force_list(uv)
    follicle_shape = maya.cmds.createNode('follicle')
    follicle = maya.cmds.listRelatives(follicle_shape, p=True)
    follicle = maya.cmds.rename(follicle, name_utils.find_unique_name(name))
    follicle_shape = maya.cmds.listRelatives(follicle, shapes=True)[0]
    maya.cmds.setAttr('{}.startDirection'.format(follicle_shape), 1)
    maya.cmds.setAttr('{}.restPose'.format(follicle_shape), 1)
    maya.cmds.setAttr('{}.degree'.format(follicle_shape), 3)
    if uv:
        maya.cmds.setAttr('{}.parameterU'.format(follicle), uv[0])
        maya.cmds.setAttr('{}.parameterV'.format(follicle), uv[1])
    if hair_system:
        connect_follicle_to_hair_system(follicle, hair_system)
    maya.cmds.connectAttr('{}.outTranslate'.format(follicle_shape),
                          '{}.translate'.format(follicle))
    maya.cmds.connectAttr('{}.outRotate'.format(follicle_shape),
                          '{}.rotate'.format(follicle))
示例#4
0
def curve_to_nurbs_surface(curve, description, spans=-1, offset_axis='X', offset_amount=1):
    """
    Creates a new NURBS surface given a curve
    :param curve: str
    :param description: str
    :param spans: int
    :param offset_axis: str
    :param offset_amount: float
    :return: str, newly created NURBS surface
    """

    curve1 = maya.cmds.duplicate(curve)[0]
    curve2 = maya.cmds.duplicate(curve)[0]
    offset_axis = offset_axis.upper()
    pos_move = vec3.get_axis_vector(offset_axis, offset_amount)
    neg_move = vec3.get_axis_vector(offset_axis, offset_amount * -1)
    maya.cmds.move(pos_move[0], pos_move[1], pos_move[2], curve1)
    maya.cmds.move(neg_move[0], neg_move[1], neg_move[2], curve2)
    curves = [curve1, curve2]

    if not spans == -1:
        for curve in curves:
            maya.cmds.rebuildCurve(
                curve, ch=False, rpo=True, rt=0, end=1, kr=False,
                kcp=False, kep=True, kt=False, spans=spans, degree=3, tol=0.01)

    loft = maya.cmds.loft(
        curve1, curve2, n=name_utils.find_unique_name('nurbsSurface_{}'.forat(description)), ss=1, degree=1, ch=False)
    spans = maya.cmds.getAttr('{}.spans'.format(curve1))
    maya.cmds.rebuildSurface(
        loft, ch=False, rpo=1, rt=0, end=1, kr=0, kcp=0, kc=0, su=1, du=1, sv=spans, dv=3, tol=0.01, fr=0, dir=2)
    maya.cmds.delete(curve1, curve2)

    return loft[0]
示例#5
0
def transforms_to_curve(transforms, spans=None, name='from_transforms'):
    """
    Creates a curve from a list of transforms. Each transform will define a curve CV
    Useful when creating a curve from a joint chain (spines/tails)
    :param transforms: list<str>, list of tranfsorms to generate the curve from. Positions will be used to place CVs
    :param spans: int, number of spans the final curve should have
    :param name: str, name for the curve
    :return: str name of the new curve
    """

    if not transforms:
        logger.warning('Impossible to create curve from transforms because no transforms given!')
        return None

    transform_positions = list()
    for xform in transforms:
        xform_pos = maya.cmds.xform(xform, q=True, ws=True, rp=True)
        transform_positions.append(xform_pos)

    curve = maya.cmds.curve(p=transform_positions, degree=1)
    if spans:
        maya.cmds.rebuildCurve(
            curve, ch=False, rpo=True, rt=0, end=1, kr=False, kcp=False, kep=True,
            kt=False, spans=spans, degree=3, tol=0.01)
    curve = maya.cmds.rename(curve, name_utils.find_unique_name(name))
    maya.cmds.setAttr('{}.inheritsTransform'.format(curve), False)

    return curve
示例#6
0
def create_multi_follow_direct(source_list,
                               target_transform,
                               node,
                               constraint_type='parentConstraint',
                               attribute_name='follow',
                               value=None):
    """
    Creates a group above the target that is constrained to multiple transforms. A switch attribute switches their
    state on/off. Constraints will be "directly" added on the target transform
    :param source_list: list(str), list of transforms that the target should be constrained by
    :param target_transform: str, name of a transform node that should follow the transforms in source_list
    :param node: str, name of the node to add the switch attribute to
    :param constraint_type: str, Maya constraint type ('parentConstraint', 'pointConstraint' or 'orientConstraint')
    :param attribute_name: str, name of the switch attribute to add to the the node
    :param value: float, value to give the switch attribute on the node
    :return: str, name of the new group
    """

    locators = list()

    if attribute_name == 'follow':
        var = attr_utils.EnumAttribute('FOLLOW')
        var.create(node)

    for source in source_list:
        locator = maya.cmds.spaceLocator(n=name_utils.find_unique_name(
            'follower_1_{}'.format(source), False))[0]
        maya.cmds.hide(locator)
        match = xform_utils.MatchTransform(target_transform, locator)
        match.translation_rotation()
        maya.cmds.parent(locator, source)
        locators.append(locator)

    if constraint_type == 'parentConstraint':
        constraint = maya.cmds.parentConstraint(locators,
                                                target_transform,
                                                mo=True)[0]
        maya.cmds.setAttr('{}.interpType'.format(constraint), 2)
    elif constraint_type == 'pointConstraint':
        constraint = maya.cmds.pointConstraint(locators,
                                               target_transform,
                                               mo=True)[0]
    elif constraint_type == 'orientConstraint':
        constraint = maya.cmds.orientConstraint(locators,
                                                target_transform,
                                                mo=True)[0]
        maya.cmds.setAttr('{}.interpType'.format(constraint), 2)
    else:
        raise RuntimeError(
            'Constraint Type: "{}" is not supported!'.format(constraint_type))

    constraint_editor = cns_utils.Constraint()
    constraint_editor.create_switch(node, attribute_name, constraint)

    if value is None:
        value = (len(source_list) - 1)
    maya.cmds.setAttr('{}.{}'.format(node, attribute_name), value)

    return target_transform
示例#7
0
def create_follow_group(source_transform,
                        target_transform,
                        prefix='follow',
                        follow_scale=False,
                        use_duplicate=False):
    """
    Creates a group above a target transform that is constrained to the source transform
    :param source_transform: str, name of the transform to follow
    :param target_transform: str, name of the transform make follow
    :param prefix: str, prefix to add to the follow group
    :param follow_scale: bool, Whether to ad a scale constraint or not
    :param use_duplicate: bool, Whether to use a duplicate or not
    :return: str, name of the follow group
    """

    parent = maya.cmds.listRelatives(target_transform, p=True, f=True)
    target_name = python.force_list(target_transform)
    name = '{}_{}'.format(prefix, target_name[0])

    if use_duplicate:
        follow_group = maya.cmds.duplicate(target_transform,
                                           n=name_utils.find_unique_name(name),
                                           po=True)[0]
        attr_utils.remove_user_defined_attributes(follow_group)
        parent = None
    else:
        follow_group = maya.cmds.group(empty=True,
                                       n=name_utils.find_unique_name(name))

    match = xform_utils.MatchTransform(source_transform, follow_group)
    match.translation_rotation()

    if parent:
        maya.cmds.parent(follow_group, parent)

    if follow_scale:
        attr_utils.connect_scale(source_transform, follow_group)

    maya.cmds.parentConstraint(source_transform, follow_group, mo=True)

    return follow_group
示例#8
0
def create_ik_chain(top_transform,
                    bottom_transform,
                    name,
                    solver=IkHandle.SOLVER_SC):
    """
    Creates a new two joint chain with an Ik handle
    :param top_transform: str, name of a transform
    :param bottom_transform: str, name of a transform
    :param name: str, name to give to new joints
    :param solver: str, type of Ik solver to use
    :return: tuple(str, str, str), tuple containing joint names and ik handle name
    """

    maya.cmds.select(clear=True)

    # Create joints and match to given transforms
    start_joint = maya.cmds.joint(n=name_utils.find_unique_name(name))
    end_joint = maya.cmds.joint(n=name_utils.find_unique_name(name))
    transform_utils.MatchTransform(top_transform, start_joint).translation()
    transform_utils.MatchTransform(bottom_transform, end_joint).translation()
    maya.cmds.joint(start_joint,
                    e=True,
                    oj='xyz',
                    secondaryAxisOrient='xup',
                    zso=True)
    maya.cmds.makeIdentity(end_joint, jo=True, apply=True)

    # Create IK handle
    ik_handle = IkHandle(name)
    ik_handle.set_start_joint(start_joint)
    ik_handle.set_end_joint(end_joint)
    ik_handle.set_solver(solver)
    ik_pole = ik_handle.create()

    if solver == IkHandle.SOLVER_RP:
        for axis in 'XYZ':
            dcc.set_attribute_value(ik_pole, 'poleVector{}'.format(axis), 0)

    return start_joint, end_joint, ik_pole
示例#9
0
def snap_joints_to_curve(joints, curve=None, count=10):
    """
    Snap given joitns to the given curve
    If the given count is greater than the number of joints, new joints will be added to the curve
    :param joints: list(str(, list of joints to snap to curve
    :param curve: str, name of a curve. If no curve given a simple curve will be created based on the joints
    :param count: int, number of joints, if the joints list does not have the same number joints,
        new ones wil be created
    :return: list(str)
    """

    if not joints:
        return

    # List that will contains temporary objects that will be removed when the snapping process is over
    delete_after = list()

    if not curve:
        curve = transforms_to_curve(joints, spans=count, description='temp')
        delete_after.append(curve)

    joint_count = len(joints)
    if joint_count < count and count:
        missing_count = count - joint_count
        for i in range(missing_count):
            new_jnt = maya.cmds.duplicate(joints[-1])[0]
            new_jnt = maya.cmds.rename(new_jnt, name_utils.find_unique_name(joints[-1]))
            maya.cmds.parent(new_jnt, joints[-1])
            joints.append(new_jnt)
    joint_count = len(joints)
    if not joint_count:
        return

    if count == 0:
        count = joint_count

    total_length = maya.cmds.arclen(curve)
    part_length = total_length / (count - 1)
    current_length = 0.0
    if count - 1 == 0:
        part_length = 0

    for i in range(count):
        param = get_parameter_from_curve_length(curve, current_length)
        pos = get_point_from_curve_parameter(curve, param)
        maya.cmds.move(
            pos[0], pos[1], pos[2], '{}.scalePivot'.format(joints[i]), '{}.rotatePivot'.format(joints[i], a=True))
        current_length += part_length

    if delete_after:
        maya.cmds.delete(delete_after)
示例#10
0
def edges_to_curve(edges, description=None):
    """
    Creates a new curve taking into account given list of edges
    :param edges: list(str), list of edges names (test.e[0], ...)
    :param description: str, name to give to the new curve
    :return: str, new crated curve
    """

    if not description:
        description = get_mesh_from_edge(edges[0])

    maya.cmds.select(edges)
    curve = maya.cmds.polyToCurve(form=2, degree=3)[0]
    curve = maya.cmds.rename(
        curve, name_utils.find_unique_name('curve_{}'.format(description)))

    return curve
示例#11
0
def create_hair_system(name=None, nucleus_node=None):
    """
    Creates a new hair system (nHair)
    :param name: str, name of the hair system.
    :param nucleus_node: str, name of a nucleus node to attach to the hair system
    :return: list(str, str), [hair system, hair system shape]
    """

    name = 'hairSystem_{}'.format(name) if name else 'hairSystem'
    hair_system_shape = maya.cmds.createNode('hairSystem')
    hair_system = maya.cmds.listRelatives(hair_system_shape, p=True)
    hair_system = maya.cmds.rename(hair_system,
                                   name_utils.find_unique_name(name))
    hair_system_shape = maya.cmds.listRelatives(hair_system, shapes=True)[0]
    maya.cmds.connectAttr('time1.outTime',
                          '{}.currentTime'.format(hair_system_shape))

    if nucleus_node:
        connect_hair_system_to_nucleus(hair_system, nucleus_node)

    return hair_system, hair_system_shape
示例#12
0
def create_local_follow_group(source_transform,
                              target_transform,
                              prefix='followLocal',
                              orient_only=False,
                              connect_scale=False):
    """
    Creates a group above a target transform that is local constrained to the source transform
    This help when setting up controls that need to be parented but only affect what they constrain when the actual
    control is moved
    :param source_transform: str, transform to follow
    :param target_transform: str, transform to make follow
    :param prefix: str, prefix to add to the follow group
    :param orient_only: bool, Whether the local constraint should just be an orient constraint
    :param connect_scale: bool, Whether local constraint should constraint also scale or not
    """

    parent = maya.cmds.listRelatives(target_transform, p=True)
    name = '{}_{}'.format(prefix, target_transform)
    follow_group = maya.cmds.group(empty=True,
                                   n=name_utils.find_unique_name(name))

    match = xform_utils.MatchTransform(source_transform, follow_group)
    match.translation_rotation()

    xform_grp = xform_utils.create_buffer_group(follow_group)

    if not orient_only:
        attr_utils.connect_translate(source_transform, follow_group)
    if orient_only or not orient_only:
        attr_utils.connect_rotate(source_transform, follow_group)
    if connect_scale:
        attr_utils.connect_scale(source_transform, follow_group)

    maya.cmds.parent(target_transform, follow_group)

    if parent:
        maya.cmds.parent(xform_grp, parent)

    return follow_group
def create_joints_along_curve(curve,
                              count,
                              description='new',
                              attach=True,
                              create_controls=False,
                              controls_file=None):
    """
    Create joints on curve that do not aim at child
    :param curve: str, name of a curve
    :param count: int, number of joints to create
    :param description: str, description for the new created joints
    :param attach: bool, Whether to attach the joints to the curve or not
    :param create_controls: bool, Whether to create controls on top of the created joints
    :param controls_file: str, file used to create new controls shapes
    :return: list(str), list of created joints
    """

    maya.cmds.select(clear=True)

    joints_group = None
    control_group = None

    if create_controls:
        joints_group = maya.cmds.group(empty=True,
                                       n=name_utils.find_unique_name(
                                           'joints_{}'.format(curve)))
        control_group = maya.cmds.group(empty=True,
                                        n=name_utils.find_unique_name(
                                            'controls_{}'.format(curve)))
        maya.cmds.addAttr(control_group, ln='twist', k=True)
        maya.cmds.addAttr(control_group,
                          ln='offsetScale',
                          min=-1,
                          dv=0,
                          k=True)

    joints = list()
    current_length = 0
    percent = 0
    segment = 1.0 / count

    total_length = maya.cmds.arclen(curve)
    part_length = total_length / (count - 1)

    for i in range(count):
        param = curve_utils.get_parameter_from_curve_length(
            curve, current_length)
        position = curve_utils.get_point_from_curve_parameter(curve, param)
        if attach:
            maya.cmds.select(clear=True)
        new_joint = maya.cmds.joint(p=position,
                                    n=name_utils.find_unique_name(
                                        '{}_jnt'.format(description)))
        maya.cmds.addAttr(new_joint, ln='param', at='double', dv=param, k=True)
        if joints:
            maya.cmds.joint(joints[-1], e=True, zso=True, oj='xyz', sao='yup')
        if attach:
            attach_node = curve_utils.attach_to_curve(new_joint,
                                                      curve,
                                                      parameter=param)
            if create_controls:
                maya.cmds.parent(new_joint, joints_group)
                maya.cmds.connectAttr('{}.param'.format(new_joint),
                                      '{}.parameter'.format(attach_node))

        current_length += part_length

        if create_controls and attach:
            new_control = control.RigControl(name_utils.find_unique_name(
                'tweaker_{}'.format(description)),
                                             controls_file=controls_file)
            new_control.set_curve_type('pin')
            new_control.rotate_shape(90, 0, 0)
            new_control.hide_visibility_attribute()
            control_name = new_control.get()
            parameter_value = maya.cmds.getAttr(
                '{}.parameter'.format(attach_node))
            percent_var = attr_utils.NumericAttribute('percent')
            percent_var.set_min_value(0)
            percent_var.set_max_value(10)
            percent_var.set_value(parameter_value * 10)
            percent_var.create(control_name)
            attr_utils.connect_multiply(percent_var.get_full_name(),
                                        '{}.parameter'.format(attach_node),
                                        0.1)
            buffer_group = transform_utils.create_buffer_group(control_name)
            for axis in 'XYZ':
                maya.cmds.connectAttr(
                    '{}.position{}'.format(attach_node, axis),
                    '{}.translate{}'.format(buffer_group, axis))
            side = new_control.update_color_respect_side(True, 0.1)
            if side != 'C':
                control_name = maya.cmds.rename(
                    control_name,
                    name_utils.find_unique_name(control_name[0:-3] +
                                                '1_{}'.format(side)))

            attr_utils.connect_translate(control_name, new_joint)
            attr_utils.connect_rotate(control_name, new_joint)
            offset = mathlib.fade_sine(percent)
            attr_utils.connect_multiply('{}.twist'.format(control_group),
                                        '{}.rotateX'.format(new_joint), offset)
            plus = maya.cmds.createNode('plusMinusAverage',
                                        n='plus_{}'.format(control_group))
            maya.cmds.setAttr('{}.input1D[0]'.format(plus), 1)
            attr_utils.connect_multiply('{}.offsetScale'.format(control_group),
                                        '{}.input1D[1]'.format(plus),
                                        offset,
                                        plus=False)
            multiply = attr_utils.MultiplyDivideNode(control_group)
            multiply.input1X_in('{}.output1D'.format(plus))
            multiply.input1Y_in('{}.output1D'.format(plus))
            multiply.input1Z_in('{}.output1D'.format(plus))
            multiply.input2X_in('{}.scaleX'.format(control_name))
            multiply.input2Y_in('{}.scaleY'.format(control_name))
            multiply.input2Z_in('{}.scaleZ'.format(control_name))
            multiply.outputX_out('{}.scaleX'.format(new_joint))
            multiply.outputY_out('{}.scaleY'.format(new_joint))
            multiply.outputZ_out('{}.scaleZ'.format(new_joint))
            maya.cmds.parent(buffer_group, control_group)

        joints.append(new_joint)
        percent += segment

    if create_controls and not attach:
        maya.cmds.parent(joints[0], joints_group)

    return joints, joints_group, control_group