예제 #1
0
    def set_parent(self, parent, **kwargs):
        """
        Sets the parent of the control
        :param parent:
        """

        dcc.set_parent(self.get_top(), parent)
    def _create_twist_joints(self):
        """
        Internal function that creates twist joints
        """

        distance = dcc.distance_between_nodes(self._twist_driver,
                                              self._twist_driven)
        distance_ratio = distance / (self._twist_joints_count - 1)
        twist_axis = self._get_twist_axis()

        root_node = dcc.node_parent(self._twist_driver, full_path=False)
        if root_node == dcc.node_short_name(self._twist_driven):
            twist_axis = (mathlib.Vector(*twist_axis) * -1.0).list()

        for i in range(self._twist_joints_count):
            dcc.clear_selection()
            twist_joint = dcc.create_joint(self._get_name('roll',
                                                          id=i,
                                                          node_type='joint'),
                                           size=self._scale)
            dcc.match_rotation(self._twist_joint or self._twist_driver,
                               twist_joint)
            dcc.match_translation(self._twist_driver, twist_joint)
            joint_utils.OrientJointAttributes.zero_orient_joint(twist_joint)
            if self._reverse_orient:
                twist_joint = dcc.set_parent(twist_joint, self._twist_driven)
            else:
                twist_joint = dcc.set_parent(twist_joint, self._twist_driver)

            new_distance = mathlib.Vector(*twist_axis) * (distance_ratio * i)
            dcc.translate_node_in_object_space(twist_joint,
                                               new_distance.list(),
                                               relative=True)
            self._twist_joints.append(twist_joint)
    def _create_nurbs_plane(self):
        """
        Internal function that creates the NURBS plane that will drive the rig system
        """

        self._nurbs_plane = dcc.create_nurbs_plane(
            name=self._get_name('flexiPlane', node_type='surface'),
            axis=(0, 1, 0), width=self._num_joints * 2, length=self._length, patches_u=self._num_joints,
            construction_history=False)
        dcc.freeze_transforms(self._nurbs_plane, translate=True, rotate=True, scale=True)
        dcc.hide_keyable_attributes(self._nurbs_plane, skip_visibility=True)

        material_name = self._get_name('flexiMat', node_type='material')
        if not dcc.node_exists(material_name):
            self._nurbs_plane_material = dcc.create_lambert_material(
                name=material_name, no_surface_shader=True, color=(0.0, 0.85, 1.0), transparency=(0.8, 0.8, 0.8))
        else:
            self._nurbs_plane_material = material_name
        dcc.apply_shader(self._nurbs_plane_material, self._nurbs_plane)

        if self._display_nurbs_plane_as_template:
            dcc.set_node_template_display(self._nurbs_plane, True)

        nurbs_plane_shape = dcc.list_shapes(self._nurbs_plane)[0]
        dcc.set_node_renderable(nurbs_plane_shape, False)
        dcc.set_attribute_value(nurbs_plane_shape, 'doubleSided', True)

        dcc.set_parent(self._nurbs_plane, self._global_move_group)
예제 #4
0
    def _duplicate_joints(self):
        """
        Internal function that duplicates current rig hierarchy of joints
        """

        if not self._create_buffer_joints:
            self._buffer_joints = self.joints
            return self._buffer_joints

        if self._build_hierarchy:
            build_hierarchy = joint_utils.BuildJointHierarchy()
            build_hierarchy.set_transforms(self.joints)
            build_hierarchy.set_replace(self._buffer_replace[0],
                                        self._buffer_replace[1])
            self._buffer_joints = build_hierarchy.create()
        else:
            duplicate_hierarhcy = transform.DuplicateHierarchy(self.joints[0])
            duplicate_hierarhcy.stop_at(self.joints[-1])
            duplicate_hierarhcy.only_these(self.joints)
            duplicate_hierarhcy.set_replace(self._buffer_replace[0],
                                            self._buffer_replace[1])
            self._buffer_joints = duplicate_hierarhcy.create()

        dcc.set_parent(self._buffer_joints[0], self._setup_group)

        return self._buffer_joints
예제 #5
0
    def create_auto(self, name=None, *args, **kwargs):
        """
        Creates an auto buffer group above the control
        :return: str
        """

        suffix = kwargs.pop('suffix', 'auto')
        name = name or 'auto'

        if self.get_auto(suffix=suffix):
            return self.get_auto(suffix=suffix)

        new_group = self._create_group(suffix, name=name, *args, **kwargs)
        node_parent = dcc.node_parent(self.get())
        if node_parent:
            new_group = dcc.set_parent(new_group, node_parent)

        root_group = self.get_root(suffix=kwargs.pop('auto_suffix', None))
        if root_group:
            if not dcc.node_short_name(dcc.node_parent(
                    new_group)) == dcc.node_short_name(root_group):
                dcc.set_parent(new_group, root_group)
            for xform in 'trs':
                for axis in 'xyz':
                    attr_value = 1.0 if xform == 's' else 0.0
                    dcc.set_attribute_value(new_group,
                                            '{}{}'.format(xform,
                                                          axis), attr_value)

        self.set_parent(new_group, parent_top=False)

        return new_group
    def _create_follicles(self):
        """
        Internal function that creates the follicles that will drive rig joints setup transforms
        :return:
        """
        u_count = self._num_joints
        v_count = 1

        for i in range(v_count):
            u_pos = (1.0 / u_count) * 0.5
            v_pos = (1.0 / v_count) * 0.5

            for j in range(u_count):
                follicle_name = self._get_name('follicle', id=j, node_type='follicle')
                new_follicle = follicle.create_surface_follicle(
                    self._nurbs_plane, follicle_name, [u_pos, v_pos], hide_follicle=True)
                dcc.set_parent(new_follicle, self._follicles_group)
                self._follicles.append(new_follicle)

                if u_count > 1:
                    u_pos = mathlib.clamp(0, u_pos + (1.0 / u_count), 1.0)
                if v_count > 1:
                    v_pos = mathlib.clamp(0, v_pos + (1.0 / v_count), 1.0)

        # We make sure that follicles are scaled if global group is scaled
        for flc in self._follicles:
            dcc.create_scale_constraint(flc, self._global_move_group)
예제 #7
0
    def set_parent(self, parent, **kwargs):
        """
        Overrides set parent to parent proper root/auto nodes if necessary
        :param parent: str, parent transform node name
        :return:
        """

        # Whether to parent ctrl transform or take into account also root/auto groups
        parent_top = kwargs.pop('parent_top', True)
        node_to_parent = self.get()

        root_group = self.get_root()
        auto_group = self.get_auto()

        if parent_top:
            mirror_group = self.get_mirror(
                suffix=kwargs.pop('mirror_suffix', None))
            if mirror_group:
                node_to_parent = mirror_group
            elif root_group and dcc.node_exists(root_group):
                node_to_parent = root_group
            else:
                if auto_group and dcc.node_exists(auto_group):
                    node_to_parent = auto_group

        dcc.set_parent(node_to_parent, parent)
예제 #8
0
    def _duplicate_joints(self):
        super(IkRig, self)._duplicate_joints()

        self._ik_chain = self._buffer_joints

        if not self._create_buffer_joints:
            return

        ik_group = self._create_group('ik')
        dcc.set_parent(self._ik_chain[0], ik_group)
        dcc.set_parent(ik_group, self._setup_group)
    def _create_groups(self):
        """
        Internal function that creates basic group hierarchy for the flexi rig setup
        """

        self._top_group = dcc.create_empty_group(name=self._get_name('flexiRoot', node_type='group'))
        dcc.hide_keyable_attributes(self._top_group, skip_visibility=True)

        self._global_move_group = dcc.create_empty_group(name=self._get_name('globalMove', node_type='group'))
        dcc.set_parent(self._global_move_group, self._top_group)

        self._extras_group = dcc.create_empty_group(name=self._get_name('extras', node_type='group'))
        dcc.hide_keyable_attributes(self._extras_group, skip_visibility=True)
        dcc.set_parent(self._extras_group, self._top_group)

        self._follicles_group = dcc.create_empty_group(name=self._get_name('follicles', node_type='group'))
        self._clusters_group = dcc.create_empty_group(name=self._get_name('clusters', node_type='group'))
        self._controls_group = dcc.create_empty_group(name=self._get_name('controls', node_type='group'))

        for group in [self._follicles_group, self._clusters_group]:
            dcc.set_parent(group, self._extras_group)
            dcc.hide_keyable_attributes(group, skip_visibility=True)

        dcc.hide_node(self._clusters_group)
        dcc.set_parent(self._controls_group, self._global_move_group)
        dcc.hide_keyable_attributes(self._controls_group, skip_visibility=True)
    def _create_wire_setup(self):
        # NOTE: We use wire deform to deform the blendShape plane because allow us to maintain the uniform spacing
        # NOTE: between surface patches while deforming the wired curve

        points_list = [(-self._num_joints, 0, -self._num_joints),
                       (0, 0, -self._num_joints),
                       (self._num_joints, 0, -self._num_joints)]
        self._wire_curve = curve.create_from_point_list(
            points_list, degree=2, name=self._get_name('flexiPlaneWire', node_type='curve'))
        dcc.hide_node(self._wire_curve)
        dcc.center_pivot(self._wire_curve)
        dcc.set_parent(self._wire_curve, self._extras_group)

        # NOTE: We create clusters in relative mode so the transforms in their above groups does not affect them
        start_cluster, start_handle = cluster.create_cluster(
            ['{}.cv[{}]'.format(self._wire_curve, i) for i in range(2)],
            name=self._get_name('wireStart', node_type='cluster'), relative=True, exclusive=False)
        dcc.set_attribute_value(start_handle, 'originX', -(self._num_joints + 1))
        dcc.move_pivot_in_object_space(start_handle, -self._num_joints / 2, 0, 0)

        end_cluster, end_handle = cluster.create_cluster(
            ['{}.cv[{}]'.format(self._wire_curve, i) for i in range(1, 3)],
            name=self._get_name('wireEnd', node_type='cluster'), relative=True, exclusive=False)
        dcc.set_attribute_value(end_handle, 'originX', self._num_joints + 1)
        dcc.move_pivot_in_object_space(end_handle, self._num_joints / 2, 0, 0)

        mid_cluster, mid_handle = cluster.create_cluster(
            '{}.cv[1]'.format(self._wire_curve), name=self._get_name('wireMid', node_type='cluster'),
            relative=True, exclusive=False)
        for cls, handle in zip([start_cluster, mid_cluster, end_cluster], [start_handle, mid_handle, end_handle]):
            self._clusters.append({'node': cls, 'handle': handle})
            dcc.set_parent(handle, self._clusters_group)

        # Make sure that mid CV is only deformer 0.5 by start/end clusters
        # This will give us a linear deformation
        maya.cmds.percent(start_cluster, '{}.cv[1]'.format(self._wire_curve), value=0.5)
        maya.cmds.percent(end_cluster, '{}.cv[1]'.format(self._wire_curve), value=0.5)

        wire_curve_shape = dcc.list_shapes(self._wire_curve)[0]
        wire_tweak = maya.cmds.listConnections(wire_curve_shape, type='tweak')[0]
        dcc.rename_node(wire_tweak, self._get_name('wireCurveClusters', node_type='tweak'))

        # TODO: Dropoff distance should be multiplied by global scale
        blendshape_curve_shape = dcc.list_shapes(self._nurbs_blendshape_plane)[0]
        self._wire_node = maya.cmds.wire(
            self._nurbs_blendshape_plane, wire=self._wire_curve,
            name=self._get_name('wireDeformer', node_type='wire'), dropoffDistance=[0, 20])
        wire_plane_tweak = maya.cmds.listConnections(blendshape_curve_shape, type='tweak')[0]
        dcc.rename_node(wire_plane_tweak, self._get_name('flexiPlaneBshpWire', node_type='tweak'))
예제 #11
0
    def _create_pole_vector(self):
        """
        Internal function that creates the Ik pole vector setup
        :return:
        """

        bottom_control = self._bottom_control.get()

        pole_vector_control = self._pole_vector_control
        pole_vector_control_buffer = pole_vector_control.create_root()

        dcc.add_title_attribute(bottom_control, 'POLE_VECTOR')
        dcc.add_bool_attribute(bottom_control,
                               'poleVisibility',
                               default_value=True)
        dcc.add_float_attribute(bottom_control, 'twist')

        if self.side == self.mirror_side:
            dcc.connect_multiply(bottom_control, 'twist', self._ik_handle,
                                 'twist', -1)
        else:
            dcc.connect_attribute(bottom_control, 'twist', self._ik_handle,
                                  'twist')

        pole_joints = self._get_pole_joints()
        position = dcc.get_pole_vector_position(
            pole_joints[0],
            pole_joints[1],
            pole_joints[2],
            offset=self._pole_vector_offset * self.scale)
        dcc.move_node(pole_vector_control.get(), position[0], position[1],
                      position[2])

        self._create_pole_vector_constraint(pole_vector_control.get(),
                                            self._ik_handle)

        rig_line_name = self._get_name('pvLine', node_type='rigLine')
        rig_line = rig_utils.RiggedLine(pole_joints[1],
                                        pole_vector_control.get(),
                                        rig_line_name).create()
        dcc.set_parent(rig_line, self._controls_group)

        dcc.connect_attribute(bottom_control, 'poleVisibility',
                              pole_vector_control_buffer, 'visibility')
        dcc.connect_attribute(bottom_control, 'poleVisibility', rig_line,
                              'visibility')

        self._pole_vector_buffer = pole_vector_control_buffer
예제 #12
0
    def _create_ik_buffer_joint(self):
        """
        Internal function that creates Ik buffer joint
        This buffer is useful when multiple rigs are attached to the same target Ik handle joint to avoid transform
        cycles and also to have clean transforms channels in the target node which helps the Ik handle to behave in
        a more solid manner
        :return: str
        """

        end_joint = self._ik_chain[self._end_index]
        buffer_name = dcc.find_unique_name('{}_ikBuffer'.format(end_joint))
        buffer_joint = dcc.duplicate_node(end_joint,
                                          new_node_name=buffer_name,
                                          only_parent=True)
        end_joint = dcc.set_parent(end_joint, buffer_joint)
        if not dcc.is_attribute_connected_to_attribute(
                buffer_joint, 'scale', end_joint, 'inverseScale'):
            dcc.connect_attribute(buffer_joint, 'scale', end_joint,
                                  'inverseScale')

        attributes = list()
        for axis in 'XYZ':
            for attr_name in ['rotate', 'jointOrient']:
                attributes.append('{}{}'.format(attr_name, axis))
        for attribute in attributes:
            dcc.set_attribute_value(end_joint, attribute, 0)

        return buffer_joint
예제 #13
0
    def _setup_bottom_control(self):
        """
        Internal function that setup bottom control after its creation
        :return:
        """

        joints = self._ik_chain

        ik_handle_parent = dcc.node_parent(self._ik_handle)

        dcc.set_parent(ik_handle_parent, self._bottom_control.get())

        if self._orient_constraint:
            dcc.create_orient_constraint(joints[self._end_index],
                                         self._bottom_control.get(),
                                         maintain_offset=True)
    def manual_orient_joints(self, data, reply):

        orient_type = data.get('orient_type', 'add')
        x_axis = data.get('x_axis', 0.0)
        y_axis = data.get('y_axis', 0.0)
        z_axis = data.get('z_axis', 0.0)
        affect_children = data.get('affect_children', False)

        if orient_type == 'add':
            tweak = 1.0
        else:
            tweak = -1.0

        tweak_rot = [x_axis * tweak, y_axis * tweak, z_axis * tweak]

        joints = dcc.selected_nodes_of_type(node_type='joint')
        if not joints:
            return

        for jnt in joints:
            dcc.set_node_rotation_axis_in_object_space(jnt, tweak_rot[0],
                                                       tweak_rot[1],
                                                       tweak_rot[2])
            dcc.zero_scale_joint(jnt)
            dcc.freeze_transforms(jnt, preserve_pivot_transforms=True)

            if affect_children:
                childs = dcc.list_children(
                    jnt,
                    children_type=['transform', 'joint'],
                    full_path=False,
                    all_hierarchy=True) or list()
                for child in childs:
                    parent = dcc.node_parent(child)
                    dcc.set_parent_to_world(child)
                    dcc.set_node_rotation_axis_in_object_space(
                        child, tweak_rot[0], tweak_rot[1], tweak_rot[2])
                    dcc.zero_scale_joint(child)
                    dcc.freeze_transforms(child,
                                          preserve_pivot_transforms=True)
                    dcc.set_parent(child, parent)

        dcc.select_node(joints, replace_selection=True)

        reply['success'] = True
    def reset_joints_orient_to_world(self, data, reply):
        apply_to_hierarchy = data.get('apply_to_hierarchy', False)

        if apply_to_hierarchy:
            dcc.select_hierarchy()

        joints = dcc.selected_nodes_of_type(node_type='joint', full_path=False)
        if not joints:
            reply['msg'] = 'No joints selected'
            reply['success'] = False
            return

        for jnt in reversed(joints):
            childs = dcc.list_children(jnt,
                                       all_hierarchy=False,
                                       children_type=['transform', 'joint'])

            # If the joints has direct childs, unparent that childs and store names
            if childs:
                if len(childs) > 0:
                    childs = dcc.set_parent_to_world(childs)

            # Get parent of this joints for later use
            parent = dcc.node_parent(jnt, full_path=False) or ''

            if parent:
                dcc.set_parent_to_world(jnt)

            # Clear joint axis
            dcc.zero_scale_joint(jnt)
            dcc.freeze_transforms(jnt, preserve_pivot_transforms=True)
            dcc.zero_orient_joint(jnt)

            # Reparent
            if parent:
                dcc.set_parent(jnt, parent)

            # Reparent child
            if childs:
                if len(childs) > 0:
                    dcc.set_parent(childs, jnt)

        dcc.select_node(joints, replace_selection=True)

        reply['success'] = True
예제 #16
0
def mirror_mesh(mesh=None):
    """
    Mirror given meshes
    """

    out_dict = {'success': False, 'result': list()}

    meshes = mesh or dcc.selected_nodes_of_type(node_type='transform')
    meshes = python.force_list(meshes)
    if not meshes:
        out_dict['msg'] = 'No meshes to mirror selected.'
        return out_dict

    for mesh in meshes:
        try:
            parent_node = dcc.node_parent(mesh)
            mirror_geo_name = xform_utils.find_transform_right_side(
                mesh, check_if_exists=False)
            mirror_geo = maya.cmds.duplicate(mesh, n=mirror_geo_name or None)
            root = maya.cmds.group(empty=True, world=True)
            maya.cmds.parent(mirror_geo, root)
            maya.cmds.setAttr('{}.rx'.format(root), 180)
            for axis in 'xyz':
                maya.cmds.setAttr('{}.s{}'.format(root, axis), -1)
            maya.cmds.parent(mirror_geo, world=True)
            maya.cmds.delete(root)
            maya.cmds.makeIdentity(mirror_geo,
                                   apply=True,
                                   t=False,
                                   r=True,
                                   s=True,
                                   n=False,
                                   pn=True)
            if parent_node:
                dcc.set_parent(mirror_geo, parent_node)
            out_dict['result'].append(mirror_geo)
        except Exception as exc:
            out_dict[
                'msg'] = 'Was not possible to mirror meshes "{}" : {}'.format(
                    meshes, exc)
            return out_dict

    out_dict['success'] = True

    return out_dict
    def _create_twist_setup(self):

        # Update rotate order for start and end controls to improve twist axis stability
        dcc.set_attribute_value(self._start_control.get(), 'rotateOrder', 3)    # xyz
        dcc.set_attribute_value(self._end_control.get(), 'rotateOrder', 3)      # xyz

        # NOTE: It's important to create the twist deform in front of the deformation chain (so its evaluated before
        # the wire deformer)
        self._twist_node, self._twist_handle = maya.cmds.nonLinear(
            self._nurbs_blendshape_plane, type='twist', frontOfChain=True)
        self._twist_node = dcc.rename_node(self._twist_node, self._get_name('twistDeformer', node_type='twist'))
        self._twist_handle = dcc.rename_node(self._twist_handle, self._get_name('twistHandle', node_type='twist'))
        dcc.set_attribute_value(self._twist_handle, 'rotateZ', 90)
        dcc.hide_node(self._twist_handle)
        dcc.set_parent(self._twist_handle, self._extras_group)

        dcc.connect_attribute(self._start_control.get(), 'rotateX', self._twist_node, 'endAngle')
        dcc.connect_attribute(self._end_control.get(), 'rotateX', self._twist_node, 'startAngle')
예제 #18
0
def combine_meshes(meshes=None, new_mesh_name=None):
    """
    Combines given meshes into one transform
    """

    out_dict = {'success': False, 'result': None}

    meshes = meshes or dcc.selected_nodes_of_type(node_type='transform')
    meshes = python.force_list(meshes)
    if not meshes:
        out_dict['msg'] = 'No meshes to combine selected.'
        return out_dict
    if len(meshes) < 2:
        out_dict['msg'] = 'You need to select at least two meshes to combine.'
        return out_dict
    new_mesh_name = new_mesh_name or dcc.node_short_name(meshes[0])

    parent_node = None
    node_parents = list(set([dcc.node_parent(mesh) for mesh in meshes]))
    if all(parent == node_parents[0] for parent in node_parents):
        parent_node = node_parents[0]

    try:
        combined_mesh = dcc.combine_meshes(construction_history=False)
        if not combined_mesh:
            out_dict[
                'msg'] = 'Combine operation was done but not combined mesh was generated'
            return out_dict
        combined_mesh = dcc.rename_node(combined_mesh, new_mesh_name)
        if parent_node:
            dcc.set_parent(combined_mesh, parent_node)

        out_dict['result'] = combined_mesh
    except Exception as exc:
        out_dict[
            'msg'] = 'Was not possible to combine meshes "{}" : {}'.format(
                meshes, exc)
        return out_dict

    out_dict['success'] = True

    return out_dict
예제 #19
0
    def _create_ik_handle(self):
        """
        Internal function that creates Ik handle
        """

        if self._ik_buffer_joint:
            buffer_joint = self._create_ik_buffer_joint()
        else:
            buffer_joint = self._ik_chain[self._end_index]

        ik_handle = ik_utils.IkHandle(
            self._get_name('ik', node_type='ikHandle'))
        ik_handle.set_start_joint(self._ik_chain[self._start_index])
        ik_handle.set_end_joint(buffer_joint)
        ik_handle.set_solver(ik_handle.SOLVER_RP)
        self._ik_handle = ik_handle.create()
        dcc.hide_node(self._ik_handle)

        ik_handle_buffer = dcc.create_buffer_group(self._ik_handle)
        dcc.set_parent(ik_handle_buffer, self._setup_group)
    def set_manual_orient_joints(self, data, reply):
        x_axis = data.get('x_axis', 0.0)
        y_axis = data.get('y_axis', 0.0)
        z_axis = data.get('z_axis', 0.0)
        affect_children = data.get('affect_children', False)

        childs = list()

        tweak_rot = [x_axis, y_axis, z_axis]

        joints = dcc.selected_nodes_of_type(node_type='joint', full_path=False)
        if not joints:
            return

        for jnt in joints:
            if not affect_children:
                childs = dcc.list_children(
                    jnt,
                    children_type=['transform', 'joint'],
                    full_path=False,
                    all_hierarchy=False) or list()
                for child in childs:
                    dcc.set_parent_to_world(child)

            # Set the rotation axis
            for i, axis in enumerate(['x', 'y', 'z']):
                dcc.set_attribute_value(jnt,
                                        'jointOrient{}'.format(axis.upper()),
                                        tweak_rot[i])

            # Clear joint axis
            dcc.zero_scale_joint(jnt)
            dcc.freeze_transforms(jnt, preserve_pivot_transforms=True)

            if childs:
                for child in childs:
                    dcc.set_parent(child, jnt)

        dcc.select_node(joints, replace_selection=True)

        reply['success'] = True
    def _create_connector_controls(self):

        self._global_control = control.RigControl(name=self._get_name('global', node_type='control'))
        global_circle1 = maya.cmds.circle(normal=(0, 1, 0), radius=0.3)[0]
        dcc.move_node(global_circle1, 0, 0, -self._length)
        global_circle2 = maya.cmds.circle(normal=(0, 1, 0), radius=0.3)[0]
        dcc.move_node(global_circle2, 0, 0, self._length)
        dcc.freeze_transforms(global_circle1)
        dcc.freeze_transforms(global_circle2)
        self._global_control.set_shape([global_circle1, global_circle2])
        self._global_control.set_color_rgb(255, 255, 0)
        dcc.delete_node([global_circle1, global_circle2])
        for shape in dcc.list_shapes(self._global_control.get()):
            dcc.rename_node(shape, '{}Shape'.format(self._global_control.get()))
        self._global_control.create_root_group()
        dcc.set_parent(self._global_control.get_top(), self._top_group)
        dcc.set_parent(self._global_move_group, self._global_control.get())

        top_end_distance = self._num_joints
        self._start_control = control.RigControl(name=self._get_name('startConnector', node_type='control'))
        self._start_control.set_curve_type(
            'square', color=(255, 255, 0), axis_order='YXZ', control_size=self._control_size)
        dcc.move_node(self._start_control.get_top(), -top_end_distance, 0, 0)

        self._end_control = control.RigControl(name=self._get_name('endConnector', node_type='control'))
        self._end_control.set_curve_type(
            'square', color=(255, 255, 0), axis_order='YXZ', control_size=self._control_size)
        dcc.move_node(self._end_control.get_top(), top_end_distance, 0, 0)

        sphere_control = maya.cmds.polySphere(subdivisionsX=12, subdivisionsY=12, radius=0.3)
        sphere_shape = dcc.list_shapes(sphere_control)[0]
        sphere_material = self._get_name('flexiBendControlMat', node_type='material')
        if not dcc.node_exists(sphere_material):
            self._mid_control_material = dcc.create_surface_shader(shader_name=sphere_material)
            dcc.set_attribute_value(self._mid_control_material, 'outColor', (1, 1, 0))
        else:
            self._mid_control_material = sphere_material
        dcc.apply_shader(self._mid_control_material, sphere_shape)
        dcc.set_node_renderable(sphere_shape, False)
        self._mid_control = control.RigControl(name=self._get_name('midBend', node_type='control'))
        self._mid_control.set_shape(sphere_control)
        maya.cmds.delete(sphere_control)
        mid_control_shape = dcc.list_shapes(self._mid_control.get())[0]
        dcc.rename_node(mid_control_shape, '{}Shape'.format(self._mid_control.get()))

        for connector_control in [self._start_control, self._mid_control, self._end_control]:
            connector_control.create_root_group()
            connector_control.create_auto_group()
            dcc.set_parent(connector_control.get_top(), self._controls_group)

        # Mid control will be positioned in the mid position between start and end controls
        dcc.create_point_constraint(
            self._mid_control.get_buffer_group('auto'), (self._start_control.get(), self._end_control.get()),
            maintain_offset=False)
    def _create_ik_handle(self):
        root_node = dcc.node_parent(self._twist_driver, full_path=False)
        if root_node == dcc.node_short_name(self._twist_driven):
            root_node = self._twist_driver

        ik_handle = ik_utils.IkHandle(
            self._get_name('roll', node_type='ikHandle'))
        ik_handle.set_solver(ik_handle.SOLVER_SC)
        ik_handle.set_start_joint(self._twist_joints[0])
        ik_handle.set_end_joint(self._twist_joints[-1])
        ik_handle = ik_handle.create()

        if root_node:
            ik_handle = dcc.set_parent(ik_handle, root_node)

        # we make sure that twist joint follows the driven joint
        dcc.create_point_constraint(ik_handle, self._twist_driven)

        self._ik_handle = ik_handle
def replace_control_curves(control_name,
                           control_type='circle',
                           controls_path=None,
                           auto_scale=True,
                           maintain_line_width=True,
                           keep_color=True,
                           **kwargs):
    """
    Replaces the given control with the given control type deleting the existing control curve shape nodes
    :param control_name:
    :param control_type:
    :param controls_path:
    :param auto_scale: bool
    :param maintain_line_width: bool
    :param keep_color: bool
    :return:
    """

    orig_sel = dcc.selected_nodes()

    line_width = -1
    orig_size = None
    orig_color = kwargs.pop('color', None)
    if auto_scale:
        orig_size = get_control_size(control_name)
    if maintain_line_width:
        line_width = curve.get_curve_line_thickness(control_name)
    if keep_color:
        orig_color = get_control_color(control_name)

    new_control = create_control_curve(control_name='new_ctrl',
                                       control_type=control_type,
                                       controls_path=controls_path,
                                       color=orig_color,
                                       **kwargs)[0]
    if auto_scale and orig_size is not None:
        new_scale = get_control_size(new_control)
        scale_factor = orig_size / new_scale
        dcc.scale_shapes(new_control, scale_factor, relative=False)

    # We need to make sure that transforms are reset in all scenarios
    # Previous implementation was failing if the target hierarchy had a mirror behaviour (group scaled negative in
    # one of the axises)
    # maya.cmds.matchTransform([new_control, target], pos=True, rot=True, scl=True, piv=True)
    target = dcc.list_nodes(control_name, node_type='transform')[0]
    dcc.delete_node(
        dcc.create_parent_constraint(new_control,
                                     target,
                                     maintain_offset=False))
    dcc.delete_node(
        dcc.create_scale_constraint(new_control, target,
                                    maintain_offset=False))
    target_parent = dcc.node_parent(target)
    if target_parent:
        new_control = dcc.set_parent(new_control, target_parent)
        for axis in 'XYZ':
            dcc.set_attribute_value(new_control, 'translate{}'.format(axis),
                                    0.0)
            dcc.set_attribute_value(new_control, 'rotate{}'.format(axis), 0.0)
            dcc.set_attribute_value(new_control, 'scale{}'.format(axis), 1.0)
        new_control = dcc.set_parent_to_world(new_control)

    if target != new_control:
        xform_utils.parent_transforms_shapes(target, [new_control],
                                             delete_original=True,
                                             delete_shape_type='nurbsCurve')

    if maintain_line_width:
        curve.set_curve_line_thickness(target, line_width=line_width)

    dcc.select_node(orig_sel)

    return target
 def _create_joints(self):
     for i in range(len(self._follicles)):
         dcc.clear_selection()
         self._joints.append(dcc.create_joint(name=self._get_name('joint', id=i, node_type='joint')))
         dcc.match_translation(self._follicles[i], self._joints[i])
         dcc.set_parent(self._joints[i], self._follicles[i])
예제 #25
0
    def create_root(self, name=None, *args, **kwargs):
        """
        Creates a root buffer group above the control
        :return: str
        """

        suffix = kwargs.pop('suffix', 'root')
        name = name or 'root'

        if self.get_root(suffix=suffix):
            return self.get_root(suffix=suffix)

        top_parent = dcc.node_parent(self.get_top())

        new_group = self._create_group(suffix, name=name, *args, **kwargs)

        # MIRROR BEHAVIOUR
        # TODO: This should be optional
        mirror_group = None
        if self.side and dcc.name_is_right(self.side):
            mirror_group = self._create_group('mirror',
                                              name='mirror',
                                              *args,
                                              **kwargs)
            # dcc.match_translation_rotation(self.get(), mirror_group)
            dcc.set_attribute_value(mirror_group, 'scaleX', -1)
            if top_parent:
                dcc.set_parent(mirror_group, top_parent)

        auto_group = self.get_auto()
        if not auto_group:
            if mirror_group:
                dcc.set_parent(new_group, mirror_group)
                self.set_parent(new_group, parent_top=False)
                for xform in 'trs':
                    for axis in 'xyz':
                        attr_value = 1.0 if xform == 's' else 0.0
                        dcc.set_attribute_value(new_group,
                                                '{}{}'.format(xform, axis),
                                                attr_value)
            else:
                node_parent = dcc.node_parent(self.get())
                if node_parent:
                    dcc.set_parent(new_group, node_parent)
                self.set_parent(new_group, parent_top=False)
        else:
            if mirror_group:
                dcc.set_parent(new_group, mirror_group)
            else:
                auto_group_parent = dcc.node_parent(auto_group)
                if auto_group_parent:
                    new_group = dcc.set_parent(new_group, auto_group_parent)
            dcc.set_parent(auto_group, new_group)

        return new_group
    def orient_joints(self, data, reply):
        aim_axis_index = data.get('aim_axis_index', 0.0)
        aim_axis_reverse = data.get('aim_axis_reverse', False)
        up_axis_index = data.get('up_axis_index', 0.0)
        up_axis_reverse = data.get('up_axis_reverse', False)
        up_world_axis_x = data.get('up_world_axis_x', 0.0)
        up_world_axis_y = data.get('up_world_axis_y', 0.0)
        up_world_axis_z = data.get('up_world_axis_z', 0.0)
        apply_to_hierarchy = data.get('apply_to_hierarchy', False)

        reset_joints = list()

        # Get up and aim axis
        aim_axis = [0, 0, 0]
        up_axis = [0, 0, 0]
        world_up_axis = [up_world_axis_x, up_world_axis_y, up_world_axis_z]

        if aim_axis_index == up_axis_index:
            LOGGER.warning(
                'aim and up axis are the same, maybe orientation wont work correctly!'
            )

        aim_axis_reverse_value = 1.0 if not aim_axis_reverse else -1.0
        up_axis_reverse_value = 1.0 if not up_axis_reverse else -1.0

        aim_axis[aim_axis_index] = aim_axis_reverse_value
        up_axis[up_axis_index] = up_axis_reverse_value

        # Get selected joints
        if apply_to_hierarchy:
            dcc.select_hierarchy()

        joints = dcc.selected_nodes_of_type(node_type='joint', full_path=False)
        if not joints:
            reply['msg'] = 'No joints selected'
            reply['success'] = False
            return

        for jnt in reversed(joints):
            childs = dcc.list_children(jnt,
                                       all_hierarchy=False,
                                       children_type=['transform', 'joint'])

            # If the joints has direct childs, unparent that childs and store names
            if childs:
                if len(childs) > 0:
                    childs = dcc.set_parent_to_world(childs)
            childs = python.force_list(childs)

            # Get parent of this joints for later use
            parent = ''
            parents = dcc.node_parent(jnt)
            if parents:
                parent = parents[0]

            # Aim to the child
            aim_target = ''
            if childs:
                for child in childs:
                    if dcc.node_type(child) == 'joint':
                        aim_target = child
                        break

            if aim_target != '':

                # Apply an aim constraint from the joint to its child (target)
                dcc.delete_node(
                    dcc.create_aim_constraint(jnt,
                                              aim_target,
                                              aim_axis=aim_axis,
                                              up_axis=up_axis,
                                              world_up_axis=world_up_axis,
                                              world_up_type='vector',
                                              weight=1.0))

                # Clear joint axis
                dcc.zero_scale_joint(jnt)
                dcc.freeze_transforms(jnt, preserve_pivot_transforms=True)

            elif parent != '':
                reset_joints.append(jnt)

            # Reparent child
            if childs:
                if len(childs) > 0:
                    dcc.set_parent(childs, jnt)

        for jnt in reset_joints:
            # If there is no target, the joint will take its parent orientation
            for axis in ['x', 'y', 'z']:
                dcc.set_attribute_value(
                    jnt, 'jointOrient{}'.format(axis.upper()),
                    dcc.get_attribute_value(jnt, 'r{}'.format(axis)))
                dcc.set_attribute_value(jnt, 'r{}'.format(axis), 0)

        dcc.select_node(joints, replace_selection=True)

        reply['success'] = True
    def _connect_twist_joints(self):
        """
        Internal function that connects twist setup
        """

        # orient locator will be used to retrieve a "clean" orientation value in the twist axis no matter how we
        # rotate the end joint of the twist chain.
        self._orient_locator = dcc.create_locator(
            name=self._get_name('orient', node_type='locator'))
        self._fixed_locator = dcc.create_locator(
            name=self._get_name('fixed', node_type='locator'))
        dcc.match_translation_rotation(self._twist_driver,
                                       self._orient_locator)
        dcc.match_translation_rotation(self._twist_driver, self._fixed_locator)
        self._fixed_locator = dcc.set_parent(
            self._fixed_locator, dcc.node_parent(self._twist_driver))
        self._orient_locator = dcc.set_parent(self._orient_locator,
                                              self._fixed_locator)

        for axis in 'XYZ':
            dcc.set_attribute_value(self._orient_locator,
                                    'localScale{}'.format(axis), self._scale)
            dcc.set_attribute_value(self._fixed_locator,
                                    'localScale{}'.format(axis), self._scale)

        # as the orient constraint is parented to the local constraint and both locators have the same transforms
        # the orient locator channels are completely clean. We use orient locator to retrieve a clean rotation of
        # the twist driver joint
        orient_constraint = dcc.create_orient_constraint(
            self._orient_locator, self._twist_driver)

        # we set the constraint interpolation type to average to avoid joint flipping
        dcc.set_attribute_value(orient_constraint, 'interpType', 1)

        axis_letter = self._get_twist_axis(as_letter=True)
        if len(axis_letter) > 1:
            axis_letter = axis_letter[-1]

        twist_value = -1
        loop_joints = self.twist_joints
        if self._reverse_orient:
            loop_joints = list(reversed(loop_joints))
        for i, twist_joint in enumerate(loop_joints):
            multiply_divide_twist = dcc.create_node(
                'multiplyDivide',
                node_name=self._get_name('twistJoint',
                                         id=i,
                                         node_type='multiplyDivide'))
            for axis in 'XYZ':
                input_attr = 'input2{}'.format(axis)
                if axis == axis_letter.upper():
                    if self._reverse_orient:
                        dcc.set_attribute_value(
                            multiply_divide_twist, input_attr,
                            1.0 / len(self.twist_joints) * i)
                    else:
                        dcc.set_attribute_value(multiply_divide_twist,
                                                input_attr, twist_value)
                else:
                    dcc.set_attribute_value(multiply_divide_twist, input_attr,
                                            0.0)
            dcc.connect_attribute(self._orient_locator, 'rotate',
                                  multiply_divide_twist, 'input1')
            dcc.connect_attribute(multiply_divide_twist, 'output', twist_joint,
                                  'rotate')
            twist_value += 1.0 / (self._twist_joints_count - 1)
def mirror_control(source_control,
                   target_control=None,
                   mirror_axis='X',
                   mirror_mode=0,
                   mirror_color=None,
                   mirror_replace=False,
                   keep_color=True,
                   from_name=None,
                   to_name=None):
    """
    Find the right side control of a left side control and mirrors the control following next rules:
        - Mirror only will be applied if corresponding right side name exists
        - Replace left prefix and suffixes checking for validity
    :param mirror_axis: str
    :param mirror_mode: int or None
    :param mirror_color: int or list(float, float, float)
    :param mirror_replace: bool
    :param keep_color: bool
    :return: str, mirrored control
    """

    if keep_color:
        target_control_color = get_control_color(source_control)
    else:
        target_control_color = get_control_color(
            source_control
        ) if not mirror_color and keep_color else mirror_color

    source_shapes = dcc.list_shapes_of_type(source_control, 'nurbsCurve')
    if not source_shapes:
        return None

    duplicated_control = duplicate_control(source_control)
    mirror_pivot_grp = dcc.create_empty_group(name='temp_mirrorPivot')
    duplicated_control = dcc.set_parent(duplicated_control, mirror_pivot_grp)

    dcc.set_attribute_value(mirror_pivot_grp,
                            'scale{}'.format(mirror_axis.upper()), -1)

    target_control = target_control or source_control.replace(
        from_name, to_name)

    # We force this conversion. This is something that we should remove in the future
    if target_control and not dcc.node_exists(target_control):
        target_control = target_control.replace('Left', 'Right')

    if target_control and not dcc.node_exists(target_control):
        target_control = dcc.node_short_name(target_control)

    if target_control and dcc.node_exists(target_control) and mirror_replace:
        if keep_color:
            target_control_color = get_control_color(target_control)
        mirrored_control = xform_utils.parent_transforms_shapes(
            target_control, duplicated_control, delete_original=True)
    else:
        mirrored_control = dcc.set_parent_to_world(duplicated_control)

    maya.cmds.delete(mirror_pivot_grp)

    if mirror_mode == 0:
        dcc.move_node(mirrored_control, 0, 0, 0, world_space=True)
    elif mirror_mode == 1:
        orig_pos = dcc.node_world_space_pivot(source_control)
        dcc.move_node(mirrored_control,
                      orig_pos[0],
                      orig_pos[1],
                      orig_pos[2],
                      world_space=True)

    if target_control_color:
        target_shapes = dcc.list_shapes_of_type(mirrored_control,
                                                shape_type='nurbsCurve')
        for target_shape in target_shapes:
            dcc.set_node_color(target_shape, target_control_color)

    if from_name and to_name and from_name != to_name:
        if from_name in mirrored_control:
            mirrored_control = dcc.rename_node(
                mirrored_control, source_control.replace(from_name, to_name))

    return mirrored_control