def is_settable(self, valid_connections=None): """ Returns True if the attribute can be set; False otherwise. :param valid_connections: list(str) or None """ valid_connections = python.force_list(valid_connections) if not self.exists(): return False if not dcc.list_attributes(self.fullname, unlocked=True, keyable=True, multi=True, scalar=True): return False connection = dcc.list_connections(self.name, self.attr, destination=False) if connection: connection_type = dcc.node_type(connection) for valid_type in valid_connections: if connection_type.startswith(valid_type): return True return False return True
def match_rotation(source_transform=None, target_transform=None): """ Matches rotation of the source node to the rotation of the given target node(s) """ out_dict = {'success': False, 'result': list()} selection = dcc.selected_nodes_of_type(node_type='transform') source_transform = source_transform or selection[ 0] if python.index_exists_in_list(selection, 0) else None if not source_transform: out_dict[ 'msg'] = 'No source transform given to match against target rotation.' return out_dict target_transform = target_transform or selection[1:] if len( selection) > 1 else None if not source_transform: out_dict[ 'msg'] = 'No target transform(s) given to match source rotation against.' return out_dict source_transform = python.force_list(source_transform) target_transform = python.force_list(target_transform) percentage = 100.0 / len(source_transform) for i, source in enumerate(source_transform): library.Command.progressCommand.emit( percentage * (i + 1), 'Matching rotation: {}'.format(source)) try: maya.cmds.delete( maya.cmds.orientConstraint(target_transform, source, maintainOffset=False)) # For joints, we store now rotation data in jointOrient attribute if dcc.node_type(source) == 'joint': for axis in 'XYZ': joint_orient_attr = 'jointOrient{}'.format(axis) joint_rotation_attr = 'rotate{}'.format(axis) dcc.set_attribute_value(source, joint_orient_attr, 0.0) joint_rotation = dcc.get_attribute_value( source, joint_rotation_attr) dcc.set_attribute_value(source, joint_orient_attr, joint_rotation) dcc.set_attribute_value(source, joint_rotation_attr, 0.0) out_dict['result'].append(source) except Exception as exc: out_dict[ 'msg'] = 'Was not possible to match node "{}" rotation to "{}" : {}'.format( source_transform, target_transform, exc) return out_dict matched_nodes = out_dict.get('result', None) if matched_nodes: dcc.select_node(matched_nodes) out_dict['success'] = True return out_dict
def is_connected(self, ignore_connections=None): """ Returns True if the attribute is connected; False otherwise. :param ignore_connections: list(str) or None :return: bool """ ignore_connections = python.force_list(ignore_connections) try: connection = dcc.list_connections(self.name, self.attr, destination=False) except ValueError: return False if not connection: return False if ignore_connections: connection_type = dcc.node_type(connection) for ignore_type in ignore_connections: if connection_type.startswith(ignore_type): return False return True
def mirror_hierarchy_joints(): """ Mirror hierarchy joints """ out_dict = {'success': False, 'result': dict()} all_joints = list() valid_joints = get_valid_joints() if not valid_joints: out_dict['msg'] = 'No joints to mirror found.' return out_dict for joint in valid_joints: all_joints.append(joint) children = dcc.list_children(joint, full_path=False, children_type='transform') found = list() if children: for child in children: if dcc.node_type(child).find('Constraint') > -1: continue found.append(child) all_joints.extend(found) all_joints = list(set(all_joints)) dcc.mirror_transform(transforms=all_joints, create_if_missing=True) out_dict['success'] = True return out_dict
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
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
def _get_node_types(self): node_types = set() for btn in self._category_buttons: dcc_type = btn.property('dcc_type') if dcc_type: node_types.add(dcc_type) else: dcc_fn = btn.property('dcc_fn') if dcc_fn: dcc_args = btn.property('dcc_args') if dcc.is_maya(): valid_args = dict() for arg_name, arg_value in dcc_args.items(): valid_args[str(arg_name)] = arg_value nodes = getattr(maya.cmds, dcc_fn)(**valid_args) for node in nodes: node_type = dcc.node_type(node) node_types.add(node_type) return list(node_types)
def from_objects(cls, objects, left_side=None, right_side=None, mirror_plane=None): """ Creates a new mirror table instance from the given objects :param objects: list(str) :param left_side: str :param right_side: str :param mirror_plane: MirrorPlane or str :return: MirrorTable """ mirror_plane = mirror_plane or MirrorPlane.YZ if python.is_string(mirror_plane): if mirror_plane.lower() == 'yz': mirror_plane = MirrorPlane.YZ elif mirror_plane.lower() == 'xz': mirror_plane = MirrorPlane.XZ elif mirror_plane.lower() == 'xy': mirror_plane = MirrorPlane.XY if left_side: left_side = left_side.split(',') left_side = [split.strip() for split in left_side] if right_side: right_side = right_side.split(',') right_side = [split.strip() for split in right_side] mirror_table = cls() mirror_table.set_metadata('left', left_side) mirror_table.set_metadata('right', right_side) mirror_table.set_metadata('mirrorPlane', mirror_plane) for obj in objects: node_type = dcc.node_type(obj) if node_type in VALID_NODE_TYPES: mirror_table.add_objects(obj) else: logger.info('Node of type {} is not supported. Node name: {}'.format(node_type, obj)) return mirror_table
def _update_names_list(self, nodes): """ Internal function that updates names list with given node names :param nodes: list(str) """ nodes_to_discard = self._get_nodes_to_discard() or list() nodes = list(set(nodes)) for obj in nodes: if obj in nodes_to_discard: continue node_type = dcc.node_type(obj) if node_type not in self._get_node_types( ) and not self._others_btn.isChecked(): is_valid = False for node_type in self._get_node_types(): is_valid = dcc.check_object_type(obj, node_type, check_sub_types=True) if is_valid: break if not is_valid: continue node_name = dcc.node_short_name(obj) item = QTreeWidgetItem(self._names_list, [node_name]) item.obj = node_name item.preview_name = '' item.full_name = obj if dcc.is_maya(): sel = api.SelectionList() sel.add(obj) item.handle = maya.OpenMaya.MObjectHandle( sel.get_depend_node(0)) self._names_list.addTopLevelItem(item)
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