def create_screen_space_motion_trail(cam, tfm, name=None, use_frame_range=None, pre_frame=None, post_frame=None, start_frame=None, end_frame=None, increment=None): """ Create a Screen-Space Maya Locator that may be solved in Screen XYZ. """ assert isinstance(cam, pycompat.TEXT_TYPE) assert isinstance(tfm, pycompat.TEXT_TYPE) if name is None: name = tfm.rpartition('|')[-1] frame_range = time_utils.get_maya_timeline_range_inner() if use_frame_range is None: use_frame_range = const.USE_FRAME_RANGE_DEFAULT if pre_frame is None: pre_frame = const.PRE_FRAME_DEFAULT if post_frame is None: post_frame = const.POST_FRAME_DEFAULT if start_frame is None: start_frame = frame_range.start if end_frame is None: end_frame = frame_range.end if increment is None: if use_frame_range: increment = const.FRAME_RANGE_INCREMENT_DEFAULT else: increment = const.PER_FRAME_INCREMENT_DEFAULT tfm_attrs = [ 'translateX', 'translateY', 'translateZ', 'rotateX', 'rotateY', 'rotateZ', 'scaleX', 'scaleY', 'scaleZ' ] maya.cmds.loadPlugin('matrixNodes', quiet=True) cam_tfm, cam_shp = camera_utils.get_camera(cam) # Create temporary group temp_grp_name = const.TEMP_OBJECT_NAME temp_grp = temp_grp_name if not maya.cmds.objExists(temp_grp): temp_grp = maya.cmds.createNode('transform', name=temp_grp_name) maya.cmds.setAttr(temp_grp + '.visibility', False) # Create Temporary transform node to calculate motion path on. temp_tfm_name = name + '_TEMP_NULL' temp_tfm_name = mmapi.find_valid_maya_node_name(temp_tfm_name) temp_tfm = maya.cmds.createNode('transform', parent=temp_grp, name=temp_tfm_name) # Create trail group under the camera. trail_handle_grp_name = const.MOTION_PATH_GROUP_NAME trail_handle_grp = cam_tfm + '|' + trail_handle_grp_name if not maya.cmds.objExists(trail_handle_grp): trail_handle_grp = maya.cmds.createNode('transform', name=trail_handle_grp_name, parent=cam_tfm) # Trails are non-selectable by default. plug_name = trail_handle_grp + '.template' maya.cmds.setAttr(plug_name, True) # Lock transform attributes. for attr in tfm_attrs: plug_name = trail_handle_grp + '.' + attr maya.cmds.setAttr(plug_name, lock=True) # Matrix Multiply mult_mat = maya.cmds.createNode('multMatrix') src = tfm + '.worldMatrix[0]' dst = mult_mat + '.matrixIn[0]' maya.cmds.connectAttr(src, dst) src = cam_tfm + '.worldInverseMatrix[0]' dst = mult_mat + '.matrixIn[1]' maya.cmds.connectAttr(src, dst) # Decompose Matrix decompose = maya.cmds.createNode('decomposeMatrix') src = mult_mat + '.matrixSum' dst = decompose + '.inputMatrix' maya.cmds.connectAttr(src, dst) src = decompose + '.outputTranslate' dst = temp_tfm + '.translate' maya.cmds.connectAttr(src, dst) # Lock the temporary transform node. for attr in tfm_attrs: plug_name = temp_tfm + '.' + attr maya.cmds.setAttr(plug_name, lock=True) # Create Motion Trail update_mode = 'always' handle_tfm, handle_shp, trail_shp = create_motion_trail_setup( temp_tfm, trail_handle_grp, name, use_frame_range, start_frame, end_frame, pre_frame, post_frame, increment, update_mode, ) return handle_tfm, handle_shp, trail_shp
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 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