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 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 transfer_animation(self, source_object, target_object, mirror_axis=None, option=None, time=None): option = option or MirrorOptions.Swap source_valid = self.is_valid_mirror(source_object, option) target_valid = self.is_valid_mirror(target_object, option) temp_obj = dcc.duplicate_node(source_object, new_node_name='DELETE_ME', only_parent=True) try: if target_valid: self._transfer_animation(source_object, temp_obj, time=time) if source_valid: self._transfer_animation(target_object, source_object, mirror_axis=mirror_axis, time=time) if target_valid: self._transfer_animation(temp_obj, target_object, mirror_axis=mirror_axis, time=time) finally: dcc.delete_node(temp_obj)
def _remove_dcc_objects(self, dcc_native_objects): """ Internal function that removes given DCC objects from current scene :param dcc_native_objects: variant or list(variant) :return: bool, True if the operation is successful; False otherwise """ return dcc.delete_node(dcc_native_objects)
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
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