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
def _save(self): if not self.library_window(): return try: path = self.folder_path() options = self._options_widget.values() name = options.get('name') objects = dcc.selected_nodes(full_path=True) or list() if not path: raise Exception( 'No folder selected. Please select a destination folder') if not name: raise Exception( 'No name specified. Please set a name before saving') if not os.path.exists(self.icon_path()): btn = self.show_thumbnail_capture_dialog() if btn == QDialogButtonBox.Cancel: return path += '/{}'.format(name) icon_path = self.icon_path() self.save(path=path, icon_path=icon_path, objects=objects) except Exception as e: messagebox.MessageBox.critical(self.library_window(), 'Error while saving', str(e)) LOGGER.error(traceback.format_exc()) raise self.library_window().stack.slide_in_index(0)
def swap_skin_weights(source_joint=None, target_joint=None, mesh=None): out_dict = {'success': False, 'result': None} selection = dcc.selected_nodes() source_joint = source_joint or ( selection[0] if python.index_exists_in_list(selection, 0) else None) if not source_joint: out_dict['msg'] = 'No source joint found to swap skin weights from.' return out_dict target_joint = target_joint or ( selection[1] if python.index_exists_in_list(selection, 1) else None) if not target_joint: out_dict['msg'] = 'No target joint found to swap skin weights to.' return out_dict mesh = mesh or (selection[2] if python.index_exists_in_list(selection, 2) else None) if not mesh: out_dict['msg'] = 'No mesh with skinning information found' return out_dict try: result = skin_utils.swap_skin_weights(source_joint, target_joint, mesh) out_dict['result'] = result except Exception as exc: out_dict['msg'] = 'Was not possible to swap skin weights: {}'.format( exc) return out_dict out_dict['success'] = True return out_dict
def search_and_replace(self, data, reply): search_str = data.get('search', '') replace_str = data.get('replace', '') nodes = data.get('nodes', list()) if not nodes: nodes = dcc.selected_nodes() handles_list = list() for obj in nodes: sel = api.SelectionList() sel.add(obj) mobj = sel.get_depend_node(0) handle = maya.api.OpenMaya.MObjectHandle(mobj) handles_list.append(handle) new_name = None for node_handle in handles_list: node = node_handle try: mobj = node_handle.object() dag_path = maya.api.OpenMaya.MDagPath.getAPathTo(mobj) node = dag_path.partialPathName() obj_short_name = dag_path.partialPathName() new_name = obj_short_name.replace(search_str, replace_str) dcc.rename_node(node, new_name) except Exception as exc: LOGGER.warning('Impossible to rename {} >> {} | {}'.format( node, new_name, exc)) reply['success'] = True
def rename_shapes(transform_node=None): """ Rename all shapes under the given transform to match the name of the transform :param transform_node: str, name of a transform """ renamed_shapes = list() transform_node = python.force_list(transform_node or dcc.selected_nodes()) for node in transform_node: node_shapes = list() short_name = name_utils.get_short_name(node) shapes = get_shapes(node) if shapes: node_shapes.append( maya.cmds.rename(shapes[0], '{}Shape'.format(short_name))) if len(shapes) > 1: i = 1 for s in shapes[1:]: node_shapes.append( maya.cmds.rename(s, '{}Shape{}'.format(short_name, i))) i += 1 renamed_shapes.append(node_shapes) return renamed_shapes
def select_hierarchy(data, reply): sel = dcc.selected_nodes() for obj in sel: dcc.select_hierarchy(obj, add=True) reply['success'] = True
def set_local_rotation_axis(data, reply): state = data.get('state', False) sel = dcc.selected_nodes() for obj in sel: if dcc.attribute_exists(obj, 'displayLocalAxis'): dcc.set_attribute_value(obj, 'displayLocalAxis', state) reply['success'] = True
def ls(cls, objects=None, selection=False): if objects is None and not selection: objects = dcc.all_scene_nodes(full_path=False) else: objects = objects or list() if selection: objects.extend(dcc.selected_nodes(full_path=False) or []) return [cls(name) for name in objects]
def delete_unused_influences(skinned_objects=None): out_dict = {'success': False, 'result': list()} skinned_objects = skinned_objects or dcc.selected_nodes() skinned_objects = python.force_list(skinned_objects) if not skinned_objects: out_dict['msg'] = 'No components to extract from found.' return out_dict percentage = 100.0 / len(skinned_objects) for i, mesh in enumerate(skinned_objects): try: library.Command.progressCommand.emit( percentage * (i + 1), 'Deleting unused influences: {}'.format(mesh)) skin_cluster_name = skin_utils.find_related_skin_cluster(mesh) if not skin_cluster_name: shape = maya.cmds.listRelatives(mesh, shapes=True) or None if shape: LOGGER.warning( 'Impossible to delete unused influences because mesh "{}" ' 'has no skin cluster attached to it!'.format(mesh)) continue attached_joints = maya.cmds.skinCluster(skin_cluster_name, query=True, influence=True) weighted_joints = maya.cmds.skinCluster(skin_cluster_name, query=True, weightedInfluence=True) non_influenced = list() for attached in attached_joints: if attached in weighted_joints: continue non_influenced.append(attached) for joint in non_influenced: maya.cmds.skinCluster(skin_cluster_name, edit=True, removeInfluence=joint) out_dict['result'].append(mesh) except Exception as exc: out_dict[ 'msg'] = 'Was not possible to delete unused influences: "{}" | {}'.format( skinned_objects, exc) return out_dict return out_dict
def _before_load(self, clear_selection=True): """ Internal function that is called before loading the pose :param clear_selection: """ logger.debug('Before Load Pose "{}"'.format(self.path)) if not self._is_loading: self._is_loading = True dcc.enable_undo() self._selection = dcc.selected_nodes() or list() self._auto_key_frame = dcc.is_auto_keyframe_enabled() dcc.set_auto_keyframe_enabled(False) if clear_selection: dcc.clear_selection()
def simple_rename(self, data, reply): new_name = data.get('new_name', '') if not new_name: reply[ 'msg'] = 'Please type a new name and try the operation again!' reply['success'] = False return rename_shape = data.get('rename_shape', True) nodes = data.get('nodes', list()) if not nodes: nodes = dcc.selected_nodes() for node in nodes: dcc.rename_node(node, new_name, rename_shape=rename_shape) reply['success'] = True
def get_objects_to_rename(hierarchy_check, selection_type, uuid=False): search_hierarchy = hierarchy_check search_selection = True if selection_type == 0 else False if not search_selection: objs_to_rename = dcc.all_scene_nodes(full_path=True) else: objs_to_rename = dcc.selected_nodes(full_path=True) if not objs_to_rename: LOGGER.warning('No objects to rename!') return if search_hierarchy: children_list = list() for obj in objs_to_rename: children = dcc.list_children(obj, all_hierarchy=True, full_path=True) if children: children_list.extend(children) children_list = list(set(children_list)) objs_to_rename.extend(children_list) if uuid and dcc.is_maya(): import tpDcc.dccs.maya as maya handles_list = list() # objs_to_rename = [obj for obj in objs_to_rename if dcc.node_type(obj) == 'transform'] for obj in objs_to_rename: mobj = maya.OpenMaya.MObject() sel = maya.OpenMaya.MSelectionList() sel.add(obj) sel.getDependNode(0, mobj) handle = maya.OpenMaya.MObjectHandle(mobj) handles_list.append(handle) return handles_list else: # We reverse the list so we update first children and later parents, otherwise we will have # problems during renaming if we use full paths objs_to_rename.reverse() return objs_to_rename
def save(self, thumbnail='', **kwargs): """ Saves all the given data to the item path on disk :param thumbnail: str :param kwargs: dict """ LOGGER.debug('Saving {} | {}'.format(self.path, kwargs)) super(SkeletonFileData, self).save(thumbnail=thumbnail, **kwargs) objects = kwargs.get('objects', None) if not objects: objects = dcc.selected_nodes(full_path=True) if not objects: LOGGER.warning( 'Select root node of the skeleton to export or the list of skeleton nodes to export' ) return False
def detach_edges(edges=None): """ Detach selected edges in different groups """ # make list of edges, that belong to certain object def _group_edges(obj, edges_list): return [item for item in edges_list if re.match(obj, item)] out_dict = {'success': False, 'result': list()} valid_edges = list() selection = edges or dcc.selected_nodes() selection = python.force_list(selection) for obj in selection: obj_type = maya.cmds.nodeType(obj) if obj_type == 'transform': continue is_edge = maya.cmds.filterExpand(sm=32) if is_edge is None: continue valid_edges.append(obj) if not valid_edges: out_dict['msg'] = 'No edges to detach selected.' return out_dict obj_list = [edge.split('.')[0] for edge in valid_edges] edge_list = [_group_edges(obj, valid_edges) for obj in obj_list] try: for edge_group in edge_list: maya.cmds.select(edge_group) maya.cmds.polySplitEdge() out_dict['result'].append(edge_group) except Exception as exc: out_dict['msg'] = 'Was not possible to detach edges "{}" : '.format( valid_edges, exc) return out_dict out_dict['success'] = True return out_dict
def detach_components(components=None): """ Detach selected components """ out_dict = {'success': False, 'result': list()} selection = components or dcc.selected_nodes() if not selection: out_dict['msg'] = 'No components to detach selected.' return out_dict try: maya.cmds.DetachComponent() except Exception as exc: out_dict[ 'msg'] = 'Was not possible to detach components "{}" : '.format( selection, exc) return out_dict out_dict['success'] = True return out_dict
def extract_skinned_selected_components(selected_components=None, **kwargs): out_dict = {'success': False, 'result': None} components = selected_components or dcc.selected_nodes(flatten=True) components = python.force_list(components) if not components: out_dict['msg'] = 'No components to extract from found.' return out_dict try: result = skin_utils.extract_skinned_selected_components( components, **kwargs) out_dict['result'] = result except Exception as exc: out_dict[ 'msg'] = 'Was not possible to transfers UVs to skinned geometry: {}'.format( exc) return out_dict out_dict['success'] = True return out_dict
def refresh(self, selected_objects=False, hierarchy=False): self._names_list.clear() self._names_list.setSortingEnabled(True) try: objs_names = list() if not selected_objects: objs_names.extend(dcc.all_scene_nodes(full_path=True)) else: objs_names.extend(dcc.selected_nodes(full_path=True)) if objs_names and hierarchy: children_list = list() for obj in objs_names: children = dcc.list_children(obj, all_hierarchy=True, full_path=True) if children: children_list.extend(children) children_list = list(set(children_list)) objs_names.extend(children_list) self._update_names_list(objs_names) self._on_filter_names_changed(self._names_filter.get_text()) finally: self._names_list.setSortingEnabled(False)
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
def solve_node_name_by_type(node_names=None, naming_file=None, dev=False, **kwargs): """ Resolves node name taking into account its type In this case, the type of the node will be used to retrieve an an automatic rule The rule name will be retrieved using auto_suffix dict from tpDcc-naming configuration file :param node_names: str or list, name of the node we want to take name of :param naming_file: str :param dev: bool :return: str """ if not dcc.is_maya(): LOGGER.warning( 'Solve Node Name by type functionality is only supported in Maya!') return None import maya.cmds from tpDcc.dccs.maya.core import name name_lib = init_lib(naming_file=naming_file, dev=dev) auto_suffix = get_auto_suffixes() if not auto_suffix: LOGGER.warning( 'Impossible to launch auto suffix functionality because no auto suffixes are defined!' ) return None solved_names = dict() return_names = list() if not node_names: node_names = dcc.selected_nodes() if not node_names: return node_names = python.force_list(node_names) for obj_name in node_names: obj_uuid = maya.cmds.ls(obj_name, uuid=True) if not obj_uuid: continue obj_uuid = obj_uuid[0] if obj_uuid in solved_names: LOGGER.warning( 'Node with name: "{} and UUID "{}" already renamed to "{}"! Skipping ...' .format(obj_name, obj_uuid, solved_names[obj_name])) continue # TODO: This code is a duplicated version of the one in # tpDcc.dccs.maya.core.name.auto_suffix_object function. Move this code to a DCC specific function obj_type = maya.cmds.objectType(obj_name) if obj_type == 'transform': shape_nodes = maya.cmds.listRelatives(obj_name, shapes=True, fullPath=True) if not shape_nodes: obj_type = 'group' else: obj_type = maya.cmds.objectType(shape_nodes[0]) elif obj_type == 'joint': shape_nodes = maya.cmds.listRelatives(obj_name, shapes=True, fullPath=True) if shape_nodes and maya.cmds.objectType( shape_nodes[0]) == 'nurbsCurve': obj_type = 'controller' if obj_type == 'nurbsCurve': connections = maya.cmds.listConnections( '{}.message'.format(obj_name)) if connections: for node in connections: if maya.cmds.nodeType(node) == 'controller': obj_type = 'controller' break if obj_type not in auto_suffix: rule_name = 'node' node_type = obj_type else: rule_name = auto_suffix[obj_type] node_type = auto_suffix[obj_type] if not name_lib.has_rule(rule_name): if not name_lib.has_rule('node'): LOGGER.warning( 'Impossible to rename node "{}" by its type "{}" because rule "{}" it is not defined and ' 'callback rule "node" either'.format( obj_name, obj_type, rule_name)) else: rule_name = 'node' if rule_name == 'node': solved_name = solve_name(obj_name, node_type=node_type, rule_name=rule_name, **kwargs) else: solved_name = solve_name(rule_name, obj_name, rule_name=rule_name, **kwargs) solved_names[obj_uuid] = solved_name if not solved_names: return unique_name = kwargs.get('unique_name', False) for obj_id, solved_name in solved_names.items(): obj_name = maya.cmds.ls(obj_id, long=True)[0] if not solved_names: return_names.append(obj_name) else: if unique_name: solved_name = dcc.find_unique_name(solved_name) new_name = name.rename(obj_name, solved_name, uuid=obj_id, rename_shape=True) return_names.append(new_name) return return_names
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