def decompose_matrix(tfm_matrix, prv_rot): """ Decompose a MTransformationMatrix into transform attributes. .. note:: It is assumed the given matrix is already re-ordered into the desired rotation order. :param tfm_matrix: Transform matrix to be decomposed. :type tfm_matrix: maya.api.OpenMaya.MTransformationMatrix :param prv_rot: The previous rotation values (on the previous frame). :type prv_rot: (float, float, float) or None :returns: Tuple of 9 values: TX, TY, TZ, RX, RY, RZ, SX, SY and SZ. :rtype: (float, float, float, float, float, float, float, float, float) """ space = OpenMaya2.MSpace.kWorld # Decompose matrix into components trans = tfm_matrix.translation(space) scl = tfm_matrix.scale(space) rot = tfm_matrix.rotation(asQuaternion=False) # Convert and clean rotation values trans = (trans[0], trans[1], trans[2]) scl = (scl[0], scl[1], scl[2]) rot = (math.degrees(rot[0]), math.degrees(rot[1]), math.degrees(rot[2])) if prv_rot is not None: rot = (animcurve_utils.euler_filter_value(prv_rot[0], rot[0]), animcurve_utils.euler_filter_value(prv_rot[1], rot[1]), animcurve_utils.euler_filter_value(prv_rot[2], rot[2])) prv_rot = rot return tuple(trans + rot + scl)
def set_transform_values(tfm_matrix_cache, times, src_tfm_node, dst_tfm_node, rotate_order=None, delete_static_anim_curves=False, eval_mode=None): """ Set transform node values on a destination node at times, using previously evaluated cached values. src_tfm_node is used to look-up into the cache for values. dst_tfm_node is the node that will be set values on. It is possible to have src_tfm_node and dst_tfm_node reference the same Maya node, or even the same object. .. note:: The function assumes the given destination node has no locked attributes. :param tfm_matrix_cache: A cache holding queried matrix values. :type tfm_matrix_cache: TransformMatrixCache :param times: The times to set transforms values on. :type times: [int or float, ...] :param src_tfm_node: Source node to get cached transform values from. :type src_tfm_node: TransformNode :param dst_tfm_node: Destination node set transform values on. :type dst_tfm_node: TransformNode :param rotate_order: The rotation order to set on the dst_node, or use the existing rotation on the dst_node if rotate_order is None. :type rotate_order: str :param delete_static_anim_curves: If an animation curve is static, it will be deleted. :type delete_static_anim_curves: bool :param eval_mode: What type of evaluation method to use? :type eval_mode: mmSolver.utils.constant.EVAL_MODE_* :rtype: None """ assert isinstance(tfm_matrix_cache, TransformMatrixCache) assert isinstance(times, (list, tuple)) assert isinstance(src_tfm_node, TransformNode) assert isinstance(dst_tfm_node, TransformNode) assert rotate_order is None or isinstance(rotate_order, (str, unicode)) if eval_mode is None: eval_mode = const.EVAL_MODE_DEFAULT assert eval_mode in const.EVAL_MODE_LIST current_frame = maya.cmds.currentTime(query=True) space = OpenMaya2.MSpace.kWorld attrs = [ 'translateX', 'translateY', 'translateZ', 'rotateX', 'rotateY', 'rotateZ', 'scaleX', 'scaleY', 'scaleZ' ] dst_node = dst_tfm_node.get_node() if rotate_order is None: rotate_order = maya.cmds.xform(dst_node, query=True, rotateOrder=True) else: maya.cmds.xform(dst_node, edit=True, rotateOrder=rotate_order) assert rotate_order in const.ROTATE_ORDER_STR_LIST rotate_order_api = ROTATE_ORDER_STR_TO_APITWO_CONSTANT[rotate_order] # Get destination node plug. dst_node = dst_tfm_node.get_node() dst_name = dst_node + '.parentInverseMatrix[0]' parent_inv_matrix_plug = node_utils.get_as_plug_apitwo(dst_name) # Query the matrix of nodes. world_mat_list = get_transform_matrix_list(tfm_matrix_cache, times, src_tfm_node, rotate_order=rotate_order) assert len(world_mat_list) == len(times) # Set transform dst_node = dst_tfm_node.get_node() prv_rot = None for t, world_mat in zip(times, world_mat_list): assert t is not None assert world_mat is not None parent_inv_mat = None if eval_mode == const.EVAL_MODE_API_DG_CONTEXT: ctx = create_dg_context_apitwo(t) parent_inv_mat = get_matrix_from_plug_apitwo( parent_inv_matrix_plug, ctx) elif eval_mode == const.EVAL_MODE_TIME_SWITCH_GET_ATTR: maya.cmds.currentTime(t, update=True) plug_name = parent_inv_matrix_plug.name() parent_inv_mat = maya.cmds.getAttr(plug_name) parent_inv_mat = OpenMaya2.MMatrix(parent_inv_mat) else: msg = 'eval_mode does not have a valid value' raise ValueError(msg % eval_mode) local_mat = world_mat.asMatrix() * parent_inv_mat local_mat = OpenMaya2.MTransformationMatrix(local_mat) local_mat.reorderRotation(rotate_order_api) # Decompose matrix into components trans = local_mat.translation(space) scl = local_mat.scale(space) rot = local_mat.rotation(asQuaternion=False) # Convert and clean rotation values trans = (trans[0], trans[1], trans[2]) scl = (scl[0], scl[1], scl[2]) rot = (math.degrees(rot[0]), math.degrees(rot[1]), math.degrees(rot[2])) if prv_rot is not None: rot = (animcurve_utils.euler_filter_value(prv_rot[0], rot[0]), animcurve_utils.euler_filter_value(prv_rot[1], rot[1]), animcurve_utils.euler_filter_value(prv_rot[2], rot[2])) prv_rot = rot # Set Keyframes values = trans + rot + scl assert len(attrs) == len(values) for attr, v in zip(attrs, values): maya.cmds.setKeyframe(dst_node, attribute=attr, time=t, value=v) if delete_static_anim_curves is True: maya.cmds.delete(dst_node, staticChannels=True) if eval_mode == const.EVAL_MODE_TIME_SWITCH_GET_ATTR: maya.cmds.currentTime(current_frame, update=True) return
def set_transform_values(tfm_matrix_cache, times, src_tfm_node, dst_tfm_node, rotate_order=None, delete_static_anim_curves=True): """ Set transform node values on a destination node at times, using previously evaluated cached values. src_tfm_node is used to look-up into the cache for values. dst_tfm_node is the node that will be set values on. It is possible to have src_tfm_node and dst_tfm_node reference the same Maya node, or even the same object. .. note:: The function assumes the given destination node has no locked attributes. :param tfm_matrix_cache: A cache holding queried matrix values. :type tfm_matrix_cache: TransformMatrixCache :param times: The times to set transforms values on. :type times: [int or float, ...] :param src_tfm_node: Source node to get cached transform values from. :type src_tfm_node: TransformNode :param dst_tfm_node: Destination node set transform values on. :type dst_tfm_node: TransformNode :param rotate_order: The rotation order to set on the dst_node, or use the existing rotation on the dst_node if rotate_order is None. :type rotate_order: str :param delete_static_anim_curves: If an animation curve is static, it will be deleted. :type delete_static_anim_curves: bool :rtype: None """ assert isinstance(tfm_matrix_cache, TransformMatrixCache) assert isinstance(times, (list, tuple)) assert isinstance(src_tfm_node, TransformNode) assert isinstance(dst_tfm_node, TransformNode) assert rotate_order is None or isinstance(rotate_order, (str, unicode)) space = OpenMaya2.MSpace.kWorld attrs = [ 'translateX', 'translateY', 'translateZ', 'rotateX', 'rotateY', 'rotateZ', 'scaleX', 'scaleY', 'scaleZ' ] dst_node = dst_tfm_node.get_node() if rotate_order is None: rotate_order = maya.cmds.xform( dst_node, query=True, rotateOrder=True) else: maya.cmds.xform( dst_node, edit=True, rotateOrder=rotate_order) assert rotate_order in const.ROTATE_ORDER_STR_LIST rotate_order = ROTATE_ORDER_STR_TO_APITWO_CONSTANT[rotate_order] # Get destination node plug. src_node = src_tfm_node.get_node() src_name = src_node + '.parentInverseMatrix[0]' parent_inv_matrix_plug = node_utils.get_as_plug_apitwo(src_name) # Query the matrix node. src_node_uuid = src_tfm_node.get_node_uuid() src_node_attrs = tfm_matrix_cache.get_attrs_for_node(src_node_uuid) with_pivot = len(src_node_attrs) > 1 world_mat_list = [] if with_pivot is False: world_mat_list = tfm_matrix_cache.get_node_attr_matrix( src_node_uuid, 'worldMatrix[0]', times, ) else: mat_list = tfm_matrix_cache.get_node_attr_matrix( src_node_uuid, 'matrix', times, ) assert len(mat_list) == len(times) par_inv_mat_list = tfm_matrix_cache.get_node_attr_matrix( src_node_uuid, 'parentInverseMatrix[0]', times, ) assert len(par_inv_mat_list) == len(times) rot_piv_x_list = tfm_matrix_cache.get_node_attr_matrix( src_node_uuid, 'rotatePivotX', times, ) assert len(rot_piv_x_list) == len(times) rot_piv_y_list = tfm_matrix_cache.get_node_attr_matrix( src_node_uuid, 'rotatePivotY', times, ) assert len(rot_piv_y_list) == len(times) rot_piv_z_list = tfm_matrix_cache.get_node_attr_matrix( src_node_uuid, 'rotatePivotZ', times, ) assert len(rot_piv_z_list) == len(times) # Reconstruct World-Matrix, accounting for pivot point. space = OpenMaya2.MSpace.kWorld loop_iter = zip(mat_list, par_inv_mat_list, rot_piv_x_list, rot_piv_y_list, rot_piv_z_list) for mat, par_inv_mat, rot_piv_x, rot_piv_y, rot_piv_z in loop_iter: assert mat is not None assert par_inv_mat is not None assert rot_piv_x is not None assert rot_piv_y is not None assert rot_piv_z is not None mat = OpenMaya2.MTransformationMatrix(mat) pivot = OpenMaya2.MVector(rot_piv_x, rot_piv_y, rot_piv_z) trans = mat.translation(space) mat.setTranslation(trans + pivot, space) mat = mat.asMatrix() world_mat = par_inv_mat * mat world_mat_list.append(world_mat) assert len(world_mat_list) == len(times) # Set transform dst_node = dst_tfm_node.get_node() prv_rot = None for t, world_mat in zip(times, world_mat_list): assert world_mat is not None ctx = create_dg_context_apitwo(t) parent_mat = get_matrix_from_plug_apitwo( parent_inv_matrix_plug, ctx ) local_mat = parent_mat * world_mat local_mat = OpenMaya2.MTransformationMatrix(local_mat) local_mat.reorderRotation(rotate_order) # Decompose matrix into components trans = local_mat.translation(space) scl = local_mat.scale(space) rot = local_mat.rotation(asQuaternion=False) # Convert and clean rotation values trans = (trans[0], trans[1], trans[2]) scl = (scl[0], scl[1], scl[2]) rot = ( math.degrees(rot[0]), math.degrees(rot[1]), math.degrees(rot[2]) ) if prv_rot is not None: rot = ( animcurve_utils.euler_filter_value(prv_rot[0], rot[0]), animcurve_utils.euler_filter_value(prv_rot[1], rot[1]), animcurve_utils.euler_filter_value(prv_rot[2], rot[2]) ) prv_rot = rot # Set Keyframes values = trans + rot + scl assert len(attrs) == len(values) for attr, v in zip(attrs, values): maya.cmds.setKeyframe(dst_node, attribute=attr, time=t, value=v) if delete_static_anim_curves is True: maya.cmds.delete(dst_node, staticChannels=True) return