示例#1
0
    def set_parent(self, parent, **kwargs):
        """
        Overrides set parent to parent proper root/auto nodes if necessary
        :param parent: str, parent transform node name
        :return:
        """

        # Whether to parent ctrl transform or take into account also root/auto groups
        parent_top = kwargs.pop('parent_top', True)
        node_to_parent = self.get()

        root_group = self.get_root()
        auto_group = self.get_auto()

        if parent_top:
            mirror_group = self.get_mirror(
                suffix=kwargs.pop('mirror_suffix', None))
            if mirror_group:
                node_to_parent = mirror_group
            elif root_group and dcc.node_exists(root_group):
                node_to_parent = root_group
            else:
                if auto_group and dcc.node_exists(auto_group):
                    node_to_parent = auto_group

        dcc.set_parent(node_to_parent, parent)
    def _reference_alembic(self, alembic_file, namespace, parent):
        """
        Internal function that references given alembic file
        :param alembic_file: str
        :param namespace: str
        :return:
        """

        all_nodes = alembic.reference_alembic(project=self._project,
                                              alembic_file=alembic_file,
                                              namespace=namespace)
        if not all_nodes:
            logger.warning(
                'Error while reference Alembic file: {}'.format(alembic_file))
            return
        for obj in all_nodes:
            if not dcc.node_exists(obj):
                continue
            if not dcc.client().node_type(obj) == 'transform':
                continue
            obj_parent = dcc.client().node_parent(obj)
            if obj_parent:
                continue
            dcc.client().set_parent(node=obj, parent=parent)

        return all_nodes
    def _create_nurbs_plane(self):
        """
        Internal function that creates the NURBS plane that will drive the rig system
        """

        self._nurbs_plane = dcc.create_nurbs_plane(
            name=self._get_name('flexiPlane', node_type='surface'),
            axis=(0, 1, 0), width=self._num_joints * 2, length=self._length, patches_u=self._num_joints,
            construction_history=False)
        dcc.freeze_transforms(self._nurbs_plane, translate=True, rotate=True, scale=True)
        dcc.hide_keyable_attributes(self._nurbs_plane, skip_visibility=True)

        material_name = self._get_name('flexiMat', node_type='material')
        if not dcc.node_exists(material_name):
            self._nurbs_plane_material = dcc.create_lambert_material(
                name=material_name, no_surface_shader=True, color=(0.0, 0.85, 1.0), transparency=(0.8, 0.8, 0.8))
        else:
            self._nurbs_plane_material = material_name
        dcc.apply_shader(self._nurbs_plane_material, self._nurbs_plane)

        if self._display_nurbs_plane_as_template:
            dcc.set_node_template_display(self._nurbs_plane, True)

        nurbs_plane_shape = dcc.list_shapes(self._nurbs_plane)[0]
        dcc.set_node_renderable(nurbs_plane_shape, False)
        dcc.set_attribute_value(nurbs_plane_shape, 'doubleSided', True)

        dcc.set_parent(self._nurbs_plane, self._global_move_group)
示例#4
0
    def is_deleted(self):
        """
        Returns whether or not the current wrapped DCC node is being deleted from current scene
        :return: bool
        """

        return not dcc.node_exists(self._dcc_native_object)
示例#5
0
    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 _get_curve_transform(self, curve):
        parent = curve
        if dcc.node_exists(curve):
            if dcc.node_type(curve) == 'nurbsCurve':
                parent = dcc.node_parent(curve)
            else:
                parent = curve

        return parent
    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)
示例#8
0
def validate_curve(crv):
    """
    Returns whether the given name corresponds to a valid NURBS curve
    :param crv: str, name of the curve we want to check
    :return: bool
    """

    if crv is None or not dcc.node_exists(crv):
        return False

    curve_shapes = dcc.get_curve_shapes(crv)

    return curve_shapes
示例#9
0
def is_character_definition(node):
    """
    Returns whether or not given node is an HumanIK character node
    :param node: str
    :return: bool
    """

    if not dcc.node_exists(node):
        return False

    if dcc.object_type(node) != 'HIKCharacterNode':
        return False

    return True
示例#10
0
    def __init__(self, nodes):

        error_text = '======= Renamer: Failed to rename one or more nodes ======='
        if not hasattr(nodes, '__iter__'):
            nodes = [nodes]
        for node in nodes:
            if not dcc.node_exists(node):
                error_text += "\t'%s' no longer exists.\n" % node
            elif dcc.node_is_locked(node):
                error_text += "\t'%s' is locked.\n" % node
            else:
                error_text += "\t'%s' failure unknows.\n" % node

        Exception.__init__(self, error_text)
示例#11
0
    def __init__(self, name, **kwargs):
        super(BaseRigControl, self).__init__()

        self._name = name or 'newCtrl'
        self._curve_type = kwargs.pop('control_type', '')
        self._controls_path = kwargs.pop('controls_path', '')
        self._naming_file = kwargs.pop('naming_file', '')
        self._name_rule = kwargs.pop('rule_name', '')
        self._name_data = kwargs.pop('name_data', dict())
        self._side = kwargs.pop('side', None)

        if self._naming_file:
            self._name = self.solve_name(self._name, unique_name=False)

        if not dcc.node_exists(self._name):
            self._create(**kwargs)
示例#12
0
def create_character(character_name, character_namespace=None, lock=True):
    """
    Creates a HumanIK character and tries to use the given name to name the new character
    :param character_name: str, name of the new HumanIK character
    """

    if character_namespace and not character_namespace.endswith(':'):
        character_namespace = '{}:'.format(character_namespace)
    character_namespace = character_namespace or ''

    character_definition = maya.mel.eval('hikCreateCharacter("{0}")'.format(character_name))
    set_current_character(character_definition)

    try:
        maya.mel.eval('hikUpdateCharacterList()')
        maya.mel.eval('hikSelectDefinitionTab()')
    except Exception:
        pass

    for bone_name, bone_data in HIK_BONES.items():
        bone_full_name = '{}{}'.format(character_namespace, bone_name)
        if not dcc.node_exists(bone_full_name):
            logger.debug('HIK bone "{}" not found in scene!'.format(bone_name))
            continue
        bone_index = bone_data['index']
        set_character_object(character_definition, bone_full_name, bone_index, 0)

    property_node = get_properties_node(character_definition)

    dcc.set_attribute_value(property_node, 'ForceActorSpace', 0)
    dcc.set_attribute_value(property_node, 'ScaleCompensationMode', 1)
    dcc.set_attribute_value(property_node, 'Mirror', 0)
    dcc.set_attribute_value(property_node, 'HipsHeightCompensationMode', 1)
    dcc.set_attribute_value(property_node, 'AnkleProximityCompensationMode', 1)
    dcc.set_attribute_value(property_node, 'AnkleHeightCompensationMode', 0)
    dcc.set_attribute_value(property_node, 'MassCenterCompensationMode', 1)

    if lock:
        maya.mel.eval('hikToggleLockDefinition')
    # else:
    #     generator_node = maya.cmds.createNode('HIKSkeletonGeneratorNode')
        # dcc.connect_attribute(
        #     generator_node, 'CharacterNode', character_definition, 'SkeletonGenerator', force=True)

    return character_definition
示例#13
0
    def import_data(self, **kwargs):

        filepath = self.format_identifier()
        if not filepath.endswith(ControlCVsData.EXTENSION):
            filepath = '{}{}'.format(filepath, ControlCVsData.EXTENSION)

        if not filepath:
            logger.warning(
                'Impossible to load Control CVs from file: "{}"!'.format(
                    filepath))
            return False

        library = self._initialize_library(filepath)

        objects = kwargs.get('objects', None)
        if not objects:
            objects = dcc.client().selected_nodes(full_path=True) or list()

        # We make sure that we store the short name of the controls
        objects = [dcc.node_short_name(obj) for obj in objects]

        updated_controls = list()
        controls = objects or controllib.get_controls()
        for control in controls:
            shapes = dcc.client().get_curve_shapes(control)
            if not shapes:
                continue
            library.set_curve(control, check_curve=True)
            updated_controls.append(control)

        # We force the update of all the curves that are stored in the library and are in the scene
        for curve_data in list(library._library_curves.values()):
            for curve_name in list(curve_data.keys()):
                if curve_name and dcc.node_exists(
                        curve_name) and curve_name not in updated_controls:
                    library.set_curve(curve_name, check_curve=True)
                    updated_controls.append(curve_name)

        logger.info('Imported {} data'.format(self.name()))

        return True
示例#14
0
    def _calculate_mirror_axis(self, source_object):
        """
        Internal function that calculates the mirror axis of the given object name
        :param source_object: str
        :return: list(int)
        """

        result = [1, 1, 1]
        target_object = self.mirror_object(source_object) or source_object
        mirror_plane = self.mirror_plane()

        if target_object == source_object or not dcc.node_exists(target_object):
            result = dcc.get_mirror_axis(source_object, mirror_plane)
        else:
            if dcc.is_axis_mirrored(source_object, target_object, [1, 0, 0], mirror_plane):
                result[0] = -1
            if dcc.is_axis_mirrored(source_object, target_object, [0, 1, 0], mirror_plane):
                result[1] = -1
            if dcc.is_axis_mirrored(source_object, target_object, [0, 0, 1], mirror_plane):
                result[2] = -1

        return result
    def _on_import_alembic(self, as_reference=False):
        """
        Overrides base AlembicImporter _on_import_alembic function
        Internal callback function that is called when Import/Reference Alembic button is clicked
        :param as_reference: bool
        """

        reference_nodes = super(
            MayaAlembicImporter,
            self)._on_import_alembic(as_reference=as_reference)

        if not self._auto_smooth_display.isChecked():
            return

        if not reference_nodes or type(reference_nodes) not in [list, tuple]:
            return

        for obj in reference_nodes:
            if not obj or not dcc.node_exists(obj):
                continue
            if dcc.client().node_type(obj) == 'shape':
                if dcc.client().attribute_exists(
                        node=obj, attribute_name='aiSubdivType'):
                    dcc.client().set_integer_attribute_value(
                        node=obj,
                        attribute_name='aiSubdivType',
                        attribute_value=1)
            elif dcc.client().node_type(obj) == 'transform':
                shapes = dcc.client().list_shapes(node=obj, full_path=True)
                if not shapes:
                    continue
                for s in shapes:
                    if dcc.client().attribute_exists(
                            node=s, attribute_name='aiSubdivType'):
                        dcc.client().set_integer_attribute_value(
                            node=s,
                            attribute_name='aiSubdivType',
                            attribute_value=1)
示例#16
0
    def transfer_static(self, source_object, target_object, mirror_axis=None, attrs=None, option=None):

        option = option or MirrorOptions.Swap

        source_value = None
        target_value = None
        source_valid = self.is_valid_mirror(source_object, option)
        target_valid = self.is_valid_mirror(target_object, option)

        attrs = attrs or dcc.list_attributes(source_object, keyable=True) or list()
        for attr in attrs:
            target_attr = '{}.{}'.format(target_object, attr)
            if dcc.node_exists(target_attr):
                if target_valid:
                    source_value = dcc.get_attribute_value(source_object, attr)
                if source_valid:
                    target_value = dcc.get_attribute_value(target_object, attr)
                if target_valid:
                    self.set_attribute(target_object, attr, source_value, mirror_axis=mirror_axis)
                if source_valid:
                    self.set_attribute(source_object, attr, target_value, mirror_axis=mirror_axis)
            else:
                logger.warning('Cannot find destination attribute "{}"'.format(target_attr))
示例#17
0
文件: node.py 项目: tpDcc/tpDcc-core
 def exists(self):
     return dcc.node_exists(self.name())
示例#18
0
    def cache_node(self, source_node, target_node, **kwargs):
        """
        :param source_node: Node
        :param target_node: Node
        Caches the given pair of nodes
        :param kwargs: dict
        """

        attrs = kwargs.get('attrs', None)
        ignore_connected = kwargs.get('ignore_connected', None)
        only_connected = kwargs.get('only_connected', None)
        using_namespaces = kwargs.get('using_namespaces', None)

        mirror_axis = None
        mirror_object = None

        # remove first pipe in case object has a parent node
        target_node.strip_first_pipe()
        source_name = source_node.name()

        if self.mirror_table():
            mirror_object = self.mirror_table().mirror_object(source_name)
            if not mirror_object or not dcc.node_exists(mirror_object):
                mirror_object = self.mirror_table().mirror_object(
                    dcc.client().node_short_name(source_name))
            if not mirror_object:
                mirror_object = source_name
                logger.warning(
                    'Cannot find mirror object in pose for "{}"'.format(
                        source_name))

            # retrieve mirror axis from mirror object or from source node
            mirror_axis = self.mirror_axis(mirror_object) or self.mirror_axis(
                source_name)

            if mirror_object and not dcc.node_exists(mirror_object):
                logger.warning(
                    'Mirror object does not exist in the scene {}'.format(
                        mirror_object))

        if using_namespaces:
            try:
                target_node = target_node.to_short_name()
            except exceptions.NoObjectFoundError as exc:
                logger.warning(exc)
                return
            except exceptions.MoreThanOneObjectFoundError as exc:
                logger.warning(exc)
                return

        for attr in self.attrs(source_name):
            if attrs and attr not in attrs:
                continue
            target_attribute = utils.Attribute(target_node.name(), attr)
            is_connected = target_attribute.is_connected()
            if (ignore_connected and is_connected) or (only_connected
                                                       and not is_connected):
                continue

            attr_type = self.attr_type(source_name, attr)
            attr_value = self.attr_value(source_name, attr)
            source_mirror_value = self.mirror_value(mirror_object,
                                                    attr,
                                                    mirror_axis=mirror_axis)
            source_attribute = utils.Attribute(target_node.name(),
                                               attr,
                                               value=attr_value,
                                               type=attr_type)
            target_attribute.clear_cache()

            self._cache.append(
                (source_attribute, target_attribute, source_mirror_value))
示例#19
0
    def import_data(self, *args, **kwargs):

        filepath = self.format_identifier()
        if not filepath.endswith(JointsData.EXTENSION):
            filepath = '{}{}'.format(filepath, JointsData.EXTENSION)

        if not filepath or not os.path.isfile(filepath):
            LOGGER.warning('Impossible to import joints data from: "{}"'.format(filepath))
            return

        LOGGER.debug('Loading: {} | {}'.format(filepath, kwargs))

        with open(filepath, 'r') as fh:
            joints_data = json.load(fh)
        if not joints_data:
            LOGGER.warning('No joints data found in file: "{}"'.format(filepath))
            return False

        # TODO: Use metadata to verify DCC and also to create nodes with proper up axis
        metadata = self.metadata()

        nodes_list = list()
        created_nodes = dict()
        for node_data in joints_data:
            node_index = node_data.get('index', 0)
            node_parent_index = node_data.get('parent_index', -1)
            node_parent_name = node_data.get('parent_name', '')
            node_name = node_data.get('name', 'new_node')
            node_type = node_data.get('type', 'joint')
            node_namespace = node_data.get('namespace', '')
            node_label_side = node_data.get('side', '')
            node_label_type = node_data.get('bone_type', '')
            node_label_other_type = node_data.get('bone_other_type', '')
            node_label_draw = node_data.get('draw_label', False)
            node_radius = node_data.get('radius', 1.0)
            node_world_matrix = node_data.get(
                'world_matrix', [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0])
            dcc.client().clear_selection()
            if node_type == 'joint':
                new_node = dcc.client().create_joint(name=node_name)
            else:
                new_node = dcc.client().create_empty_group(name=node_name)
            dcc.client().set_node_world_matrix(new_node, node_world_matrix)
            created_nodes[node_index] = {
                'node': new_node, 'parent_index': node_parent_index, 'parent_name': node_parent_name,
                'namespace': node_namespace, 'label_side': node_label_side, 'label_type': node_label_type,
                'label_other_type': node_label_other_type, 'label_draw': node_label_draw, 'radius': node_radius
            }

            if node_type == 'joint':
                dcc.client().zero_orient_joint(new_node)

            nodes_list.append(new_node)

        for node_index, node_data in created_nodes.items():
            parent_index = node_data['parent_index']
            if parent_index < -1:
                continue
            node_data = created_nodes.get(node_index, None)
            if not node_data:
                continue
            node_name = node_data.get('node')

            dcc.client().set_side_labelling(node_name, node_data.get('label_side'))
            dcc.client().set_type_labelling(node_name, node_data.get('label_type'))
            dcc.client().set_other_type_labelling(node_name, node_data.get('label_other_type'))
            dcc.client().set_draw_label_labelling(node_name, node_data.get('label_draw'))
            dcc.client().set_joint_radius(node_name, node_data.get('radius'))

            parent_node_name = None
            parent_node_data = created_nodes.get(parent_index, None)
            if not parent_node_data:
                parent_node_name = node_data.get('parent_name', '')
                if not parent_node_name or not dcc.node_exists(parent_node_name):
                    continue

            if not parent_node_name:
                parent_node_name = parent_node_data.get('node')
            dcc.client().set_parent(node_name, parent_node_name)

        # We assign namespaces once the hierarchy of nodes is created
        for node_index, node_data in created_nodes.items():
            node_name = node_data.get('node')
            node_namespace = node_data.get('namespace')
            if node_namespace:
                dcc.client().assign_node_namespace(node_name, node_namespace, force_create=True)

        # dcc.client().select_node(nodes_list)
        # dcc.client().fit_view()
        dcc.client().clear_selection()

        LOGGER.debug('Loaded: {} | {}'.format(filepath, kwargs))

        return nodes_list
    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 save(self, *args, **kwargs):
        """
        Saves NG Skin weights file
        """

        dependencies = dict()

        filepath = self.format_identifier()
        if not filepath:
            logger.warning(
                'Impossible to save NGSkin Cluster Weights file because save file path not defined!'
            )
            return

        objects = kwargs.get('objects', None)
        if not objects:
            objects = dcc.client().selected_nodes(full_path=True)
        if not objects:
            logger.warning(
                'Nothing selected to export skin weights of. Please, select a mesh,'
                ' curve, NURBS surface or lattice with skin weights to export')
            return False

        logger.debug('Saving {} | {}'.format(filepath, kwargs))

        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 export ngSkin data'
            )
            return False

        valid_nodes = list()

        # Check that all objects that we are going to export have at least one skin cluster node associated
        # Make sure also that all objects skin output folder have been created
        obj_dirs = OrderedDict()
        skin_nodes = OrderedDict()
        geo_paths = OrderedDict()
        skin_weights = OrderedDict()
        for obj in objects:
            if dcc.client().node_is_a_shape(obj):
                obj = dcc.client().node_parent(obj, full_path=True)
            obj_filename = obj
            if obj.find('|') > -1:
                obj_filename = obj_filename.replace('|', '.')
                if obj_filename.startswith('.'):
                    obj_filename = obj_filename[1:]
            if obj_filename.find(':') > -1:
                obj_filename = obj_filename.replace(':', '-')

            skin = dcc.client().find_deformer_by_type(obj, 'skinCluster')
            if not skin:
                logger.warning(
                    'Skip skin weights export for object because no skinCluster found!'
                    .format(obj))
                continue
            valid_nodes.append((obj, obj_filename, skin))

        if not valid_nodes:
            logger.warning(
                'Skin exported failed! No objects found with skinClusters applied!'
            )
            return False

        # Create skin folder only is valid nodes are available
        file_name = '.{}'.format(os.path.basename(filepath))
        file_folder = path_utils.join_path(os.path.dirname(filepath),
                                           file_name)
        if not os.path.isdir(file_folder):
            skin_folder = folder.create_folder(file_folder, make_unique=True)
            dependencies[skin_folder] = 'skin_folder'

        for node_data in valid_nodes:
            obj, obj_filename, skin = node_data

            geo_path = path_utils.join_path(file_folder, obj_filename)
            if path_utils.is_dir(geo_path):
                folder.delete_folder(obj_filename, file_folder)
            geo_path = folder.create_folder(obj_filename, file_folder)
            if not geo_path:
                logger.error(
                    'Unable to create skin weights directory: "{}" in "{}"'.
                    format(obj_filename, file_folder))
                return False
            dependencies[geo_path] = 'geo_path'

            weights = dcc.client().get_skin_weights(skin)

            obj_dirs[obj] = obj_filename
            skin_nodes[obj] = skin
            geo_paths[obj] = geo_path
            skin_weights[obj] = weights

        for (obj, skin_node), (_, geo_path), (_, skin_weights) in zip(
                skin_nodes.items(), geo_paths.items(), skin_weights.items()):

            logger.info('Exporting weights: {} > {} --> "{}"'.format(
                obj, skin_node, geo_path))

            info_lines = list()
            info_file = fileio.create_file('influence.info', geo_path)

            for influence in skin_weights:
                if influence is None or influence == 'None':
                    continue
                weight_list = skin_weights[influence]
                if not weight_list:
                    continue

                influence_name = skin_utils.get_skin_influence_at_index(
                    influence, skin_node)
                if not influence_name or not dcc.node_exists(influence_name):
                    continue

                influence_position = dcc.node_world_space_translation(
                    influence_name)
                influence_line = "{'%s' : {'position' : %s}}" % (
                    influence_name, str(influence_position))
                info_lines.append(influence_line)

            writer = fileio.FileWriter(info_file)
            writer.write(info_lines)

            settings_file = fileio.create_file('settings.info', geo_path)
            setting_lines = list()
            if shape_utils.has_shape_of_type(obj, 'mesh'):
                self._export_mesh_obj(obj, geo_path)

            setting_lines.append("['skinNodeName', '{}']".format(
                dcc.node_short_name(skin_node)))
            if dcc.attribute_exists(skin_node, 'blendWeights'):
                blend_weights = skin_utils.get_skin_blend_weights(skin_node)
                setting_lines.append(
                    "['blendWeights', {}]".format(blend_weights))
            if dcc.attribute_exists(skin_node, 'skinningMethod'):
                skin_method = dcc.get_attribute_value(skin_node,
                                                      'skinningMethod')
                setting_lines.append(
                    "['skinningMethod', {}]".format(skin_method))

            write_settings = fileio.FileWriter(settings_file)
            write_settings.write(setting_lines)

            ng_skin_file_name = os.path.join(geo_path, 'ngdata.json')
            ngst_api.export_json(obj, file=ng_skin_file_name)

            logger.info(
                'Skin weights exported successfully: {} > {} --> "{}"'.format(
                    obj, skin_node, geo_path))

        data_to_save = OrderedDict()
        for obj, obj_filename in obj_dirs.items():
            data_to_save[obj] = {'enabled': True, 'folder': obj_filename}
        with open(filepath, 'w') as fh:
            json.dump(data_to_save, fh)

        logger.info('Skin weights export operation completed successfully!')

        return True
示例#22
0
    def _find_manual_available_name(
            self, items, name, prefix=None, suffix=None, side='', index=-1, padding=0, letters=False, capital=False,
            remove_first=0, remove_last=0, search_str=None, replace_str=None, joint_end=False):

        if dcc.is_maya():
            import maya.api.OpenMaya

        if prefix:
            if side and side != '':
                test_name = '{}_{}_{}'.format(prefix, side, name)
            else:
                test_name = '{}_{}'.format(prefix, name)
        else:
            if side and side != '':
                test_name = '{}_{}'.format(side, name)
            else:
                test_name = name

        if index >= 0:
            if letters:
                letter = strings.get_alpha(index, capital)
                test_name = '{}_{}'.format(test_name, letter)
            else:
                test_name = '{}_{}'.format(test_name, str(index).zfill(padding))

        if suffix:
            test_name = '{}_{}'.format(test_name, suffix)

        if remove_first and remove_first > 0:
            test_name = test_name[remove_first:]

        if remove_last and remove_last > 0:
            test_name = test_name[:-remove_last]

        if search_str is not None and search_str != '' and replace_str is not None:
            test_name = test_name.replace(search_str, replace_str)

        item_names = list()
        for item in items:
            if hasattr(item, 'obj'):
                item_names.append(item.obj)
            else:
                if dcc.is_maya():
                    if hasattr(item, 'object'):
                        mobj = item.object()
                        try:
                            dag_path = maya.api.OpenMaya.MDagPath.getAPathTo(mobj)
                            item_to_add = dag_path.partialPathName()
                            item_names.append(item_to_add)
                            continue
                        except Exception as exc:
                            LOGGER.warning('Error while retrieving node path from MObject: {}'.format(exc))
                            continue
                else:
                    item_names.append(item)

        # if object exists, try next index
        if dcc.node_exists(test_name) or test_name in item_names:
            new_index = int(index) + 1
            return self._find_manual_available_name(
                items, name, prefix=prefix, index=new_index, padding=padding,
                letters=letters, capital=capital, remove_first=remove_first, remove_last=remove_last,
                joint_end=joint_end, search_str=search_str, replace_str=replace_str
            )

        return test_name
    def reference_alembic(project,
                          alembic_path,
                          namespace=None,
                          fix_path=False):
        """
        References alembic file in current DCC scene
        :param project: ArtellaProject
        :param alembic_path: str
        :param namespace: str
        :param fix_path: bool
        """

        if not alembic_path or not os.path.isfile(alembic_path):
            logger.warning(
                'Alembic file {} does not exits!'.format(alembic_path))
            return None

        abc_name = os.path.basename(alembic_path).split('.')[0]
        tag_json_file = os.path.join(
            os.path.dirname(alembic_path),
            os.path.basename(alembic_path).replace('.abc', '_abc.info'))
        if not os.path.isfile(tag_json_file):
            logger.warning('No Alembic Info file found!')
            return

        with open(tag_json_file, 'r') as f:
            tag_info = json.loads(f.read())
        if not tag_info:
            logger.warning('No Alembic Info loaded!')
            return

        root = dcc.client().create_empty_group(name=abc_name)
        BaseAlembicImporter._add_tag_info_data(project, tag_info, root)
        sel = [root]
        sel = sel or None

        if not namespace:
            namespace = abc_name

        new_nodes = alembic.reference_alembic(project=project,
                                              alembic_file=alembic_path,
                                              namespace=namespace,
                                              fix_path=fix_path)
        if not new_nodes:
            logger.warning(
                'Error while reference Alembic file: {}'.format(alembic_path))
            return
        for obj in new_nodes:
            if not dcc.node_exists(obj):
                continue
            if not dcc.client().node_type(obj) == 'transform':
                continue
            obj_parent = dcc.client().node_parent(obj)
            if obj_parent:
                continue
            dcc.client().set_parent(obj, sel[0])
        dcc.client().select_node(sel[0])

        new_nodes.insert(0, sel[0])

        # After parenting referenced nodes, full path changes, here we update node paths
        if dcc.client().is_maya():
            new_paths = list()
            for n in new_nodes:
                if dcc.node_exists(n):
                    new_paths.append(n)
                else:
                    if n.startswith('|'):
                        new_paths.append('{}{}'.format(sel[0], n))
                    else:
                        new_paths.append('{}|{}'.format(sel[0], n))
            return new_paths

        return new_nodes
示例#24
0
    def load(self, *args, **kwargs):

        objects = kwargs.get('objects', None)
        namespaces = kwargs.get('namespaces', None)
        option = kwargs.get('option', None)
        keys_option = kwargs.get('keys_option', None)
        time = kwargs.get('time', None)

        if option and not isinstance(option, int):
            if option.lower() == 'swap':
                option = 0
            elif option.lower() == 'left to right':
                option = 1
            elif option.lower() == 'right to left':
                option = 2
            else:
                raise ValueError('Invalid load option: {}'.format(option))

        self.validate(namespaces=namespaces)

        results = dict()
        animation = True
        found_object = False
        source_objects = list(self.objects().keys())

        if option is None:
            option = mirrortable.MirrorOptions.Swap
        if keys_option == mirrortable.KeysOptions.All:
            time = None
        elif keys_option == mirrortable.KeysOptions.SelectedRange:
            time = anim_utils.get_selected_frame_range()

        # check that given time is not a single frame
        if time and time[0] == time[1]:
            time = None
            animation = None

        matches = utils.match_names(source_objects=source_objects,
                                    target_objects=objects,
                                    target_namespaces=namespaces)
        for source_node, target_node in matches:
            target_object = target_node.name()
            target_object2 = self.mirror_object(target_object) or target_object
            if target_object2 not in results:
                results[target_object] = target_object2
                mirror_axis = self.mirror_axis(source_node.name())
                target_object_exists = dcc.node_exists(target_object)
                target_object2_exists = dcc.node_exists(target_object2)
                if target_object_exists and target_object2_exists:
                    found_object = True
                    if animation:
                        self.transfer_animation(target_object,
                                                target_object2,
                                                mirror_axis=mirror_axis,
                                                option=option,
                                                time=time)
                    else:
                        self.transfer_static(target_object,
                                             target_object2,
                                             mirror_axis=mirror_axis,
                                             option=option)
                else:
                    if not target_object_exists:
                        logger.warning(
                            'Cannot find destination object {}'.format(
                                target_object))
                    if not target_object2_exists:
                        logger.warning(
                            'Cannot find mirrored destination object {}'.
                            format(target_object2))

        dcc.focus_ui_panel('MayaWindow')

        if not found_object:
            raise exceptions.NoMatchFoundError(
                'No objects match wne loading mirror table data')
示例#25
0
    def _export(self):
        """
        Internal function that exports Alembic
        """

        out_folder = self._export_path_line.text()
        if not os.path.exists(out_folder):
            dcc.client().confirm_dialog(
                title='Error during Alembic Exportation',
                message='Output Path does not exists: {}. Select a valid one!'.
                format(out_folder))
            return

        nodes_to_export = dcc.client().selected_nodes()
        if not nodes_to_export:
            logger.error('No nodes to export as Alembic!')
            return False

        for n in nodes_to_export:
            if not dcc.node_exists(n):
                logger.error(
                    'Node "{}" does not exists in current scene!'.format(n))
                return False

        root_nodes = list()
        for n in nodes_to_export:
            root_node = dcc.client().node_root(node=n)
            if root_node not in root_nodes:
                root_nodes.append(root_node)

        if not root_nodes:
            logger.error('Not nodes to export as Alembic!')
            return False

        file_paths = list()

        export_info = list()
        if self._export_all_alembics_together_cbx.isChecked():
            export_path = path_utils.clean_path(
                out_folder + dcc.client().node_short_name(root_nodes[0]) +
                '.abc')
            file_paths.append(export_path)
            export_info.append({'path': export_path, 'nodes': root_nodes})
        else:
            for n in root_nodes:
                export_path = path_utils.clean_path(
                    out_folder + dcc.client().node_short_name(n) + '.abc')
                file_paths.append(export_path)
                export_info.append({'path': export_path, 'nodes': [n]})

        res = dcc.client().confirm_dialog(
            title='Export Alembic File',
            message='Are you sure you want to export Alembic to files?\n\n' +
            '\n'.join([p for p in file_paths]),
            button=['Yes', 'No'],
            default_button='Yes',
            cancel_button='No',
            dismiss_string='No')
        if res != 'Yes':
            logger.debug('Aborting Alembic Export operation ...')
            return

        result = True
        try:
            self._export_alembics(export_info)
        except Exception as exc:
            logger.error(
                'Something went wrong during Alembic export process: {}'.
                format(exc))
            result = False

        self._stack.slide_in_index(0)

        return result
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 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 import_alembic(cls,
                       project,
                       alembic_path,
                       parent=None,
                       fix_path=False):
        """
        Implements  AlembicImporter import_alembic function
        Imports Alembic in current DCC scene
        :param project: ArtellaProject
        :param alembic_path: str
        :param parent: object
        :param fix_path: bool
        :return: bool
        """

        if not alembic_path or not os.path.isfile(alembic_path):
            logger.warning(
                'Alembic file {} does not exits!'.format(alembic_path))
            return None

        tag_json_file = os.path.join(
            os.path.dirname(alembic_path),
            os.path.basename(alembic_path).replace('.abc', '_abc.info'))
        valid_tag_info = True
        if os.path.isfile(tag_json_file):
            with open(tag_json_file, 'r') as f:
                tag_info = json.loads(f.read())
            if not tag_info:
                logger.warning('No Alembic Info loaded!')
                valid_tag_info = False
        else:
            logger.warning(
                'No Alembic Info file found! '
                'Take into account that imported Alembic is not supported by our current pipeline!'
            )
            valid_tag_info = False

        if not parent:
            parent = dcc.client().create_empty_group(
                name=os.path.basename(alembic_path))
        else:
            if not dcc.node_exists(parent):
                parent = dcc.client().create_empty_group(name=parent)
            else:
                logger.warning(
                    'Impossible to import Alembic into scene because'
                    ' node named "{}" already exists in the scene!'.format(
                        parent))
                return

        if parent and valid_tag_info:
            cls._add_tag_info_data(project=project,
                                   tag_info=tag_info,
                                   attr_node=parent)

        track_nodes = maya_scene.TrackNodes()
        track_nodes.load()
        valid_import = alembic.import_alembic(project,
                                              alembic_path,
                                              mode='import',
                                              nodes=None,
                                              parent=parent,
                                              fix_path=fix_path)

        if not valid_import:
            return
        res = track_nodes.get_delta()

        # maya.cmds.viewFit(res, animate=True)

        return res