def create_skeleton(character_name='Character1', attrs_dict=None): """ Creates a new HumanIk skeleton """ if attrs_dict is None: attrs_dict = dict() sync_skeleton_generator_from_ui() create_character(character_name=character_name, lock=False) current_name = get_current_character() if not current_name: return False skeleton_generator_node = create_skeleton_generator_node(current_name) if not skeleton_generator_node: logger.warning('Was not possible to create HIK Skeleton Generator node.') return False load_default_human_ik_pose_onto_skeleton_generator_node(skeleton_generator_node) set_skeleton_generator_defaults(skeleton_generator_node) set_skeleton_generator_attrs(skeleton_generator_node, attrs_dict) reset_current_source() # If we have no characters yet, select the newly created character to refresh both the character and sources list dcc.select_node(current_name) update_current_character_from_scene() update_definition_ui() select_skeleton_tab() return True
def load(self, *args, **kwargs): objects = kwargs.get('objects', None) namespaces = kwargs.get('namespaces', None) valid_nodes = list() target_objects = objects source_objects = self.objects() self.validate(namespaces=namespaces) matches = utils.match_names(source_objects, target_objects=target_objects, target_namespaces=namespaces) for source_node, target_node in matches: if '*' in target_node.name(): valid_nodes.append(target_node.name()) else: target_node.strip_first_pipe() try: target_node = target_node.to_short_name() except exceptions.NoObjectFoundError as exc: logger.warning(exc) continue except exceptions.MoreThanOneObjectFoundError as exc: logger.warning(exc) valid_nodes.append(target_node.name()) if valid_nodes: dcc.select_node(valid_nodes, **kwargs) dcc.focus_ui_panel('MayaWindow') else: raise exceptions.NoMatchFoundError( 'No objects match when loading selection set data')
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 selection_mirror(self, data, reply): selected_geo = data['geo'] selected_vertices = data['selected_vertices'] symmetry_table = data['symmetry_table'] mirror_vertices = list() dcc.enable_wait_cursor() try: for selected_vertex in selected_vertices: vert_num = int( re.search(r'\[(\w+)\]', selected_vertex).group(1)) mirror_vert_num = consts.get_mirror_vertex_index( symmetry_table, vert_num) if mirror_vert_num != -1: mirror_vertices.append( dcc.node_vertex_name(selected_geo, mirror_vert_num)) else: mirror_vertices.append( dcc.node_vertex_name(selected_geo, vert_num)) if mirror_vertices: dcc.select_node(mirror_vertices) reply['success'] = True except Exception as exc: logger.error('Error while selecting mirror: {} | {}'.format( exc, traceback.format_exc())) reply['success'] = False finally: dcc.disable_wait_cursor() reply['result'] = mirror_vertices
def select_controls(**kwargs): """ Select all controls in current scene """ namespace = kwargs.get('namespace', '') all_controls = get_controls(namespace=namespace, **kwargs) if not all_controls: return dcc.select_node(all_controls)
def freeze_skinned_mesh(skinned_mesh, **kwargs): out_dict = {'success': False, 'result': list()} meshes = skinned_mesh or dcc.selected_nodes_of_type('transform') meshes = python.force_list(meshes) if not meshes: return False if kwargs.pop('auto_assign_labels', False): joint_utils.auto_assign_labels_to_mesh_influences( meshes, input_left=kwargs.pop('left_side_label', None), input_right=kwargs.pop('right_side_label', None), check_labels=True) percentage = 100.0 / len(meshes) for i, mesh in enumerate(meshes): library.Command.progressCommand.emit( percentage * (i + 1), 'Cleaning Skinned Mesh: {}'.format(mesh)) try: skin_cluster_name = skin_utils.find_related_skin_cluster(mesh) if not skin_cluster_name: continue attached_joints = maya.cmds.skinCluster(skin_cluster_name, query=True, inf=True) mesh_shape_name = maya.cmds.listRelatives(mesh, shapes=True)[0] out_influences_array = api_skin.get_skin_weights( skin_cluster_name, mesh_shape_name) maya.cmds.skinCluster(mesh_shape_name, edit=True, unbind=True) maya.cmds.delete(mesh, ch=True) maya.cmds.makeIdentity(mesh, apply=True) new_skin_cluster_name = maya.cmds.skinCluster( attached_joints, mesh, toSelectedBones=True, bindMethod=0, normalizeWeights=True)[0] api_skin.set_skin_weights(new_skin_cluster_name, mesh_shape_name, out_influences_array) out_dict['result'].append(mesh) except Exception as exc: out_dict[ 'msg'] = 'Was not possible to freeze skinned meshes: "{}" | {}'.format( meshes, exc) return out_dict dcc.select_node(meshes) out_dict['success'] = True return out_dict
def select_moved_vertices(self, data, reply): obj = data['geo'] base_obj = data['base_geo'] tolerance = data['tolerance'] moved_vertices = list() total_vertices = dcc.total_vertices(obj) dcc_progress_bar = progressbar.ProgressBar(title='Working', count=total_vertices) dcc_progress_bar.status('Checking Verts') mod = math.ceil(total_vertices / 50) dcc.enable_wait_cursor() try: for i in range(total_vertices): if i % mod == 0: prog_num = i prog = (prog_num / total_vertices) * 100.0 dcc_progress_bar.inc(prog) vtx = dcc.node_vertex_name(obj, i) vec1 = mathlib.Vector( *dcc.node_vertex_object_space_translation(base_obj, i)) vec2 = mathlib.Vector( *dcc.node_vertex_object_space_translation(obj, i)) if mathlib.get_distance_between_vectors(vec1, vec2) > tolerance: moved_vertices.append(vtx) if len(moved_vertices) > 0: dcc.select_node(obj) dcc.enable_component_selection() dcc.select_node(moved_vertices, replace_selection=False) reply['success'] = True except Exception as exc: logger.error( 'Error while selecting moving vertices: {} | {}'.format( exc, traceback.format_exc())) reply['success'] = False finally: dcc.disable_wait_cursor() dcc_progress_bar.end() reply['result'] = moved_vertices
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 match_scale(source_transform=None, target_transform=None): """ Matches scale of the source node to the scale 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 scale.' 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 scale 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 scale: {}'.format(source)) try: maya.cmds.delete( maya.cmds.scaleConstraint(target_transform, source, maintainOffset=False)) out_dict['result'].append(source) except Exception as exc: out_dict[ 'msg'] = 'Was not possible to match node "{}" scale 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 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
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
def _after_load(self): """ Internal function that is called after loading the pose """ if not self._is_loading: return logger.debug('After Load Pose "{}"'.format(self.path)) self._is_loading = False if self._selection: dcc.select_node(self._selection) self._selection = None dcc.set_auto_keyframe_enabled(self._auto_key_frame) dcc.disable_undo() logger.info('Loaded Pose "{}"'.format(self.path))
def set_manual_orient_joints(self, data, reply): 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) childs = list() tweak_rot = [x_axis, y_axis, z_axis] joints = dcc.selected_nodes_of_type(node_type='joint', full_path=False) if not joints: return for jnt in joints: if not affect_children: childs = dcc.list_children( jnt, children_type=['transform', 'joint'], full_path=False, all_hierarchy=False) or list() for child in childs: dcc.set_parent_to_world(child) # Set the rotation axis for i, axis in enumerate(['x', 'y', 'z']): dcc.set_attribute_value(jnt, 'jointOrient{}'.format(axis.upper()), tweak_rot[i]) # Clear joint axis dcc.zero_scale_joint(jnt) dcc.freeze_transforms(jnt, preserve_pivot_transforms=True) if childs: for child in childs: dcc.set_parent(child, jnt) dcc.select_node(joints, replace_selection=True) reply['success'] = True
def check_symmetry(self, data, reply): obj = data['geo'] axis = data['axis'] tolerance = data['tolerance'] table = data['table'] use_pivot = data['use_pivot'] select_asymmetric_vertices = data['select_asymmetric_vertices'] pos_verts = list() neg_verts = list() pos_verts_int = list() neg_verts_int = list() pos_verts_trans = list() neg_verts_trans = list() vert_counter = 0 non_symm_verts = list() is_symmetric = False axis_ind = axis axis_2_ind = (axis_ind + 1) % 3 axis_3_ind = (axis_ind + 2) % 3 if use_pivot: vtx_trans = dcc.node_world_space_translation(obj) mid = vtx_trans[axis_ind] else: if table: bounding_box = dcc.node_world_bounding_box(obj) mid = bounding_box[axis_ind] + ( (bounding_box[axis_ind + 3] - bounding_box[axis_ind]) / 2) else: mid = 0 symmetry_table = list() total_vertices = dcc.total_vertices(obj) dcc.enable_wait_cursor() dcc_progress_bar = progressbar.ProgressBar(title='Working', count=total_vertices) dcc_progress_bar.status('Sorting') mod = math.ceil(total_vertices / 50) try: for i in range(total_vertices): if i % mod == 0: prog_num = i prog = (prog_num / total_vertices) * 100.0 dcc_progress_bar.inc(prog) vtx = dcc.node_vertex_name(obj, i) vtx_trans = dcc.node_vertex_world_space_translation(obj, i) mid_offset = vtx_trans[axis_ind] - mid if mid_offset >= consts.MID_OFFSET_TOLERANCE: pos_verts.append(vtx) if table: pos_verts_int.append(i) pos_verts_trans.append(vtx_trans[axis_ind]) else: if mid_offset < consts.MID_OFFSET_TOLERANCE: neg_verts.append(vtx) if table: neg_verts_int.append(i) neg_verts_trans.append(vtx_trans[axis_ind]) msg = 'Building Symmetry Table' if table else 'Checking for Symmetry' dcc_progress_bar.set_progress(0) dcc_progress_bar.status(msg) for i in range(len(pos_verts)): # if i % mod == 0: # prog_num = i # prog = (prog_num / total_vertices) * 100.0 # dcc_progress_bar.inc(prog) vtx = pos_verts[i] pos_offset = pos_verts_trans[i] - mid if pos_offset < tolerance: pos_verts[i] = consts.MATCH_STR vert_counter += 1 continue for j in range(len(neg_verts)): if neg_verts[j] == consts.MATCH_STR: continue neg_offset = mid - neg_verts_trans[j] if neg_offset < tolerance: neg_verts[j] = consts.MATCH_STR vert_counter += 1 continue if abs(pos_offset - neg_offset) <= tolerance: vtx_trans = dcc.node_vertex_world_space_translation( vtx) vtx2_trans = dcc.node_vertex_world_space_translation( neg_verts[j]) test1 = vtx_trans[axis_2_ind] - vtx2_trans[axis_2_ind] test2 = vtx_trans[axis_3_ind] - vtx2_trans[axis_3_ind] if abs(test1) < tolerance and abs(test2) < tolerance: if table: symmetry_table.append(pos_verts_int[i]) symmetry_table.append(neg_verts_int[j]) vert_counter += 2 pos_verts[i] = neg_verts[j] = consts.MATCH_STR break pos_verts = [x for x in pos_verts if x not in [consts.MATCH_STR]] neg_verts = [x for x in neg_verts if x not in [consts.MATCH_STR]] non_symm_verts = pos_verts + neg_verts if table: if vert_counter != total_vertices: logger.warning( 'Base geometry is not symmetrical, not all vertices can be mirrored' ) else: logger.info('Base geometry is symmetrical') is_symmetric = True reply['success'] = True except Exception as exc: logger.error('Error while checking symmetry: {} | {}'.format( exc, traceback.format_exc())) reply['success'] = False finally: dcc.disable_wait_cursor() dcc_progress_bar.end() if select_asymmetric_vertices: total_vertices_to_select = len(non_symm_verts) if total_vertices_to_select > 0: dcc.enable_component_selection() dcc.select_node(non_symm_verts) logger.info( '{} asymmetric vert(s)'.format(total_vertices_to_select)) else: dcc.select_node(obj) reply['result'] = non_symm_verts, symmetry_table, is_symmetric
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
def select(self): """ Selects wrapped meta node in current scene """ dcc.select_node(self.poser.meta_node)
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