Пример #1
0
def parent(src_nodes, dst_node, current_frame=None, eval_mode=None):
    """
    Parent nodes under a new parent node.

    :param src_nodes: List of nodes to reparent.
    :type src_nodes: [str, ..]

    :param dst_node: The new parent node for the given source nodes.
    :type dst_node: str

    :param current_frame: What frame number is considered to be
                          'current' when evaluating transforms without
                          any keyframes.
    :type current_frame: float or int

    :param eval_mode: What type of transform evaluation method to use?
    :type eval_mode: mmSolver.utils.constant.EVAL_MODE_*

    """
    assert len(src_nodes) > 0
    assert len(dst_node) > 0
    if current_frame is None:
        current_frame = maya.cmds.currentTime(query=True)
    assert current_frame is not None

    src_tfm_nodes = [tfm_utils.TransformNode(node=n) for n in src_nodes]
    tfm_dst_node = tfm_utils.TransformNode(node=dst_node)

    # Query keyframe times on each node attribute
    key_times_map = time_utils.get_keyframe_times_for_node_attrs(
        src_nodes, const.TFM_ATTRS)

    # Create Transform Cache, add and process cache.
    times = []
    cache = tfm_utils.TransformMatrixCache()
    for src_tfm_node in src_tfm_nodes:
        src_node = src_tfm_node.get_node()
        times = key_times_map.get(src_node, [current_frame])
        cache.add_node(src_tfm_node, times)
    cache.process(eval_mode=eval_mode)

    # Re-parent the nodes.
    dst_node = tfm_dst_node.get_node()
    src_nodes = [tfm_node.get_node() for tfm_node in src_tfm_nodes]
    maya.cmds.parent(src_nodes, dst_node, relative=True)

    # Set transforms for all source nodes.
    # anim_curves = []
    for src_tfm_node in src_tfm_nodes:
        src_node = src_tfm_node.get_node()
        src_times = key_times_map.get(src_node, [current_frame])
        assert len(src_times) > 0
        tfm_utils.set_transform_values(cache,
                                       src_times,
                                       src_tfm_node,
                                       src_tfm_node,
                                       delete_static_anim_curves=False)

    src_nodes = [tfm_node.get_node() for tfm_node in src_tfm_nodes]
    return src_nodes
Пример #2
0
    def test_set_transform_values(self):
        """
        """
        start_frame = 1001
        end_frame = 1101
        node = maya.cmds.createNode('transform')
        maya.cmds.setKeyframe(node, attribute='translateX', time=start_frame, value=-100.0)
        maya.cmds.setKeyframe(node, attribute='translateX', time=end_frame, value=100.0)
        maya.cmds.setKeyframe(node, attribute='translateY', time=start_frame, value=-10.0)
        maya.cmds.setKeyframe(node, attribute='translateY', time=end_frame, value=10.0)
        maya.cmds.setKeyframe(node, attribute='rotateY', time=start_frame, value=90.0)
        maya.cmds.setKeyframe(node, attribute='rotateY', time=end_frame, value=-90.0)
        frame_range = list(range(start_frame, end_frame + 1))

        tfm_node = mod.TransformNode(node=node)

        tfm_cache = mod.TransformMatrixCache()
        tfm_cache.add_node_attr(tfm_node, 'worldMatrix[0]', frame_range)
        tfm_cache.process()

        dst_node = maya.cmds.createNode('transform')
        dst_tfm_node = mod.TransformNode(node=dst_node)

        mod.set_transform_values(tfm_cache, frame_range,
            tfm_node, dst_tfm_node,
            delete_static_anim_curves=True,
        )

        # save the output scene file
        path = 'test_transform.ma'
        path = self.get_data_path(path)
        maya.cmds.file(rename=path)
        maya.cmds.file(save=True, type='mayaAscii', force=True)
        return
Пример #3
0
 def test_TransformMatrixCache_init(self):
     start_frame = 1001
     end_frame = 1101
     times = list(range(start_frame, end_frame))
     node = maya.cmds.createNode('transform')
     tfm_node = mod.TransformNode(node=node)
     tfm_matrix_cache = mod.TransformMatrixCache()
     return
Пример #4
0
 def test_TransformMatrixCache_usage(self):
     start_frame = 1001
     end_frame = 1101
     times = list(range(start_frame, end_frame))
     node = maya.cmds.createNode('transform')
     tfm_node = mod.TransformNode(node=node)
     tfm_matrix_cache = mod.TransformMatrixCache()
     tfm_matrix_cache.add_node(tfm_node, times)
     tfm_matrix_cache.process()
     attr_name = 'translateX'
     tfm_matrix_cache.get_node_attr_matrix(tfm_node, attr_name, times)
     return
Пример #5
0
def query_camera_data(cam_tfm, cam_shp, frames, rotate_order, test_disk):
    """
    Get the camera information from the given cameras
    """
    assert isinstance(cam_tfm, (str, unicode, basestring))
    assert isinstance(cam_shp, (str, unicode, basestring))
    assert len(cam_tfm) > 0
    assert len(cam_shp) > 0
    assert maya.cmds.objExists(cam_tfm)
    assert maya.cmds.objExists(cam_shp)
    assert isinstance(frames, (list, tuple))

    cam_data = {}
    attr_data = {}

    # Get the camera name, by parsing node name.
    name = cam_tfm.rpartition('|')[-1]
    cam_data['name'] = name

    # Add 'translate' and 'rotate' attributes to list to evaluate.
    tfm_node = tfm_utils.TransformNode(cam_tfm)
    tfm_cache = tfm_utils.TransformMatrixCache()
    tfm_cache.add_node(tfm_node, frames)
    tfm_cache.process()
    tfm_mat_list = tfm_utils.get_transform_matrix_list(
        tfm_cache, frames, tfm_node, rotate_order=rotate_order)
    assert len(tfm_mat_list) == len(frames)
    tx_values = []
    ty_values = []
    tz_values = []
    rx_values = []
    ry_values = []
    rz_values = []
    prv_rot = None
    for f, mat in zip(frames, tfm_mat_list):
        tx, ty, tz, rx, ry, rz, _, _, _ = tfm_utils.decompose_matrix(
            mat, prv_rot)
        tx_values.append((f, tx))
        ty_values.append((f, ty))
        tz_values.append((f, tz))
        rx_values.append((f, rx))
        ry_values.append((f, ry))
        rz_values.append((f, rz))
    attr_data['translateX'] = tx_values
    attr_data['translateY'] = ty_values
    attr_data['translateZ'] = tz_values
    attr_data['rotateX'] = rx_values
    attr_data['rotateY'] = ry_values
    attr_data['rotateZ'] = rz_values

    # Get the camera shape node attributes:
    # - focal length
    # - film back
    # - film back offset
    #
    # The values are stored in millimetres (mm).
    attrs = [
        ('focalLength', 'focalLength', lambda x: x),
        ('horizontalFilmAperture', 'filmBackWidth', lambda x: x * 25.4),
        ('verticalFilmAperture', 'filmBackHeight', lambda x: x * 25.4),
        ('horizontalFilmOffset', 'filmBackOffsetX', lambda x: x * 25.4),
        ('verticalFilmOffset', 'filmBackOffsetY', lambda x: x * 25.4),
    ]
    for attr, attr_name, convert_func in attrs:
        plug = '{0}.{1}'.format(cam_tfm, attr)
        attr_values = []
        for f in frames:
            v = maya.cmds.getAttr(plug, time=f)
            v = convert_func(v)
            attr_values.append((f, v))
        attr_data[attr_name] = attr_values

    cam_data['attr'] = attr_data
    return cam_data
Пример #6
0
def remove(nodes, current_frame=None, eval_mode=None):
    """
    Remove a controller and push the animation back to the controlled
    object.

    Order the nodes to remove by hierarchy depth. This means that
    children will be removed first, then parents, this ensures we
    don't delete a controller accidentally when a parent controller is
    deleted first.

    :param nodes: The nodes to delete.
    :type nodes: [str, ..]

    :param current_frame: What frame number is considered to be
                          'current' when evaluating transforms without
                          any keyframes.
    :type current_frame: float or int

    :param eval_mode: What type of transform evaluation method to use?
    :type eval_mode: mmSolver.utils.constant.EVAL_MODE_*

    :returns: List of once controlled transform nodes, that are no
              longer controlled.
    :rtype: [str, ..]
    """
    if current_frame is None:
        current_frame = maya.cmds.currentTime(query=True)
    assert current_frame is not None
    sparse = False

    nodes = _sort_by_hierarchy(nodes, children_first=True)
    tfm_nodes = [tfm_utils.TransformNode(node=n) for n in nodes]

    # Find controlled nodes from controller nodes
    ctrl_to_ctrlled_map = {}
    for tfm_node in tfm_nodes:
        node = tfm_node.get_node()
        constraints = _get_constraints_from_ctrls(node)
        dests = _get_destination_nodes_from_ctrls(constraints)
        if len(dests) == 0:
            continue
        dests = _sort_by_hierarchy(dests, children_first=True)
        ctrl_to_ctrlled_map[node] = (constraints, dests)

    # Query keyframe times on controller nodes.
    start_frame, end_frame = time_utils.get_maya_timeline_range_outer()
    keytime_obj = keytime_utils.KeyframeTimes()
    for node in nodes:
        keytime_obj.add_node_attrs(node, const.TFM_ATTRS, start_frame,
                                   end_frame)
    fallback_frame_range = keytime_obj.sum_frame_range_for_nodes(nodes)
    fallback_times = list(
        range(fallback_frame_range[0], fallback_frame_range[1] + 1))

    # Query keyframe times on each node attribute
    key_times_map = time_utils.get_keyframe_times_for_node_attrs(
        nodes, const.TFM_ATTRS)

    # Query transform matrix on controlled nodes.
    cache = tfm_utils.TransformMatrixCache()
    for src_node, (constraints, dst_nodes) in ctrl_to_ctrlled_map.items():
        times = key_times_map.get(src_node, [current_frame])
        assert len(times) > 0
        ctrl = tfm_utils.TransformNode(node=src_node)
        cache.add_node(ctrl, times)
        for dst_node in dst_nodes:
            dst = tfm_utils.TransformNode(node=dst_node)
            cache.add_node(dst, times)
    cache.process(eval_mode=eval_mode)

    # Get Controlled nodes
    ctrlled_nodes = set()
    for src_node, (_, dst_nodes) in ctrl_to_ctrlled_map.items():
        for dst_node in dst_nodes:
            ctrlled_nodes.add(dst_node)

    # Delete constraints on controlled nodes.
    const_nodes = set()
    for src_node, (constraints, _) in ctrl_to_ctrlled_map.items():
        assert src_node not in constraints
        const_nodes |= constraints
    if len(const_nodes) > 0:
        maya.cmds.delete(list(const_nodes))

    # Set keyframes (per-frame) on controlled nodes
    for ctrl_node, (_, ctrlled_nodes) in ctrl_to_ctrlled_map.items():
        times = key_times_map.get(ctrl_node, [current_frame])
        ctrl = tfm_utils.TransformNode(node=ctrl_node)
        for ctrlled_node in ctrlled_nodes:
            ctrlled = tfm_utils.TransformNode(node=ctrlled_node)
            tfm_utils.set_transform_values(cache,
                                           times,
                                           ctrl,
                                           ctrlled,
                                           delete_static_anim_curves=False)

    parent_nodes = []
    anim_curves = []
    for src_node, (_, dst_nodes) in ctrl_to_ctrlled_map.items():
        src_times = key_times_map.get(src_node, [current_frame])
        assert len(src_times) > 0
        ctrl = tfm_utils.TransformNode(node=src_node)
        for dst_node in dst_nodes:
            dst = tfm_utils.TransformNode(node=dst_node)
            tfm_utils.set_transform_values(cache,
                                           src_times,
                                           ctrl,
                                           dst,
                                           delete_static_anim_curves=False)

            # Re-parent controller child nodes under controlled node.
            ctrl_children = maya.cmds.listRelatives(
                src_node,
                children=True,
                shapes=False,
                fullPath=True,
                type='transform',
            ) or []
            for child_node in ctrl_children:
                if child_node in nodes:
                    continue
                child = tfm_utils.TransformNode(node=child_node)
                parent_nodes.append((child, dst))

            src_had_keys = key_times_map.get(src_node) is not None
            if src_had_keys is True:
                continue
            # Maintain that destination node will not have keyframes now, the
            # same as the source node.
            dst_node = dst.get_node()
            keyable_attrs = _get_keyable_attrs(dst_node, const.TFM_ATTRS)
            anim_curves += anim_utils.get_anim_curves_from_nodes(
                list(keyable_attrs), )

    # Reparent children back to under the controlled.
    for src, dst in parent_nodes:
        src_node = src.get_node()
        dst_node = dst.get_node()
        maya.cmds.parent(src_node, dst_node, absolute=True)

    # Remove animation curves.
    anim_curves = [
        n for n in anim_curves if node_utils.node_is_referenced(n) is False
    ]
    if len(anim_curves) > 0:
        maya.cmds.delete(anim_curves)

    # Delete controller nodes
    ctrl_nodes = [n.get_node() for n in tfm_nodes]
    if len(ctrl_nodes) > 0:
        maya.cmds.delete(ctrl_nodes)
    return list(ctrlled_nodes)
Пример #7
0
def create(nodes, current_frame=None, eval_mode=None):
    """
    Create a Controller for the given nodes.

    :param nodes: The nodes to create Controller for.
    :type nodes: [str, ..]

    :param current_frame: What frame number is considered to be
                          'current' when evaluating transforms without
                          any keyframes.
    :type current_frame: float or int

    :param eval_mode: What type of transform evaluation method to use?
    :type eval_mode: mmSolver.utils.constant.EVAL_MODE_*

    :returns: List of controller transform nodes.
    :rtype: [str, ..]
    """
    if current_frame is None:
        current_frame = maya.cmds.currentTime(query=True)
    assert current_frame is not None
    sparse = False

    tfm_nodes = [tfm_utils.TransformNode(node=n) for n in nodes]

    # Force into long-names.
    nodes = [n.get_node() for n in tfm_nodes]

    # Ensure node attributes are editable.
    keyable_attrs = set()
    for node in nodes:
        keyable_attrs |= _get_keyable_attrs(node, const.TFM_ATTRS)

    # Query keyframe times on each node attribute
    start_frame, end_frame = time_utils.get_maya_timeline_range_outer()
    keytime_obj = keytime_utils.KeyframeTimes()
    for node in nodes:
        keytime_obj.add_node_attrs(node, const.TFM_ATTRS, start_frame,
                                   end_frame)
    fallback_frame_range = keytime_obj.sum_frame_range_for_nodes(nodes)
    fallback_times = list(
        range(fallback_frame_range[0], fallback_frame_range[1] + 1))
    key_times_map = time_utils.get_keyframe_times_for_node_attrs(
        nodes, const.TFM_ATTRS)

    # Query the transform matrix for the nodes
    cache = tfm_utils.TransformMatrixCache()
    for tfm_node in tfm_nodes:
        node = tfm_node.get_node()
        times = key_times_map.get(node, [current_frame])
        cache.add_node(tfm_node, times)
    cache.process(eval_mode=eval_mode)

    depth_to_tfm_node_map = _sort_hierarchy_depth_to_tfm_nodes(tfm_nodes)
    nodes_parent = _get_node_parent_map(nodes)

    # Create new (locator) node for each input node
    ctrl_list = []
    node_to_ctrl_map = {}
    node_to_ctrl_tfm_map = {}
    depths = sorted(depth_to_tfm_node_map.keys())
    for depth in depths:
        depth_tfm_nodes = depth_to_tfm_node_map.get(depth)
        assert depth_tfm_nodes is not None
        sorted_tfm_nodes = sorted(depth_tfm_nodes, key=lambda x: x.get_node())
        for tfm_node in sorted_tfm_nodes:
            node = tfm_node.get_node()
            node_parent = nodes_parent.get(node)
            if node_parent is not None:
                node_parent = node_to_ctrl_map.get(node_parent)
            name = node.rpartition('|')[-1]
            assert '|' not in name
            name = name.replace(':', '_')
            name = name + '_CTRL'
            name = mmapi.find_valid_maya_node_name(name)
            tfm = maya.cmds.createNode('transform',
                                       name=name,
                                       parent=node_parent)
            tfm = node_utils.get_long_name(tfm)
            shape_name = name + 'Shape'
            maya.cmds.createNode('locator', name=shape_name, parent=tfm)
            rot_order = maya.cmds.xform(node, query=True, rotateOrder=True)
            maya.cmds.xform(tfm, rotateOrder=rot_order, preserve=True)
            ctrl_tfm = tfm_utils.TransformNode(node=tfm)
            ctrl_list.append(tfm)
            node_to_ctrl_map[node] = tfm
            node_to_ctrl_tfm_map[node] = ctrl_tfm

    # Set transform matrix on new node
    anim_curves = []
    for src in tfm_nodes:
        src_node = src.get_node()
        src_times = key_times_map.get(src_node, [current_frame])
        dst = node_to_ctrl_tfm_map.get(src_node)
        assert len(src_times) > 0
        tfm_utils.set_transform_values(cache,
                                       src_times,
                                       src,
                                       dst,
                                       delete_static_anim_curves=False,
                                       eval_mode=eval_mode)
        src_had_keys = key_times_map.get(src_node) is not None
        if src_had_keys is True:
            continue
        # Maintain that destination node will not have keyframes now, the
        # same as the source node.
        dst_node = dst.get_node()
        keyable_attrs = _get_keyable_attrs(dst_node, const.TFM_ATTRS)
        anim_curves += anim_utils.get_anim_curves_from_nodes(
            list(keyable_attrs), )
    anim_curves = [
        n for n in anim_curves if node_utils.node_is_referenced(n) is False
    ]
    if len(anim_curves) > 0:
        maya.cmds.delete(anim_curves)

    # Delete all keyframes on controlled nodes
    keyable_attrs = set()
    for tfm_node in tfm_nodes:
        node = tfm_node.get_node()
        keyable_attrs |= _get_keyable_attrs(node, const.TFM_ATTRS)
    anim_curves = anim_utils.get_anim_curves_from_nodes(list(keyable_attrs), )
    anim_curves = [
        n for n in anim_curves if node_utils.node_is_referenced(n) is False
    ]
    if len(anim_curves) > 0:
        maya.cmds.delete(anim_curves)

    # Create constraint(s) to previous nodes.
    for tfm_node in tfm_nodes:
        src_node = tfm_node.get_node()
        ctrl = node_to_ctrl_tfm_map.get(src_node)
        dst_node = ctrl.get_node()
        _create_constraint(src_node, dst_node)
    return ctrl_list
    def test_set_transform_values_with_rotate_pivot(self):
        path = self.get_data_path('scenes', 'bookHierarchy.ma')
        maya.cmds.file(path, open=True, force=True)

        book_node = 'book_GRP'
        spine_node = 'spine_GRP'
        cover_node = 'front_cover_GRP'

        maya.cmds.setAttr(book_node + '.ty', 10.0)
        maya.cmds.setAttr(book_node + '.rz', 90.0)
        maya.cmds.setAttr(spine_node + '.rz', 90.0)
        maya.cmds.setAttr(cover_node + '.rz', 90.0)

        book_tfm = mod.TransformNode(book_node)
        spine_tfm = mod.TransformNode(spine_node)
        cover_tfm = mod.TransformNode(cover_node)
        tfm_nodes = [book_tfm, spine_tfm, cover_tfm]

        current_frame = maya.cmds.currentTime(query=True)
        frame_range = [current_frame]

        # Query the transform matrix for the nodes
        cache = mod.TransformMatrixCache()
        for tfm_node in tfm_nodes:
            cache.add_node(tfm_node, frame_range)
        cache.process()

        book_dst_node = maya.cmds.createNode('transform', name='book_CTRL')
        book_dst_tfm_node = mod.TransformNode(node=book_dst_node)
        mod.set_transform_values(cache,
                                 frame_range,
                                 book_tfm,
                                 book_dst_tfm_node,
                                 delete_static_anim_curves=False)

        spine_dst_node = maya.cmds.createNode('transform', name='spine_CTRL')
        spine_dst_tfm_node = mod.TransformNode(node=spine_dst_node)
        mod.set_transform_values(cache,
                                 frame_range,
                                 spine_tfm,
                                 spine_dst_tfm_node,
                                 delete_static_anim_curves=False)

        cover_dst_node = maya.cmds.createNode('transform', name='cover_CTRL')
        cover_dst_tfm_node = mod.TransformNode(node=cover_dst_node)
        mod.set_transform_values(cache,
                                 frame_range,
                                 cover_tfm,
                                 cover_dst_tfm_node,
                                 delete_static_anim_curves=False)

        # save the output scene file
        path = 'test_transform_set_transforms_with_rotate_pivot.ma'
        path = self.get_data_path(path)
        maya.cmds.file(rename=path)
        maya.cmds.file(save=True, type='mayaAscii', force=True)

        # Expected Matrices
        expected_book_matrix = [
            0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
            10.0, 0.0, 1.0
        ]
        expected_spine_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.3518918752670288, 8.476484298706055, 0.0029969215393066406, 1.0
        ]
        expected_cover_matrix = [
            0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
            0.3488234877586365, 7.9185943603515625, 0.0029969215393066406, 1.0
        ]
        expected_spine_par_inv_matrix = [
            0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -10.0,
            0.0, 0.0, 1.0
        ]
        expected_front_cover_par_inv_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,
            -1.1716232898755894, 8.124592860140336, 0.0, 1.0
        ]

        # Confirm attributes in the cache are correct
        book_attrs = cache.get_attrs_for_node(book_tfm)
        self.assertItemsEqual(book_attrs, ["worldMatrix[0]"])

        attr_names_with_pivot = [
            "worldMatrix[0]",
            "matrix",
            "parentInverseMatrix[0]",
            "rotatePivotX",
            "rotatePivotY",
            "rotatePivotZ",
        ]
        spine_attrs = cache.get_attrs_for_node(spine_tfm)
        self.assertItemsEqual(spine_attrs, attr_names_with_pivot)

        cover_attrs = cache.get_attrs_for_node(cover_tfm)
        self.assertItemsEqual(cover_attrs, attr_names_with_pivot)

        # Confirm matrix values in the cache are correct
        book_world_matrix = list(
            cache.get_node_attr(book_tfm, "worldMatrix[0]", frame_range)[0])
        self.assertGreater(
            closeness.compare_floats(book_world_matrix, expected_book_matrix),
            closeness.DEFAULT_SIGNIFICANT_DIGITS)

        spine_par_inv_matrix = list(
            cache.get_node_attr(spine_tfm, "parentInverseMatrix[0]",
                                frame_range)[0])
        self.assertGreater(
            closeness.compare_floats(spine_par_inv_matrix,
                                     expected_spine_par_inv_matrix),
            closeness.DEFAULT_SIGNIFICANT_DIGITS)

        cover_par_inv_matrix = list(
            cache.get_node_attr(cover_tfm, "parentInverseMatrix[0]",
                                frame_range)[0])
        self.assertGreater(
            closeness.compare_floats(cover_par_inv_matrix,
                                     expected_front_cover_par_inv_matrix),
            closeness.DEFAULT_SIGNIFICANT_DIGITS)

        # Compare destination node matrices with the original
        book_matrix = maya.cmds.xform(book_dst_node,
                                      query=True,
                                      matrix=True,
                                      worldSpace=True)
        self.assertGreater(
            closeness.compare_floats(book_matrix, expected_book_matrix),
            closeness.DEFAULT_SIGNIFICANT_DIGITS)

        spine_matrix = maya.cmds.xform(spine_dst_node,
                                       query=True,
                                       matrix=True,
                                       worldSpace=True)
        self.assertGreater(
            closeness.compare_floats(spine_matrix, expected_spine_matrix),
            closeness.DEFAULT_SIGNIFICANT_DIGITS)

        cover_matrix = maya.cmds.xform(cover_dst_node,
                                       query=True,
                                       matrix=True,
                                       worldSpace=True)
        self.assertGreater(
            closeness.compare_floats(cover_matrix, expected_cover_matrix),
            closeness.DEFAULT_SIGNIFICANT_DIGITS)
        return
    def test_get_transform_matrix_list_45degrees(self):
        path = self.get_data_path('scenes', 'bookHierarchy.ma')
        maya.cmds.file(path, open=True, force=True)

        book_node = 'book_GRP'
        spine_node = 'spine_GRP'
        cover_node = 'front_cover_GRP'
        latch_node = 'latch_GRP'

        maya.cmds.setAttr(book_node + '.ty', 10.0)
        maya.cmds.setAttr(book_node + '.rz', 45.0)  # <<< 45 degrees
        maya.cmds.setAttr(spine_node + '.rz', 90.0)
        maya.cmds.setAttr(cover_node + '.rz', 90.0)

        book_tfm = mod.TransformNode(book_node)
        spine_tfm = mod.TransformNode(spine_node)
        cover_tfm = mod.TransformNode(cover_node)
        latch_tfm = mod.TransformNode(latch_node)
        tfm_nodes = [book_tfm, spine_tfm, cover_tfm, latch_tfm]

        current_frame = maya.cmds.currentTime(query=True)
        frame_range = [current_frame]

        # Query the transform matrix for the nodes
        cache = mod.TransformMatrixCache()
        for tfm_node in tfm_nodes:
            cache.add_node(tfm_node, frame_range)
        cache.process()

        book_world_matrix_list = mod.get_transform_matrix_list(
            cache, frame_range, book_tfm)
        self.assertEqual(len(book_world_matrix_list), 1)
        book_world_matrix = list(book_world_matrix_list[0].asMatrix())

        spine_world_matrix_list = mod.get_transform_matrix_list(
            cache, frame_range, spine_tfm)
        self.assertEqual(len(spine_world_matrix_list), 1)
        spine_world_matrix = list(spine_world_matrix_list[0].asMatrix())

        cover_world_matrix_list = mod.get_transform_matrix_list(
            cache, frame_range, cover_tfm)
        self.assertEqual(len(cover_world_matrix_list), 1)
        cover_world_matrix = list(cover_world_matrix_list[0].asMatrix())

        latch_world_matrix_list = mod.get_transform_matrix_list(
            cache, frame_range, latch_tfm)
        self.assertEqual(len(latch_world_matrix_list), 1)
        latch_world_matrix = list(latch_world_matrix_list[0].asMatrix())

        # Expected Matrices
        expected_book_matrix = [
            0.7071067811865475, 0.7071067811865476, 0.0, 0.0,
            -0.7071067811865476, 0.7071067811865475, 0.0, 0.0, 0.0, 0.0, 1.0,
            0.0, 0.0, 10.0, 0.0, 1.0
        ]
        expected_spine_matrix = [
            -0.7071067811865475, 0.7071067811865477, 0.0, 0.0,
            -0.7071067811865477, -0.7071067811865475, 0.0, 0.0, 0.0, 0.0, 1.0,
            0.0, -0.8284631523833599, 8.673886585125107, 0.0029969215393066406,
            1.0
        ]
        expected_cover_matrix = [
            -0.7071067811865479, -0.7071067811865474, 0.0, 0.0,
            0.7071067811865474, -0.7071067811865479, 0.0, 0.0, 0.0, 0.0, 1.0,
            0.0, -1.2251205885640575, 8.281568504173393, 0.0029969215393066406,
            1.0
        ]
        expected_latch_matrix = [
            0.7071067811865475, 0.7071067811865476, 0.0, 0.0,
            -0.7071067811865476, 0.7071067811865475, 0.0, 0.0, 0.0, 0.0, 1.0,
            0.0, 1.417462229728698, 10.932249069213867, 0.0001980811357498169,
            1.0
        ]

        # Confirm matrix values in the cache are correct
        self.assertGreater(
            closeness.compare_floats(book_world_matrix, expected_book_matrix),
            closeness.DEFAULT_SIGNIFICANT_DIGITS)

        tol = 0.000001
        mat_a = OpenMaya2.MMatrix(book_world_matrix)
        mat_b = OpenMaya2.MMatrix(expected_book_matrix)
        self.assertTrue(mat_a.isEquivalent(mat_b, tol))

        self.assertGreater(
            closeness.compare_floats(spine_world_matrix,
                                     expected_spine_matrix),
            closeness.DEFAULT_SIGNIFICANT_DIGITS)
        mat_a = OpenMaya2.MMatrix(spine_world_matrix)
        mat_b = OpenMaya2.MMatrix(expected_spine_matrix)
        self.assertTrue(mat_a.isEquivalent(mat_b, tol))

        self.assertGreater(
            closeness.compare_floats(cover_world_matrix,
                                     expected_cover_matrix),
            closeness.DEFAULT_SIGNIFICANT_DIGITS)
        mat_a = OpenMaya2.MMatrix(cover_world_matrix)
        mat_b = OpenMaya2.MMatrix(expected_cover_matrix)
        self.assertTrue(mat_a.isEquivalent(mat_b, tol))

        self.assertGreater(
            closeness.compare_floats(latch_world_matrix,
                                     expected_latch_matrix),
            closeness.DEFAULT_SIGNIFICANT_DIGITS)
        mat_a = OpenMaya2.MMatrix(latch_world_matrix)
        mat_b = OpenMaya2.MMatrix(expected_latch_matrix)
        self.assertTrue(mat_a.isEquivalent(mat_b, tol))
        return
    def test_get_transform_matrix_list_90degrees(self):
        path = self.get_data_path('scenes', 'bookHierarchy.ma')
        maya.cmds.file(path, open=True, force=True)

        book_node = 'book_GRP'
        spine_node = 'spine_GRP'
        cover_node = 'front_cover_GRP'
        latch_node = 'latch_GRP'

        maya.cmds.setAttr(book_node + '.ty', 10.0)
        maya.cmds.setAttr(book_node + '.rz', 90.0)  # <<< 90 degrees
        maya.cmds.setAttr(spine_node + '.rz', 90.0)
        maya.cmds.setAttr(cover_node + '.rz', 90.0)

        book_tfm = mod.TransformNode(book_node)
        spine_tfm = mod.TransformNode(spine_node)
        cover_tfm = mod.TransformNode(cover_node)
        latch_tfm = mod.TransformNode(latch_node)
        tfm_nodes = [book_tfm, spine_tfm, cover_tfm, latch_tfm]

        current_frame = maya.cmds.currentTime(query=True)
        frame_range = [current_frame]

        # Query the transform matrix for the nodes
        cache = mod.TransformMatrixCache()
        for tfm_node in tfm_nodes:
            cache.add_node(tfm_node, frame_range)
        cache.process()

        book_world_matrix_list = mod.get_transform_matrix_list(
            cache, frame_range, book_tfm)
        self.assertEqual(len(book_world_matrix_list), 1)
        book_world_matrix = list(book_world_matrix_list[0].asMatrix())

        spine_world_matrix_list = mod.get_transform_matrix_list(
            cache, frame_range, spine_tfm)
        self.assertEqual(len(spine_world_matrix_list), 1)
        spine_world_matrix = list(spine_world_matrix_list[0].asMatrix())

        cover_world_matrix_list = mod.get_transform_matrix_list(
            cache, frame_range, cover_tfm)
        self.assertEqual(len(cover_world_matrix_list), 1)
        cover_world_matrix = list(cover_world_matrix_list[0].asMatrix())

        latch_world_matrix_list = mod.get_transform_matrix_list(
            cache, frame_range, latch_tfm)
        self.assertEqual(len(latch_world_matrix_list), 1)
        latch_world_matrix = list(latch_world_matrix_list[0].asMatrix())

        # Expected Matrices
        expected_book_matrix = [
            0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
            10.0, 0.0, 1.0
        ]
        expected_spine_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.3518918752670288, 8.476484298706055, 0.0029969215393066406, 1.0
        ]
        expected_cover_matrix = [
            0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
            0.3488234877586365, 7.9185943603515625, 0.0029969215393066406, 1.0
        ]
        expected_latch_matrix = [
            0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
            0.3430972993373871, 11.661497116088867, 0.0001980811357498169, 1.0
        ]

        # Confirm matrix values in the cache are correct
        self.assertGreater(
            closeness.compare_floats(book_world_matrix, expected_book_matrix),
            closeness.DEFAULT_SIGNIFICANT_DIGITS)

        self.assertGreater(
            closeness.compare_floats(spine_world_matrix,
                                     expected_spine_matrix),
            closeness.DEFAULT_SIGNIFICANT_DIGITS)

        self.assertGreater(
            closeness.compare_floats(cover_world_matrix,
                                     expected_cover_matrix),
            closeness.DEFAULT_SIGNIFICANT_DIGITS)

        self.assertGreater(
            closeness.compare_floats(latch_world_matrix,
                                     expected_latch_matrix),
            closeness.DEFAULT_SIGNIFICANT_DIGITS)
        return
Пример #11
0
def remove(nodes, sparse=True):
    """
    Remove a controller and push the animation back to the controlled
    object.

    .. todo:: What should we do with any transforms parented under the
    controller? Should these objects be re-parented under the
    controlled object? Probably yes.

    """
    # Find controlled nodes from controller nodes
    ctrl_to_ctrlled_map = {}
    for ctrl_node in nodes:
        constraints = _get_constraints_from_ctrls(ctrl_node)
        dests = _get_destination_nodes_from_ctrls(constraints)
        if len(dests) == 0:
            continue
        ctrl_to_ctrlled_map[ctrl_node] = (constraints, dests)

    # Query keyframe times on controller nodes.
    start_frame, end_frame = time_utils.get_maya_timeline_range_outer()
    keytime_obj = keytime_utils.KeyframeTimes()
    for node in nodes:
        keytime_obj.add_node_attrs(node, const.TFM_ATTRS, start_frame, end_frame)
    fallback_frame_range = keytime_obj.sum_frame_range_for_nodes(nodes)
    fallback_times = list(range(fallback_frame_range[0],
                                fallback_frame_range[1]+1))

    # Query transform matrix on controlled nodes.
    cache = tfm_utils.TransformMatrixCache()
    for ctrl_node, (constraints, dest_nodes) in ctrl_to_ctrlled_map.items():
        times = keytime_obj.get_times(ctrl_node, sparse) or fallback_times
        ctrl = tfm_utils.TransformNode(node=ctrl_node)
        cache.add_node(ctrl, times)
        for dest_node in dest_nodes:
            dest = tfm_utils.TransformNode(node=dest_node)
            cache.add_node(dest, times)
    cache.process()

    # Get Controlled nodes
    ctrlled_nodes = set()
    for ctrl_node, (_, dest_nodes) in ctrl_to_ctrlled_map.items():
        for dest_node in dest_nodes:
            ctrlled_nodes.add(dest_node)

    # Delete constraints on controlled nodes.
    const_nodes = set()
    for ctrl_node, (constraints, _) in ctrl_to_ctrlled_map.items():
        const_nodes |= constraints
    if len(const_nodes) > 0:
        maya.cmds.delete(list(const_nodes))

    # Set keyframes (per-frame) on controlled nodes
    for ctrl_node, (_, ctrlled_nodes) in ctrl_to_ctrlled_map.items():
        times = keytime_obj.get_times(ctrl_node, sparse) or fallback_times
        ctrl = tfm_utils.TransformNode(node=ctrl_node)
        for ctrlled_node in ctrlled_nodes:
            ctrlled = tfm_utils.TransformNode(node=ctrlled_node)
            tfm_utils.set_transform_values(cache, times, ctrl, ctrlled,
                                           delete_static_anim_curves=False)

            # Re-parent controller child nodes under controlled node.
            ctrl_children = maya.cmds.listRelatives(
                ctrl_node,
                children=True,
                shapes=False,
                fullPath=True,
                type='transform',
            ) or []
            for child_node in ctrl_children:
                maya.cmds.parent(child_node, ctrlled_node, absolute=True)

    # Delete controller nodes
    ctrl_nodes = ctrl_to_ctrlled_map.keys()
    if len(ctrl_nodes) > 0:
        maya.cmds.delete(ctrl_nodes)
    return list(ctrlled_nodes)
Пример #12
0
def create(nodes, sparse=True):
    tfm_nodes = [tfm_utils.TransformNode(node=n) for n in nodes]

    # Force into long-names.
    nodes = [n.get_node() for n in tfm_nodes]

    # Ensure node attributes are editable.
    keyable_attrs = set()
    for node in nodes:
        keyable_attrs |= _get_keyable_attrs(node, const.TFM_ATTRS)

    # Query keyframe times on each node attribute
    start_frame, end_frame = time_utils.get_maya_timeline_range_outer()
    keytime_obj = keytime_utils.KeyframeTimes()
    for node in nodes:
        keytime_obj.add_node_attrs(node, const.TFM_ATTRS, start_frame, end_frame)
    fallback_frame_range = keytime_obj.sum_frame_range_for_nodes(nodes)
    fallback_times = list(range(fallback_frame_range[0],
                                fallback_frame_range[1]+1))

    # Query the transform matrix for the nodes
    cache = tfm_utils.TransformMatrixCache()
    for tfm_node in tfm_nodes:
        node = tfm_node.get_node()
        times = keytime_obj.get_times(node, sparse) or fallback_times
        cache.add_node(tfm_node, times)
    cache.process()

    # Create new (locator) node for each input node
    ctrl_list = []
    for tfm_node in tfm_nodes:
        node = tfm_node.get_node()
        name = node.rpartition('|')[-1]
        assert '|' not in name
        name = name.replace(':', '_')
        name = name + '_CTRL'
        name = mmapi.find_valid_maya_node_name(name)
        # TODO: Allow maintaining relative hierarchy of nodes.
        tfm = maya.cmds.createNode('transform', name=name)
        maya.cmds.createNode('locator', parent=tfm)
        rot_order = maya.cmds.xform(node, query=True, rotateOrder=True)
        maya.cmds.xform(tfm, rotateOrder=rot_order, preserve=True)
        ctrl_list.append(tfm)
    ctrl_tfm_nodes = [tfm_utils.TransformNode(node=tfm)
                      for tfm in ctrl_list]

    # Set transform matrix on new node
    for src, dst in zip(tfm_nodes, ctrl_tfm_nodes):
        src_node = src.get_node()
        times = keytime_obj.get_times(src_node, sparse) or fallback_times
        tfm_utils.set_transform_values(
            cache, times, src, dst,
            delete_static_anim_curves=False
        )
        if sparse is True:
            # Remove keyframes
            src_times = keytime_obj.get_times(src_node, sparse) or []
            dst_node = dst.get_node()
            if len(src_times) == 0:
                time_range = keytime_obj.get_frame_range_for_node(src_node)
                assert time_range[0] is not None
                assert time_range[1] is not None
                maya.cmds.cutKey(
                    dst_node,
                    attribute=const.TFM_ATTRS,
                    time=time_range,
                    clear=True
                )

    # Delete all keyframes on controlled nodes
    anim_curves = anim_utils.get_anim_curves_from_nodes(
        list(keyable_attrs),
    )
    anim_curves = [n for n in anim_curves
                   if node_utils.node_is_referenced(n) is False]
    if len(anim_curves) > 0:
        maya.cmds.delete(anim_curves)

    # Create constraint(s) to previous nodes.
    for tfm_node, ctrl in zip(tfm_nodes, ctrl_tfm_nodes):
        src_node = tfm_node.get_node()
        dst_node = ctrl.get_node()
        _create_constraint(src_node, dst_node)
    return ctrl_list
Пример #13
0
def reparent(children, parent, sparse=True, delete_static_anim_curves=False):
    """
    Reparent the children under the given parent.

    :param children: List of child nodes to be modified.
    :type children: [TransformNode, ..]

    :param parent: The new parent node for children, or None means
                   un-parent.
    :type parent: TransformNode or None

    :param sparse: Keyframe animation on the children each frame
                   (dense) or sparse (only at keyframes).
    :type sparse: bool

    :param delete_static_anim_curves: Delete any animCurves that all
                                      have the same values.
    :type delete_static_anim_curves: bool

    :returns: List of 'children' TransformNodes modified, will not
              contain child nodes if the child is already parented under
              'parent'.
    :rtype: [TransformNode, ..]
    """
    assert len(children) > 0
    assert isinstance(children[0], tfm_utils.TransformNode)
    assert parent is None or isinstance(parent, tfm_utils.TransformNode)
    assert isinstance(sparse, bool)
    assert isinstance(delete_static_anim_curves, bool)
    children_nodes = [tn.get_node() for tn in children]

    parent_parent_nodes = []
    if parent is not None:
        parent_node = parent.get_node()
        parent_parent_nodes = [parent_node]
        parent_parent_nodes += node_utils.get_node_parents(parent_node) or []

    # Query keyframe times on each node attribute
    start_frame, end_frame = time_utils.get_maya_timeline_range_outer()
    keytime_obj = keytime_utils.KeyframeTimes()
    for child_node in children_nodes:
        child_parent_nodes = list(parent_parent_nodes)
        child_parent_nodes += node_utils.get_node_parents(child_node) or []
        keytime_obj.add_node_attrs(child_node,
                                   TFM_ATTRS,
                                   start_frame,
                                   end_frame,
                                   parents=child_parent_nodes)
    fallback_frame_range = keytime_obj.sum_frame_range_for_nodes(
        children_nodes)
    fallback_times = list(
        range(fallback_frame_range[0], fallback_frame_range[1] + 1))

    # Query current transforms
    tfm_cache = tfm_utils.TransformMatrixCache()
    for tfm_node, node in zip(children, children_nodes):
        times = keytime_obj.get_times(node, sparse) or fallback_times
        tfm_cache.add_node_attr(tfm_node, 'worldMatrix[0]', times)
    tfm_cache.process()

    # Apply parenting logic for the children nodes.
    changed_list = [False] * len(children)
    if parent is not None:
        parent_node = parent.get_node()
        assert maya.cmds.objExists(parent_node)
        for i, tfm_node in enumerate(children):
            node = tfm_node.get_node()
            current_parent = tfm_node.get_parent()
            if current_parent == parent:
                continue
            maya.cmds.parent(node, parent_node, absolute=True)
            changed_list[i] = True
    else:
        for i, (tfm_node, node) in enumerate(zip(children, children_nodes)):
            current_parent = tfm_node.get_parent()
            if current_parent is None:
                continue
            maya.cmds.parent(node, world=True, absolute=True)
            changed_list[i] = True
    assert len(changed_list) == len(children)

    # Set transforms again.
    changed_tfm_nodes = [
        tn for tn, c in zip(children, changed_list) if c is True
    ]
    for tfm_node in changed_tfm_nodes:
        node = tfm_node.get_node()
        times = keytime_obj.get_times(node, sparse) or []
        if len(times) > 0:
            tfm_utils.set_transform_values(
                tfm_cache,
                times,
                tfm_node,
                tfm_node,
                delete_static_anim_curves=delete_static_anim_curves,
            )
    return changed_tfm_nodes