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 _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_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'))
def separate_meshes(meshes=None, new_mesh_name=None): """ Separates 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 separate selected.' return out_dict new_mesh_name = new_mesh_name or dcc.node_short_name(meshes[0]) try: result_meshes = list() separated_meshes = dcc.separate_meshes(construction_history=False) if not separated_meshes: out_dict[ 'msg'] = 'Separate operation was done but not separated mesh was generated' return out_dict for separated_mesh in separated_meshes: separated_mesh = dcc.rename_node(separated_mesh, new_mesh_name) result_meshes.append(separated_mesh) out_dict['result'] = result_meshes except Exception as exc: out_dict[ 'msg'] = 'Was not possible to separate meshes "{}" : {}'.format( meshes, exc) return out_dict out_dict['success'] = True return out_dict
def _create_blendshape_setup(self): if not self._nurbs_plane: return self._nurbs_blendshape_plane = dcc.duplicate_node( self._nurbs_plane, new_node_name=self._get_name('flexiPlaneBshp', node_type='surface'))[0] dcc.move_node(self._nurbs_blendshape_plane, 0, 0, -self._num_joints) self._nurbs_blendshape_node = blendshape.create( self._nurbs_plane, self._nurbs_blendshape_plane, name=self._get_name('flexiPlane', node_type='blendShape')) dcc.set_attribute_value(self._nurbs_blendshape_node, self._nurbs_blendshape_plane, 1.0) # Rename blendshape tweak node nurbs_plane_shape = dcc.list_shapes(self._nurbs_plane)[0] bs_tweak = maya.cmds.listConnections(nurbs_plane_shape, type='tweak')[0] dcc.rename_node(bs_tweak, self._get_name('flexiPlaneBshp', node_type='tweak'))
def rename(self, **kwargs): hierarchy_check = self._model.hierarchy_check selection_type = self._model.selection_type nodes = utils.get_objects_to_rename(hierarchy_check=hierarchy_check, selection_type=selection_type, uuid=True) generated_names = self.generate_names(items=nodes, **kwargs) if not generated_names or len(nodes) != len(generated_names): LOGGER.warning('Impossible to rename because was impossible to generate some of the names ...') return if dcc.is_maya(): import maya.api.OpenMaya for item, new_name in zip(nodes, generated_names): if dcc.is_maya(): mobj = None if hasattr(item, 'handle'): mobj = item.handle.object() elif hasattr(item, 'object'): mobj = item.object() if mobj: try: dag_path = maya.api.OpenMaya.MDagPath.getAPathTo(mobj) full_name = dag_path.fullPathName() except Exception as exc: if hasattr(item, 'full_name'): full_name = item.full_name else: LOGGER.warning('Impossible to retrieve Maya node full path: {}'.format(item)) continue else: full_name = item else: if hasattr(item, 'full_name'): full_name = item.full_name else: full_name = item try: dcc.rename_node(full_name, new_name) if hasattr(item, 'obj') and hasattr(item, 'preview_name'): item.obj = item.preview_name item.preview_name = '' except Exception: LOGGER.error('Impossible to rename: {} to {} | {}'.format(full_name, new_name, traceback.format_exc()))
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 _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')
def remove_last(self, data, reply): num_to_remove = data.get('count', 0) rename_shape = data.get('rename_shape', True) search_hierarchy = data.get('hierarchy_check', False) selection_only = data.get('only_selection', True) filter_type = data.get('filter_type', None) if not num_to_remove > 0: msg = 'Specify a number of characters to remove greater than zero ({})'.format( num_to_remove) LOGGER.warning(msg) reply['success'] = False reply['msg'] = msg return if not search_hierarchy and not selection_only: msg = 'Remove last must be used with "Selected" options not with "All"' LOGGER.warning(msg) reply['success'] = False reply['msg'] = msg return filtered_obj_list = dcc.filter_nodes_by_type( filter_type=filter_type, search_hierarchy=search_hierarchy, selection_only=selection_only) for obj in filtered_obj_list: original_name = dcc.node_short_name(obj) new_name = obj[:-num_to_remove] if not new_name: LOGGER.warning( 'Impossible to rename {}. Total characters to remove is greater or equal than ' 'the original name length: {} >= {}'.format( original_name, num_to_remove, len(original_name))) continue dcc.rename_node(obj, new_name, rename_shape=rename_shape) reply['success'] = True
def set_shape(crv, crv_shape_list, size=None, select_new_shape=False, keep_color=False): """ Creates a new shape on the given curve :param crv: :param crv_shape_list: :param size: :param select_new_shape: bool :param keep_color: bool """ crv_shapes = controlutils.validate_curve(crv) orig_size = None orig_color = None if crv_shapes: orig_size = dcc.node_bounding_box_size(crv) # If there are multiple shapes, we only take into account the color of the first shape orig_color = dcc.node_color(crv_shapes[0]) if crv_shapes: dcc.delete_node(crv_shapes) for i, c in enumerate(crv_shape_list): new_shape = dcc.list_shapes(c)[0] new_shape = dcc.rename_node( new_shape, dcc.node_short_name(crv) + 'Shape' + str(i + 1).zfill(2)) dcc.enable_overrides(new_shape) if orig_color is not None and keep_color: dcc.set_node_color(new_shape, orig_color) dcc.combine_shapes(crv, new_shape, delete_after_combine=True) new_size = dcc.node_bounding_box_size(crv) if orig_size and new_size: scale_size = orig_size / new_size dcc.scale_shapes(crv, scale_size, relative=False) if size: dcc.scale_shapes(crv, size, relative=True) if select_new_shape: dcc.select_node(crv) return crv
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
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
def auto_rename(self, tokens_dict, unique_id=True, last_joint_end=True): import maya.cmds active_rule = self._model.active_rule if not active_rule: LOGGER.warning('Impossible to auto rename because no active rule defined.') return False rule_name = active_rule.name hierarchy_check = self._model.hierarchy_check selection_type = self._model.selection_type rename_shape = self._model.rename_shape objs_to_rename = utils.get_objects_to_rename( hierarchy_check=hierarchy_check, selection_type=selection_type, uuid=False) or list() if not objs_to_rename: LOGGER.warning('No objects to rename. Please select at least one object!') return False # generated_names = self.generate_names(items=objs_to_rename, **kwargs) if not self._naming_lib.has_rule(rule_name): return False current_rule = self._naming_lib.active_rule() self._naming_lib.set_active_rule(rule_name) # TODO: Naming config should be define the name of the rule to use when using auto renaming solved_names = dict() if rule_name == 'node' and self._model.config: auto_suffix = self._model.naming_config.get('auto_suffixes', default=dict()) if auto_suffix: solved_names = dict() for i, obj_name in enumerate(reversed(objs_to_rename)): obj_uuid = maya.cmds.ls(obj_name, uuid=True)[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' else: children = dcc.list_children(obj_name) if not children and last_joint_end: obj_type = 'jointEnd' 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 'node_type' in tokens_dict and tokens_dict['node_type']: node_type = tokens_dict.pop('node_type') node_name = dcc.node_short_name(obj_name) if 'description' in tokens_dict and tokens_dict['description']: description = tokens_dict['description'] else: description = node_name side = tokens_dict.get('side', None) if unique_id: solved_name = self._naming_lib.solve( description, side=side, node_type=node_type, id=i) else: solved_name = self._naming_lib.solve( description, side=side, node_type=node_type) if not solved_name: continue solved_name = dcc.find_unique_name(solved_name) solved_names[obj_uuid] = solved_name if solved_names: for obj_id, solved_name in solved_names.items(): obj_name = maya.cmds.ls(obj_id, long=True)[0] dcc.rename_node(obj_name, solved_name, uuid=obj_id, rename_shape=rename_shape) else: for obj_name in objs_to_rename: solve_name = self._naming_lib.solve(**tokens_dict) if not solve_name: LOGGER.warning( 'Impossible to rename "{}" with rule "{}" | "{}"'.format(obj_name, rule_name, tokens_dict)) continue try: dcc.rename_node(obj_name, solve_name, rename_shape=rename_shape) except Exception as exc: LOGGER.error('Impossible to rename "{}" to "{}" | {}'.format(obj_name, solve_name, exc)) continue if current_rule: self._naming_lib.set_active_rule(current_rule.name)