コード例 #1
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
コード例 #2
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
コード例 #3
0
    def get_selected_info(self, data, reply):
        """
        Function that returns selected geometry info (its name and its vertices)
        :return: tuple(str, list(list(float, float, float))
        """

        nodes = dcc.selected_nodes(flatten=True)
        selected_geo = dcc.filter_nodes_by_selected_components(filter_type=12,
                                                               nodes=nodes,
                                                               full_path=True)
        selected_vertices = None
        if selected_geo:
            selected_geo = selected_geo[0]
        if not selected_geo:
            hilited_geo = dcc.selected_hilited_nodes(full_path=True)
            if len(hilited_geo) == 1:
                selected_geo = hilited_geo[0]
                selected_vertices = dcc.filter_nodes_by_selected_components(
                    filter_type=31, nodes=nodes, full_path=False)
            elif len(hilited_geo) > 1:
                logger.warning(
                    'Only one object can be hilited in component mode!')

        if selected_geo:
            if dcc.node_is_a_shape(selected_geo):
                selected_geo = dcc.node_parent(selected_geo, full_path=True)

        if not selected_geo or not dcc.node_exists(selected_geo):
            reply['success'] = False
            reply['result'] = '', list()
            return

        reply['success'] = True
        reply['result'] = selected_geo, selected_vertices
コード例 #4
0
def duplicate_control(control_name,
                      duplicate_name=None,
                      use_selected_name=True,
                      copy_tracker=True,
                      delete_node_shapes=False):
    """
    Duplicates the given control transform node to a new transform parented to the world
    :param control_name: str, name of the control to duplicate
    :param duplicate_name: str, name of the duplicated control
    :param use_selected_name: bool, Whether or not
    :param copy_tracker:
    :param delete_node_shapes:
    :return:
    """

    if not duplicate_name and use_selected_name:
        duplicate_name = control_name
    duplicated_control = xform_utils.duplicate_transform_without_children(
        control_name,
        node_name=duplicate_name,
        delete_shapes=delete_node_shapes)

    if dcc.node_parent(duplicated_control):
        duplicated_control = dcc.set_parent_to_world(duplicated_control)

    if dcc.node_type(duplicated_control) == 'joint':
        pass

    return duplicated_control
コード例 #5
0
    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)
コード例 #6
0
    def _get_curve_transform(self, curve):
        parent = curve
        if dcc.node_exists(curve):
            if dcc.node_type(curve) == 'nurbsCurve':
                parent = dcc.node_parent(curve)
            else:
                parent = curve

        return parent
コード例 #7
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)
コード例 #8
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
コード例 #9
0
    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
コード例 #10
0
    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
コード例 #11
0
    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
コード例 #12
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
コード例 #13
0
def create_control_curve(control_name='new_ctrl',
                         control_type='circle',
                         controls_path=None,
                         control_size=1.0,
                         translate_offset=(0.0, 0.0, 0.0),
                         rotate_offset=(0.0, 0.0, 0.0),
                         scale=(1.0, 1.0, 1.0),
                         axis_order='XYZ',
                         mirror=None,
                         color=None,
                         line_width=-1,
                         create_buffers=False,
                         buffers_depth=0,
                         match_translate=False,
                         match_rotate=False,
                         match_scale=False,
                         parent=None,
                         **kwargs):
    """
    Creates a new curve based control
    :param control_name: str, name of the new control to create
    :param control_type: str, curve types used by the new control
    :param controls_path: str or None, path were control curve types can be located
    :param control_size: float, global size of the control
    :param translate_offset: tuple(float, float, float), XYZ translation offset to apply to the control curves
    :param rotate_offset: tuple(float, float, float), XYZ rotation offset to apply to the control curves
    :param scale: tuple(float, float, float), scale of the control.
    :param axis_order: str, axis order of the control. Default is XYZ.
    :param mirror: str or None, axis mirror to apply to the control curves (None, 'X', 'Y' or 'Z')
    :param color: list(float, float, float), RGB or index color to apply to the control
    :param line_width: str, If given, the new shapes will be parented to given node
    :param create_buffers: bool, Whether or not control buffer groups should be created.
    :param buffers_depth: int, Number of buffers groups to create.
    :param parent: str, If given, the new shapes will be parented to given node
    :param match_translate: bool, Whether or not new control root node should match the translate with the
        translation of the current DCC selected node
    :param match_translate: bool, Whether or not new control root node should match the rotate with the
        rotation of the current DCC selected node
    :param match_scale: bool, Whether or not new control root node should match the scale with the
        scale of the current DCC selected node
    :return:
    """

    current_selection = dcc.selected_nodes()

    parent_mobj = None
    if parent:
        parent_mobj = api_node.as_mobject(parent)

    runner = command.CommandRunner()

    control_data = kwargs.pop('control_data', None)
    if control_data:
        parent_mobj, shape_mobjs = runner.run(
            'tpDcc-libs-curves-dccs-maya-createCurveFromData',
            curve_data=control_data,
            curve_size=control_size,
            translate_offset=translate_offset,
            scale=scale,
            axis_order=axis_order,
            mirror=mirror,
            parent=parent_mobj)
    else:
        parent_mobj, shape_mobjs = runner.run(
            'tpDcc-libs-curves-dccs-maya-createCurveFromPath',
            curve_type=control_type,
            curves_path=controls_path,
            curve_size=control_size,
            translate_offset=translate_offset,
            scale=scale,
            axis_order=axis_order,
            mirror=mirror,
            parent=parent_mobj)

    if parent_mobj:
        for shape in shape_mobjs:
            api_node.rename_mobject(shape, control_name)
        curve_long_name_list = api_node.names_from_mobject_handles(shape_mobjs)
    else:
        api_node.rename_mobject(shape_mobjs[0], control_name)
        curve_long_name = api_node.names_from_mobject_handles(shape_mobjs)[0]
        curve_long_name_list = [curve_long_name]

    if rotate_offset != (0.0, 0.0, 0.0):
        shape_utils.rotate_node_shape_cvs(curve_long_name_list, rotate_offset)
    if line_width != -1:
        curve.set_curve_line_thickness(curve_long_name_list,
                                       line_width=line_width)

    # TODO: Support index based color
    if color is not None:
        if isinstance(color, int):
            node_utils.set_color(curve_long_name_list, color)
        else:
            node_utils.set_rgb_color(curve_long_name_list,
                                     color,
                                     linear=True,
                                     color_shapes=True)

    transforms = list()
    for curve_shape in curve_long_name_list:
        parent = dcc.node_parent(curve_shape)
        if parent:
            if parent not in transforms:
                transforms.append(parent)
        else:
            if curve_shape not in transforms:
                transforms.append(curve_shape)

    if not parent and transforms:
        if create_buffers and buffers_depth > 0:
            transforms = create_buffer_groups(transforms, buffers_depth)
        if current_selection:
            match_transform = current_selection[0]
            if match_transform and dcc.node_exists(match_transform):
                for transform in transforms:
                    if match_translate:
                        dcc.match_translation(match_transform, transform)
                    if match_rotate:
                        dcc.match_rotation(match_transform, transform)
                    if match_scale:
                        dcc.match_scale(match_transform, transform)

    return transforms
コード例 #14
0
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
コード例 #15
0
    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)
コード例 #16
0
    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