def get_controls(**kwargs): """ Returns all controls in current scene Checks for the following info: - Check if the controls start with a control prefx or ends with a control suffix - Check if the controls have a specific control attribute - Check if a transform has an attribute called tag (with value) and the transform has a nurbsCurve at least :param namespace: str, only controls with the given namespace will be search. :return: list(str), list of control names """ namespace = kwargs.get('namespace', '') name = '{}:*'.format(namespace) if namespace else '*' transforms = dcc.list_nodes(name, node_type='transform', full_path=False) joints = dcc.list_nodes(name, node_type='joint', full_path=False) if joints: transforms += joints found = list() found_with_value = list() for transform_node in transforms: if is_control(transform_node, only_tagged=True, **kwargs): found_with_value.append(transform_node) elif is_control(transform_node, only_tagged=False, **kwargs): found.append(transform_node) return found_with_value if found_with_value else found
def _get_nodes_to_discard(self): """ Internal function that returns list of nodes that should be discarded during renaming process """ discard_nodes = self._default_nodes_to_discard[:] or list() if self._hide_default_scene_nodes_cbx and self._hide_default_scene_nodes_cbx.isChecked( ): discard_nodes.extend(dcc.default_scene_nodes(full_path=False)) # discard_nodes.extend(dcc.list_nodes(node_type='camera')) for btn in self._category_buttons: if not btn.isChecked(): dcc_type = btn.property('dcc_type') if dcc_type: discard_nodes.extend( dcc.list_nodes(node_type=btn.property('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) discard_nodes.extend(nodes) return list(set(discard_nodes))
def restore_to_bind_pose(skinned_mesh=None): out_dict = {'success': False, 'result': None} skinned_meshes = skinned_mesh or dcc.selected_nodes_of_type('transform') skinned_meshes = python.force_list(skinned_meshes) if not skinned_meshes: skinned_meshes = list() meshes = dcc.list_nodes(node_type='mesh') for mesh in meshes: skinned_meshes.append( maya.cmds.listRelatives(mesh, parent=True)[0]) if not skinned_meshes: out_dict['msg'] = 'No skinned meshes to restore bind poses of found.' return out_dict try: result = skin_utils.restore_to_bind_pose(skinned_mesh) out_dict['result'] = result except Exception as exc: out_dict[ 'msg'] = 'Was not possible to restore skinned mesh to bind pose: {}'.format( exc) return out_dict out_dict['success'] = True return out_dict
def to_short_name(self): names = dcc.list_nodes(node_name=self.short_name()) if len(names) == 1: return Node(names[0]) elif len(names) > 1: raise exceptions.MoreThanOneObjectFoundError( 'More than one object found {}'.format(str(names))) else: raise exceptions.NoObjectFoundError('No object found {}'.format( self.short_name()))
def refresh(self): """ Syncs view to the current state of its model """ self._hierarchy_cbx.setChecked(self._model.hierarchy_check) self._node_types_combo.clear() for btn in self._buttons_grp.buttons(): self._buttons_grp.removeButton(btn) node_types = self._model.node_types if not node_types: self._node_types_combo.setVisible(False) else: self._node_types_combo.setVisible(True) for node_type in node_types: self._node_types_combo.addItem(str(node_type).split('.')[-1]) categories = self._model.categories or dict() nodes_to_discard = self._model.nodes_to_discard types_to_discard = self._model.types_to_discard for node_type in types_to_discard: nodes_to_discard.extend(dcc.list_nodes(node_type=node_type)) for i, category in enumerate(categories): for category_name, category_data in category.items(): title = category_data.get('title', category) icon = category_data.get('icon', None) types = category_data.get('types', dict()) category_btn = buttons.BaseButton(title) category_btn.setCheckable(True) if icon: category_btn.setIcon(resources.icon(icon)) if i == 0: category_btn.setChecked(True) self._buttons_grp.addButton(category_btn) self._categories_layout.addWidget(category_btn) category_widget = categorywidget.CategoryWidget( types=types, nodes_to_discard=nodes_to_discard) self._stack.addWidget(category_widget) # category_widget.doRefresh.connect(self._on_refresh_category) # category_widget.doPreview.connect(self._set_preview_names) # category_widget.togglePreview.connect(self.update_current_items) # category_widget.doRename.connect(self._on_rename) # category_btn.clicked.connect(partial(self._on_category_selected, i + 1)) self._auto_rename_widget.refresh() self._controller.update_rules()
def get_valid_joints(joints=None): valid_joints = list() joints = joints or dcc.selected_nodes_of_type(node_type='joint', full_path=False) joints = python.force_list(joints) for joint in joints: if not dcc.object_type(joint) == 'joint': continue valid_joints.append(joint) if not valid_joints: valid_joints = dcc.list_nodes(node_type='joint') return valid_joints
def zero_joint_orient_all_joints(): """ Zeroes out the orient of all joints in current scene """ out_dict = {'success': False, 'result': dict()} all_joints = dcc.list_nodes(node_type='joint', full_path=False) if not all_joints: out_dict['msg'] = 'No joints to remove orient data from found.' return out_dict joint_utils.OrientJointAttributes.zero_orient_joint(all_joints) out_dict['success'] = True return out_dict
def mirror_all_joints(): """ Mirror all joints in current scene """ out_dict = {'success': False, 'result': dict()} all_joints = dcc.list_nodes(node_type='joint', full_path=False) if not all_joints: out_dict['msg'] = 'No joints to mirror found.' return out_dict dcc.mirror_transform(all_joints, create_if_missing=True) out_dict['success'] = True return out_dict
def add_orient_data_all_joints(): """ Add orient data to all joints in current scene """ out_dict = {'success': False, 'result': dict()} all_joints = dcc.list_nodes(node_type='joint', full_path=False) if not all_joints: out_dict['msg'] = 'No joints to add orient data to found.' return out_dict joint_utils.OrientJointAttributes.add_orient_attributes(all_joints) out_dict['success'] = True return out_dict
def zero_joint_orient(joints=None): """ Zeroes out the data of joints """ out_dict = {'success': False, 'result': dict()} valid_joints = get_valid_joints(joints) if not valid_joints: valid_joints = dcc.list_nodes(node_type='joint') if not valid_joints: out_dict['msg'] = 'No joints to zero out orient of found.' return out_dict joint_utils.OrientJointAttributes.zero_orient_joint(valid_joints) out_dict['success'] = True return out_dict
def mirror_joints(joints=None): """ Mirror joints """ out_dict = {'success': False, 'result': dict()} valid_joints = get_valid_joints(joints) if not valid_joints: valid_joints = dcc.list_nodes(node_type='joint') if not valid_joints: out_dict['msg'] = 'No joints to mirror found.' return out_dict dcc.mirror_transform(valid_joints) out_dict['success'] = True return out_dict
def orient_all_joints(force_orient_attributes=True): """ Orients all joints :param force_orient_attributes: bool, Whether to force the orientation through OrientJointAttributes or not """ out_dict = {'success': False, 'result': dict()} all_joints = dcc.list_nodes(node_type='joint', full_path=False) if not all_joints: out_dict['msg'] = 'No joints to orient found.' return out_dict dcc.orient_joints(joints_to_orient=all_joints, force_orient_attributes=force_orient_attributes) out_dict['success'] = True return out_dict
def clean_orient_data(joints=None): """ Clean orient data from joints """ out_dict = {'success': False, 'result': dict()} valid_joints = get_valid_joints(joints) if not valid_joints: valid_joints = dcc.list_nodes(node_type='joint') if not valid_joints: out_dict['msg'] = 'No joints to remove orient data from found.' return out_dict joint_utils.OrientJointAttributes.remove_orient_attributes(valid_joints) out_dict['success'] = True return out_dict
def add_orient_data(joints=None): """ Add orient data to joints """ out_dict = {'success': False, 'result': dict()} valid_joints = get_valid_joints(joints) if not valid_joints: valid_joints = dcc.list_nodes(node_type='joint') if not valid_joints: out_dict['msg'] = 'No joints to add orient data to found.' return out_dict joint_utils.OrientJointAttributes.add_orient_attributes(valid_joints) out_dict['success'] = True return out_dict
def orient_joints(joints=None, force_orient_attributes=True): """ Orients all joints that have OrientJointAttributes added :param joints: list(str) or None :param force_orient_attributes: bool, Whether to force the orientation through OrientJointAttributes or not """ out_dict = {'success': False, 'result': dict()} valid_joints = get_valid_joints(joints) if not valid_joints: valid_joints = dcc.list_nodes(node_type='joint') if not valid_joints: out_dict['msg'] = 'No joints to orient found.' return out_dict dcc.orient_joints(joints_to_orient=valid_joints, force_orient_attributes=force_orient_attributes) out_dict['success'] = True return out_dict
def _import_skin_weights(self, data_path, mesh): if not dcc.node_exists(mesh) or not os.path.isdir(data_path): return False try: if not dcc.is_plugin_loaded('ngSkinTools2'): dcc.load_plugin('ngSkinTools2') import ngSkinTools2 from ngSkinTools2 import api as ngst_api except ImportError: logger.warning( 'NgSkinTools 2.0 is not installed. Impossible to import ngSkin data' ) return False ng_skin_data_path = path_utils.join_path(data_path, 'ngdata.json') if not path_utils.is_file(ng_skin_data_path): logger.warning( 'No Ng Skin Data file found: "{}", aborting import skin weights operation ...' .format(ng_skin_data_path)) return False is_valid_mesh = False shape_types = ['mesh', 'nurbsSurface', 'nurbsCurve', 'lattice'] for shape_type in shape_types: if shape_utils.has_shape_of_type(mesh, shape_type): is_valid_mesh = True break if not is_valid_mesh: logger.warning( 'Node "{}" is not a valid mesh node! Currently supported nodes include: {}' .format(mesh, shape_types)) return False logger.info('Importing skin clusters {} --> "{}"'.format( mesh, data_path)) influence_dict = self._get_influences(data_path) if not influence_dict: logger.warning('No influences data found for: {}'.format(mesh)) return False influences = influence_dict.keys() if not influences: logger.warning('No influences found for: "{}"'.format(mesh)) return False influences.sort() logger.debug('Influences found for {}: {}'.format(mesh, influences)) short_name = dcc.node_short_name(mesh) transfer_mesh = None if shape_utils.has_shape_of_type(mesh, 'mesh'): orig_mesh = self._import_mesh_obj(data_path) if orig_mesh: mesh_match = geo_utils.is_mesh_compatible(orig_mesh, mesh) if not mesh_match: transfer_mesh = mesh mesh = orig_mesh else: dcc.delete_node(orig_mesh) # Check if there are duplicated influences and also for the creation of influences that does not currently # in the scene add_joints = list() remove_entries = list() for influence in influences: joints = dcc.list_nodes(influence, full_path=True) if type(joints) == list and len(joints) > 1: add_joints.append(joints[0]) conflicting_count = len(joints) logger.warning( 'Found {} joints with name {}. Using only the first one: {}' .format(conflicting_count, influence, joints[0])) remove_entries.append(influence) influence = joints[0] if not dcc.node_exists(influence): dcc.clear_selection() dcc.create_joint( name=influence, position=influence_dict[influence]['position']) for entry in remove_entries: influences.remove(entry) influences += add_joints settings_data = dict() settings_path = path_utils.join_path(data_path, 'settings.info') if path_utils.is_file(settings_path): lines = fileio.get_file_lines(settings_path) for line in lines: test_line = line.strip() if not test_line: continue line_list = eval(line) attr_name = line_list[0] value = line_list[1] settings_data[attr_name] = value # Create skin cluster and removes if it already exists skin_cluster = deform_utils.find_deformer_by_type(mesh, 'skinCluster') if skin_cluster: dcc.delete_node(skin_cluster) skin_node_name = settings_data.pop('skinNodeName', 'skin_{}'.format(short_name)) skin_cluster = maya.cmds.skinCluster( influences, mesh, tsb=True, n=dcc.find_unique_name(skin_node_name))[0] dcc.set_attribute_value(skin_cluster, 'normalizeWeights', 0) skin_utils.set_skin_weights_to_zero(skin_cluster) # TODO: This Influence mapping configuration should be generated during export and imported here as JSON file # Import ng skin data config = ngst_api.InfluenceMappingConfig() config.use_distance_matching = True config.use_label_matching = True config.use_name_matching = True ngst_api.import_json(mesh, file=ng_skin_data_path, influences_mapping_config=config) maya.cmds.skinCluster(skin_cluster, edit=True, normalizeWeights=1) maya.cmds.skinCluster(skin_cluster, edit=True, forceNormalizeWeights=True) for attr_name, value in settings_data.items(): if attr_name == 'blendWeights': skin_utils.set_skin_blend_weights(skin_cluster, value) else: if dcc.attribute_exists(skin_cluster, attr_name): dcc.set_attribute_value(skin_cluster, attr_name, value) if transfer_mesh: logger.info( 'Import sking weights: mesh topology does not match. Trying to transfer topology ...' ) skin_utils.skin_mesh_from_mesh(mesh, transfer_mesh) dcc.delete_node(mesh) logger.info('Import skinCluster weights: {} from {}'.format( short_name, data_path)) return True
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